From 7d2b996fe7746c04eb46d83ded2de353b41b2784 Mon Sep 17 00:00:00 2001 From: Iwan Suryaningrat Date: Tue, 20 Aug 2024 10:01:06 +0700 Subject: [PATCH] Fix Thumbnail --- src/pages/Admin/AddAdmin.tsx | 854 ++++++++++++++--------------- src/pages/Admin/EditAdmin.tsx | 834 ++++++++++++++-------------- src/pages/Students/AddStudent.tsx | 556 +++++++++---------- src/pages/Students/EditStudent.tsx | 844 ++++++++++++++-------------- 4 files changed, 1544 insertions(+), 1544 deletions(-) diff --git a/src/pages/Admin/AddAdmin.tsx b/src/pages/Admin/AddAdmin.tsx index 5857315..54339e5 100644 --- a/src/pages/Admin/AddAdmin.tsx +++ b/src/pages/Admin/AddAdmin.tsx @@ -12,451 +12,451 @@ import { setAllowedToast } from "../../features/toastSlice"; import Breadcrumb from "../../components/Breadcrumb"; import { showErrorToast, showSuccessToast } from "../../components/Toast"; import { - ChevronDownIcon, - EyeIcon, - EyeOffIcon, - Loader2Icon, - UploadCloudIcon, + ChevronDownIcon, + EyeIcon, + EyeOffIcon, + Loader2Icon, + UploadCloudIcon, } from "lucide-react"; import type { AdminAddRequest, School } from "../../types"; const MAX_FILE_SIZE = 3 * 1024 * 1024; const schema = yup.object().shape({ - name: yup.string().required("Nama harus diisi"), - email: yup.string().email("Email tidak valid").required("Email harus diisi"), - phoneNumber: yup.string().required("Nomor telepon harus diisi"), - password: yup.string().required("Password harus diisi"), - school: yup.string().required("Sekolah harus diisi"), - media: yup - .mixed() - .test( - "fileSize", - "Ukuran file terlalu besar. Maksimal 3MB", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.size <= MAX_FILE_SIZE; - } - ) - .test( - "fileType", - "Tipe file tidak valid. Hanya menerima file gambar", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.type.startsWith("image/"); - } - ) - .nullable(), + name: yup.string().required("Nama harus diisi"), + email: yup.string().email("Email tidak valid").required("Email harus diisi"), + phoneNumber: yup.string().required("Nomor telepon harus diisi"), + password: yup.string().required("Password harus diisi"), + school: yup.string().required("Sekolah harus diisi"), + media: yup + .mixed() + .test( + "fileSize", + "Ukuran file terlalu besar. Maksimal 3MB", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.size <= MAX_FILE_SIZE; + } + ) + .test( + "fileType", + "Tipe file tidak valid. Hanya menerima file gambar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.type.startsWith("image/"); + } + ) + .nullable(), }); function AddAdmin() { - const [showPassword, setShowPassword] = useState(false); - const mediaRef = useRef(null); - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const [addAdmin, { isLoading }] = useAddAdminMutation(); - const [getSchool, { isLoading: isLoadingGet, data: schools }] = - useGetSchoolMutation(); + const [showPassword, setShowPassword] = useState(false); + const mediaRef = useRef(null); + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const [addAdmin, { isLoading }] = useAddAdminMutation(); + const [getSchool, { isLoading: isLoadingGet, data: schools }] = + useGetSchoolMutation(); - const fetchSchool = async () => { - try { - await getSchool({ search: "", limit: 100 }).unwrap(); - } catch (error) { - dispatch(setAllowedToast()); - showErrorToast("Gagal memuat data sekolah"); - navigate("/admin"); - } - }; + const fetchSchool = async () => { + try { + await getSchool({ search: "", limit: 100 }).unwrap(); + } catch (error) { + dispatch(setAllowedToast()); + showErrorToast("Gagal memuat data sekolah"); + navigate("/admin"); + } + }; - const { - clearErrors, - formState: { errors }, - handleSubmit, - register, - setValue, - watch, - } = useForm({ - mode: "all", - resolver: yupResolver(schema), - }); + const { + clearErrors, + formState: { errors }, + handleSubmit, + register, + setValue, + watch, + } = useForm({ + mode: "all", + resolver: yupResolver(schema), + }); - const onDrop = useCallback( - (acceptedFiles: File[]) => { - setValue("media", acceptedFiles); - }, - [setValue] - ); - const { getInputProps, getRootProps, isDragActive } = useDropzone({ - onDrop, - maxFiles: 1, - multiple: false, - }); + const onDrop = useCallback( + (acceptedFiles: File[]) => { + setValue("media", acceptedFiles); + }, + [setValue] + ); + const { getInputProps, getRootProps, isDragActive } = useDropzone({ + onDrop, + maxFiles: 1, + multiple: false, + }); - const watchMedia = watch("media"); + const watchMedia = watch("media"); - const handleApplyMedia = () => { - if ( - mediaRef.current && - watchMedia?.length > 0 && - watchMedia[0].size <= MAX_FILE_SIZE && - watchMedia[0].type.startsWith("image/") - ) { - clearErrors("media"); - mediaRef.current.src = URL.createObjectURL(watchMedia[0]); - } - }; - const handleDeleteMedia = () => setValue("media", null); + const handleApplyMedia = () => { + if ( + mediaRef.current && + watchMedia?.length > 0 && + watchMedia[0].size <= MAX_FILE_SIZE && + watchMedia[0].type.startsWith("image/") + ) { + clearErrors("media"); + mediaRef.current.src = URL.createObjectURL(watchMedia[0]); + } + }; + const handleDeleteMedia = () => setValue("media", null); - const onSubmit: SubmitHandler = async (data) => { - try { - await addAdmin(data).unwrap(); - dispatch(setAllowedToast()); - showSuccessToast("Data admin berhasil ditambahkan"); - navigate("/admin"); - } catch (error) { - showErrorToast("Gagal menambahkan data admin"); - } - }; + const onSubmit: SubmitHandler = async (data) => { + try { + await addAdmin(data).unwrap(); + dispatch(setAllowedToast()); + showSuccessToast("Data admin berhasil ditambahkan"); + navigate("/admin"); + } catch (error) { + showErrorToast("Gagal menambahkan data admin"); + } + }; - useEffect(() => { - fetchSchool(); - }, []); + useEffect(() => { + fetchSchool(); + }, []); - useEffect(() => { - const newBreadcrumb = [ - { - icon: "admin", - label: "Admin", - path: "/admin", - }, - { - icon: "user_add", - label: "Add Admin", - path: "/admin/add", - }, - ]; - dispatch(setBreadcrumb(newBreadcrumb)); - }, [dispatch]); + useEffect(() => { + const newBreadcrumb = [ + { + icon: "admin", + label: "Admin", + path: "/admin", + }, + { + icon: "user_add", + label: "Add Admin", + path: "/admin/add", + }, + ]; + dispatch(setBreadcrumb(newBreadcrumb)); + }, [dispatch]); - return ( -
-
- -
-
-
- Tambah Admin - {isLoadingGet && ( - - - - )} -
-

- Tambahkan admin baru ke dalam sistem. -

-
-
- - Kembali - - -
-
-
-
-
-
-
-

Informasi Admin

-

- Informasi admin yang akan ditambahkan ke dalam sistem. -

-
-
-
- {/* name */} -
- - - {errors.name && ( -

- {errors.name.message} -

- )} -
- {/* email */} -
- - - {errors.email && ( -

- {errors.email.message} -

- )} -
- {/* phone number */} -
- - - {errors.phoneNumber && ( -

- {errors.phoneNumber.message} -

- )} -
- {/* password */} -
- -
- -
setShowPassword(!showPassword)} - > - {showPassword ? ( - - ) : ( - - )} -
-
- {errors.password && ( -

- {errors.password.message} -

- )} -
- {/* school::select */} -
- -
- -
- -
-
- {errors.school && ( -

- {errors.school.message} -

- )} -
-
-
-
-
-
-
-
-

