Added saves state of dashboard and reloads it now
This commit is contained in:
@@ -19,7 +19,9 @@ const useAuthStore = create((set) => ({
|
||||
firstName: res.data.first_name,
|
||||
lastName: res.data.last_name,
|
||||
email: res.data.email,
|
||||
fullName: [res.data.first_name, res.data.last_name].filter(Boolean).join(' ')
|
||||
fullName: [res.data.first_name, res.data.last_name].filter(Boolean).join(' '),
|
||||
// Catch the layout and map data on fresh login!
|
||||
preferences: res.data.preferences || {}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -42,7 +44,7 @@ const useAuthStore = create((set) => ({
|
||||
checkAuth: async () => {
|
||||
try {
|
||||
// Hit the new lightweight endpoint
|
||||
const res = await api.get('session');
|
||||
const res = await api.get('session/');
|
||||
|
||||
// Rehydrate the store with the user's info!
|
||||
set({
|
||||
@@ -53,13 +55,37 @@ const useAuthStore = create((set) => ({
|
||||
firstName: res.data.first_name,
|
||||
lastName: res.data.last_name,
|
||||
email: res.data.email,
|
||||
fullName: [res.data.first_name, res.data.last_name].filter(Boolean).join(' ')
|
||||
fullName: [res.data.first_name, res.data.last_name].filter(Boolean).join(' '),
|
||||
// Catch the layout and map data on page refresh!
|
||||
preferences: res.data.preferences || {}
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
// If it fails, ensure the store is completely wiped
|
||||
set({ isAuthenticated: false, isLoading: false, user: null });
|
||||
}
|
||||
},
|
||||
|
||||
// Allow the UI to save widget placement
|
||||
saveDashboardLayout: async (newLayout) => {
|
||||
try {
|
||||
// 1. Optimistically update React state for zero UI lag
|
||||
set((state) => ({
|
||||
user: {
|
||||
...state.user,
|
||||
preferences: {
|
||||
...state.user.preferences,
|
||||
dashboard_layout: newLayout
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// 2. Quietly push the save command to Django
|
||||
await api.post('dashboard/save/', { layout: newLayout });
|
||||
|
||||
} catch (error) {
|
||||
console.error("Failed to save layout to database", error);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ 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)
|
||||
@@ -25,18 +28,22 @@ export const useDashboardStore = create((set, get) => ({
|
||||
}),
|
||||
|
||||
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) });
|
||||
// 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
|
||||
}
|
||||
},
|
||||
|
||||
addWidget: (widgetId, sizeKey) => {
|
||||
// Look up the exact rules for this widget from your constant
|
||||
const registryEntry = WIDGET_REGISTRY[widgetId];
|
||||
|
||||
if (!registryEntry || !registryEntry.allowedSizes[sizeKey]) {
|
||||
@@ -47,21 +54,14 @@ export const useDashboardStore = create((set, get) => ({
|
||||
const dimensions = registryEntry.allowedSizes[sizeKey];
|
||||
const widgets = get().widgets;
|
||||
|
||||
// Default to spawning on the far left on a new row
|
||||
let startX = 0;
|
||||
let startY = Infinity;
|
||||
|
||||
if (widgets.length > 0) {
|
||||
// 1. Find the lowest 'y' value (the start of the bottom row)
|
||||
const bottomRowY = Math.max(...widgets.map(w => w.y));
|
||||
|
||||
// 2. Grab all the widgets that are sitting on that exact row
|
||||
const bottomRowWidgets = widgets.filter(w => w.y === bottomRowY);
|
||||
|
||||
// 3. Find the right-most edge of those widgets (x position + width)
|
||||
const rightmostEdge = Math.max(...bottomRowWidgets.map(w => w.x + w.w));
|
||||
|
||||
// 4. If the right-most edge PLUS the new widget's width fits in 12 columns...
|
||||
if (rightmostEdge + dimensions.w <= 12) {
|
||||
startX = rightmostEdge; // ...tuck it right next to the last widget!
|
||||
startY = bottomRowY; // ...and keep it on the same row.
|
||||
@@ -84,16 +84,15 @@ export const useDashboardStore = create((set, get) => ({
|
||||
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;
|
||||
})
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
// NEW: Action to hydrate the store on initial page load
|
||||
setWidgets: (savedWidgets) => set({ widgets: savedWidgets || [] })
|
||||
}));
|
||||
Reference in New Issue
Block a user