Refactor updating how widgets work and removed prop drilling

This commit is contained in:
2026-06-09 14:06:01 -07:00
parent 7744d6b8ce
commit 305ee4e757
16 changed files with 474 additions and 110 deletions
+78
View File
@@ -0,0 +1,78 @@
import { create } from 'zustand';
import { v4 as uuid } from 'uuid';
import { WIDGET_REGISTRY } from '../constants/widgetRegistry.jsx';
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 () => {
const payload = get().widgets;
// 💾 This is perfectly formatted for your backend DB right now
console.log("Saving dashboard to API:", JSON.stringify(payload, null, 2));
// Example: await fetch('/api/user/dashboard', { method: 'POST', body: JSON.stringify(payload) });
set({ isEditing: false, backupWidgets: [] });
},
addWidget: (widgetId, sizeKey) => {
// Look up the exact rules for this widget from your constant
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 newWidget = {
id: uuid(),
type: widgetId,
size: sizeKey,
x: 0,
y: Infinity, // RGL's auto-packer drops this exactly into the first available slot at the bottom
w: dimensions.w,
h: dimensions.h
};
set((state) => ({ widgets: [...state.widgets, newWidget] }));
},
removeWidget: (id) => set((state) => ({
widgets: state.widgets.filter(w => w.id !== id)
})),
// Called automatically by React-Grid-Layout when the user lets go of the mouse
updateLayoutPositions: (rglLayout) => {
set((state) => ({
widgets: state.widgets.map(widget => {
// Find where RGL says this widget currently is
const gridItem = rglLayout.find(l => l.i === widget.id);
// Only update X and Y. We completely ignore W and H so users can't resize!
return gridItem ? { ...widget, x: gridItem.x, y: gridItem.y } : widget;
})
}));
}
}));