Files
HealthLog/src/components/onboarding/sample-briefing-card.tsx
T
Marc-André Bombeck 0adba584a9 feat(onboarding): make AI insights reachable early without a gate
Close the gap between the welcome carousel's AI promise and the payoff:
a fresh keyless user used to meet "No AI provider connected" on every AI
surface, because the only setup prompt was a skippable card on the final
screen.

Add an "insights" row to the getting-started checklist, derived from real
provider state — any personal key, local model, OAuth sign-in, or the
operator's shared key flips it done via /api/user/ai-provider. It persists
past onboarding, self-satisfies on connect, and dismisses like the others.

Elevate the done-screen AI card into a value-first panel: it leads with a
static, clearly-labelled example briefing (no model call, no egress, no
consent), then the local-first ladder — local model, bring-your-own-key,
subscription sign-in with the training caveat — and the honest line that
HealthLog is fully useful without AI. All three exits stay, so the panel
gates nothing. On a deployment with a shared provider it says so plainly.

Extract the worked example into a shared SampleBriefingCard. Add
onboarding.ai.* copy across all six locales and retire the old
single-card done-screen keys.
2026-07-09 20:32:33 +02:00

58 lines
2.0 KiB
TypeScript

"use client";
import { Sparkles } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { TileHeader } from "@/components/insights/tile-header";
import { cn } from "@/lib/utils";
import { useTranslations } from "@/lib/i18n/context";
/**
* The onboarding "aha" artifact — a static, clearly-labelled *example*
* daily briefing shown BEFORE any AI provider is connected.
*
* It exists so a fresh user feels the payoff of AI Insights with zero
* setup: no provider is configured yet, so this makes no model call, no
* fetch, no egress, and needs no consent. Every number is fixed copy
* from the `onboarding.ai.sample*` keys (the worked example the
* no-provider briefing empty state already carries) — it is never
* derived from the user's own record, and the "Example" badge plus the
* caption make that explicit so it is never mistaken for real data.
*
* Presentational only — no state, no effect, no data fetch. Reused by
* the onboarding done-screen panel; safe to drop into any surface that
* wants to show what a briefing reads like.
*/
export function SampleBriefingCard({ className }: { className?: string }) {
const { t } = useTranslations();
return (
<Card
data-slot="sample-briefing-card"
aria-label={t("onboarding.ai.sampleAriaLabel")}
className={cn("bg-muted/30 gap-2 py-3 md:py-4", className)}
>
<CardHeader>
<TileHeader
icon={Sparkles}
title={t("onboarding.ai.sampleTitle")}
right={
<Badge variant="secondary" data-slot="sample-briefing-tag">
{t("onboarding.ai.sampleTag")}
</Badge>
}
/>
</CardHeader>
<CardContent className="space-y-2">
<p className="text-foreground text-sm leading-relaxed">
{t("onboarding.ai.sampleBody")}
</p>
<p className="text-muted-foreground text-xs leading-relaxed">
{t("onboarding.ai.sampleCaption")}
</p>
</CardContent>
</Card>
);
}