Files
evrak/frontend/src/store/useProjectStore.ts
gitmuhammedalbayrak b9148cfa4b
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
feat: Add full CRUD functionality, project detail panel, and improved UI
- Add UPDATE and DELETE endpoints to backend
- Implement project detail panel with comprehensive editing
- Add drag-and-drop functionality for projects in mind map
- Show all projects in map (not just selected + children)
- Fix infinite render loop in MindMap component
- Improve UI spacing and button layouts
- Add local development database schema with RLS disabled
- Update docker-compose for regular docker-compose (not Swarm)
- Add CORS support and nginx API proxying
- Improve button spacing and modern design principles
2025-11-27 03:18:48 +03:00

140 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { create } from 'zustand';
interface Project {
id: string;
name: string;
path: string;
parentId: string | null;
description?: string | null;
attributes?: Record<string, any>;
children?: Project[];
}
interface ProjectState {
projects: Project[];
expandedKeys: string[];
selectedKey: string | null;
setProjects: (projects: Project[]) => void;
setExpandedKeys: (keys: string[]) => void;
setSelectedKey: (key: string | null) => void;
expandNode: (key: string) => void;
fetchProjects: () => Promise<void>;
createProject: (data: { name: string; parentId?: string | null; description?: string }) => Promise<void>;
updateProject: (id: string, data: { name?: string; description?: string; parentId?: string | null }) => Promise<void>;
deleteProject: (id: string) => Promise<void>;
}
const DUMMY_PROJECTS: Project[] = [
{ id: '1', name: 'Genel Merkez', path: 'root', parentId: null },
{ id: '2', name: 'Yazılım Departmanı', path: 'root.software', parentId: '1' },
{ id: '3', name: 'İnsan Kaynakları', path: 'root.hr', parentId: '1' },
{ id: '4', name: 'Evrak Projesi', path: 'root.software.evrak', parentId: '2' },
{ id: '5', name: 'Website Yenileme', path: 'root.software.website', parentId: '2' },
];
export const useProjectStore = create<ProjectState>((set) => ({
projects: [],
expandedKeys: [],
selectedKey: null,
setProjects: (projects) => set({ projects }),
setExpandedKeys: (expandedKeys) => set({ expandedKeys }),
setSelectedKey: (selectedKey) => set({ selectedKey }),
expandNode: (key) =>
set((state) => ({
expandedKeys: state.expandedKeys.includes(key)
? state.expandedKeys
: [...state.expandedKeys, key],
})),
fetchProjects: async () => {
try {
// Use relative path when proxied through nginx, or environment variable
const apiUrl = import.meta.env.VITE_API_URL || '/projects';
const response = await fetch(apiUrl);
if (response.ok) {
const data = await response.json();
// Map API response to frontend format (parent_id -> parentId)
const mappedData = data.map((p: any) => ({
...p,
parentId: p.parent_id || null,
}));
set({ projects: mappedData });
} else {
console.error('Failed to fetch projects');
set({ projects: DUMMY_PROJECTS });
}
} catch (error) {
console.error('Error fetching projects:', error);
set({ projects: DUMMY_PROJECTS });
}
},
createProject: async (data) => {
try {
const apiUrl = import.meta.env.VITE_API_URL || '/projects';
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: data.name,
description: data.description || null,
parent_id: data.parentId || null,
tenant_id: '00000000-0000-0000-0000-000000000001', // Default tenant for local dev
}),
});
if (response.ok) {
await useProjectStore.getState().fetchProjects();
} else {
const error = await response.json();
throw new Error(error.message || 'Failed to create project');
}
} catch (error) {
console.error('Error creating project:', error);
throw error;
}
},
updateProject: async (id, data) => {
try {
const apiUrl = import.meta.env.VITE_API_URL || '/projects';
const response = await fetch(`${apiUrl}/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...(data.name && { name: data.name }),
...(data.description !== undefined && { description: data.description }),
...(data.parentId !== undefined && { parent_id: data.parentId }),
}),
});
if (response.ok) {
await useProjectStore.getState().fetchProjects();
} else {
const error = await response.json();
throw new Error(error.message || 'Failed to update project');
}
} catch (error) {
console.error('Error updating project:', error);
throw error;
}
},
deleteProject: async (id) => {
try {
const apiUrl = import.meta.env.VITE_API_URL || '/projects';
const response = await fetch(`${apiUrl}/${id}`, {
method: 'DELETE',
});
if (response.ok) {
await useProjectStore.getState().fetchProjects();
// Clear selection if deleted project was selected
const state = useProjectStore.getState();
if (state.selectedKey === id) {
state.setSelectedKey(null);
}
} else {
const error = await response.json();
throw new Error(error.message || 'Failed to delete project');
}
} catch (error) {
console.error('Error deleting project:', error);
throw error;
}
},
}));