1
0
Fork 0
polaris-task-force/src/components/frontend/account/AccountProfileForm.tsx
Z8MB1E c81036bd82 feat(account): add self-service account page with profile, password, Discord request, and preferences
- Add /account page backed by server actions
- Allow editing display name, changing password, and requesting a Discord username change
- Add notification muting and callsign display preferences UI
- Add shadcn card component and account event types
2026-08-11 23:25:21 -04:00

62 lines
1.9 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { Loader2Icon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { updateDisplayName } from "@/app/(frontend)/account/actions";
export function AccountProfileForm({ displayName }: { displayName: string }) {
const router = useRouter();
const [value, setValue] = useState(displayName);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
setError(null);
setSuccess(null);
try {
const res = await updateDisplayName({ displayName: value });
if (!res.success) {
setError(res.error ?? "Failed to update display name.");
return;
}
setSuccess("Display name updated.");
router.refresh();
} catch {
setError("Something went wrong. Please try again.");
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="displayName">In-Game Name</Label>
<Input
id="displayName"
name="displayName"
value={value}
onChange={(e) => setValue(e.target.value)}
maxLength={60}
required
/>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
{success && <p className="text-sm text-emerald-500">{success}</p>}
<div>
<Button type="submit" disabled={loading}>
{loading && <Loader2Icon className="size-4 animate-spin" />}
{loading ? "Saving..." : "Save"}
</Button>
</div>
</form>
);
}