Files
Web-Frontend/client/src/store/useDashboardStore.jsx
T

109 lines
3.7 KiB
React
Raw Normal View History

import { create } from 'zustand';
import { v4 as uuid } from 'uuid';
import { WIDGET_REGISTRY } from '../constants/widgetRegistry.jsx';
// 1. Import your database messenger
import useAuthStore from './authStore';
export const useDashboardStore = create((set, get) => ({
// ==========================================
// 1. STATE (The Data)
// ==========================================
isEditing: false,
widgets: [], // The master array of what is currently on the screen
backupWidgets: [], // Holds the layout snapshot for the "Cancel" button
// ==========================================
// 2. ACTIONS (The Logic)
// ==========================================
enterEditMode: () => set({
isEditing: true,
backupWidgets: get().widgets // 📸 Take a snapshot of current positions
}),
cancelEdit: () => set({
isEditing: false,
widgets: get().backupWidgets // ⏪ Restore snapshot, instantly undoing any drags
}),
saveEdit: async () => {
// 1. Grab the exact current state of the grid
const currentLayout = get().widgets;
// 2. Lock the UI immediately so the user feels zero lag
set({ isEditing: false, backupWidgets: [] });
// 3. Reach outside this store and trigger the Django API call!
try {
await useAuthStore.getState().saveDashboardLayout(currentLayout);
} catch (error) {
console.error("Failed to sync layout to MariaDB:", error);
// If the database save fails, you could technically revert the UI here if needed
}
},
2026-07-10 14:56:11 -07:00
updateWidgetSettings: (id, newSettings) => set((state) => {
console.log("2. Zustand updating widget:", id, "with:", newSettings);
return {
widgets: state.widgets.map(widget =>
widget.id === id
? { ...widget, settings: { ...widget.settings, ...newSettings } }
: widget
)
};
}),
addWidget: (widgetId, sizeKey) => {
const registryEntry = WIDGET_REGISTRY[widgetId];
if (!registryEntry || !registryEntry.allowedSizes[sizeKey]) {
console.error(`Invalid widget ID or Size: ${widgetId} - ${sizeKey}`);
return;
}
const dimensions = registryEntry.allowedSizes[sizeKey];
const widgets = get().widgets;
let startX = 0;
let startY = Infinity;
if (widgets.length > 0) {
const bottomRowY = Math.max(...widgets.map(w => w.y));
const bottomRowWidgets = widgets.filter(w => w.y === bottomRowY);
const rightmostEdge = Math.max(...bottomRowWidgets.map(w => w.x + w.w));
if (rightmostEdge + dimensions.w <= 12) {
startX = rightmostEdge; // ...tuck it right next to the last widget!
startY = bottomRowY; // ...and keep it on the same row.
}
}
const newWidget = {
id: uuid(),
type: widgetId,
size: sizeKey,
x: startX,
y: startY,
w: dimensions.w,
h: dimensions.h
};
set((state) => ({ widgets: [...state.widgets, newWidget] }));
},
removeWidget: (id) => set((state) => ({
widgets: state.widgets.filter(w => w.id !== id)
})),
updateLayoutPositions: (rglLayout) => {
set((state) => ({
widgets: state.widgets.map(widget => {
const gridItem = rglLayout.find(l => l.i === widget.id);
return gridItem ? { ...widget, x: gridItem.x, y: gridItem.y } : widget;
})
}));
},
// NEW: Action to hydrate the store on initial page load
setWidgets: (savedWidgets) => set({ widgets: savedWidgets || [] })
}));