178 lines
5.4 KiB
TypeScript
178 lines
5.4 KiB
TypeScript
import type { KycSubmission } from './kyc.types';
|
|
import { useForm } from '@tanstack/react-form';
|
|
import { useState } from 'react';
|
|
import { toast } from 'sonner';
|
|
import z from 'zod';
|
|
import {
|
|
Field,
|
|
FieldError,
|
|
FieldLabel,
|
|
} from '@/components/ui/field';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
import { Button } from '../../ui/button';
|
|
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog';
|
|
|
|
const CnridSchema = z.object({
|
|
cnrid: z.string().min(18, '身份证号应为18位').max(18, '身份证号应为18位'),
|
|
name: z.string().min(2, '姓名应至少2个字符').max(10, '姓名应不超过10个字符'),
|
|
});
|
|
|
|
function CnridForm({ onSubmit }: { onSubmit: OnSubmit }) {
|
|
const form = useForm({
|
|
defaultValues: {
|
|
cnrid: '',
|
|
name: '',
|
|
},
|
|
validators: {
|
|
onSubmit: CnridSchema,
|
|
},
|
|
onSubmit: async (values) => {
|
|
await onSubmit({
|
|
method: 'cnrid',
|
|
...values.value,
|
|
}).catch(() => {
|
|
toast('认证失败,请稍后再试');
|
|
});
|
|
},
|
|
});
|
|
return (
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
void form.handleSubmit();
|
|
}}
|
|
className="flex flex-col gap-4"
|
|
>
|
|
<form.Field name="name">
|
|
{field => (
|
|
<Field>
|
|
<FieldLabel htmlFor="name">姓名</FieldLabel>
|
|
<Input
|
|
id="name"
|
|
name="name"
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={e => field.handleChange(e.target.value)}
|
|
/>
|
|
<FieldError errors={field.state.meta.errors} />
|
|
</Field>
|
|
)}
|
|
</form.Field>
|
|
<form.Field name="cnrid">
|
|
{field => (
|
|
<Field>
|
|
<FieldLabel htmlFor="cnrid">身份证号</FieldLabel>
|
|
<Input
|
|
id="cnrid"
|
|
name="cnrid"
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={e => field.handleChange(e.target.value)}
|
|
/>
|
|
<FieldError errors={field.state.meta.errors} />
|
|
</Field>
|
|
)}
|
|
</form.Field>
|
|
<DialogFooter>
|
|
<form.Subscribe
|
|
selector={state => [state.canSubmit, state.isPristine, state.isSubmitting]}
|
|
children={([canSubmit, isPristine, isSubmitting]) => (
|
|
<Button type="submit" disabled={!canSubmit || isPristine || isSubmitting}>{isSubmitting ? '...' : '开始认证'}</Button>
|
|
)}
|
|
/>
|
|
</DialogFooter>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
const PassportSchema = z.object({
|
|
passportId: z.string().min(9, '护照号应为9个字符').max(9, '护照号应为9个字符'),
|
|
});
|
|
|
|
function PassportForm({ onSubmit }: { onSubmit: OnSubmit }) {
|
|
const form = useForm({
|
|
defaultValues: {
|
|
passportId: '',
|
|
},
|
|
validators: {
|
|
onSubmit: PassportSchema,
|
|
},
|
|
onSubmit: async (values) => {
|
|
await onSubmit({
|
|
method: 'passport',
|
|
...values.value,
|
|
}).catch(() => {
|
|
toast('认证失败,请稍后再试');
|
|
});
|
|
},
|
|
});
|
|
return (
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
void form.handleSubmit();
|
|
}}
|
|
className="flex flex-col gap-4"
|
|
>
|
|
<form.Field name="passportId">
|
|
{field => (
|
|
<Field>
|
|
<FieldLabel htmlFor="passportId">护照号</FieldLabel>
|
|
<Input
|
|
id="passportId"
|
|
name="passportId"
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={e => field.handleChange(e.target.value)}
|
|
/>
|
|
<FieldError errors={field.state.meta.errors} />
|
|
</Field>
|
|
)}
|
|
</form.Field>
|
|
<DialogFooter>
|
|
<form.Subscribe
|
|
selector={state => [state.canSubmit, state.isPristine, state.isSubmitting]}
|
|
children={([canSubmit, isPristine, isSubmitting]) => (
|
|
<Button type="submit" disabled={!canSubmit || isPristine || isSubmitting}>{isSubmitting ? '...' : '开始认证'}</Button>
|
|
)}
|
|
/>
|
|
</DialogFooter>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
type OnSubmit = (submission: KycSubmission) => Promise<void>;
|
|
|
|
export function KycMethodSelectionDialogView({ onSubmit }: { onSubmit: OnSubmit }) {
|
|
const [kycMethod, setKycMethod] = useState<string | null>(null);
|
|
|
|
return (
|
|
<DialogContent className="max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>选择身份认证模式</DialogTitle>
|
|
<DialogDescription className="prose">
|
|
<p>我们支持身份证和护照认证。</p>
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<Label htmlFor="selection">身份认证模式</Label>
|
|
<Select onValueChange={setKycMethod}>
|
|
<SelectTrigger className="w-[180px]">
|
|
<SelectValue placeholder="请选择..." />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectGroup id="selection">
|
|
<SelectItem value="cnrid">身份证</SelectItem>
|
|
<SelectItem value="passport">护照</SelectItem>
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
{kycMethod === 'cnrid' && <CnridForm onSubmit={onSubmit} />}
|
|
{kycMethod === 'passport' && <PassportForm onSubmit={onSubmit} />}
|
|
</DialogContent>
|
|
);
|
|
}
|