Foto Profil

-

- Foto profil admin yang akan ditambahkan ke dalam sistem. -

-
-
-
-
- 0 - ? URL.createObjectURL(watchMedia[0]) - : "https://ui-avatars.com/api/?name=Gameon" - } - alt="Profile Placeholder" - className="w-full h-full object-cover object-center" - /> -
-
-
- Tambah Foto Profil -
-
-

- Hapus -

-

- Terapkan -

-
-
-
-
-
- -
- -
-

- - Pilih file - {" "} - atau drag and drop file di sini -

-

- SVG, PNG, atau JPG (maks. 3MB) -

-
-
- {errors.media && ( -

- {errors.media.message?.toString()} -

- )} -
-
-
-
-
- ); + return ( +
+
+ +
+
+
+ Tambah Admin + {isLoadingGet && ( + + + + )} +
+

+ Tambahkan admin baru ke dalam sistem. +

+
+
+ + Kembali + + +
+
+
+
+
+
+
+

Informasi Admin

+

+ Informasi admin yang akan ditambahkan ke dalam sistem. +

+
+
+
+ {/* name */} +
+ + + {errors.name && ( +

+ {errors.name.message} +

+ )} +
+ {/* email */} +
+ + + {errors.email && ( +

+ {errors.email.message} +

+ )} +
+ {/* phone number */} +
+ + + {errors.phoneNumber && ( +

+ {errors.phoneNumber.message} +

+ )} +
+ {/* password */} +
+ +
+ +
setShowPassword(!showPassword)} + > + {showPassword ? ( + + ) : ( + + )} +
+
+ {errors.password && ( +

+ {errors.password.message} +

+ )} +
+ {/* school::select */} +
+ +
+ +
+ +
+
+ {errors.school && ( +

+ {errors.school.message} +

+ )} +
+
+
+
+
+
+
+
+

