Added house function: add, update, view (admin function)

update npm package
This commit is contained in:
2026-02-05 21:10:45 +07:00
parent 018f693998
commit 7b14b30320
104 changed files with 3447 additions and 2518 deletions

View 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;