Files
tonePage/apps/frontend/app/console/(with-menu)/profile/page.tsx

217 lines
8.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { Button } from "@/components/ui/button";
import { Field, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from "@/components/ui/field";
import { useUserStore } from "@/store/useUserStore";
import { Checkbox } from "@radix-ui/react-checkbox";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { ReactElement, useMemo, useState } from "react";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { AuthAPI } from "@/lib/api/client";
import { GeneralErrorHandler, handleAPIError } from "@/lib/api/common";
import { startRegistration } from '@simplewebauthn/browser';
import { toast } from "sonner";
export default function Page() {
const userStore = useUserStore();
const user = userStore.user;
return (
<div className="w-full">
<form onSubmit={e => {
e.preventDefault();
}}>
<FieldGroup className="gap-5">
<FieldSet>
<FieldLegend></FieldLegend>
<FieldDescription></FieldDescription>
<FieldGroup className="gap-5">
{
[
{
name: 'username',
localName: '用户名',
required: true,
defaultValue: user?.username,
},
{
name: 'nickname',
localName: '昵称',
required: true,
defaultValue: user?.nickname,
},
{
name: 'email',
localName: '电子邮箱',
required: false,
defaultValue: user?.email,
},
{
name: 'phone',
localName: '手机号',
required: false,
defaultValue: user?.phone,
description: '当前仅支持中国大陆(+86手机号'
},
].map(({ name, localName, required, defaultValue, description }) => (
<Field key={name} className="gap-2">
<FieldLabel htmlFor={`console-profile-${name}`} className="text-zinc-800">
{localName}
</FieldLabel>
<Input
id={`console-profile-${name}`}
name={name}
defaultValue={defaultValue}
placeholder={localName}
required={required}
disabled
/>
{
description && (
<FieldDescription>
{description}
</FieldDescription>
)
}
</Field>
))
}
</FieldGroup>
</FieldSet>
<Field orientation="horizontal">
<Button type="submit" disabled></Button>
<Button variant="outline" type="button" disabled>
</Button>
</Field>
</FieldGroup>
</form>
<FieldSeparator className="mt-2 mb-2" />
<FieldGroup className="gap-5">
<FieldSet>
<FieldLegend></FieldLegend>
<FieldDescription>
PassKey
</FieldDescription>
<PasskeyList />
<div>
<AddPasskeyDialog>
<Button></Button>
</AddPasskeyDialog>
</div>
</FieldSet>
</FieldGroup>
</div>
)
}
interface AddPasskeyDialogProps {
children: ReactElement;
}
function AddPasskeyDialog({ children }: AddPasskeyDialogProps) {
const [open, setOpen] = useState(false);
const handleSubmit = async (name: string) => {
try {
name = name.trim();
if (name.length === 0) {
throw new Error('通行证名称不能为空')
}
const options = await AuthAPI.getPasskeyRegisterOptions();
const credential = await startRegistration({ optionsJSON: options }).catch(() => null);
if (credential === null) {
throw new Error('认证超时');
}
const registerRes = await AuthAPI.passkeyRegister(name, credential);
if (registerRes.id) {
toast.success('添加成功');
setOpen(false);
}
} catch (error) {
console.log(error)
handleAPIError(error, GeneralErrorHandler);
}
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
{children}
</DialogTrigger>
<DialogContent className="sm:max-w-100">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
😊
</DialogDescription>
</DialogHeader>
<form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
handleSubmit(formData.get('name')?.toString() || '');
}}>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="console-add-passkey-name"></Label>
<Input id="console-add-passkey-name" name="name" required />
</div>
</div>
<DialogFooter className="mt-6">
<DialogClose asChild>
<Button variant="outline"></Button>
</DialogClose>
<Button type="submit"></Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog >
)
}
function PasskeyList() {
return (
<Table>
{/* <TableCaption>A list of your recent invoices.</TableCaption> */}
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">INV001</TableCell>
<TableCell>Paid</TableCell>
<TableCell>Credit Card</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
</TableBody>
</Table>
)
}