chore(style): repo-wide prettier sweep before v1.4.6 tag

Long-overdue prettier sweep; prettier had drifted vs. checked-in code
across ~130 files (mostly long-argument line-break wrapping in TS and
table-padding in markdown). Pure formatting — no semantic changes —
and required to clear the v1.4.6 release gate's `pnpm format:check`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 02:27:17 +02:00
1 parent 67575180b8
commit 02b99553b9
135 files changed
+2159 -1583

No files matched your search

@@ -206,8 +206,7 @@ function FeedbackCategoryBadge({
> = {
BUG: {
label: t("admin.feedback.categoryBug"),
className:
"bg-dracula-red/15 text-dracula-red border-dracula-red/30",
className: "bg-dracula-red/15 text-dracula-red border-dracula-red/30",
},
FEATURE_REQUEST: {
label: t("admin.feedback.categoryFeature"),
@@ -216,8 +215,7 @@ function FeedbackCategoryBadge({
},
QUESTION: {
label: t("admin.feedback.categoryQuestion"),
className:
"bg-dracula-cyan/15 text-dracula-cyan border-dracula-cyan/30",
className: "bg-dracula-cyan/15 text-dracula-cyan border-dracula-cyan/30",
},
OTHER: {
label: t("admin.feedback.categoryOther"),
+19 -5
View File
@@ -76,7 +76,13 @@ export function ComplianceHeatmap({
} | null>(null);
const WEEKDAY_LABELS = [
t("charts.weekdays.mon"), "", t("charts.weekdays.wed"), "", t("charts.weekdays.fri"), "", t("charts.weekdays.sun"),
t("charts.weekdays.mon"),
"",
t("charts.weekdays.wed"),
"",
t("charts.weekdays.fri"),
"",
t("charts.weekdays.sun"),
];
useEffect(() => {
if (!stretch) return;
@@ -98,10 +104,18 @@ export function ComplianceHeatmap({
const { cells, weeks, monthMarkers } = useMemo(() => {
const MONTH_LABELS = [
t("charts.months.jan"), t("charts.months.feb"), t("charts.months.mar"),
t("charts.months.apr"), t("charts.months.may"), t("charts.months.jun"),
t("charts.months.jul"), t("charts.months.aug"), t("charts.months.sep"),
t("charts.months.oct"), t("charts.months.nov"), t("charts.months.dec"),
t("charts.months.jan"),
t("charts.months.feb"),
t("charts.months.mar"),
t("charts.months.apr"),
t("charts.months.may"),
t("charts.months.jun"),
t("charts.months.jul"),
t("charts.months.aug"),
t("charts.months.sep"),
t("charts.months.oct"),
t("charts.months.nov"),
t("charts.months.dec"),
];
const now = new Date();
const cellList: Array<{
+26 -16
View File
@@ -17,12 +17,7 @@ import { useState, useMemo, useId } from "react";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import {
Card,
CardHeader,
CardTitle,
CardContent,
} from "@/components/ui/card";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { formatDateShort } from "@/lib/format";
import { useTranslations } from "@/lib/i18n/context";
import type { DataSummary } from "@/lib/analytics/trends";
@@ -50,10 +45,26 @@ interface MoodChartProps {
// --- Constants ---
const TIME_RANGES_KEYS = [
{ labelKey: "charts.points7Label", points: 7, titleKey: "charts.points7Title" },
{ labelKey: "charts.points30Label", points: 30, titleKey: "charts.points30Title" },
{ labelKey: "charts.points90Label", points: 90, titleKey: "charts.points90Title" },
{ labelKey: "charts.pointsAllLabel", points: 0, titleKey: "charts.pointsAllTitle" },
{
labelKey: "charts.points7Label",
points: 7,
titleKey: "charts.points7Title",
},
{
labelKey: "charts.points30Label",
points: 30,
titleKey: "charts.points30Title",
},
{
labelKey: "charts.points90Label",
points: 90,
titleKey: "charts.points90Title",
},
{
labelKey: "charts.pointsAllLabel",
points: 0,
titleKey: "charts.pointsAllTitle",
},
] as const;
// MOOD_LABELS built dynamically via t() in the component
@@ -95,9 +106,10 @@ function movingAverageByPoints(
});
}
function buildTrendLine(
data: Array<{ date: Date; value: number }>,
): { points: Array<{ date: Date; value: number }>; slopePerDay: number } | null {
function buildTrendLine(data: Array<{ date: Date; value: number }>): {
points: Array<{ date: Date; value: number }>;
slopePerDay: number;
} | null {
if (data.length < 2) return null;
const sorted = [...data].sort((a, b) => a.date.getTime() - b.date.getTime());
@@ -188,9 +200,7 @@ export function MoodChart({ title }: MoodChartProps) {
const ma = movingAverageByPoints(scoreData, 7);
for (const point of ma) {
const pointTimestamp = point.date.getTime();
const existing = enriched.find(
(d) => d.timestamp === pointTimestamp,
);
const existing = enriched.find((d) => d.timestamp === pointTimestamp);
if (existing) {
existing.ma = point.value;
}
+3 -9
View File
@@ -88,9 +88,7 @@ export function TrendCard({
</div>
<div className="mt-2 flex items-baseline gap-2">
<span className="text-3xl font-bold tracking-tight tabular-nums">
{latest !== null
? renderPair(latest, secondary?.latest)
: "—"}
{latest !== null ? renderPair(latest, secondary?.latest) : "—"}
</span>
<span className="text-muted-foreground text-sm tabular-nums">
{unit}
@@ -115,9 +113,7 @@ export function TrendCard({
</TooltipContent>
</Tooltip>
) : (
<span
className={cn("font-medium tabular-nums", avg7ColorClass)}
>
<span className={cn("font-medium tabular-nums", avg7ColorClass)}>
{avg7 !== null ? renderPair(avg7, secondary?.avg7) : "—"}
</span>
)}
@@ -138,9 +134,7 @@ export function TrendCard({
</TooltipContent>
</Tooltip>
) : (
<span
className={cn("font-medium tabular-nums", avg30ColorClass)}
>
<span className={cn("font-medium tabular-nums", avg30ColorClass)}>
{avg30 !== null ? renderPair(avg30, secondary?.avg30) : "—"}
</span>
)}
+4 -6
View File
@@ -39,8 +39,7 @@ export function ErrorDetails({
// in the query string (Withings connect, password reset) and we don't
// want users pasting those into public GitHub issues. Preserve the count
// for context without exposing values.
const loc =
typeof window !== "undefined" ? window.location : null;
const loc = typeof window !== "undefined" ? window.location : null;
const urlPath = loc?.pathname ?? null;
const searchParamCount = loc?.search
? new URLSearchParams(loc.search).toString().split("&").filter(Boolean)
@@ -55,8 +54,7 @@ export function ErrorDetails({
requestId: requestId ?? null,
urlPath,
searchParamCount,
userAgent:
typeof navigator !== "undefined" ? navigator.userAgent : null,
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : null,
locale,
timestamp: new Date().toISOString(),
context,
@@ -79,7 +77,7 @@ export function ErrorDetails({
<p className="text-muted-foreground text-sm">
{t("errorBoundary.description")}
</p>
<div className="bg-muted/50 rounded-md border p-3 font-mono text-xs text-muted-foreground break-all">
<div className="bg-muted/50 text-muted-foreground rounded-md border p-3 font-mono text-xs break-all">
{error.message || t("common.unknownError")}
</div>
<div className="flex flex-wrap items-center gap-2">
@@ -91,7 +89,7 @@ export function ErrorDetails({
)}
<Button onClick={handleCopy} variant="outline" size="sm">
{copied ? (
<CheckCircle2 className="mr-2 h-4 w-4 text-dracula-green" />
<CheckCircle2 className="text-dracula-green mr-2 h-4 w-4" />
) : (
<Copy className="mr-2 h-4 w-4" />
)}
@@ -33,8 +33,8 @@ export function InsightStatusCard({
return (
<Card>
<CardContent className="flex items-center justify-center py-8">
<Loader2 className="h-5 w-5 animate-spin text-dracula-purple" />
<span className="ml-2 text-sm text-muted-foreground">
<Loader2 className="text-dracula-purple h-5 w-5 animate-spin" />
<span className="text-muted-foreground ml-2 text-sm">
{t("common.loading")}
</span>
</CardContent>
@@ -52,7 +52,7 @@ export function InsightStatusCard({
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
<p className="text-muted-foreground text-sm">
{t("insights.noProviderConfigured")}
</p>
</CardContent>
@@ -70,7 +70,7 @@ export function InsightStatusCard({
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
<p className="text-muted-foreground text-sm">
{t("insights.noAnalysisYet")}
</p>
</CardContent>
@@ -79,7 +79,7 @@ export function InsightStatusCard({
}
return (
<Card className="animate-insight-in border-l-2 border-l-dracula-purple">
<Card className="animate-insight-in border-l-dracula-purple border-l-2">
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
@@ -87,14 +87,14 @@ export function InsightStatusCard({
<CardTitle className="text-base">{title}</CardTitle>
</div>
{cached && (
<span className="text-xs text-muted-foreground">
<span className="text-muted-foreground text-xs">
{t("insights.cached")}
</span>
)}
</div>
</CardHeader>
<CardContent className="space-y-2">
<p className="text-sm leading-relaxed text-muted-foreground">{text}</p>
<p className="text-muted-foreground text-sm leading-relaxed">{text}</p>
<LastUpdatedFooter updatedAt={updatedAt} />
</CardContent>
</Card>
@@ -106,7 +106,7 @@ function LastUpdatedFooter({ updatedAt }: { updatedAt: string | null }) {
const fmt = useFormatters();
if (!updatedAt) return null;
return (
<p className="text-xs text-muted-foreground">
<p className="text-muted-foreground text-xs">
{t("insights.lastUpdated")}: {fmt.dateTime(updatedAt)}
</p>
);
+26 -8
View File
@@ -74,7 +74,8 @@ export function InsightsCard() {
});
// Don't show if no API key configured
if (!(settings?.codexStatus === "connected" || settings?.hasAdminKey)) return null;
if (!(settings?.codexStatus === "connected" || settings?.hasAdminKey))
return null;
const insights = generate.data?.insights;
@@ -84,7 +85,9 @@ export function InsightsCard() {
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Sparkles className="text-dracula-purple h-5 w-5" />
<CardTitle className="text-lg">{t("insights.aiInsights")}</CardTitle>
<CardTitle className="text-lg">
{t("insights.aiInsights")}
</CardTitle>
</div>
<Button
variant="ghost"
@@ -97,7 +100,9 @@ export function InsightsCard() {
) : (
<RefreshCw className="mr-1 h-3.5 w-3.5" />
)}
{insights ? t("insights.refreshButton") : t("insights.generateButton")}
{insights
? t("insights.refreshButton")
: t("insights.generateButton")}
</Button>
</div>
</CardHeader>
@@ -123,7 +128,8 @@ export function InsightsCard() {
<div className="space-y-4">
<div className="flex items-center gap-2">
<Badge className={CONFIDENCE_COLORS[insights.confidence] ?? ""}>
{t("insights.confidence")}: {t(`insights.confidence_${insights.confidence}`)}
{t("insights.confidence")}:{" "}
{t(`insights.confidence_${insights.confidence}`)}
</Badge>
{generate.data?.cached && (
<Badge variant="outline" className="text-xs">
@@ -132,10 +138,22 @@ export function InsightsCard() {
)}
</div>
<Section title={t("insights.sectionChanged")} text={insights.changed} />
<Section title={t("insights.sectionStable")} text={insights.stable} />
<Section title={t("insights.sectionDrivers")} text={insights.drivers} />
<Section title={t("insights.sectionNextSteps")} text={insights.nextSteps} />
<Section
title={t("insights.sectionChanged")}
text={insights.changed}
/>
<Section
title={t("insights.sectionStable")}
text={insights.stable}
/>
<Section
title={t("insights.sectionDrivers")}
text={insights.drivers}
/>
<Section
title={t("insights.sectionNextSteps")}
text={insights.nextSteps}
/>
<div className="bg-muted/50 rounded-lg p-3">
<p className="text-muted-foreground text-xs">
+1 -1
View File
@@ -116,7 +116,7 @@ export function AuthShell({ children }: { children: React.ReactNode }) {
) : null}
<a
href="#main-content"
className="bg-primary text-primary-foreground fixed left-2 top-2 z-[100] rounded-md px-4 py-2 text-sm font-medium opacity-0 focus:opacity-100"
className="bg-primary text-primary-foreground fixed top-2 left-2 z-[100] rounded-md px-4 py-2 text-sm font-medium opacity-0 focus:opacity-100"
>
{t("nav.skipToContent")}
</a>
@@ -545,7 +545,11 @@ export function MeasurementList({ onEdit }: MeasurementListProps) {
</div>
{editError && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{editError}
</div>
)}
@@ -88,7 +88,11 @@ function dateTimeLocalToISO(value: string): string {
return new Date(value).toISOString();
}
export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange }: IntakeHistoryListProps) {
export function IntakeHistoryList({
medicationId,
createOpen,
onCreateOpenChange,
}: IntakeHistoryListProps) {
const { isAuthenticated } = useAuth();
const queryClient = useQueryClient();
const { t } = useTranslations();
@@ -120,16 +124,19 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
const [createSkipped, setCreateSkipped] = useState(false);
const [createError, setCreateError] = useState<string | null>(null);
const setCreatingRaw = onCreateOpenChange ?? setInternalCreating;
const setCreating = useCallback((open: boolean) => {
if (open) {
const now = toDateTimeLocalValue(new Date().toISOString());
setCreateScheduledFor(now);
setCreateTakenAt(now);
setCreateSkipped(false);
setCreateError(null);
}
setCreatingRaw(open);
}, [setCreatingRaw]);
const setCreating = useCallback(
(open: boolean) => {
if (open) {
const now = toDateTimeLocalValue(new Date().toISOString());
setCreateScheduledFor(now);
setCreateTakenAt(now);
setCreateSkipped(false);
setCreateError(null);
}
setCreatingRaw(open);
},
[setCreatingRaw],
);
function toggleSort(column: string) {
if (sortBy === column) {
@@ -142,14 +149,7 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
}
const { data, isLoading } = useQuery({
queryKey: [
"medications",
medicationId,
"intake",
page,
sortBy,
sortDir,
],
queryKey: ["medications", medicationId, "intake", page, sortBy, sortDir],
queryFn: async () => {
const params = new URLSearchParams();
params.set("limit", String(PAGE_SIZE));
@@ -227,14 +227,11 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
takenAt: string | null;
skipped: boolean;
}) => {
const res = await fetch(
`/api/medications/${medicationId}/intake`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ scheduledFor, takenAt, skipped }),
},
);
const res = await fetch(`/api/medications/${medicationId}/intake`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ scheduledFor, takenAt, skipped }),
});
const json = await res.json();
if (!res.ok) throw new Error(json.error ?? "Create failed");
},
@@ -267,7 +264,6 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
setEditDeleteDialogOpen(false);
}
function closeCreate() {
if (createMutation.isPending) return;
setCreating(false);
@@ -299,9 +295,8 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
updateMutation.mutate({
eventId: editing.id,
scheduledFor: dateTimeLocalToISO(editScheduledFor),
takenAt: editSkipped || !editTakenAt
? null
: dateTimeLocalToISO(editTakenAt),
takenAt:
editSkipped || !editTakenAt ? null : dateTimeLocalToISO(editTakenAt),
skipped: editSkipped,
});
}
@@ -318,9 +313,10 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
setCreateError(null);
createMutation.mutate({
scheduledFor: dateTimeLocalToISO(createScheduledFor),
takenAt: createSkipped || !createTakenAt
? null
: dateTimeLocalToISO(createTakenAt),
takenAt:
createSkipped || !createTakenAt
? null
: dateTimeLocalToISO(createTakenAt),
skipped: createSkipped,
});
}
@@ -336,7 +332,10 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
}
if (event.takenAt) {
return (
<Badge variant="secondary" className="gap-1 bg-green-500/20 text-green-400">
<Badge
variant="secondary"
className="gap-1 bg-green-500/20 text-green-400"
>
<Check className="h-3 w-3" />
{t("medications.intakeStatusTaken")}
</Badge>
@@ -398,7 +397,9 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
currentDir={sortDir}
onSort={toggleSort}
/>
<TableHead className="w-32">{t("medications.intakeStatus")}</TableHead>
<TableHead className="w-32">
{t("medications.intakeStatus")}
</TableHead>
<SortableHead
column="source"
label={t("medications.intakeSource")}
@@ -419,9 +420,7 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
{formatDateTime(event.scheduledFor)}
</TableCell>
<TableCell className="text-muted-foreground text-sm tabular-nums">
{event.takenAt
? formatDateTime(event.takenAt)
: "—"}
{event.takenAt ? formatDateTime(event.takenAt) : "—"}
</TableCell>
<TableCell>{getStatusBadge(event)}</TableCell>
<TableCell>
@@ -442,7 +441,9 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</Button>
<DeleteButton
label={t("medications.intakeDeleteConfirm")}
description={t("medications.intakeDeleteDescription")}
description={t(
"medications.intakeDeleteDescription",
)}
onConfirm={() => deleteMutation.mutate(event.id)}
/>
</div>
@@ -467,7 +468,8 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</p>
{event.takenAt && (
<p className="text-muted-foreground text-xs tabular-nums">
{t("medications.intakeTakenAt")}: {formatDateTime(event.takenAt)}
{t("medications.intakeTakenAt")}:{" "}
{formatDateTime(event.takenAt)}
</p>
)}
<div className="flex items-center gap-1.5">
@@ -550,7 +552,9 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</div>
<div className="space-y-2">
<Label htmlFor="edit-takenAt">{t("medications.intakeTakenAt")}</Label>
<Label htmlFor="edit-takenAt">
{t("medications.intakeTakenAt")}
</Label>
<Input
id="edit-takenAt"
type="datetime-local"
@@ -575,7 +579,11 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</div>
{editError && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{editError}
</div>
)}
@@ -688,7 +696,9 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</div>
<div className="space-y-2">
<Label htmlFor="create-takenAt">{t("medications.intakeTakenAt")}</Label>
<Label htmlFor="create-takenAt">
{t("medications.intakeTakenAt")}
</Label>
<Input
id="create-takenAt"
type="datetime-local"
@@ -713,7 +723,11 @@ export function IntakeHistoryList({ medicationId, createOpen, onCreateOpenChange
</div>
{createError && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{createError}
</div>
)}
+10 -3
View File
@@ -238,12 +238,15 @@ export function MedicationForm({
const fmt = useFormatters();
const doseUnits = [
"mg", "g", "ml",
"mg",
"g",
"ml",
t("medications.unitDrops"),
t("medications.unitTablets"),
t("medications.unitCapsules"),
t("medications.unitPieces"),
"IE", "µg",
"IE",
"µg",
];
const [name, setName] = useState(initial?.name ?? "");
@@ -739,7 +742,11 @@ export function MedicationForm({
</div>
{error && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{error}
</div>
)}
+5 -1
View File
@@ -162,7 +162,11 @@ export function MoodForm({ onSuccess, onCancel }: MoodFormProps) {
</div>
{error && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{error}
</div>
)}
+21 -6
View File
@@ -76,7 +76,6 @@ const MOOD_LABEL_KEYS: Record<string, string> = {
LAUSIG: "mood.levelLausig",
};
interface MoodEntry {
id: string;
date: string;
@@ -342,7 +341,11 @@ export function MoodList() {
<TableCell className="pl-4 font-semibold tabular-nums">
{entry.score}{" "}
<span className="text-muted-foreground font-normal">
({MOOD_LABEL_KEYS[entry.mood] ? t(MOOD_LABEL_KEYS[entry.mood]) : entry.mood})
(
{MOOD_LABEL_KEYS[entry.mood]
? t(MOOD_LABEL_KEYS[entry.mood])
: entry.mood}
)
</span>
</TableCell>
<TableCell className="text-muted-foreground text-sm">
@@ -388,7 +391,7 @@ export function MoodList() {
className="bg-card border-border flex items-center justify-between rounded-lg border p-3"
>
<div className="flex items-center gap-2.5 overflow-hidden">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-muted">
<div className="bg-muted flex h-8 w-8 shrink-0 items-center justify-center rounded-lg">
<span className="text-lg font-bold tabular-nums">
{entry.score}
</span>
@@ -397,7 +400,11 @@ export function MoodList() {
<span className="text-sm font-semibold tabular-nums">
{entry.score}{" "}
<span className="text-muted-foreground font-normal">
({MOOD_LABEL_KEYS[entry.mood] ? t(MOOD_LABEL_KEYS[entry.mood]) : entry.mood})
(
{MOOD_LABEL_KEYS[entry.mood]
? t(MOOD_LABEL_KEYS[entry.mood])
: entry.mood}
)
</span>
</span>
<p className="text-muted-foreground truncate text-xs">
@@ -471,7 +478,11 @@ export function MoodList() {
<form onSubmit={submitEdit} className="space-y-4">
<div className="space-y-2">
<Label id="edit-mood-level-label">{t("mood.moodLevel")}</Label>
<div role="radiogroup" aria-labelledby="edit-mood-level-label" className="grid grid-cols-5 gap-2">
<div
role="radiogroup"
aria-labelledby="edit-mood-level-label"
className="grid grid-cols-5 gap-2"
>
{MOOD_LEVELS_LIST.map((level) => {
const isSelected = editMood === level;
return (
@@ -530,7 +541,11 @@ export function MoodList() {
</div>
{editError && (
<div role="alert" aria-live="assertive" className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm">
<div
role="alert"
aria-live="assertive"
className="bg-destructive/10 text-destructive rounded-lg p-3 text-sm"
>
{editError}
</div>
)}
+9 -5
View File
@@ -127,6 +127,10 @@ export function AboutSection() {
// Auto-check on mount when the last successful check is older than the
// refresh interval (or has never run). Keeps the UI populated without
// requiring a click — but won't spam GitHub on every navigation.
// The setState inside runCheck() is intentional: the check is the
// whole point of the effect, and the staleness gate prevents a
// cascading-render loop because the timestamp resets after the run.
/* eslint-disable react-hooks/exhaustive-deps, react-hooks/set-state-in-effect */
useEffect(() => {
if (!version) return;
const last = readLastCheckedISO();
@@ -136,8 +140,8 @@ export function AboutSection() {
if (stale) {
void runCheck();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [version?.version]);
/* eslint-enable react-hooks/exhaustive-deps, react-hooks/set-state-in-effect */
return (
<section
@@ -176,14 +180,14 @@ export function AboutSection() {
) : (
<dl className="flex flex-wrap items-baseline gap-x-6 gap-y-3 text-sm">
<div className="flex items-baseline gap-2">
<dt className="text-muted-foreground text-xs uppercase tracking-wide">
<dt className="text-muted-foreground text-xs tracking-wide uppercase">
{t("settings.about.version")}
</dt>
<dd className="font-mono font-medium">v{version.version}</dd>
</div>
<div className="flex items-baseline gap-2">
<dt className="text-muted-foreground text-xs uppercase tracking-wide">
<dt className="text-muted-foreground text-xs tracking-wide uppercase">
{t("settings.about.license")}
</dt>
<dd className="font-mono">{version.license}</dd>
@@ -191,7 +195,7 @@ export function AboutSection() {
{version.buildSha && (
<div className="flex items-baseline gap-2">
<dt className="text-muted-foreground text-xs uppercase tracking-wide">
<dt className="text-muted-foreground text-xs tracking-wide uppercase">
{t("settings.about.gitSha")}
</dt>
<dd className="font-mono">{version.buildSha.slice(0, 7)}</dd>
@@ -200,7 +204,7 @@ export function AboutSection() {
{version.builtAt && (
<div className="flex items-baseline gap-2">
<dt className="text-muted-foreground text-xs uppercase tracking-wide">
<dt className="text-muted-foreground text-xs tracking-wide uppercase">
{t("settings.about.builtAt", { time: "" }).trim() ||
t("settings.about.gitSha")}
</dt>
+10 -6
View File
@@ -487,7 +487,9 @@ function UserAIProviderSubsection() {
queryClient.invalidateQueries({ queryKey: ["insights"] });
},
onError: (e) => {
setSaveMsg(e instanceof Error ? e.message : t("settings.ai.errorGeneric"));
setSaveMsg(
e instanceof Error ? e.message : t("settings.ai.errorGeneric"),
);
setSaveOk(false);
},
});
@@ -522,9 +524,7 @@ function UserAIProviderSubsection() {
);
setTestOk(true);
} catch (e) {
setTestMsg(
e instanceof Error ? e.message : t("settings.ai.testFailed"),
);
setTestMsg(e instanceof Error ? e.message : t("settings.ai.testFailed"));
setTestOk(false);
} finally {
setTesting(false);
@@ -556,11 +556,15 @@ function UserAIProviderSubsection() {
className="bg-background border-input mt-1 h-9 w-full rounded-md border px-2 text-sm"
>
<option value="">{t("settings.ai.providerOptionDefault")}</option>
<option value="OPENAI">{t("settings.ai.providerOptionOpenai")}</option>
<option value="OPENAI">
{t("settings.ai.providerOptionOpenai")}
</option>
<option value="ANTHROPIC">
{t("settings.ai.providerOptionAnthropic")}
</option>
<option value="LOCAL">{t("settings.ai.providerOptionLocal")}</option>
<option value="LOCAL">
{t("settings.ai.providerOptionLocal")}
</option>
</select>
</div>
+15 -8
View File
@@ -3,7 +3,12 @@
import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { SlidersHorizontal, RotateCcw, Loader2, AlertTriangle } from "lucide-react";
import {
SlidersHorizontal,
RotateCcw,
Loader2,
AlertTriangle,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -91,7 +96,9 @@ export function ThresholdsSection({ id }: { id: string }) {
toast.success(t("thresholds.saveSuccess"));
},
onError: (err) =>
toast.error(err instanceof Error ? err.message : t("thresholds.saveError")),
toast.error(
err instanceof Error ? err.message : t("thresholds.saveError"),
),
});
const resetMutation = useMutation({
@@ -114,7 +121,7 @@ export function ThresholdsSection({ id }: { id: string }) {
return (
<div
id={id}
className="bg-card border-border scroll-mt-28 rounded-xl border p-6 space-y-5"
className="bg-card border-border scroll-mt-28 space-y-5 rounded-xl border p-6"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
@@ -138,7 +145,7 @@ export function ThresholdsSection({ id }: { id: string }) {
</p>
{isLoading || !data ? (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<div className="text-muted-foreground flex items-center gap-2 text-sm">
<Loader2 className="h-4 w-4 animate-spin" />
{t("common.loading")}
</div>
@@ -202,7 +209,7 @@ function MetricRow({
const defaultRange = effective?.default;
return (
<div className="rounded-lg border border-border p-4 space-y-3">
<div className="border-border space-y-3 rounded-lg border p-4">
<div className="flex items-center justify-between gap-3">
<div className="min-w-0">
<p className="text-sm font-medium">{t(METRIC_LABEL_KEYS[metric])}</p>
@@ -212,7 +219,7 @@ function MetricRow({
: t("thresholds.unsetExplanation")}
</p>
</div>
<div className="flex items-center gap-2 shrink-0">
<div className="flex shrink-0 items-center gap-2">
<Label htmlFor={`override-${metric}`} className="text-xs">
{overrideMode
? t("thresholds.overrideModeLabel")
@@ -300,8 +307,8 @@ function MetricRow({
defaultRange &&
(override!.min < defaultRange.greenMin * 0.7 ||
override!.max > defaultRange.greenMax * 1.3) && (
<div className="flex items-start gap-2 rounded-md border-l-2 border-dracula-orange/50 bg-dracula-orange/5 p-2 text-xs">
<AlertTriangle className="mt-0.5 h-3 w-3 shrink-0 text-dracula-orange" />
<div className="border-dracula-orange/50 bg-dracula-orange/5 flex items-start gap-2 rounded-md border-l-2 p-2 text-xs">
<AlertTriangle className="text-dracula-orange mt-0.5 h-3 w-3 shrink-0" />
<span>{t("thresholds.overrideWarning")}</span>
</div>
)}
+1 -4
View File
@@ -85,10 +85,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="dialog-header"
className={cn(
"flex flex-col gap-2 pr-9 text-left",
className,
)}
className={cn("flex flex-col gap-2 pr-9 text-left", className)}
{...props}
/>
);
+1 -4
View File
@@ -23,10 +23,7 @@ export function PasswordStrength({
minLength = 12,
}: PasswordStrengthProps) {
const { t, locale } = useTranslations();
const { translate } = useMemo(
() => getZxcvbnTranslations(locale),
[locale],
);
const { translate } = useMemo(() => getZxcvbnTranslations(locale), [locale]);
const [result, setResult] = useState<{
score: number;
feedback: { warning: string; suggestions: string[] };