import { create, type StateCreator } from 'zustand' import { immer } from 'zustand/middleware/immer' function functionalUpdate (updater, previous) { return typeof updater === 'function' ? updater(previous) : updater } export type Store = { url: { page: Page context: PageContext } setPage: (page: Page, context?: PageContext) => void createProject: () => void } export type PageContext = { projectId?: string } export type Page = 'projects' | 'projects.project' const urlMiddleware = ( prev: StateCreator ): StateCreator => (set, get, api) => { const parseUrlState = () => { try { const search = new URLSearchParams(window.location.search.substring(1)).get( 'state' ) || '' const decoded = atob(search) return JSON.parse(decoded) } catch (e) { return } } const initialState = prev( (...args) => { set(...args) const stringified = JSON.stringify(get().url) const encoded = btoa(stringified) history.pushState(null, '', `/?state=${encoded}`) }, get, api ) window.addEventListener('popstate', () => { set((state) => { return { ...state, url: parseUrlState(), } }) }) return { ...initialState, url: parseUrlState() || initialState.url, } } export const useStore = create( urlMiddleware( immer((set) => { return { url: { page: 'projects', context: {}, }, setPage: (page, context) => set((draft) => { draft.url.page = page if (context) { draft.url.context = functionalUpdate(context, draft.url.context) } }), createProject: () => { set((draft) => { draft.url.page = 'projects.project' draft.url.context.projectId = undefined }) }, } }) ) )