diff --git a/messages/de.json b/messages/de.json index f8063b94a..689eb18a4 100644 --- a/messages/de.json +++ b/messages/de.json @@ -259,6 +259,7 @@ "emptyTitle": "Dein Dashboard ist leer", "emptyDescription": "Erfasse den ersten Messwert oder Stimmungseintrag. Kacheln und Charts erscheinen automatisch, sobald Daten vorhanden sind.", "emptyAddMeasurement": "Ersten Messwert erfassen", + "staleHint": "Letzter Wert vor {count} T.", "recentWorkouts": { "title": "Letzte Workouts", "viewAll": "Alle anzeigen", @@ -866,7 +867,7 @@ "bmiEmptyDescription": "Für den BMI wird deine Körpergröße benötigt. Hinterlege sie unter Einstellungen → Account.", "bmiEmptyAction": "Account-Einstellungen öffnen", "noAnalysisYet": "Noch keine Analyse vorhanden.", - "noProviderConfigured": "KI-Provider nicht konfiguriert.", + "noProviderConfigured": "Auswertung nicht verfügbar.", "startAnalysis": "Analyse starten", "refreshAnalysis": "Analyse aktualisieren", "keyTakeaway": "Das Wichtigste", @@ -876,9 +877,6 @@ "heroFindingAttention": "Beachten", "heroFindingWarning": "Wichtigster Alarm", "correlationsTitle": "Zusammenhänge", - "briefingDisabledByOperator": "Das Tagesbriefing ist auf diesem Server derzeit nicht verfügbar.", - "statusDisabledByOperator": "Status-Karten sind auf diesem Server derzeit nicht verfügbar.", - "correlationsDisabledByOperator": "Korrelations-Erzählung ist auf diesem Server derzeit nicht verfügbar.", "recommendationsTitle": "Empfehlungen", "personalRecord": { "badge": "PR", @@ -1035,7 +1033,6 @@ "composerHint": "Enter zum Senden, Umschalt+Enter für eine neue Zeile.", "composerDisclaimer": "Coach-Antworten sind generiert. Klinische Entscheidungen gehören in die Hand deines Arztes.", "voiceComingSoon": "Spracheingabe kommt mit der iOS-App in v1.5.", - "disabledByOperator": "Der Coach ist auf diesem Server derzeit nicht verfügbar.", "threadEmpty": "Frag mich etwas zu deinen Trends, Medikamenten oder Messwerten, um zu starten.", "historyTitle": "Unterhaltungen", "historySearchPlaceholder": "Unterhaltungen durchsuchen…", @@ -1898,6 +1895,7 @@ "moodLogWebhookSecretHelp": "Dieses Secret in moodLog als Webhook-Secret eintragen", "moodLogSync": "Sync starten", "moodLogFullSync": "Voll-Sync", + "moodLogFullSyncConfirm": "Vollständig synchronisieren", "moodLogFullSyncTitle": "Vollsynchronisierung?", "moodLogFullSyncDescription": "Alle verfügbaren Stimmungsdaten werden vollständig synchronisiert.", "moodLogDisconnect": "Trennen", diff --git a/messages/en.json b/messages/en.json index f6cf4dd50..eb6081666 100644 --- a/messages/en.json +++ b/messages/en.json @@ -866,7 +866,7 @@ "bmiEmptyTitle": "Set your height to see BMI", "bmiEmptyDescription": "BMI needs your height. Add it under Settings → Account.", "bmiEmptyAction": "Open account settings", - "noProviderConfigured": "AI provider not configured.", + "noProviderConfigured": "Assessment unavailable.", "startAnalysis": "Start analysis", "refreshAnalysis": "Refresh analysis", "keyTakeaway": "Key Takeaway", @@ -1898,6 +1898,7 @@ "moodLogWebhookSecretHelp": "Enter this secret in moodLog as webhook secret", "moodLogSync": "Start sync", "moodLogFullSync": "Full sync", + "moodLogFullSyncConfirm": "Synchronize fully", "moodLogFullSyncTitle": "Full sync?", "moodLogFullSyncDescription": "All available mood data will be fully synchronized.", "moodLogDisconnect": "Disconnect", diff --git a/src/components/insights/insights-layout-shell.tsx b/src/components/insights/insights-layout-shell.tsx index 3b2342a52..a2d96c27d 100644 --- a/src/components/insights/insights-layout-shell.tsx +++ b/src/components/insights/insights-layout-shell.tsx @@ -4,6 +4,7 @@ import { useMemo, type ReactNode } from "react"; import { useQuery } from "@tanstack/react-query"; import { useAuth } from "@/hooks/use-auth"; +import { useFeatureFlags } from "@/hooks/use-feature-flags"; import { useWorkouts } from "@/hooks/use-workouts"; import { InsightsTabStrip } from "@/components/insights/insights-tab-strip"; import { useInsightsAdvisorQuery } from "@/components/insights/use-insights-advisor"; @@ -41,7 +42,22 @@ interface ComprehensivePayload { export function InsightsLayoutShell({ children }: { children: ReactNode }) { const { isAuthenticated } = useAuth(); - const advisor = useInsightsAdvisorQuery(isAuthenticated); + // v1.4.33 F18 — gate the advisor POST on the operator's assistant + // feature flag. Pre-fix, every /insights mount fired POST + // /api/insights/generate even when the operator had disabled the + // briefing surface or the user had no AI provider configured. The + // server returned 422 in that case and the regenerate button on the + // tab strip rendered a non-functional spinner. Reading the flag + // matrix off `/api/feature-flags` keeps the hot path one fetch + // (shared `["feature-flags"]` cache, 60s staleTime) and skips the + // advisor request entirely when the operator has the briefing gate + // off. The fail-open default in `useFeatureFlags` means a network + // hiccup still renders the advisor — the gate only takes effect when + // the operator has explicitly turned the surface off. + const flags = useFeatureFlags(); + const advisorEnabled = + isAuthenticated && flags.enabled && flags.briefing; + const advisor = useInsightsAdvisorQuery(advisorEnabled); // Shared analytics fetch — sub-pages consume the same cache key. const analyticsQuery = useQuery({ @@ -96,7 +112,7 @@ export function InsightsLayoutShell({ children }: { children: ReactNode }) { return (