feat: add project
This commit is contained in:
@@ -16,17 +16,22 @@ export interface ChartConfig {
|
||||
|
||||
interface DashboardState {
|
||||
charts: ChartConfig[];
|
||||
addChart: (chart: Omit<ChartConfig, 'layout'>) => void;
|
||||
removeChart: (id: string) => void;
|
||||
updateLayout: (layouts: GridLayout[]) => void;
|
||||
addChart: (chart: Omit<ChartConfig, 'layout'>, projectId: number) => void;
|
||||
removeChart: (id: string, projectId: number) => void;
|
||||
updateLayout: (layouts: GridLayout[], projectId: number) => void;
|
||||
loadCharts: (projectId: number) => void;
|
||||
}
|
||||
|
||||
const DASHBOARD_STORAGE_KEY = 'dashboard_charts_v1';
|
||||
const DASHBOARD_STORAGE_KEY_PREFIX = 'dashboard_charts_v1_project_';
|
||||
|
||||
function loadChartsFromStorage(): ChartConfig[] {
|
||||
function getStorageKey(projectId: number) {
|
||||
return `${DASHBOARD_STORAGE_KEY_PREFIX}${projectId}`;
|
||||
}
|
||||
|
||||
function loadChartsFromStorage(projectId: number): ChartConfig[] {
|
||||
if (typeof window === 'undefined') return [];
|
||||
try {
|
||||
const raw = window.localStorage.getItem(DASHBOARD_STORAGE_KEY);
|
||||
const raw = window.localStorage.getItem(getStorageKey(projectId));
|
||||
if (!raw) return [];
|
||||
const parsed = JSON.parse(raw);
|
||||
if (!Array.isArray(parsed)) return [];
|
||||
@@ -47,14 +52,17 @@ function loadChartsFromStorage(): ChartConfig[] {
|
||||
}
|
||||
}
|
||||
|
||||
function saveChartsToStorage(charts: ChartConfig[]) {
|
||||
function saveChartsToStorage(charts: ChartConfig[], projectId: number) {
|
||||
if (typeof window === 'undefined') return;
|
||||
window.localStorage.setItem(DASHBOARD_STORAGE_KEY, JSON.stringify(charts));
|
||||
window.localStorage.setItem(getStorageKey(projectId), JSON.stringify(charts));
|
||||
}
|
||||
|
||||
export const useDashboardStore = create<DashboardState>((set) => ({
|
||||
charts: loadChartsFromStorage(),
|
||||
addChart: (chart) => set((state) => {
|
||||
export const useDashboardStore = create<DashboardState>((set, get) => ({
|
||||
charts: [],
|
||||
loadCharts: (projectId) => {
|
||||
set({ charts: loadChartsFromStorage(projectId) });
|
||||
},
|
||||
addChart: (chart, projectId) => set((state) => {
|
||||
const colSize = 4;
|
||||
const cols = 12 / colSize;
|
||||
const index = state.charts.length;
|
||||
@@ -66,22 +74,20 @@ export const useDashboardStore = create<DashboardState>((set) => ({
|
||||
h: 4,
|
||||
};
|
||||
const nextCharts = [...state.charts, { ...chart, layout: newLayout }];
|
||||
saveChartsToStorage(nextCharts);
|
||||
saveChartsToStorage(nextCharts, projectId);
|
||||
return { charts: nextCharts };
|
||||
}),
|
||||
removeChart: (id) => set((state) => ({
|
||||
charts: (() => {
|
||||
const nextCharts = state.charts.filter((c) => c.id !== id);
|
||||
saveChartsToStorage(nextCharts);
|
||||
return nextCharts;
|
||||
})(),
|
||||
})),
|
||||
updateLayout: (layouts) => set((state) => {
|
||||
removeChart: (id, projectId) => set((state) => {
|
||||
const nextCharts = state.charts.filter((c) => c.id !== id);
|
||||
saveChartsToStorage(nextCharts, projectId);
|
||||
return { charts: nextCharts };
|
||||
}),
|
||||
updateLayout: (layouts, projectId) => set((state) => {
|
||||
const nextCharts = state.charts.map((chart) => {
|
||||
const layout = layouts.find((l) => l.i === chart.id);
|
||||
return layout ? { ...chart, layout } : chart;
|
||||
});
|
||||
saveChartsToStorage(nextCharts);
|
||||
saveChartsToStorage(nextCharts, projectId);
|
||||
return { charts: nextCharts };
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { create } from 'zustand';
|
||||
import { api } from '@/lib/api';
|
||||
|
||||
export interface Project {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
owner_id: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface ProjectState {
|
||||
projects: Project[];
|
||||
currentProject: Project | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
fetchProjects: () => Promise<void>;
|
||||
setCurrentProject: (project: Project) => void;
|
||||
addProject: (name: string, description?: string) => Promise<Project>;
|
||||
updateProject: (id: number, name: string, description?: string) => Promise<Project>;
|
||||
deleteProject: (id: number) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useProjectStore = create<ProjectState>((set, get) => ({
|
||||
projects: [],
|
||||
currentProject: JSON.parse(localStorage.getItem('currentProject') || 'null'),
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
fetchProjects: async () => {
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
const projects = await api.get<Project[]>('/api/v1/projects');
|
||||
set({ projects, loading: false });
|
||||
|
||||
// Set current project if not set or not in list
|
||||
const current = get().currentProject;
|
||||
if (projects.length > 0) {
|
||||
if (!current || !projects.find((p: Project) => p.id === current.id)) {
|
||||
get().setCurrentProject(projects[0]);
|
||||
}
|
||||
} else {
|
||||
set({ currentProject: null });
|
||||
localStorage.removeItem('currentProject');
|
||||
}
|
||||
} catch (error: any) {
|
||||
set({ error: error.message, loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
setCurrentProject: (project: Project) => {
|
||||
localStorage.setItem('currentProject', JSON.stringify(project));
|
||||
set({ currentProject: project });
|
||||
},
|
||||
|
||||
addProject: async (name: string, description?: string) => {
|
||||
try {
|
||||
const newProject = await api.post<Project>('/api/v1/projects', { name, description });
|
||||
set((state) => ({ projects: [...state.projects, newProject] }));
|
||||
if (!get().currentProject) {
|
||||
get().setCurrentProject(newProject);
|
||||
}
|
||||
return newProject;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message || 'Failed to create project');
|
||||
}
|
||||
},
|
||||
|
||||
updateProject: async (id: number, name: string, description?: string) => {
|
||||
try {
|
||||
const updatedProject = await api.put<Project>(`/api/v1/projects/${id}`, { name, description });
|
||||
set((state) => ({
|
||||
projects: state.projects.map((p) => (p.id === id ? updatedProject : p)),
|
||||
currentProject: state.currentProject?.id === id ? updatedProject : state.currentProject,
|
||||
}));
|
||||
if (get().currentProject?.id === id) {
|
||||
localStorage.setItem('currentProject', JSON.stringify(updatedProject));
|
||||
}
|
||||
return updatedProject;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message || 'Failed to update project');
|
||||
}
|
||||
},
|
||||
|
||||
deleteProject: async (id: number) => {
|
||||
try {
|
||||
await api.delete(`/api/v1/projects/${id}`);
|
||||
set((state) => {
|
||||
const projects = state.projects.filter((p) => p.id !== id);
|
||||
let currentProject = state.currentProject;
|
||||
if (currentProject?.id === id) {
|
||||
currentProject = projects.length > 0 ? projects[0] : null;
|
||||
if (currentProject) {
|
||||
localStorage.setItem('currentProject', JSON.stringify(currentProject));
|
||||
} else {
|
||||
localStorage.removeItem('currentProject');
|
||||
}
|
||||
}
|
||||
return { projects, currentProject };
|
||||
});
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message || 'Failed to delete project');
|
||||
}
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user