@jjdenhertog/ai-driven-development
Version:
AI-driven development workflow with learning capabilities for Claude
174 lines (149 loc) • 4.81 kB
text/typescript
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
interface User {
readonly id: string;
readonly name: string;
readonly email: string;
readonly role: 'admin' | 'user' | 'guest';
}
interface AppState {
// State
user: User | null;
sidebarOpen: boolean;
theme: 'light' | 'dark';
notifications: Notification[];
// Actions
setUser: (user: User | null) => void;
toggleSidebar: () => void;
setTheme: (theme: 'light' | 'dark') => void;
addNotification: (notification: Notification) => void;
removeNotification: (id: string) => void;
clearNotifications: () => void;
}
interface Notification {
readonly id: string;
readonly type: 'success' | 'error' | 'warning' | 'info';
readonly message: string;
readonly timestamp: number;
}
export const useAppStore = create<AppState>()(
devtools(
persist(
immer((set) => ({
// Initial state
user: null,
sidebarOpen: true,
theme: 'dark',
notifications: [],
// Actions
setUser: (user) => set((state) => {
state.user = user;
}),
toggleSidebar: () => set((state) => {
state.sidebarOpen = !state.sidebarOpen;
}),
setTheme: (theme) => set((state) => {
state.theme = theme;
// Also update DOM for CSS variables
document.documentElement.setAttribute('data-theme', theme);
}),
addNotification: (notification) => set((state) => {
// Keep only last 10 notifications
if (state.notifications.length >= 10)
state.notifications.shift();
state.notifications.push(notification);
}),
removeNotification: (id) => set((state) => {
state.notifications = state.notifications.filter(n => n.id !== id);
}),
clearNotifications: () => set((state) => {
state.notifications = [];
}),
})),
{
name: 'app-store',
// Only persist theme and sidebar state
partialize: (state) => ({
theme: state.theme,
sidebarOpen: state.sidebarOpen,
}),
}
)
)
);
// Selectors
export const useUser = () => useAppStore((state) => state.user);
export const useTheme = () => useAppStore((state) => state.theme);
export const useSidebarOpen = () => useAppStore((state) => state.sidebarOpen);
export const useNotifications = () => useAppStore((state) => state.notifications);
// Actions
export const useAppActions = () => {
const setUser = useAppStore((state) => state.setUser);
const toggleSidebar = useAppStore((state) => state.toggleSidebar);
const setTheme = useAppStore((state) => state.setTheme);
const addNotification = useAppStore((state) => state.addNotification);
const removeNotification = useAppStore((state) => state.removeNotification);
const clearNotifications = useAppStore((state) => state.clearNotifications);
return {
setUser,
toggleSidebar,
setTheme,
addNotification,
removeNotification,
clearNotifications,
};
};
// Helper to create notifications
export function createNotification(type: Notification['type'], message: string): Notification {
return {
id: `${Date.now()}-${Math.random()}`,
type,
message,
timestamp: Date.now(),
};
}
// Example of a derived store for feature-specific state
interface FeatureState {
selectedItems: string[];
filter: 'all' | 'active' | 'inactive';
sortBy: 'name' | 'date' | 'status';
selectItem: (id: string) => void;
deselectItem: (id: string) => void;
toggleItem: (id: string) => void;
clearSelection: () => void;
setFilter: (filter: FeatureState['filter']) => void;
setSortBy: (sortBy: FeatureState['sortBy']) => void;
}
export const useFeatureStore = create<FeatureState>()(
immer((set) => ({
// State
selectedItems: [],
filter: 'all',
sortBy: 'name',
// Actions
selectItem: (id) => set((state) => {
if (!state.selectedItems.includes(id))
state.selectedItems.push(id);
}),
deselectItem: (id) => set((state) => {
state.selectedItems = state.selectedItems.filter(item => item !== id);
}),
toggleItem: (id) => set((state) => {
const index = state.selectedItems.indexOf(id);
if (index === -1)
state.selectedItems.push(id);
else
state.selectedItems.splice(index, 1);
}),
clearSelection: () => set((state) => {
state.selectedItems = [];
}),
setFilter: (filter) => set((state) => {
state.filter = filter;
}),
setSortBy: (sortBy) => set((state) => {
state.sortBy = sortBy;
}),
}))
);