Added house function: add, update, view (admin function)
update npm package
This commit is contained in:
149
src/components/form/account/profile-form.tsx
Normal file
149
src/components/form/account/profile-form.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
import { useAuth } from '@components/auth/auth-provider';
|
||||
import AvatarUser from '@components/avatar/avatar-user';
|
||||
import RoleBadge from '@components/avatar/role-badge';
|
||||
import { useAppForm } from '@hooks/use-app-form';
|
||||
import { authClient } from '@lib/auth-client';
|
||||
import { m } from '@paraglide/messages';
|
||||
import { UserCircleIcon } from '@phosphor-icons/react';
|
||||
import { uploadProfileImage } from '@service/profile.api';
|
||||
import { ProfileInput, profileUpdateSchema } from '@service/profile.schema';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@ui/card';
|
||||
import { Field, FieldGroup, FieldLabel } from '@ui/field';
|
||||
import { Input } from '@ui/input';
|
||||
import { useRef } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const defaultValues: ProfileInput = {
|
||||
name: '',
|
||||
image: undefined,
|
||||
};
|
||||
|
||||
const ProfileForm = () => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { data: session, isPending } = useAuth();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
...defaultValues,
|
||||
name: session?.user?.name || '',
|
||||
},
|
||||
validators: {
|
||||
onSubmit: profileUpdateSchema,
|
||||
onChange: profileUpdateSchema,
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
try {
|
||||
let imageKey;
|
||||
if (value.image) {
|
||||
// upload image
|
||||
const formData = new FormData();
|
||||
formData.set('file', value.image);
|
||||
const { imageKey: uploadedKey } = await uploadProfileImage({
|
||||
data: formData,
|
||||
});
|
||||
imageKey = uploadedKey;
|
||||
}
|
||||
|
||||
await authClient.updateUser(
|
||||
{
|
||||
name: value.name,
|
||||
image: imageKey,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
form.reset();
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = '';
|
||||
}
|
||||
queryClient.refetchQueries({
|
||||
queryKey: ['auth', 'session'],
|
||||
});
|
||||
toast.success(m.profile_messages_update_success(), {
|
||||
richColors: true,
|
||||
});
|
||||
},
|
||||
onError: (ctx) => {
|
||||
console.error(ctx.error.code);
|
||||
toast.error(m.backend_message({ code: ctx.error.code }), {
|
||||
richColors: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('update load file', error);
|
||||
toast.error(JSON.stringify(error), {
|
||||
richColors: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (isPending) return null;
|
||||
if (!session?.user?.name) return null;
|
||||
|
||||
return (
|
||||
<Card className="@container/card col-span-1">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl flex items-center gap-2">
|
||||
<UserCircleIcon size={20} />
|
||||
{m.profile_ui_title()}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form
|
||||
id="profile-form"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<FieldGroup>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<AvatarUser className="h-20 w-20" textSize="2xl" />
|
||||
<form.AppField name="image">
|
||||
{(field) => (
|
||||
<field.FileField
|
||||
label="Avatar"
|
||||
className="col-span-2"
|
||||
accept=".jpg, .jpeg, .png, .webp"
|
||||
onChange={(e) => field.handleChange(e.target.files?.[0])}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
</div>
|
||||
<form.AppField name="name">
|
||||
{(field) => <field.TextField label={m.profile_form_name()} />}
|
||||
</form.AppField>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="name">{m.profile_form_email()}</FieldLabel>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
value={session?.user?.email || ''}
|
||||
disabled
|
||||
className="disabled:opacity-80"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="name">{m.profile_form_role()}</FieldLabel>
|
||||
<div className="flex gap-2">
|
||||
<RoleBadge type={session?.user?.role} />
|
||||
</div>
|
||||
</Field>
|
||||
<Field>
|
||||
<form.AppForm>
|
||||
<form.SubscribeButton label={m.ui_update_btn()} />
|
||||
</form.AppForm>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileForm;
|
||||
Reference in New Issue
Block a user