feat: initial SPA frontend for network app
This commit is contained in:
87
src/stores/clients.ts
Normal file
87
src/stores/clients.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { create } from 'zustand';
|
||||
import type { Client, ClientCreate } from '@/types';
|
||||
import { api } from '@/lib/api';
|
||||
|
||||
interface ClientsState {
|
||||
clients: Client[];
|
||||
selectedClient: Client | null;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
searchQuery: string;
|
||||
selectedTag: string | null;
|
||||
|
||||
setSearchQuery: (query: string) => void;
|
||||
setSelectedTag: (tag: string | null) => void;
|
||||
fetchClients: () => Promise<void>;
|
||||
fetchClient: (id: string) => Promise<void>;
|
||||
createClient: (data: ClientCreate) => Promise<Client>;
|
||||
updateClient: (id: string, data: Partial<ClientCreate>) => Promise<void>;
|
||||
deleteClient: (id: string) => Promise<void>;
|
||||
markContacted: (id: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useClientsStore = create<ClientsState>()((set, get) => ({
|
||||
clients: [],
|
||||
selectedClient: null,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
searchQuery: '',
|
||||
selectedTag: null,
|
||||
|
||||
setSearchQuery: (query) => set({ searchQuery: query }),
|
||||
setSelectedTag: (tag) => set({ selectedTag: tag }),
|
||||
|
||||
fetchClients: async () => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const { searchQuery, selectedTag } = get();
|
||||
const clients = await api.getClients({
|
||||
search: searchQuery || undefined,
|
||||
tag: selectedTag || undefined,
|
||||
});
|
||||
set({ clients, isLoading: false });
|
||||
} catch (err: any) {
|
||||
set({ error: err.message, isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
fetchClient: async (id) => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const client = await api.getClient(id);
|
||||
set({ selectedClient: client, isLoading: false });
|
||||
} catch (err: any) {
|
||||
set({ error: err.message, isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
createClient: async (data) => {
|
||||
const client = await api.createClient(data);
|
||||
set((state) => ({ clients: [...state.clients, client] }));
|
||||
return client;
|
||||
},
|
||||
|
||||
updateClient: async (id, data) => {
|
||||
const updated = await api.updateClient(id, data);
|
||||
set((state) => ({
|
||||
clients: state.clients.map((c) => (c.id === id ? updated : c)),
|
||||
selectedClient: state.selectedClient?.id === id ? updated : state.selectedClient,
|
||||
}));
|
||||
},
|
||||
|
||||
deleteClient: async (id) => {
|
||||
await api.deleteClient(id);
|
||||
set((state) => ({
|
||||
clients: state.clients.filter((c) => c.id !== id),
|
||||
selectedClient: state.selectedClient?.id === id ? null : state.selectedClient,
|
||||
}));
|
||||
},
|
||||
|
||||
markContacted: async (id) => {
|
||||
const updated = await api.markContacted(id);
|
||||
set((state) => ({
|
||||
clients: state.clients.map((c) => (c.id === id ? updated : c)),
|
||||
selectedClient: state.selectedClient?.id === id ? updated : state.selectedClient,
|
||||
}));
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user