Foto Profil

+

+ Foto profil admin yang akan ditambahkan ke dalam sistem. +

+
+
+
+
+ 0 + ? URL.createObjectURL(watchMedia[0]) + : "https://ui-avatars.com/api/?name=Kognitif+Game" + } + alt="Profile Placeholder" + className="w-full h-full object-cover object-center" + /> +
+
+
+ Tambah Foto Profil +
+
+

+ Hapus +

+

+ Terapkan +

+
+
+
+
+
+ +
+ +
+

+ + Pilih file + {" "} + atau drag and drop file di sini +

+

+ SVG, PNG, atau JPG (maks. 3MB) +

+
+
+ {errors.media && ( +

+ {errors.media.message?.toString()} +

+ )} +
+
+
+
+
+ ); } export default AddAdmin; diff --git a/src/pages/Admin/EditAdmin.tsx b/src/pages/Admin/EditAdmin.tsx index 0966217..a2ba4fb 100644 --- a/src/pages/Admin/EditAdmin.tsx +++ b/src/pages/Admin/EditAdmin.tsx @@ -6,8 +6,8 @@ import { useForm, type SubmitHandler } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { useAppDispatch } from "../../app/hooks"; import { - useGetAdminByIdMutation, - useUpdateAdminMutation, + useGetAdminByIdMutation, + useUpdateAdminMutation, } from "../../services/adminApi"; import { useGetSchoolMutation } from "../../services/schoolApi"; import { setBreadcrumb } from "../../features/breadcrumbSlice"; @@ -20,433 +20,433 @@ import type { Admin, AdminUpdateRequest, School } from "../../types"; const MAX_FILE_SIZE = 3 * 1024 * 1024; const schema = yup.object().shape({ - name: yup.string().required("Nama harus diisi"), - email: yup.string().email("Email tidak valid").required("Email harus diisi"), - phoneNumber: yup.string().required("Nomor telepon harus diisi"), - school: yup.string().required("Sekolah harus diisi"), - media: yup - .mixed() - .test( - "fileSize", - "Ukuran file terlalu besar. Maksimal 3MB", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.size <= MAX_FILE_SIZE; - } - ) - .test( - "fileType", - "Tipe file tidak valid. Hanya menerima file gambar", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.type.startsWith("image/"); - } - ) - .nullable(), + name: yup.string().required("Nama harus diisi"), + email: yup.string().email("Email tidak valid").required("Email harus diisi"), + phoneNumber: yup.string().required("Nomor telepon harus diisi"), + school: yup.string().required("Sekolah harus diisi"), + media: yup + .mixed() + .test( + "fileSize", + "Ukuran file terlalu besar. Maksimal 3MB", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.size <= MAX_FILE_SIZE; + } + ) + .test( + "fileType", + "Tipe file tidak valid. Hanya menerima file gambar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.type.startsWith("image/"); + } + ) + .nullable(), }); function EditAdmin() { - const mediaRef = useRef(null); - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const { adminId } = useParams(); - const [getAdminById, { isLoading: isLoadingGet }] = useGetAdminByIdMutation(); - const [updateAdmin, { isLoading: isLoadingUpdate }] = - useUpdateAdminMutation(); - const [getSchool, { isLoading: isLoadingGetSchool, data: schools }] = - useGetSchoolMutation(); + const mediaRef = useRef(null); + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const { adminId } = useParams(); + const [getAdminById, { isLoading: isLoadingGet }] = useGetAdminByIdMutation(); + const [updateAdmin, { isLoading: isLoadingUpdate }] = + useUpdateAdminMutation(); + const [getSchool, { isLoading: isLoadingGetSchool, data: schools }] = + useGetSchoolMutation(); - const fetchSchool = async () => { - try { - await getSchool({ search: "", limit: 100 }).unwrap(); - } catch (error) { - dispatch(setAllowedToast()); - showErrorToast("Gagal memuat data sekolah"); - navigate("/admin"); - } - }; + const fetchSchool = async () => { + try { + await getSchool({ search: "", limit: 100 }).unwrap(); + } catch (error) { + dispatch(setAllowedToast()); + showErrorToast("Gagal memuat data sekolah"); + navigate("/admin"); + } + }; - const { - clearErrors, - formState: { errors }, - handleSubmit, - register, - setValue, - watch, - } = useForm({ - mode: "all", - resolver: yupResolver(schema), - }); + const { + clearErrors, + formState: { errors }, + handleSubmit, + register, + setValue, + watch, + } = useForm({ + mode: "all", + resolver: yupResolver(schema), + }); - const setFormValue = (response: Admin) => { - if (response) { - setValue("name", response.name); - setValue("email", response.email); - setValue("phoneNumber", response.phoneNumber); - setValue("school", response?.school?._id || ""); - if (response?.image && mediaRef.current) { - mediaRef.current.src = response.image.fileLink; - } - } - }; + const setFormValue = (response: Admin) => { + if (response) { + setValue("name", response.name); + setValue("email", response.email); + setValue("phoneNumber", response.phoneNumber); + setValue("school", response?.school?._id || ""); + if (response?.image && mediaRef.current) { + mediaRef.current.src = response.image.fileLink; + } + } + }; - const fetchAdminById = async (id: string) => { - try { - const response = await getAdminById({ id }).unwrap(); - if (response.success) { - setFormValue(response.data); - } - } catch (error) { - dispatch(setAllowedToast()); - showErrorToast("Data admin tidak ditemukan"); - navigate("/admin"); - } - }; + const fetchAdminById = async (id: string) => { + try { + const response = await getAdminById({ id }).unwrap(); + if (response.success) { + setFormValue(response.data); + } + } catch (error) { + dispatch(setAllowedToast()); + showErrorToast("Data admin tidak ditemukan"); + navigate("/admin"); + } + }; - const onDrop = useCallback( - (acceptedFiles: File[]) => { - setValue("media", acceptedFiles); - }, - [setValue] - ); - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg"] }, - multiple: false, - }); + const onDrop = useCallback( + (acceptedFiles: File[]) => { + setValue("media", acceptedFiles); + }, + [setValue] + ); + const { getRootProps, getInputProps, isDragActive } = useDropzone({ + onDrop, + accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg"] }, + multiple: false, + }); - const watchMedia = watch("media"); - const handleApplyMedia = () => { - if ( - mediaRef.current && - watchMedia?.length > 0 && - watchMedia[0].size <= MAX_FILE_SIZE && - watchMedia[0].type.startsWith("image/") - ) { - clearErrors("media"); - mediaRef.current.src = URL.createObjectURL(watchMedia[0]); - } - }; - const handleDeleteMedia = () => setValue("media", null); + const watchMedia = watch("media"); + const handleApplyMedia = () => { + if ( + mediaRef.current && + watchMedia?.length > 0 && + watchMedia[0].size <= MAX_FILE_SIZE && + watchMedia[0].type.startsWith("image/") + ) { + clearErrors("media"); + mediaRef.current.src = URL.createObjectURL(watchMedia[0]); + } + }; + const handleDeleteMedia = () => setValue("media", null); - const onSubmit: SubmitHandler = async (data) => { - try { - await updateAdmin({ ...data, id: adminId }).unwrap(); - dispatch(setAllowedToast()); - showSuccessToast("Data admin berhasil diperbarui!"); - navigate("/admin"); - } catch (error) { - showErrorToast("Data admin gagal disimpan"); - } - }; + const onSubmit: SubmitHandler = async (data) => { + try { + await updateAdmin({ ...data, id: adminId }).unwrap(); + dispatch(setAllowedToast()); + showSuccessToast("Data admin berhasil diperbarui!"); + navigate("/admin"); + } catch (error) { + showErrorToast("Data admin gagal disimpan"); + } + }; - useEffect(() => { - const newBreadcrumb = [ - { - icon: "admin", - label: "Admin", - path: "/admin", - }, - { - icon: "edit", - label: "Edit Admin", - path: `/admin/edit/${adminId}`, - }, - ]; - dispatch(setBreadcrumb(newBreadcrumb)); - }, [dispatch, adminId]); - useEffect(() => { - if (adminId) { - fetchSchool(); - fetchAdminById(adminId); - } - }, [adminId]); + useEffect(() => { + const newBreadcrumb = [ + { + icon: "admin", + label: "Admin", + path: "/admin", + }, + { + icon: "edit", + label: "Edit Admin", + path: `/admin/edit/${adminId}`, + }, + ]; + dispatch(setBreadcrumb(newBreadcrumb)); + }, [dispatch, adminId]); + useEffect(() => { + if (adminId) { + fetchSchool(); + fetchAdminById(adminId); + } + }, [adminId]); - return ( -
-
- -
-
-
- Edit Admin - {isLoadingGet || isLoadingGetSchool ? ( - - - - ) : ( - "" - )} -
-

Edit data admin.

-
-
- - Kembali - - -
-
-
-
-
-
-
-

Informasi Admin

-

- Informasi admin yang akan ditambahkan ke dalam sistem. -

-
-
-
- {/* name */} -
- - - {errors.name && ( -

- {errors.name.message} -

- )} -
- {/* email */} -
- - - {errors.email && ( -

- {errors.email.message} -

- )} -
- {/* phone number */} -
- - - {errors.phoneNumber && ( -

- {errors.phoneNumber.message} -

- )} -
- {/* school::select */} -
- -
- -
- -
-
- {errors.school && ( -

- {errors.school.message} -

- )} -
-
-
-
-
-
-
-
-

Foto Profil

-

- Foto profil admin yang akan ditambahkan ke dalam sistem. -

-
-
-
-
- 0 - ? URL.createObjectURL(watchMedia[0]) - : "https://ui-avatars.com/api/?name=Gameon" - } - alt="Profile Placeholder" - className="w-full h-full object-cover object-center" - /> -
-
-
- Tambah Foto Profil -
-
-

- Hapus -

-

- Terapkan -

-
-
-
-
-
- -
- -
-

- - Pilih file - {" "} - atau drag and drop file di sini -

-

- SVG, PNG, atau JPG (maks. 3MB) -

-
-
- {watchMedia?.length > 0 && errors.media && ( -

- {errors.media.message?.toString()} -

- )} -
-
-
-
-
- ); + return ( +
+
+ +
+
+
+ Edit Admin + {isLoadingGet || isLoadingGetSchool ? ( + + + + ) : ( + "" + )} +
+

Edit data admin.

+
+
+ + Kembali + + +
+
+
+
+
+
+
+

Informasi Admin

+

+ Informasi admin yang akan ditambahkan ke dalam sistem. +

+
+
+
+ {/* name */} +
+ + + {errors.name && ( +

+ {errors.name.message} +

+ )} +
+ {/* email */} +
+ + + {errors.email && ( +

+ {errors.email.message} +

+ )} +
+ {/* phone number */} +
+ + + {errors.phoneNumber && ( +

+ {errors.phoneNumber.message} +

+ )} +
+ {/* school::select */} +
+ +
+ +
+ +
+
+ {errors.school && ( +

+ {errors.school.message} +

+ )} +
+
+
+
+
+
+
+
+

Foto Profil

+

+ Foto profil admin yang akan ditambahkan ke dalam sistem. +

+
+
+
+
+ 0 + ? URL.createObjectURL(watchMedia[0]) + : `https://ui-avatars.com/api/?name=${watch("name")}` + } + alt="Profile Placeholder" + className="w-full h-full object-cover object-center" + /> +
+
+
+ Tambah Foto Profil +
+
+

