feat(ux): Sprint 1 — quick wins: EmptyState, DateRangePresets, debounce, save feedback, scenarios nav

- EmptyState shared component; replace AllocationsClient inline empty state
- DateRangePresets (this month/quarter/3 months/year) integrated into AllocationModal
- Debounce conflict-check inputs in AllocationModal (400ms) using existing useDebounce
- Dashboard layout save feedback via SuccessToast after DB write completes
- Scenarios nav item in Planning sidebar + /scenarios list page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 13:08:19 +02:00
parent a16c41e739
commit 6831e199c6
9 changed files with 272 additions and 35 deletions
@@ -8,6 +8,7 @@ import { useDashboardLayout } from "~/hooks/useDashboardLayout.js";
import { WidgetContainer } from "./WidgetContainer.js";
import { AddWidgetModal } from "./AddWidgetModal.js";
import { getWidget } from "./widget-registry.js";
import { SuccessToast } from "~/components/ui/SuccessToast.js";
// Import CSS for react-grid-layout
import "react-grid-layout/css/styles.css";
@@ -146,7 +147,7 @@ function DeferredWidgetBody({
export function DashboardClient() {
const [addModalOpen, setAddModalOpen] = useState(false);
const { config, isHydrated, addWidget, removeWidget, updateWidgetConfig, onLayoutChange, resetLayout } =
const { config, isHydrated, saveStatus, addWidget, removeWidget, updateWidgetConfig, onLayoutChange, resetLayout } =
useDashboardLayout();
// Measure grid container width so Responsive knows the column size.
@@ -331,6 +332,7 @@ export function DashboardClient() {
)}
{addModalOpen && <AddWidgetModal onAdd={addWidget} onClose={() => setAddModalOpen(false)} />}
<SuccessToast show={saveStatus === "saved"} message="Layout saved" variant="info" />
</div>
);
}