chore: onboarding/MFA-modal WIP, dev-workflow guidance, ideas updates
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { api } from "../api/client";
|
||||
import { showError } from "../banner";
|
||||
import { showError, showSuccess } from "../banner";
|
||||
import type { AuthResponse } from "../types/api";
|
||||
import { GarminMFAModal } from "./GarminMFAModal";
|
||||
import { SyncModal } from "./SyncModal";
|
||||
|
||||
export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () => Promise<void> }) {
|
||||
const [auth, setAuth] = useState<AuthResponse | null>(null);
|
||||
const [code, setCode] = useState("");
|
||||
const [busy, setBusy] = useState(false);
|
||||
// There's no real Garmin logout -- the backend session just sits idle.
|
||||
// "Disconnect" only hides that and shows Connect again locally; a real
|
||||
@@ -29,8 +29,10 @@ export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () =>
|
||||
setBusy(true);
|
||||
try {
|
||||
await onBeforeConnect?.();
|
||||
setAuth(await api.login());
|
||||
const result = await api.login();
|
||||
setAuth(result);
|
||||
setDisconnected(false);
|
||||
if (result.status === "authenticated") showSuccess("Connected to Garmin successfully.");
|
||||
} catch (e) {
|
||||
showError(String(e));
|
||||
} finally {
|
||||
@@ -42,12 +44,13 @@ export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () =>
|
||||
setDisconnected(true);
|
||||
}
|
||||
|
||||
async function submitMFA() {
|
||||
async function submitMFA(code: string) {
|
||||
if (!code.trim()) return;
|
||||
setBusy(true);
|
||||
try {
|
||||
setAuth(await api.submitMFA(code.trim()));
|
||||
setCode("");
|
||||
const result = await api.submitMFA(code.trim());
|
||||
setAuth(result);
|
||||
if (result.status === "authenticated") showSuccess("Connected to Garmin successfully.");
|
||||
} catch (e) {
|
||||
showError(String(e));
|
||||
} finally {
|
||||
@@ -97,7 +100,7 @@ export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () =>
|
||||
<div className="garmin-connection-actions">
|
||||
{status !== "authenticated" && status !== "mfa_required" && (
|
||||
<button disabled={busy} onClick={connect}>
|
||||
Connect to Garmin
|
||||
Connect
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -134,20 +137,12 @@ export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () =>
|
||||
</div>
|
||||
|
||||
{status === "mfa_required" && (
|
||||
<div className="garmin-connection-row">
|
||||
<input
|
||||
placeholder="MFA code"
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
onKeyDown={(e) => e.key === "Enter" && submitMFA()}
|
||||
/>
|
||||
<button disabled={busy} onClick={submitMFA}>
|
||||
Submit code
|
||||
</button>
|
||||
</div>
|
||||
<GarminMFAModal message={auth?.message} busy={busy} onSubmit={submitMFA} onCancel={disconnect} />
|
||||
)}
|
||||
|
||||
{!disconnected && auth?.message && <p className="garmin-connection-message">{auth.message}</p>}
|
||||
{!disconnected && auth?.message && status !== "authenticated" && (
|
||||
<p className="garmin-connection-message">{auth.message}</p>
|
||||
)}
|
||||
|
||||
{showSyncModal && <SyncModal onClose={() => setShowSyncModal(false)} />}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user