+ Hapus +

+

+ Terapkan +

+
+
+
+
+
+ +
+ +
+

+ + Pilih file + {" "} + atau drag and drop file di sini +

+

+ SVG, PNG, atau JPG (maks. 3MB) +

+
+
+ {watchMedia?.length > 0 && errors.media && ( +

+ {errors.media.message?.toString()} +

+ )} +
+
+
+
+
+ ); } export default EditAdmin; diff --git a/src/pages/Students/AddStudent.tsx b/src/pages/Students/AddStudent.tsx index 9a7db95..9e7be88 100644 --- a/src/pages/Students/AddStudent.tsx +++ b/src/pages/Students/AddStudent.tsx @@ -137,284 +137,284 @@ function AddStudent() { }, [dispatch]); return ( -
-
- -
-
-
- Tambah Siswa - {isLoadingGet || isLoadingProfile ? ( - - - - ) : ( - "" - )} -
-

- Tambahkan siswa baru ke dalam sistem. -

-
-
- - Kembali - - -
-
-
-
-
-
-
-

Informasi Siswa

-

- Informasi siswa yang akan ditambahkan ke dalam sistem. -

-
-
-
- {/* name */} -
- - - {errors.name && ( -

- {errors.name.message} -

- )} -
- {/* email */} -
- - - {errors.email && ( -

- {errors.email.message} -

- )} -
- {/* phone number */} -
- - - {errors.phoneNumber && ( -

- {errors.phoneNumber.message} -

- )} -
- {/* school::select */} -
- -
- -
- -
-
- {errors.school && ( -

- {errors.school.message} -

- )} -
-
-
-
-
-
-
-
-

Foto Profil

-

- Foto profil siswa yang akan ditambahkan ke dalam sistem. -

-
-
-
-
- 0 - ? URL.createObjectURL(watchMedia[0]) - : "https://ui-avatars.com/api/?name=Gameon" - } - alt="Profile Placeholder" - className="w-full h-full object-cover object-center" - /> -
-
-
- Tambah Foto Profil -
-
-

