Spaces:
Running
Running
| import { create } from 'zustand'; | |
| import { getSocket } from '../hooks/useWebSocket'; | |
| import { Project, FrameworkType } from '../types'; | |
| interface ProjectStore { | |
| projects: Project[]; | |
| currentProject: Project | null; | |
| loading: boolean; | |
| error: string | null; | |
| fetchProjects: () => Promise<void>; | |
| loadProject: (id: string) => Promise<void>; | |
| createProject: (name: string, framework: FrameworkType, description?: string) => Promise<Project>; | |
| updateProject: (id: string, updates: any) => Promise<void>; | |
| deleteProject: (id: string) => Promise<void>; | |
| setCurrentProject: (project: Project | null) => void; | |
| syncProject: (id: string) => Promise<void>; | |
| } | |
| function wsEmit<T>(event: string, data?: any): Promise<T> { | |
| return new Promise((resolve, reject) => { | |
| // Wait for socket to be connected (with timeout) | |
| const attempt = (tries: number) => { | |
| const socket = getSocket(); | |
| if (socket?.connected) { | |
| socket.emit(event, data ?? {}, (response: any) => { | |
| if (response?.error) reject(new Error(response.error)); | |
| else resolve(response as T); | |
| }); | |
| } else if (tries < 50) { | |
| setTimeout(() => attempt(tries + 1), 100); | |
| } else { | |
| reject(new Error('Not connected to server')); | |
| } | |
| }; | |
| attempt(0); | |
| }); | |
| } | |
| export const useProjectStore = create<ProjectStore>((set, get) => ({ | |
| projects: [], | |
| currentProject: null, | |
| loading: false, | |
| error: null, | |
| fetchProjects: async () => { | |
| set({ loading: true, error: null }); | |
| try { | |
| const { projects } = await wsEmit<{ projects: Project[] }>('project_list'); | |
| set({ projects, loading: false }); | |
| } catch (err: any) { | |
| set({ error: err.message, loading: false }); | |
| } | |
| }, | |
| loadProject: async (id: string) => { | |
| set({ loading: true, error: null }); | |
| try { | |
| const { project } = await wsEmit<{ project: Project }>('project_load', { projectId: id }); | |
| set({ currentProject: project, loading: false }); | |
| } catch (err: any) { | |
| set({ error: err.message, loading: false }); | |
| } | |
| }, | |
| createProject: async (name: string, framework: FrameworkType, description?: string) => { | |
| set({ loading: true, error: null }); | |
| try { | |
| const { project } = await wsEmit<{ project: Project }>('project_create', { | |
| name, framework, description, | |
| }); | |
| set((state) => ({ projects: [project, ...state.projects], loading: false })); | |
| return project; | |
| } catch (err: any) { | |
| set({ error: err.message, loading: false }); | |
| throw err; | |
| } | |
| }, | |
| updateProject: async (id: string, updates: any) => { | |
| try { | |
| await wsEmit('project_update', { projectId: id, updates }); | |
| set((state) => ({ | |
| currentProject: state.currentProject?.id === id | |
| ? { ...state.currentProject, ...updates } | |
| : state.currentProject, | |
| })); | |
| } catch (err: any) { | |
| set({ error: err.message }); | |
| } | |
| }, | |
| deleteProject: async (id: string) => { | |
| try { | |
| await wsEmit('project_delete', { projectId: id }); | |
| set((state) => ({ | |
| projects: state.projects.filter((p) => p.id !== id), | |
| currentProject: state.currentProject?.id === id ? null : state.currentProject, | |
| })); | |
| } catch (err: any) { | |
| set({ error: err.message }); | |
| } | |
| }, | |
| setCurrentProject: (project) => set({ currentProject: project }), | |
| syncProject: async (id: string) => { | |
| try { | |
| await wsEmit('project_sync', { projectId: id }); | |
| } catch (err: any) { | |
| set({ error: err.message }); | |
| } | |
| }, | |
| })); | |