satupeta-main/app/(modules)/admin/user/_components/form.tsx

330 lines
10 KiB
TypeScript
Raw Normal View History

2026-01-27 02:31:12 +00:00
"use client";
import { Button } from "@/shared/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/shared/components/ui/form";
import { Input } from "@/shared/components/ui/input";
import { Switch } from "@/shared/components/ui/switch";
import { ImageUpload } from "@/shared/components/image-upload";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/components/ui/select";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { userSchema } from "@/shared/schemas/user"; // You should define this Zod schema
import { useQuery } from "@tanstack/react-query";
import organizationApi from "@/shared/services/organization";
import { Organization } from "@/shared/types/organization";
import { Role } from "@/shared/types/role";
import roleApi from "@/shared/services/role";
import { getRoleLabelById } from "@/shared/config/role";
import { User } from "@/shared/types/user";
type UserFormValues = z.infer<typeof userSchema>;
// Helper component for required field labels
const RequiredFormLabel = ({ children }: { children: React.ReactNode }) => (
<FormLabel>
{children} <span className="text-red-500">*</span>
</FormLabel>
);
interface UserFormProps {
defaultValues?: Partial<User>;
onSubmitAction: (data: UserFormValues) => void;
isSubmitting?: boolean;
onCancelAction?: () => void;
isAdministrator?: boolean;
}
export function UserForm({
defaultValues,
onSubmitAction,
isSubmitting,
onCancelAction,
isAdministrator = false,
}: UserFormProps) {
const form = useForm<UserFormValues>({
resolver: zodResolver(userSchema),
defaultValues: {
name: defaultValues?.name || "",
email: defaultValues?.email || "",
username: defaultValues?.username || "",
employee_id: defaultValues?.employee_id || "",
position: defaultValues?.position || "",
profile_picture: defaultValues?.profile_picture || "",
role_id: defaultValues?.role?.id || "",
organization_id: defaultValues?.organization?.id || "",
is_active: defaultValues?.is_active ?? true,
},
});
const { data: organizations, isLoading: isOrgLoading } = useQuery<
Organization[]
>({
queryKey: ["organizations"],
queryFn: () =>
organizationApi.getOrganizations().then((response) => response.items),
});
const { data: roles, isLoading: isRolesLoading } = useQuery<Role[]>({
queryKey: ["roles"],
queryFn: () => roleApi.getRoles().then((response) => response.items),
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmitAction)} className="space-y-6">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Nama Lengkap</RequiredFormLabel>
<FormControl>
<Input placeholder="Masukkan nama lengkap" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Username</RequiredFormLabel>
<FormControl>
<Input placeholder="Masukkan username" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Password</RequiredFormLabel>
<FormControl>
<Input
type="password"
placeholder="Masukkan password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="confirm_password"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Konfirmasi Password</RequiredFormLabel>
<FormControl>
<Input
type="password"
placeholder="Ulangi password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Email</RequiredFormLabel>
<FormControl>
<Input placeholder="Masukkan email" type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="employee_id"
render={({ field }) => (
<FormItem>
<FormLabel>NIP</FormLabel>
<FormControl>
<Input placeholder="Masukkan NIP" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="position"
render={({ field }) => (
<FormItem>
<FormLabel>Jabatan</FormLabel>
<FormControl>
<Input placeholder="Masukkan jabatan" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="role_id"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Role</RequiredFormLabel>
<FormControl>
<Select
value={field.value}
onValueChange={field.onChange}
disabled={isRolesLoading}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Pilih role">
{roles?.find((role) => role.id === field.value)?.name
? getRoleLabelById(
roles?.find((role) => role.id === field.value)
?.name || ""
)
: ""}
</SelectValue>
</SelectTrigger>
<SelectContent>
{roles
?.filter(
(role) =>
isAdministrator || role.name !== "administrator"
)
.map((role: Role) => (
<SelectItem key={role.id} value={role.id}>
{getRoleLabelById(role.name)}
</SelectItem>
))}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="organization_id"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Organisasi</RequiredFormLabel>
<FormControl>
<Select
value={field.value}
onValueChange={field.onChange}
disabled={isOrgLoading}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Pilih organisasi">
{Array.isArray(organizations)
? organizations.find((org) => org.id === field.value)
?.name ?? ""
: ""}
</SelectValue>
</SelectTrigger>
<SelectContent>
{Array.isArray(organizations)
? organizations.map((org: Organization) => (
<SelectItem key={org.id} value={org.id}>
{org.name}
</SelectItem>
))
: null}
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="profile_picture"
render={({ field }) => (
<FormItem>
<FormLabel>Foto Profil</FormLabel>
<FormControl>
<ImageUpload
value={field.value}
onChange={field.onChange}
onRemove={() => field.onChange("")}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="is_active"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
<div className="space-y-0.5">
<FormLabel className="text-base">Status</FormLabel>
<div className="text-sm text-muted-foreground">
Aktifkan atau nonaktifkan pengguna
</div>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<div className="flex justify-end space-x-4">
{onCancelAction && (
<Button
type="button"
variant="outline"
onClick={onCancelAction}
disabled={isSubmitting}
>
Batal
</Button>
)}
<Button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Menyimpan..." : "Simpan"}
</Button>
</div>
</form>
</Form>
);
}