From 1631d8042ccfa8270b20f6926304baefa83c280e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 10 May 2026 22:17:29 +0200 Subject: [PATCH] refactor: simplify-pass apply-yes cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five independent atomic edits from the W5 simplify review, grouped in a single commit since none pull weight as a compound theme: - coach-input: collapse `!disabled && value.trim().length > 0` triplication onto a single `canSubmit` (S-01). - hero-strip: extract the duplicate weekly-report Button shell into a shared label fragment with the Link wrapping conditionally (S-02). - api-token-overview-section: extract `` so the desktop table and mobile card list stay in lock-step on the revoked / expired / active 3-way ternary (S-03). - trends-row: hoist the dynamic-load chart skeleton to a shared `ChartSkeleton` component (S-04). No chart-visual change — placeholder only. - correlation-row: collapse the grid className ternary onto `cn()` with a conditional `md:grid-cols-2` (S-05). Test count unchanged (2105). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../admin/api-token-overview-section.tsx | 78 ++++++++++--------- .../insights/coach-panel/coach-input.tsx | 22 ++---- src/components/insights/correlation-row.tsx | 10 +-- src/components/insights/hero-strip.tsx | 58 ++++++++------ src/components/insights/trends-row.tsx | 22 +++--- 5 files changed, 98 insertions(+), 92 deletions(-) diff --git a/src/components/admin/api-token-overview-section.tsx b/src/components/admin/api-token-overview-section.tsx index 0c3946931..1ab015c19 100644 --- a/src/components/admin/api-token-overview-section.tsx +++ b/src/components/admin/api-token-overview-section.tsx @@ -55,6 +55,46 @@ function TruncatedCell({ ); } +/** + * v1.4.22 W5 reconcile (S-03) — the revoked / isExpired / active + * 3-way ternary is identical between the desktop table and the + * mobile card list; the only difference is `text-xs` vs `text-[10px]`. + * Centralise so the two surfaces stay in lock-step. + */ +function TokenStatusBadge({ + token, + size, +}: { + token: ApiTokenInfo; + size: "sm" | "xs"; +}) { + const { t } = useTranslations(); + const expired = + token.expiresAt != null && new Date(token.expiresAt) < new Date(); + const sizeClass = size === "xs" ? "text-[10px]" : "text-xs"; + if (token.revoked) { + return ( + + {t("settings.tokenRevoked")} + + ); + } + if (expired) { + return ( + + {t("settings.tokenExpired")} + + ); + } + return ( + + {t("common.active")} + + ); +} + /** * F-18 (v1.4.19): the auto-login flow names tokens * "web auto-login 2026-05-05T19:46:20.603Z" / "iOS auto-login …" by @@ -181,8 +221,6 @@ export function ApiTokenOverviewSection() { {tokens.map((token, i) => { - const isExpired = - token.expiresAt && new Date(token.expiresAt) < new Date(); return ( - {token.revoked ? ( - - {t("settings.tokenRevoked")} - - ) : isExpired ? ( - - {t("settings.tokenExpired")} - - ) : ( - - {t("common.active")} - - )} + {/* v1.4.22 C2 (5th attempt) — drop `whitespace-nowrap` on the date cells. The @@ -264,8 +290,6 @@ export function ApiTokenOverviewSection() { data-testid="admin-tokens-mobile-list" > {tokens.map((token) => { - const isExpired = - token.expiresAt && new Date(token.expiresAt) < new Date(); return (
  • - {token.revoked ? ( - - {t("settings.tokenRevoked")} - - ) : isExpired ? ( - - {t("settings.tokenExpired")} - - ) : ( - - {t("common.active")} - - )} + 0; + const handleKeyDown = useCallback( (event: KeyboardEvent) => { - if (event.key !== "Enter") return; - // Shift+Enter inserts a newline. - if (event.shiftKey) return; - // Plain Enter and ⌘/Ctrl+Enter both submit. + // Shift+Enter inserts a newline; plain Enter and ⌘/Ctrl+Enter submit. + if (event.key !== "Enter" || event.shiftKey) return; event.preventDefault(); - if (!disabled && value.trim().length > 0) { - onSubmit(); - } + if (canSubmit) onSubmit(); }, - [disabled, onSubmit, value], + [canSubmit, onSubmit], ); const handleFormSubmit = useCallback( (event: FormEvent) => { event.preventDefault(); - if (!disabled && value.trim().length > 0) { - onSubmit(); - } + if (canSubmit) onSubmit(); }, - [disabled, onSubmit, value], + [canSubmit, onSubmit], ); - const canSubmit = !disabled && value.trim().length > 0; - return (
    1 && "md:grid-cols-2", + )} > {okResults.map((result) => ( diff --git a/src/components/insights/hero-strip.tsx b/src/components/insights/hero-strip.tsx index 1b3874974..d20d8539c 100644 --- a/src/components/insights/hero-strip.tsx +++ b/src/components/insights/hero-strip.tsx @@ -238,33 +238,41 @@ export function HeroStrip({ * current ISO week. Older parents that haven't adopted the * weeklyReportHref prop still get the disabled affordance. */} - {weeklyReportHref ? ( - - ) : ( - - )} + + ); + return weeklyReportHref ? ( + + ) : ( + + ); + })()} {/* B2b wires this into the Coach drawer. The button is enabled whenever the parent supplies an `onAskCoach` handler; older parents that haven't adopted B2b yet diff --git a/src/components/insights/trends-row.tsx b/src/components/insights/trends-row.tsx index 81f91c353..3e510ccc7 100644 --- a/src/components/insights/trends-row.tsx +++ b/src/components/insights/trends-row.tsx @@ -26,17 +26,20 @@ import { * the row's visual rhythm. */ +// v1.4.22 W5 reconcile (S-04) — both `dynamic()` calls used the same +// pulse-skeleton placeholder. Hoist so the loading affordance stays +// in lock-step (cleared against `feedback_charts_visual_identity.md` +// — placeholder only, no chart visual change). +const ChartSkeleton = () => ( +
    +); + const HealthChart = dynamic( () => import("@/components/charts/health-chart").then((mod) => ({ default: mod.HealthChart, })), - { - ssr: false, - loading: () => ( -
    - ), - }, + { ssr: false, loading: ChartSkeleton }, ); const MoodChart = dynamic( @@ -44,12 +47,7 @@ const MoodChart = dynamic( import("@/components/charts/mood-chart").then((mod) => ({ default: mod.MoodChart, })), - { - ssr: false, - loading: () => ( -
    - ), - }, + { ssr: false, loading: ChartSkeleton }, ); interface TrendsRowProps {