Files
internify-fe/src/Pages/EditMentorForm.tsx
T
Kemas M. Aryadary Rasyad da67ad86d8 Refactor internify components and services
- Updated LoginInternify to remove unnecessary state initialization.
- Cleaned up NotificationList by removing unused code and fixing button click handler.
- Added project_id prop to InternClaimCert for better data handling.
- Enhanced CertificateNotAvailable to include claim functionality with loading and error states.
- Modified HomeHeader to display a default user name.
- Corrected ProjectTimeline to import ProjectTask from the correct type file.
- Implemented loading and error handling in CertificateListPage.
- Improved MentorProjectDetailPage to handle task updates and navigation correctly.
- Enhanced MentorSettingsPage to manage profile picture errors and state.
- Updated AddInternsDialog to use the correct hook for fetching interns.
- Refactored EditSubmissionTask to handle task updates and errors more effectively.
- Improved MentorProjectCard to include project archiving functionality.
- Removed deprecated useInterns hook and replaced it with useUser for fetching user data.
- Added new useMentors hook for managing mentor-related operations.
- Cleaned up CertificateService by removing unused verifyCertificate function.
- Created MentorServices for managing mentor data operations.
- Updated UserService to include fetching Mahasiswa data and removed unused UserServices file.
2026-06-29 15:42:48 +07:00

273 lines
10 KiB
TypeScript

import { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import NavbarAdmin from "../Layout/NavbarAdmin";
import SidebarAdmin from "../Layout/SidebarAdmin";
import { useMentorDetail, useUpdateMentor } from "../hooks/useMentors";
import type { UpdateMentorPayload } from "../services/MentorServices";
const EditMentorForm = () => {
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const mentorId = id ? parseInt(id, 10) : null;
const { mentor, loading: fetching, error: fetchError } = useMentorDetail(mentorId);
const { updateMentor, loading: updating, error: updateError } = useUpdateMentor();
const [form, setForm] = useState({
nama_depan: "",
nama_belakang: "",
email: "",
password: "",
signature: "",
professional_bio: "",
});
const [profilePicture, setProfilePicture] = useState<File | null>(null);
const [preview, setPreview] = useState<string | null>(null);
// Populate form once mentor data is loaded
useEffect(() => {
if (mentor) {
setForm({
nama_depan: mentor.nama_depan ?? "",
nama_belakang: mentor.nama_belakang ?? "",
email: mentor.email ?? "",
password: "",
signature: mentor.signature ?? "",
professional_bio: mentor.professional_bio ?? "",
});
if (mentor.profile_picture) {
setPreview(mentor.profile_picture);
}
}
}, [mentor]);
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
};
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0] ?? null;
setProfilePicture(file);
if (file) {
setPreview(URL.createObjectURL(file));
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!mentorId) return;
const payload: UpdateMentorPayload = {
nama_depan: form.nama_depan || undefined,
nama_belakang: form.nama_belakang || undefined,
email: form.email || undefined,
signature: form.signature || undefined,
professional_bio: form.professional_bio || undefined,
...(form.password ? { password: form.password } : {}),
...(profilePicture ? { profile_picture: profilePicture } : {}),
};
const result = await updateMentor(mentorId, payload);
if (result) {
alert("Data mentor berhasil diperbarui!");
navigate("/mentor-admin");
}
};
if (fetching) {
return (
<div className="min-h-screen w-full overflow-hidden">
<NavbarAdmin />
<div className="flex flex-row">
<SidebarAdmin />
<div className="p-10 w-full flex items-center justify-center">
<p className="text-gray-500">Memuat data mentor...</p>
</div>
</div>
</div>
);
}
if (fetchError || !mentor) {
return (
<div className="min-h-screen w-full overflow-hidden">
<NavbarAdmin />
<div className="flex flex-row">
<SidebarAdmin />
<div className="p-10 w-full flex items-center justify-center">
<p className="text-red-500">{fetchError ?? "Mentor tidak ditemukan."}</p>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen w-full overflow-hidden">
<NavbarAdmin />
<div className="flex flex-row">
<SidebarAdmin />
<div className="p-10 bg-white flex-col w-full">
{/* Header */}
<div className="flex flex-row justify-between items-center mb-[40px]">
<div>
<button
className="text-sm text-gray-500 hover:text-gray-800 flex items-center gap-1 mb-2 cursor-pointer"
onClick={() => navigate("/mentor-admin")}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-4"
>
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
</svg>
Kembali
</button>
<h2 className="text-[24px] font-semibold">Edit Mentor</h2>
<p className="text-sm text-gray-500 mt-1">
Mengedit data: <span className="font-medium text-gray-700">{mentor.full_name}</span>
</p>
</div>
</div>
{updateError && (
<div className="mb-6 px-4 py-3 bg-red-50 border border-red-200 text-red-600 rounded-xl text-sm">
{updateError}
</div>
)}
<form onSubmit={handleSubmit} className="max-w-2xl flex flex-col gap-5">
{/* Nama Depan */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Nama Depan</label>
<input
type="text"
name="nama_depan"
value={form.nama_depan}
onChange={handleChange}
placeholder="Contoh: Budi"
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent"
/>
</div>
{/* Nama Belakang */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Nama Belakang</label>
<input
type="text"
name="nama_belakang"
value={form.nama_belakang}
onChange={handleChange}
placeholder="Contoh: Santoso"
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent"
/>
</div>
{/* Email */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Email</label>
<input
type="email"
name="email"
value={form.email}
onChange={handleChange}
placeholder="mentor@example.com"
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent"
/>
</div>
{/* Password */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">
Password{" "}
<span className="text-gray-400 font-normal text-xs">(kosongkan jika tidak ingin mengubah)</span>
</label>
<input
type="password"
name="password"
value={form.password}
onChange={handleChange}
placeholder="Password baru (opsional)"
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent"
/>
</div>
{/* Signature */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Signature</label>
<input
type="text"
name="signature"
value={form.signature}
onChange={handleChange}
placeholder="Tanda tangan / jabatan"
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent"
/>
</div>
{/* Professional Bio */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Bio Profesional</label>
<textarea
name="professional_bio"
value={form.professional_bio}
onChange={handleChange}
rows={4}
placeholder="Ceritakan pengalaman dan keahlian mentor..."
className="px-4 py-3 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-[#1F4A92] focus:border-transparent resize-none"
/>
</div>
{/* Profile Picture */}
<div className="flex flex-col gap-1">
<label className="text-sm font-medium text-gray-700">Foto Profil</label>
{preview && (
<img
src={preview}
alt="Preview"
className="w-20 h-20 rounded-full object-cover mb-2 border border-gray-200"
/>
)}
<input
type="file"
accept="image/*"
onChange={handleFileChange}
className="text-sm text-gray-600 file:mr-4 file:py-2 file:px-4 file:rounded-xl file:border-0 file:text-sm file:font-semibold file:bg-[#1F4A92] file:text-white hover:file:bg-[#677c9f] cursor-pointer"
/>
</div>
{/* Actions */}
<div className="flex gap-3 mt-2">
<button
type="button"
onClick={() => navigate("/mentor-admin")}
className="px-6 py-3 rounded-xl border border-gray-300 text-gray-600 text-sm font-semibold hover:bg-gray-50 cursor-pointer"
>
Batal
</button>
<button
type="submit"
disabled={updating}
className="px-6 py-3 rounded-xl bg-[#1F4A92] hover:bg-[#677c9f] text-white text-sm font-semibold cursor-pointer disabled:opacity-60 disabled:cursor-not-allowed"
>
{updating ? "Menyimpan..." : "Simpan Perubahan"}
</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default EditMentorForm;