TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import { useRouter } from "next/navigation";4import { updateProfileName } from "@/actions/account";5import { Button } from "@/components/ui/button";6import { Input } from "@/components/ui/input";7import { Field, Hint, Label } from "@/components/ui/label";8import { Alert } from "@/components/ui/alert";910export function ProfileNameForm({ name }: { name: string }) {11 const router = useRouter();12 const [value, setValue] = React.useState(name);13 const [error, setError] = React.useState<string | null>(null);14 const [saved, setSaved] = React.useState(false);15 const [pending, startTransition] = React.useTransition();16 const dirty = value.trim() !== name;1718 return (19 <form20 className="grid gap-3"21 onSubmit={(e) => {22 e.preventDefault();23 setError(null);24 setSaved(false);25 startTransition(async () => {26 const res = await updateProfileName(value);27 if (!res.ok) {28 setError(res.error);29 return;30 }31 setSaved(true);32 router.refresh();33 });34 }}35 >36 {error ? <Alert variant="danger">{error}</Alert> : null}37 {saved ? <Alert variant="success">Name updated.</Alert> : null}38 <Field>39 <Label htmlFor="profile-name">Full name</Label>40 <div className="flex gap-2">41 <Input id="profile-name" value={value} onChange={(e) => setValue(e.target.value)} maxLength={80} autoComplete="name" className="sm:max-w-sm" />42 <Button type="submit" variant="primary" loading={pending} disabled={!dirty || value.trim().length === 0}>43 Save44 </Button>45 </div>46 <Hint>Shown in the dashboard and in emails we send you.</Hint>47 </Field>48 </form>49 );50}51