557 lines
17 KiB
TypeScript
557 lines
17 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Button } from "@/components/ui/button";
|
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import {
|
|
createUser,
|
|
updateUser,
|
|
getUserDetail,
|
|
createWorkHistory,
|
|
createEducationHistory,
|
|
UserData,
|
|
WorkHistoryData,
|
|
EducationHistoryData,
|
|
} from "@/service/user";
|
|
import { toast } from "react-hot-toast";
|
|
import Navbar from "../navbar";
|
|
|
|
interface UserFormProps {
|
|
userId?: number;
|
|
mode: "create" | "edit";
|
|
}
|
|
|
|
interface EducationItem {
|
|
schoolName: string;
|
|
major: string;
|
|
educationLevel: string;
|
|
graduationYear: string;
|
|
}
|
|
|
|
interface WorkItem {
|
|
jobTitle: string;
|
|
companyName: string;
|
|
startDate: string;
|
|
endDate: string;
|
|
}
|
|
|
|
export default function UserForm({ userId, mode }: UserFormProps) {
|
|
const router = useRouter();
|
|
const [mounted, setMounted] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [userType, setUserType] = useState<"tenaga_ahli" | "pengguna_umum">(
|
|
"tenaga_ahli",
|
|
);
|
|
const [educationList, setEducationList] = useState<EducationItem[]>([
|
|
{ schoolName: "", major: "", educationLevel: "", graduationYear: "" },
|
|
]);
|
|
const [workList, setWorkList] = useState<WorkItem[]>([
|
|
{ jobTitle: "", companyName: "", startDate: "", endDate: "" },
|
|
]);
|
|
const [formData, setFormData] = useState<UserData>({
|
|
username: "",
|
|
email: "",
|
|
fullname: "",
|
|
address: "",
|
|
phoneNumber: "",
|
|
whatsappNumber: "",
|
|
password: "",
|
|
dateOfBirth: "",
|
|
genderType: "male",
|
|
degree: "",
|
|
userLevelId: 3,
|
|
userRoleId: 3,
|
|
});
|
|
|
|
// Handle mounting and load user data for edit mode
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
if (mode === "edit" && userId) {
|
|
loadUserData();
|
|
}
|
|
}, [userId, mode]);
|
|
|
|
const loadUserData = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const response = await getUserDetail(userId!);
|
|
if (response.success) {
|
|
const data = response.data;
|
|
|
|
setFormData({
|
|
username: data.username,
|
|
email: data.email,
|
|
fullname: data.fullname,
|
|
address: data.address,
|
|
phoneNumber: data.phoneNumber,
|
|
whatsappNumber: data.whatsappNumber,
|
|
password: "", // Don't load password for security
|
|
dateOfBirth: data.dateOfBirth,
|
|
genderType: data.genderType as "male" | "female",
|
|
degree: data.degree || "",
|
|
userLevelId: data.userLevelId,
|
|
userRoleId: data.userRoleId,
|
|
});
|
|
|
|
// Set user type based on role
|
|
setUserType(data.userRoleId === 2 ? "tenaga_ahli" : "pengguna_umum");
|
|
}
|
|
} catch (error) {
|
|
toast.error("Gagal memuat data user");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleInputChange = (field: keyof UserData, value: any) => {
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
[field]: value,
|
|
}));
|
|
};
|
|
|
|
const handleAddEducation = () => {
|
|
setEducationList([
|
|
...educationList,
|
|
{ schoolName: "", major: "", educationLevel: "", graduationYear: "" },
|
|
]);
|
|
};
|
|
|
|
const handleAddWork = () => {
|
|
setWorkList([
|
|
...workList,
|
|
{ jobTitle: "", companyName: "", startDate: "", endDate: "" },
|
|
]);
|
|
};
|
|
|
|
const handleEducationChange = (
|
|
index: number,
|
|
field: keyof EducationItem,
|
|
value: string,
|
|
) => {
|
|
const updated = [...educationList];
|
|
updated[index][field] = value;
|
|
setEducationList(updated);
|
|
};
|
|
|
|
const handleWorkChange = (
|
|
index: number,
|
|
field: keyof WorkItem,
|
|
value: string,
|
|
) => {
|
|
const updated = [...workList];
|
|
updated[index][field] = value;
|
|
setWorkList(updated);
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
try {
|
|
setLoading(true);
|
|
|
|
// Set user role and level based on user type
|
|
const userData = {
|
|
...formData,
|
|
userRoleId: userType === "tenaga_ahli" ? 3 : 4,
|
|
userLevelId: userType === "tenaga_ahli" ? 3 : 4,
|
|
};
|
|
|
|
let response;
|
|
if (mode === "create") {
|
|
response = await createUser(userData);
|
|
} else {
|
|
// Remove password from update if empty
|
|
const updateData = { ...userData };
|
|
if (!updateData.password) {
|
|
const { password, ...updateDataWithoutPassword } = updateData;
|
|
response = await updateUser(userId!, updateDataWithoutPassword);
|
|
} else {
|
|
response = await updateUser(userId!, updateData);
|
|
}
|
|
}
|
|
|
|
if (!response?.error) {
|
|
const userId = response?.data?.data?.id;
|
|
|
|
if (userId && userType === "tenaga_ahli") {
|
|
// Create education history
|
|
for (const education of educationList) {
|
|
if (
|
|
education.schoolName &&
|
|
education.major &&
|
|
education.educationLevel &&
|
|
education.graduationYear
|
|
) {
|
|
const educationData: EducationHistoryData = {
|
|
userId: userId,
|
|
schoolName: education.schoolName,
|
|
major: education.major,
|
|
educationLevel: education.educationLevel,
|
|
graduationYear: parseInt(education.graduationYear),
|
|
};
|
|
await createEducationHistory(educationData);
|
|
}
|
|
}
|
|
|
|
// Create work history
|
|
for (const work of workList) {
|
|
if (
|
|
work.jobTitle &&
|
|
work.companyName &&
|
|
work.startDate &&
|
|
work.endDate
|
|
) {
|
|
const workData: WorkHistoryData = {
|
|
userId: userId,
|
|
jobTitle: work.jobTitle,
|
|
companyName: work.companyName,
|
|
startDate: work.startDate,
|
|
endDate: work.endDate,
|
|
};
|
|
await createWorkHistory(workData);
|
|
}
|
|
}
|
|
}
|
|
|
|
toast.success(
|
|
`User berhasil ${mode === "create" ? "dibuat" : "diperbarui"}`,
|
|
);
|
|
router.push("/admin/management-user");
|
|
} else {
|
|
toast.error(response.message || "Terjadi kesalahan");
|
|
}
|
|
} catch (error) {
|
|
toast.error("Terjadi kesalahan saat menyimpan user");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (!mounted) {
|
|
return (
|
|
<div className="flex justify-center items-center h-64">
|
|
<div className="text-lg">Loading...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (loading && mode === "edit") {
|
|
return (
|
|
<div className="flex justify-center items-center h-64">
|
|
<div className="text-lg">Memuat data...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex-1 overflow-hidden flex flex-col h-[90vh]">
|
|
<Navbar
|
|
title="Management User,/admin/management-user"
|
|
subTitle="Edit User"
|
|
/>
|
|
|
|
<div className="flex items-center justify-between mt-10">
|
|
<h1 className="text-2xl font-semibold">
|
|
{mode === "create" ? "Tambah User Baru" : "Edit User"}
|
|
</h1>
|
|
<Button variant="outline" onClick={() => router.back()}>
|
|
Kembali
|
|
</Button>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
{/* User Type Selection */}
|
|
<div className="bg-white p-6 rounded-lg border">
|
|
<h2 className="text-lg font-semibold mb-4">Jenis Pengguna</h2>
|
|
<RadioGroup
|
|
value={userType}
|
|
onValueChange={(value: "tenaga_ahli" | "pengguna_umum") =>
|
|
setUserType(value)
|
|
}
|
|
className="flex space-x-6"
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="tenaga_ahli" id="tenaga_ahli" />
|
|
<Label htmlFor="tenaga_ahli">Tenaga Ahli</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="pengguna_umum" id="pengguna_umum" />
|
|
<Label htmlFor="pengguna_umum">Pengguna Umum</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</div>
|
|
|
|
{/* Basic Information */}
|
|
<div className="bg-white p-6 rounded-lg border">
|
|
<h2 className="text-lg font-semibold mb-4">Informasi Dasar</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<Label htmlFor="fullname">Nama Lengkap *</Label>
|
|
<Input
|
|
id="fullname"
|
|
value={formData.fullname}
|
|
onChange={(e) => handleInputChange("fullname", e.target.value)}
|
|
placeholder="Masukkan Nama Lengkap"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="username">Username *</Label>
|
|
<Input
|
|
id="username"
|
|
value={formData.username}
|
|
onChange={(e) => handleInputChange("username", e.target.value)}
|
|
placeholder="Masukkan Username"
|
|
required
|
|
/>
|
|
</div>
|
|
{userType === "tenaga_ahli" && (
|
|
<div>
|
|
<Label htmlFor="degree">Gelar</Label>
|
|
<Input
|
|
id="degree"
|
|
value={formData.degree}
|
|
onChange={(e) => handleInputChange("degree", e.target.value)}
|
|
placeholder="Masukkan Gelar"
|
|
/>
|
|
</div>
|
|
)}
|
|
<div>
|
|
<Label htmlFor="email">Email *</Label>
|
|
<Input
|
|
id="email"
|
|
type="email"
|
|
value={formData.email}
|
|
onChange={(e) => handleInputChange("email", e.target.value)}
|
|
placeholder="Masukkan Email"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="phoneNumber">No Telepon *</Label>
|
|
<Input
|
|
id="phoneNumber"
|
|
value={formData.phoneNumber}
|
|
onChange={(e) =>
|
|
handleInputChange("phoneNumber", e.target.value)
|
|
}
|
|
placeholder="Masukkan No Telepon"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="whatsappNumber">No Whatsapp *</Label>
|
|
<Input
|
|
id="whatsappNumber"
|
|
value={formData.whatsappNumber}
|
|
onChange={(e) =>
|
|
handleInputChange("whatsappNumber", e.target.value)
|
|
}
|
|
placeholder="Masukkan No Whatsapp"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="dateOfBirth">Tanggal Lahir *</Label>
|
|
<Input
|
|
id="dateOfBirth"
|
|
type="date"
|
|
value={formData.dateOfBirth}
|
|
onChange={(e) =>
|
|
handleInputChange("dateOfBirth", e.target.value)
|
|
}
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="genderType">Jenis Kelamin *</Label>
|
|
<Select
|
|
value={formData.genderType}
|
|
onValueChange={(value: "male" | "female") =>
|
|
handleInputChange("genderType", value)
|
|
}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Pilih Jenis Kelamin" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="male">Laki-laki</SelectItem>
|
|
<SelectItem value="female">Perempuan</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="address">Alamat *</Label>
|
|
<Input
|
|
id="address"
|
|
value={formData.address}
|
|
onChange={(e) => handleInputChange("address", e.target.value)}
|
|
placeholder="Masukkan Alamat"
|
|
required
|
|
/>
|
|
</div>
|
|
{mode === "create" && (
|
|
<div>
|
|
<Label htmlFor="password">Kata Sandi *</Label>
|
|
<Input
|
|
id="password"
|
|
type="password"
|
|
value={formData.password}
|
|
onChange={(e) =>
|
|
handleInputChange("password", e.target.value)
|
|
}
|
|
placeholder="Masukkan Kata Sandi"
|
|
required={mode === "create"}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Education History - only for Tenaga Ahli */}
|
|
{userType === "tenaga_ahli" && (
|
|
<div className="bg-white p-6 rounded-lg border">
|
|
<h2 className="text-lg font-semibold mb-4">Riwayat Pendidikan</h2>
|
|
{educationList.map((education, index) => (
|
|
<div
|
|
key={index}
|
|
className="grid grid-cols-1 md:grid-cols-5 gap-4 mb-4"
|
|
>
|
|
<Input
|
|
placeholder="Masukkan Nama Sekolah/Universitas"
|
|
value={education.schoolName}
|
|
onChange={(e) =>
|
|
handleEducationChange(index, "schoolName", e.target.value)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Masukkan Jurusan"
|
|
value={education.major}
|
|
onChange={(e) =>
|
|
handleEducationChange(index, "major", e.target.value)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Masukkan Tingkat Pendidikan"
|
|
value={education.educationLevel}
|
|
onChange={(e) =>
|
|
handleEducationChange(
|
|
index,
|
|
"educationLevel",
|
|
e.target.value,
|
|
)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Masukkan Tahun Lulus"
|
|
type="number"
|
|
value={education.graduationYear}
|
|
onChange={(e) =>
|
|
handleEducationChange(
|
|
index,
|
|
"graduationYear",
|
|
e.target.value,
|
|
)
|
|
}
|
|
/>
|
|
<div className="flex gap-2">
|
|
<Button variant="secondary" className="whitespace-nowrap">
|
|
+ Ijazah
|
|
</Button>
|
|
{index === educationList.length - 1 && (
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={handleAddEducation}
|
|
>
|
|
+ Tambah
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Work History - only for Tenaga Ahli */}
|
|
{userType === "tenaga_ahli" && (
|
|
<div className="bg-white p-6 rounded-lg border">
|
|
<h2 className="text-lg font-semibold mb-4">Riwayat Pekerjaan</h2>
|
|
{workList.map((work, index) => (
|
|
<div
|
|
key={index}
|
|
className="grid grid-cols-1 md:grid-cols-5 gap-4 mb-4"
|
|
>
|
|
<Input
|
|
placeholder="Masukkan Jabatan"
|
|
value={work.jobTitle}
|
|
onChange={(e) =>
|
|
handleWorkChange(index, "jobTitle", e.target.value)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Masukkan Nama Perusahaan"
|
|
value={work.companyName}
|
|
onChange={(e) =>
|
|
handleWorkChange(index, "companyName", e.target.value)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Tanggal Mulai"
|
|
type="date"
|
|
value={work.startDate}
|
|
onChange={(e) =>
|
|
handleWorkChange(index, "startDate", e.target.value)
|
|
}
|
|
/>
|
|
<Input
|
|
placeholder="Tanggal Selesai"
|
|
type="date"
|
|
value={work.endDate}
|
|
onChange={(e) =>
|
|
handleWorkChange(index, "endDate", e.target.value)
|
|
}
|
|
/>
|
|
{index === workList.length - 1 && (
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={handleAddWork}
|
|
>
|
|
+ Tambah
|
|
</Button>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Submit Button */}
|
|
<div className="flex justify-end space-x-4">
|
|
<Button type="button" variant="outline" onClick={() => router.back()}>
|
|
Batal
|
|
</Button>
|
|
<Button type="submit" disabled={loading}>
|
|
{loading
|
|
? "Menyimpan..."
|
|
: mode === "create"
|
|
? "Buat User"
|
|
: "Perbarui User"}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|