From d6e35e4749d2a48304f7985953ee71b7032b2023 Mon Sep 17 00:00:00 2001 From: Skylar Barrera Date: Mon, 25 Mar 2024 16:04:35 -0400 Subject: [PATCH] init browser state (#5552) * init browser state * get tab index * rm --- src/state/browserState/index.test.ts | 95 ++++++++++++++++++++++++++++ src/state/browserState/index.ts | 67 ++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/state/browserState/index.test.ts create mode 100644 src/state/browserState/index.ts diff --git a/src/state/browserState/index.test.ts b/src/state/browserState/index.test.ts new file mode 100644 index 00000000000..e2bf5143668 --- /dev/null +++ b/src/state/browserState/index.test.ts @@ -0,0 +1,95 @@ +import { useBrowserStateStore } from '.'; + +describe('BrowserStateStore', () => { + beforeEach(() => { + // Reset the store to its initial state before each test + useBrowserStateStore.setState( + { + tabs: [], + }, + true + ); // The second argument 'true' is to replace the state instead of merging + }); + + test('should be able to add a tab', () => { + const { addTab, tabs } = useBrowserStateStore.getState(); + expect(tabs.length).toBe(0); + addTab({ + name: 'Test Tab', + isActive: true, + screenshot: 'test_screenshot.png', + history: [ + { + name: 'Test Site', + url: 'https://test.com', + image: 'test_image.png', + timestamp: Date.now(), + }, + ], + }); + expect(useBrowserStateStore.getState().tabs.length).toBe(1); + }); + + test('should place new tabs at the end', () => { + const { addTab } = useBrowserStateStore.getState(); + addTab({ name: 'First Tab', screenshot: '', history: [], isActive: false }); + addTab({ name: 'Second Tab', screenshot: '', history: [], isActive: false }); + const tabs = useBrowserStateStore.getState().tabs; + expect(tabs[tabs.length - 1].name).toBe('Second Tab'); + }); + + test('should be able to delete a tab', () => { + const { addTab, deleteTab, tabs } = useBrowserStateStore.getState(); + addTab({ name: 'Tab to Delete', screenshot: '', history: [], isActive: false }); + expect(tabs.length).toBe(1); + deleteTab(0); + expect(useBrowserStateStore.getState().tabs.length).toBe(0); + }); + + test('should handle deleting the active tab', () => { + const { addTab, deleteTab, setActiveTab, getActiveTab } = useBrowserStateStore.getState(); + addTab({ name: 'Active Tab', screenshot: '', history: [], isActive: false }); + addTab({ name: 'Next Tab', screenshot: '', history: [], isActive: false }); + setActiveTab(0); + expect(getActiveTab()?.name).toBe('Active Tab'); + deleteTab(0); + expect(getActiveTab()?.name).toBe('Next Tab'); + }); + + test('should be able to edit a tab', () => { + const { addTab, editTab, tabs } = useBrowserStateStore.getState(); + addTab({ name: 'Tab to Edit', screenshot: '', history: [], isActive: false }); + editTab(0, { name: 'Edited Tab' }); + expect(tabs[0].name).toBe('Edited Tab'); + }); + + test('editing a non-existent tab should do nothing', () => { + const { editTab, tabs } = useBrowserStateStore.getState(); + editTab(999, { name: 'Ghost Tab' }); // Assuming there's no tab at index 999 + expect(tabs.length).toBe(0); // No tabs should have been added or modified + }); + + test('should be able to set and get the active tab', () => { + const { addTab, setActiveTab, getActiveTab } = useBrowserStateStore.getState(); + addTab({ name: 'First Tab', screenshot: '', history: [], isActive: false }); + addTab({ name: 'Second Tab', screenshot: '', history: [], isActive: false }); + setActiveTab(1); + expect(getActiveTab()?.name).toBe('Second Tab'); + }); + + test('setting an active tab should deactivate others', () => { + const { addTab, setActiveTab, tabs } = useBrowserStateStore.getState(); + addTab({ name: 'First Tab', screenshot: '', history: [], isActive: true }); + addTab({ name: 'Second Tab', screenshot: '', history: [], isActive: false }); + setActiveTab(1); + expect(tabs[0].isActive).toBe(false); + expect(tabs[1].isActive).toBe(true); + }); + + test('deleting the only tab should result in no active tabs', () => { + const { addTab, deleteTab, tabs } = useBrowserStateStore.getState(); + addTab({ name: 'Lonely Tab', screenshot: '', history: [], isActive: true }); + deleteTab(0); + expect(tabs.find(tab => tab.isActive)).toBe(undefined); + }); +}); diff --git a/src/state/browserState/index.ts b/src/state/browserState/index.ts new file mode 100644 index 00000000000..31165c16a44 --- /dev/null +++ b/src/state/browserState/index.ts @@ -0,0 +1,67 @@ +import create from 'zustand'; + +export interface Site { + name: string; + url: string; + image: string; + timestamp: number; // Assuming timestamp is a Unix timestamp for simplicity +} + +export interface Tab { + history: Site[]; + name: string; + screenshot: string; // Assuming this is a URL or base64 encoded image + isActive: boolean; +} + +interface BrowserState { + tabs: Tab[]; + addTab: (tab: Tab) => void; + deleteTab: (tabIndex: number) => void; + editTab: (tabIndex: number, newTabData: Partial) => void; + setActiveTab: (tabIndex: number) => void; + getActiveTab: () => Tab | undefined; + getActiveTabIndex: () => number; +} + +export const useBrowserStateStore = create((set, get) => ({ + tabs: [], // Initial state of tabs is an empty array for now + + addTab: tab => + set(state => ({ + tabs: [...state.tabs, { ...tab, isActive: false }], + })), + + deleteTab: tabIndex => + set(state => { + const newTabs = state.tabs.filter((_, index) => index !== tabIndex); + // If the deleted tab was active, set the next tab as active, or the previous one if it was the last tab + if (state.tabs[tabIndex].isActive) { + if (newTabs.length > 0) { + if (tabIndex === 0 || tabIndex < newTabs.length) { + newTabs[tabIndex].isActive = true; + } else { + newTabs[tabIndex - 1].isActive = true; + } + } + } + return { tabs: newTabs }; + }), + + editTab: (tabIndex, newTabData) => { + set(state => ({ + tabs: state.tabs.map((tab, index) => (index === tabIndex ? { ...tab, ...newTabData, timestamp: Date.now() } : tab)), + })); + }, + + setActiveTab: tabIndex => + set(state => ({ + tabs: state.tabs.map((tab, index) => ({ + ...tab, + isActive: index === tabIndex, + })), + })), + + getActiveTab: () => get().tabs.find(tab => tab.isActive), + getActiveTabIndex: () => get().tabs.findIndex(tab => tab.isActive), +}));