89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import { CheckCircle2, XCircle } from "lucide-react";
|
|
import { SyncButton } from "@/components/sync-button";
|
|
import { formatDate } from "@/lib/format";
|
|
import { getLastSyncAt } from "@/lib/models/running";
|
|
import { getGarminCredentials, getSavedOauth1Token } from "@/lib/models/garmin-auth";
|
|
import { getCurrentUserId } from "@/lib/session";
|
|
import { GarminCredentialsForm } from "./garmin-credentials-form";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
function StatusRow({ label, ok, okLabel = "Skonfigurowano", failLabel = "Brak konfiguracji" }: {
|
|
label: string;
|
|
ok: boolean;
|
|
okLabel?: string;
|
|
failLabel?: string;
|
|
}) {
|
|
return (
|
|
<div className="flex items-center justify-between rounded-lg border border-muted/40 bg-surface p-4">
|
|
<span className="text-fg">{label}</span>
|
|
{ok ? (
|
|
<span className="flex items-center gap-1.5 text-sm text-fg/70">
|
|
<CheckCircle2 size={16} className="text-accent" />
|
|
{okLabel}
|
|
</span>
|
|
) : (
|
|
<span className="flex items-center gap-1.5 text-sm text-fg/50">
|
|
<XCircle size={16} />
|
|
{failLabel}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default async function SettingsPage() {
|
|
const userId = await getCurrentUserId();
|
|
const [lastSyncAt, garminCreds, garminToken] = await Promise.all([
|
|
getLastSyncAt(userId),
|
|
getGarminCredentials(userId),
|
|
getSavedOauth1Token(userId),
|
|
]);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-fg">Ustawienia</h1>
|
|
<p className="mt-1 text-sm text-fg/60">Konfiguracja konta i synchronizacja Garmin.</p>
|
|
</div>
|
|
|
|
<section className="flex flex-col gap-3">
|
|
<h2 className="text-lg font-semibold text-fg">Status</h2>
|
|
<StatusRow label="MongoDB" ok={Boolean(process.env.MONGODB_URI)} />
|
|
<StatusRow
|
|
label="Garmin Connect — token sesji"
|
|
ok={Boolean(garminToken)}
|
|
okLabel="Aktywny (synchronizacja działa)"
|
|
failLabel="Brak tokenu — wymagane logowanie"
|
|
/>
|
|
<StatusRow
|
|
label="Garmin Connect — dane logowania"
|
|
ok={Boolean(garminCreds)}
|
|
okLabel={`Zapisano (${garminCreds?.email})`}
|
|
failLabel="Brak — potrzebne gdy token wygaśnie"
|
|
/>
|
|
<StatusRow label="Claude API" ok={Boolean(process.env.ANTHROPIC_API_KEY)} />
|
|
</section>
|
|
|
|
<section className="flex flex-col gap-3">
|
|
<h2 className="text-lg font-semibold text-fg">Konto Garmin Connect</h2>
|
|
<div className="rounded-lg border border-muted/40 bg-surface p-4">
|
|
<GarminCredentialsForm savedEmail={garminCreds?.email ?? null} />
|
|
</div>
|
|
</section>
|
|
|
|
<section className="flex flex-col gap-3">
|
|
<h2 className="text-lg font-semibold text-fg">Synchronizacja z Garmin</h2>
|
|
<div className="flex items-center justify-between rounded-lg border border-muted/40 bg-surface p-4">
|
|
<span className="text-sm text-fg/70">
|
|
{lastSyncAt
|
|
? `Ostatnia synchronizacja: ${formatDate(lastSyncAt)}`
|
|
: "Jeszcze nie zsynchronizowano"}
|
|
</span>
|
|
<SyncButton />
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|