- Hapus -

-

- Terapkan -

-
-
-
-
-
- -
- -
-

- - Pilih file - {" "} - atau drag and drop file di sini -

-

- SVG, PNG, atau JPG (maks. 3MB) -

-
-
- {errors.media && ( -

- {errors.media.message?.toString()} -

- )} -
-
-
-
-
- ); +
+
+ +
+
+
+ Tambah Siswa + {isLoadingGet || isLoadingProfile ? ( + + + + ) : ( + "" + )} +
+

+ Tambahkan siswa baru ke dalam sistem. +

+
+
+ + Kembali + + +
+
+
+
+
+
+
+

Informasi Siswa

+

+ Informasi siswa yang akan ditambahkan ke dalam sistem. +

+
+
+
+ {/* name */} +
+ + + {errors.name && ( +

+ {errors.name.message} +

+ )} +
+ {/* email */} +
+ + + {errors.email && ( +

+ {errors.email.message} +

+ )} +
+ {/* phone number */} +
+ + + {errors.phoneNumber && ( +

+ {errors.phoneNumber.message} +

+ )} +
+ {/* school::select */} +
+ +
+ +
+ +
+
+ {errors.school && ( +

+ {errors.school.message} +

+ )} +
+
+
+
+
+
+
+
+

Foto Profil

