Two visit steps join the getting-started path: "Browse categories and keywords" (5th) and "Browse the reports" (8th). Nothing in the database counts them: they are done by "Got it" on their card, stored as onboarding_acknowledged_<key> in user_preferences (no migration). - computeChecklist: eight rows; the visit rows are locked until the profile's visit steps are initialized, so a finished path does not flash a "Next step" before they are marked done. - initializeVisitSteps: once per profile, after the first successful load with the Budget entitlement known; acknowledges both steps when every other step is done or skipped, then sets the flag. No transaction (D16): idempotent writes, the flag last. - Reducer: ACKNOWLEDGE wins over an older snapshot like SKIP but keeps the card latch, so the card says "Done." and offers the next step. - StepCard: "Got it" before "Skip this step" when onAcknowledge is given; OnboardingStepCard passes it for a visit step. - Banner counter, card rank and end of path wait for budgetReady && visitStepsInitialized; the list shows the visit rows "pending" until then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { LayoutDashboard } from "lucide-react";
|
|
import EmptyState from "../shared/EmptyState";
|
|
import OnboardingChecklist from "./OnboardingChecklist";
|
|
import type { Checklist } from "../../utils/onboardingChecklist";
|
|
import type { ChecklistItemKey } from "../../shared/types";
|
|
|
|
interface DashboardEmptyStateProps {
|
|
checklist: Checklist;
|
|
budgetReady: boolean;
|
|
/** The visit steps are initialized (#425): their rows stay "pending" until then. */
|
|
visitStepsInitialized: boolean;
|
|
/** The user dismissed the checklist: the welcome card stays, the list goes. */
|
|
hidden: boolean;
|
|
onHide: () => void;
|
|
/** "Resume" on a skipped row of the list (#397). */
|
|
onResume: (key: ChecklistItemKey) => void;
|
|
}
|
|
|
|
/**
|
|
* Dashboard of a profile without any transaction (#352): a welcome card with
|
|
* the detailed getting-started checklist and one primary action towards the
|
|
* import page, in place of widgets showing 0 $. The getting-started banner
|
|
* stays off this page (D11): the card already holds the list.
|
|
*/
|
|
export default function DashboardEmptyState({
|
|
checklist,
|
|
budgetReady,
|
|
visitStepsInitialized,
|
|
hidden,
|
|
onHide,
|
|
onResume,
|
|
}: DashboardEmptyStateProps) {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<EmptyState
|
|
icon={<LayoutDashboard size={40} />}
|
|
title={t("dashboard.empty.title")}
|
|
description={t("dashboard.empty.description")}
|
|
primaryAction={{ label: t("dashboard.empty.cta"), to: "/import" }}
|
|
>
|
|
{!hidden && (
|
|
<OnboardingChecklist
|
|
items={checklist.items}
|
|
done={checklist.done}
|
|
total={checklist.total}
|
|
budgetReady={budgetReady}
|
|
visitStepsInitialized={visitStepsInitialized}
|
|
onHide={onHide}
|
|
onResume={onResume}
|
|
/>
|
|
)}
|
|
</EmptyState>
|
|
);
|
|
}
|