diff --git a/messages/en.json b/messages/en.json index 2203abae4..6639f5cde 100644 --- a/messages/en.json +++ b/messages/en.json @@ -878,9 +878,6 @@ "heroFindingWarning": "Top alert", "correlationsTitle": "Correlations", "recommendationsTitle": "Recommendations", - "briefingDisabledByOperator": "The Daily Briefing is currently unavailable on this server.", - "statusDisabledByOperator": "Status cards are currently unavailable on this server.", - "correlationsDisabledByOperator": "Correlation narration is currently unavailable on this server.", "personalRecord": { "badge": "PR", "tooltip": "Personal record: {value} {unit} on {date}" @@ -1036,7 +1033,6 @@ "composerHint": "Press Enter to send, Shift+Enter for a new line.", "composerDisclaimer": "Coach replies are generated. Clinical decisions belong with your doctor.", "voiceComingSoon": "Voice input arrives with the iOS app in v1.5.", - "disabledByOperator": "Coach is currently unavailable on this server.", "threadEmpty": "Ask anything about your trends, medications, or readings to start a conversation.", "historyTitle": "Conversations", "historySearchPlaceholder": "Search conversations…", @@ -1621,9 +1617,6 @@ "about": { "title": "About", "description": "Version, license, links." - }, - "placeholder": { - "coming_soon": "Moving here with the next release update." } }, "profile": "Profile", diff --git a/src/components/insights/__tests__/assistant-disabled-notice.test.tsx b/src/components/insights/__tests__/assistant-disabled-notice.test.tsx deleted file mode 100644 index c236f7c7c..000000000 --- a/src/components/insights/__tests__/assistant-disabled-notice.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { renderToStaticMarkup } from "react-dom/server"; - -import { I18nProvider } from "@/lib/i18n/context"; -import { AssistantDisabledNotice } from "../assistant-disabled-notice"; - -function render(node: React.ReactNode) { - return renderToStaticMarkup( - {node}, - ); -} - -describe("", () => { - it("renders the coach copy in the card variant", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - expect(html.toLowerCase()).toContain("coach"); - }); - - it("renders the briefing copy", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - }); - - it("renders the status copy", () => { - const html = render(); - expect(html).toContain("data-slot=\"assistant-disabled-notice\""); - }); - - it("renders the inline variant without the Card wrapper", () => { - const html = render( - , - ); - expect(html).toContain(""` response - * from the server or that detected the matching flag locally via - * `useFeatureFlags()`. - * - * The copy intentionally stays generic — "currently unavailable on - * this server" — so the surface doesn't leak operator-identity - * info into a user-facing string. Marc-voice English; the locale - * key carries the surface-specific phrasing. - */ -export type AssistantDisabledSurface = - | "coach" - | "briefing" - | "insightStatus" - | "correlations"; - -interface AssistantDisabledNoticeProps { - surface: AssistantDisabledSurface; - className?: string; - variant?: "card" | "inline"; -} - -const SURFACE_LABEL_KEY: Record = { - coach: "insights.coach.disabledByOperator", - briefing: "insights.briefingDisabledByOperator", - insightStatus: "insights.statusDisabledByOperator", - correlations: "insights.correlationsDisabledByOperator", -}; - -export function AssistantDisabledNotice({ - surface, - className, - variant = "card", -}: AssistantDisabledNoticeProps) { - const { t } = useTranslations(); - const message = t(SURFACE_LABEL_KEY[surface]); - - if (variant === "inline") { - return ( -

- {message} -

- ); - } - - return ( - - - - - ); -} diff --git a/src/components/settings/section-placeholder.tsx b/src/components/settings/section-placeholder.tsx index 999dcc296..3f05ea25d 100644 --- a/src/components/settings/section-placeholder.tsx +++ b/src/components/settings/section-placeholder.tsx @@ -54,6 +54,14 @@ export function SectionPlaceholder({ slug }: SectionPlaceholderProps) { const sectionTitle = t(`settings.sections.${slug}.title`); const sectionDescription = t(`settings.sections.${slug}.description`); + // v1.4.33 A4 — `` is a defensive fallback for + // slugs added to SETTINGS_SECTION_SLUGS without a matching component. + // The type system blocks that path today, so the EmptyState body is + // effectively unreachable. We retire the dedicated locale key + // (`settings.sections.placeholder.coming_soon`) and inherit the + // section's own description so the guard still renders meaningful + // copy if it ever does fire — no more dead-string maintenance across + // six locale files. return (
} title={sectionTitle} - description={t("settings.sections.placeholder.coming_soon")} + description={sectionDescription} />
); diff --git a/src/lib/api-handler.ts b/src/lib/api-handler.ts index 86c042fde..eb208a54c 100644 --- a/src/lib/api-handler.ts +++ b/src/lib/api-handler.ts @@ -169,8 +169,8 @@ export function apiHandler Promise>( // envelope is locked per // `.planning/RESPONSE-TO-IOS-TEAM-2026-05-16.md` §3 R5. // Older iOS clients that don't know the errorCode surface - // this as a generic 403; v1.4.31+ clients render the - // `` empty state. + // this as a generic 403; v1.4.31+ clients can branch on the + // errorCode to render an inline operator-disabled notice. evt.setError(error); response = NextResponse.json( {