+

+ Foto profil siswa yang akan ditambahkan ke dalam sistem. +

+
+
+
+
+ 0 + ? URL.createObjectURL(watchMedia[0]) + : "https://ui-avatars.com/api/?name=Kognitif+Game" + } + alt="Profile Placeholder" + className="w-full h-full object-cover object-center" + /> +
+
+
+ Tambah Foto Profil +
+
+

+ Hapus +

+

+ Terapkan +

+
+
+
+
+
+ +
+ +
+

+ + Pilih file + {" "} + atau drag and drop file di sini +

+

+ SVG, PNG, atau JPG (maks. 3MB) +

+
+
+ {errors.media && ( +

+ {errors.media.message?.toString()} +

+ )} +
+
+
+
+
+ ); } export default AddStudent; diff --git a/src/pages/Students/EditStudent.tsx b/src/pages/Students/EditStudent.tsx index 8a75d6e..f21cda1 100644 --- a/src/pages/Students/EditStudent.tsx +++ b/src/pages/Students/EditStudent.tsx @@ -7,8 +7,8 @@ import * as yup from "yup"; import { useAppDispatch } from "../../app/hooks"; import { useUser } from "../../hook/authHooks"; import { - useGetStudentByIdMutation, - useUpdateStudentMutation, + useGetStudentByIdMutation, + useUpdateStudentMutation, } from "../../services/studentApi"; import { useGetSchoolMutation } from "../../services/schoolApi"; import { useGetProfileQuery } from "../../services/profileApi"; @@ -22,438 +22,438 @@ import type { School, Student, StudentUpdateRequest } from "../../types"; const MAX_FILE_SIZE = 3 * 1024 * 1024; const schema = yup.object().shape({ - name: yup.string().required("Nama harus diisi"), - email: yup.string().email("Email tidak valid").required("Email harus diisi"), - phoneNumber: yup.string().required("Nomor telepon harus diisi"), - school: yup.string().required("Sekolah harus diisi"), - media: yup - .mixed() - .test( - "fileSize", - "Ukuran file terlalu besar. Maksimal 3MB", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.size <= MAX_FILE_SIZE; - } - ) - .test( - "fileType", - "Tipe file tidak valid. Hanya menerima file gambar", - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (value: any) => { - if (!value) return true; // Allow empty files - return value.length && value[0]?.type.startsWith("image/"); - } - ) - .nullable(), + name: yup.string().required("Nama harus diisi"), + email: yup.string().email("Email tidak valid").required("Email harus diisi"), + phoneNumber: yup.string().required("Nomor telepon harus diisi"), + school: yup.string().required("Sekolah harus diisi"), + media: yup + .mixed() + .test( + "fileSize", + "Ukuran file terlalu besar. Maksimal 3MB", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.size <= MAX_FILE_SIZE; + } + ) + .test( + "fileType", + "Tipe file tidak valid. Hanya menerima file gambar", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (value: any) => { + if (!value) return true; // Allow empty files + return value.length && value[0]?.type.startsWith("image/"); + } + ) + .nullable(), }); function EditStudent() { - const { user: currentUser } = useUser(); - const mediaRef = useRef(null); - const navigate = useNavigate(); - const dispatch = useAppDispatch(); - const { studentId } = useParams(); - const [getStudentById, { isLoading: isLoadingGet }] = - useGetStudentByIdMutation(); - const [updateStudent, { isLoading: isLoadingUpdate }] = - useUpdateStudentMutation(); - const [getSchool, { isLoading: isLoadingGetSchool, data: schools }] = - useGetSchoolMutation(); - const { data: user, isLoading: isLoadingProfile } = useGetProfileQuery(); + const { user: currentUser } = useUser(); + const mediaRef = useRef(null); + const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const { studentId } = useParams(); + const [getStudentById, { isLoading: isLoadingGet }] = + useGetStudentByIdMutation(); + const [updateStudent, { isLoading: isLoadingUpdate }] = + useUpdateStudentMutation(); + const [getSchool, { isLoading: isLoadingGetSchool, data: schools }] = + useGetSchoolMutation(); + const { data: user, isLoading: isLoadingProfile } = useGetProfileQuery(); - const fetchSchool = async () => { - try { - await getSchool({ search: "", limit: 100 }).unwrap(); - } catch (error) { - dispatch(setAllowedToast()); - showErrorToast("Gagal memuat data sekolah"); - navigate("/student"); - } - }; + const fetchSchool = async () => { + try { + await getSchool({ search: "", limit: 100 }).unwrap(); + } catch (error) { + dispatch(setAllowedToast()); + showErrorToast("Gagal memuat data sekolah"); + navigate("/student"); + } + }; - const { - clearErrors, - formState: { errors }, - handleSubmit, - register, - setValue, - watch, - } = useForm({ - mode: "all", - resolver: yupResolver(schema), - }); + const { + clearErrors, + formState: { errors }, + handleSubmit, + register, + setValue, + watch, + } = useForm({ + mode: "all", + resolver: yupResolver(schema), + }); - const setFormValue = (response: Student) => { - if (response) { - setValue("name", response.name); - setValue("email", response.email); - setValue("phoneNumber", response.phoneNumber); - setValue("school", response?.school?._id || ""); - if (response?.image && mediaRef.current) { - mediaRef.current.src = response.image.fileLink; - } - } - }; + const setFormValue = (response: Student) => { + if (response) { + setValue("name", response.name); + setValue("email", response.email); + setValue("phoneNumber", response.phoneNumber); + setValue("school", response?.school?._id || ""); + if (response?.image && mediaRef.current) { + mediaRef.current.src = response.image.fileLink; + } + } + }; - const fetchStudentById = async (id: string) => { - try { - const response = await getStudentById({ id }).unwrap(); - if (response.success) { - setFormValue(response.data); - } - } catch (error) { - dispatch(setAllowedToast()); - showErrorToast("Data siswa tidak ditemukan"); - navigate("/student"); - } - }; + const fetchStudentById = async (id: string) => { + try { + const response = await getStudentById({ id }).unwrap(); + if (response.success) { + setFormValue(response.data); + } + } catch (error) { + dispatch(setAllowedToast()); + showErrorToast("Data siswa tidak ditemukan"); + navigate("/student"); + } + }; - const onDrop = useCallback( - (acceptedFiles: File[]) => { - setValue("media", acceptedFiles); - }, - [setValue] - ); - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg"] }, - multiple: false, - }); + const onDrop = useCallback( + (acceptedFiles: File[]) => { + setValue("media", acceptedFiles); + }, + [setValue] + ); + const { getRootProps, getInputProps, isDragActive } = useDropzone({ + onDrop, + accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg"] }, + multiple: false, + }); - const watchMedia = watch("media"); - const handleApplyMedia = () => { - if ( - mediaRef.current && - watchMedia?.length > 0 && - watchMedia[0].size <= MAX_FILE_SIZE && - watchMedia[0].type.startsWith("image/") - ) { - clearErrors("media"); - mediaRef.current.src = URL.createObjectURL(watchMedia[0]); - } - }; - const handleDeleteMedia = () => setValue("media", null); + const watchMedia = watch("media"); + const handleApplyMedia = () => { + if ( + mediaRef.current && + watchMedia?.length > 0 && + watchMedia[0].size <= MAX_FILE_SIZE && + watchMedia[0].type.startsWith("image/") + ) { + clearErrors("media"); + mediaRef.current.src = URL.createObjectURL(watchMedia[0]); + } + }; + const handleDeleteMedia = () => setValue("media", null); - const onSubmit: SubmitHandler = async (data) => { - try { - await updateStudent({ ...data, id: studentId }).unwrap(); - dispatch(setAllowedToast()); - showSuccessToast("Data siswa berhasil diperbarui!"); - navigate("/student"); - } catch (error) { - showErrorToast("Data siswa gagal disimpan"); - } - }; + const onSubmit: SubmitHandler = async (data) => { + try { + await updateStudent({ ...data, id: studentId }).unwrap(); + dispatch(setAllowedToast()); + showSuccessToast("Data siswa berhasil diperbarui!"); + navigate("/student"); + } catch (error) { + showErrorToast("Data siswa gagal disimpan"); + } + }; - useEffect(() => { - const newBreadcrumb = [ - { - icon: "student", - label: "Students", - path: "/student", - }, - { - icon: "edit", - label: "Edit Student", - path: `/student/edit/${studentId}`, - }, - ]; - dispatch(setBreadcrumb(newBreadcrumb)); - }, [dispatch, studentId]); - useEffect(() => { - if (studentId) { - if (currentUser?.role === "Super Admin") fetchSchool(); - fetchStudentById(studentId); - } - }, [studentId, currentUser]); + useEffect(() => { + const newBreadcrumb = [ + { + icon: "student", + label: "Students", + path: "/student", + }, + { + icon: "edit", + label: "Edit Student", + path: `/student/edit/${studentId}`, + }, + ]; + dispatch(setBreadcrumb(newBreadcrumb)); + }, [dispatch, studentId]); + useEffect(() => { + if (studentId) { + if (currentUser?.role === "Super Admin") fetchSchool(); + fetchStudentById(studentId); + } + }, [studentId, currentUser]); - return ( -
-
- -
-
-
- Edit Siswa - {isLoadingGet || isLoadingGetSchool || isLoadingProfile ? ( - - - - ) : ( - "" - )} -
-

Edit data siswa.

-
-
- - Kembali - - -
-
-
-
-
-
-
-

Informasi Siswa

-

- Informasi siswa yang akan ditambahkan ke dalam sistem. -

-
-
-
- {/* name */} -
- - - {errors.name && ( -

- {errors.name.message} -

- )} -
- {/* email */} -
- - - {errors.email && ( -

- {errors.email.message} -

- )} -
- {/* phone number */} -
- - - {errors.phoneNumber && ( -

- {errors.phoneNumber.message} -

- )} -
- {/* school::select */} -
- -
- -
- -
-
- {errors.school && ( -

- {errors.school.message} -

- )} -
-
-
-
-
-
-
-
-

Foto Profil

-

- Foto profil siswa yang akan ditambahkan ke dalam sistem. -

-
-
-
-
- 0 - ? URL.createObjectURL(watchMedia[0]) - : "https://ui-avatars.com/api/?name=Gameon" - } - alt="Profile Placeholder" - className="w-full h-full object-cover object-center" - /> -
-
-
- Tambah Foto Profil -
-
-

- Hapus -

-

- Terapkan -

-
-
-
-
-
- -
- -
-

- - Pilih file - {" "} - atau drag and drop file di sini -

-

- SVG, PNG, atau JPG (maks. 3MB) -

-
-
- {errors.media && ( -

- {errors.media.message?.toString()} -

- )} -
-
-
-
-
- ); + return ( +
+
+ +
+
+
+ Edit Siswa + {isLoadingGet || isLoadingGetSchool || isLoadingProfile ? ( + + + + ) : ( + "" + )} +
+

Edit data siswa.

+
+
+ + Kembali + + +
+
+
+
+
+
+
+

Informasi Siswa

+

+ Informasi siswa yang akan ditambahkan ke dalam sistem. +

+
+
+
+ {/* name */} +
+ + + {errors.name && ( +

+ {errors.name.message} +

+ )} +
+ {/* email */} +
+ + + {errors.email && ( +

+ {errors.email.message} +

+ )} +
+ {/* phone number */} +
+ + + {errors.phoneNumber && ( +

+ {errors.phoneNumber.message} +

+ )} +
+ {/* school::select */} +
+ +
+ +
+ +
+
+ {errors.school && ( +

+ {errors.school.message} +

+ )} +
+
+
+
+
+
+
+
+

Foto Profil

+

+ Foto profil siswa yang akan ditambahkan ke dalam sistem. +

+
+
+
+
+ 0 + ? URL.createObjectURL(watchMedia[0]) + : `https://ui-avatars.com/api/?name=${watch("name")}` + } + alt="Profile Placeholder" + className="w-full h-full object-cover object-center" + /> +
+
+
+ Tambah Foto Profil +
+
+

+ Hapus +

+

+ Terapkan +

+
+
+
+
+
+ +
+ +
+

+ + Pilih file + {" "} + atau drag and drop file di sini +

+

+ SVG, PNG, atau JPG (maks. 3MB) +

+
+
+ {errors.media && ( +

+ {errors.media.message?.toString()} +

+ )} +
+
+
+
+
+ ); } export default EditStudent;