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:
@@ -0,0 +1,36 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
interface EmptyStateProps {
|
||||
icon?: ReactNode;
|
||||
title: string;
|
||||
detail?: string;
|
||||
action?: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export function EmptyState({ icon, title, detail, action, testId }: EmptyStateProps) {
|
||||
return (
|
||||
<div
|
||||
data-testid={testId}
|
||||
className="flex flex-col items-center gap-2 py-12 text-center text-sm text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
{icon && (
|
||||
<div className="mb-1 text-gray-300 dark:text-gray-600">{icon}</div>
|
||||
)}
|
||||
<p className="font-medium text-gray-700 dark:text-gray-200">{title}</p>
|
||||
{detail && <p>{detail}</p>}
|
||||
{action && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={action.onClick}
|
||||
className="mt-1 rounded-lg border border-gray-300 px-3 py-1.5 text-xs font-medium text-gray-700 transition hover:border-gray-400 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-gray-800"
|
||||
>
|
||||
{action.label}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user