"use client"; import { useState, type FormEvent } from "react"; import { useRouter } from "next/navigation"; import { Loader2Icon } from "lucide-react"; import { updatePreferences } from "@/app/(frontend)/account/actions"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Switch } from "@/components/ui/switch"; import { cn } from "@/lib/utils"; import { MUTEABLE_NOTIFICATION_TYPES } from "@/lib/notifications/notificationTypes"; interface PreferencesFormProps { readonly mutedAll: boolean; readonly mutedTypes: readonly string[]; readonly showCallsign: boolean; readonly showVersionOverlay: boolean; readonly showBackgroundTexture: boolean; readonly leadOrActual: "lead" | "actual"; readonly discordEnabled: boolean; readonly discordMutedTypes: readonly string[]; readonly xpDisplayMini: boolean; } export function PreferencesForm({ mutedAll: initialMutedAll, mutedTypes: initialMutedTypes, showCallsign: initialShowCallsign, showVersionOverlay: initialShowVersionOverlay, showBackgroundTexture: initialShowBackgroundTexture, leadOrActual: initialLeadOrActual, discordEnabled: initialDiscordEnabled, discordMutedTypes: initialDiscordMutedTypes, xpDisplayMini: initialXPDisplayMini, }: PreferencesFormProps) { const router = useRouter(); const [mutedAll, setMutedAll] = useState(initialMutedAll); const [mutedTypes, setMutedTypes] = useState(() => [...initialMutedTypes]); const [showCallsign, setShowCallsign] = useState(initialShowCallsign); const [showVersionOverlay, setShowVersionOverlay] = useState(initialShowVersionOverlay); const [showBackgroundTexture, setShowBackgroundTexture] = useState(initialShowBackgroundTexture); const [leadOrActual, setLeadOrActual] = useState<"lead" | "actual">(initialLeadOrActual); const [discordEnabled, setDiscordEnabled] = useState(initialDiscordEnabled); const [discordMutedTypes, setDiscordMutedTypes] = useState(() => [ ...initialDiscordMutedTypes, ]); const [xpDisplayMini, setXPDisplayMini] = useState(initialXPDisplayMini); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [loading, setLoading] = useState(false); const toggleType = (value: string, checked: boolean) => { setMutedTypes((previous) => checked ? [...new Set([...previous, value])] : previous.filter((type) => type !== value), ); }; const toggleDiscordType = (value: string, checked: boolean) => { setDiscordMutedTypes((previous) => checked ? [...new Set([...previous, value])] : previous.filter((type) => type !== value), ); }; const handleSubmit = async (event: FormEvent) => { event.preventDefault(); setLoading(true); setError(null); setSuccess(null); try { const result = await updatePreferences({ mutedAll, mutedTypes, showCallsign, showVersionOverlay, showBackgroundTexture, leadOrActual, discordEnabled, discordMutedTypes, xpDisplayMini, }); if (!result.success) { setError(result.error ?? "Could not save preferences."); return; } setSuccess("Preferences updated."); router.refresh(); } catch (caughtError) { setError( caughtError instanceof Error ? caughtError.message : "Could not save preferences. Please try again.", ); } finally { setLoading(false); } }; return (
Display Choose what appears in the app shell and roster views.
Roster leader label Choose the label used when reviewing the unit roster.
{ if (value === "lead" || value === "actual") setLeadOrActual(value); }} className="flex flex-wrap gap-4" aria-label="Roster leader label" >
Notifications Control the in-app alerts that appear in your inbox.
{MUTEABLE_NOTIFICATION_TYPES.map((notificationType) => { const id = `notification-${notificationType.value.replace(":", "-")}`; return ( ); })}
Discord Choose whether the bot can send you direct messages.
{MUTEABLE_NOTIFICATION_TYPES.map((notificationType) => { const id = `discord-${notificationType.value.replace(":", "-")}`; return ( ); })}
{error && (

{error}

)} {success && (

{success}

)}
); }