diff --git a/src/Pages/internify/UpdateProfileDialogue.tsx b/src/Pages/internify/UpdateProfileDialogue.tsx index 5950ed2..007b93c 100644 --- a/src/Pages/internify/UpdateProfileDialogue.tsx +++ b/src/Pages/internify/UpdateProfileDialogue.tsx @@ -45,7 +45,7 @@ export default function UpdateProfileDialog({ }} > {/* Header */} -
+

Simpan Perubahan

@@ -101,7 +101,7 @@ export default function UpdateProfileDialog({ disabled={loading} className="px-5 py-2 bg-[#B30000] hover:bg-[#990000] text-white text-xs font-bold rounded-lg shadow-sm transition-colors uppercase tracking-wider disabled:opacity-60" > - {loading ? "Menyimpan..." : "Ya, Simpan"} + {loading ? "Menyimpan..." : "Simpan"}
diff --git a/src/Pages/internify/intern/InternCertList.tsx b/src/Pages/internify/intern/InternCertList.tsx index 637ce10..50f95ad 100644 --- a/src/Pages/internify/intern/InternCertList.tsx +++ b/src/Pages/internify/intern/InternCertList.tsx @@ -79,7 +79,7 @@ export default function SertificateList() { {new Date(item.start_date).toLocaleDateString("id-ID", { year: "numeric", month: "long", - })} until {new Date(item.end_date).toLocaleDateString("id-ID", { + })} - {new Date(item.end_date).toLocaleDateString("id-ID", { year: "numeric", month: "long", })} @@ -88,7 +88,7 @@ export default function SertificateList() { {item.project_name}

- Status Projek: {item.status} + Status: {item.status}

diff --git a/src/Pages/internify/intern/components/CertificateAvailabe.tsx b/src/Pages/internify/intern/components/CertificateAvailabe.tsx index aea9320..80a56b9 100644 --- a/src/Pages/internify/intern/components/CertificateAvailabe.tsx +++ b/src/Pages/internify/intern/components/CertificateAvailabe.tsx @@ -104,7 +104,7 @@ export default function CertificateAvailable({ project, certificate, templateUrl return (
{/* Certificate Card */} -
+
{loadingPreview ? (
Memuat sertifikat... @@ -113,7 +113,7 @@ export default function CertificateAvailable({ project, certificate, templateUrl Certificate ) : (
diff --git a/src/Pages/internify/intern/components/ProjectTimeline.tsx b/src/Pages/internify/intern/components/ProjectTimeline.tsx index fde4be4..c13dbdb 100644 --- a/src/Pages/internify/intern/components/ProjectTimeline.tsx +++ b/src/Pages/internify/intern/components/ProjectTimeline.tsx @@ -29,11 +29,11 @@ export default function ProjectTimeline({ tasks }: { tasks: InternTaskItem[] }) active ? 'bg-red' : 'bg-gray-400' } ${isToday ? 'shadow-md' : ''}`} /> -
- {isToday ? 'Hari ini' : formatDate(task.deadline_at)} +
+ {task.title}
- {task.title} + {isToday ? 'Hari ini' : formatDate(task.deadline_at)}
); diff --git a/src/Pages/internify/intern/components/TaskForm-link.tsx b/src/Pages/internify/intern/components/TaskForm-link.tsx index 84d46ee..ecfef0c 100644 --- a/src/Pages/internify/intern/components/TaskForm-link.tsx +++ b/src/Pages/internify/intern/components/TaskForm-link.tsx @@ -34,18 +34,14 @@ export default function TaskFormLink({ loading: isEditing ? "Memperbarui Link..." : "Mengirim Link...", success: (res) => ({ title: isEditing ? "Link diperbaharui" : "Link berhasil dikirim", - description: - res?.message ?? - (isEditing - ? "Perubahan submission Anda telah disimpan." - : "Link berhasil dikirim."), + description: res?.message + // ?? (isEditing ? "Perubahan submission Anda telah disimpan." : "Link berhasil dikirim."), }), error: (err) => ({ title: isEditing ? "Gagal memperbarui link!" : "Gagal mengirim link!", description: - err?.response?.data?.message || - err?.message || - "Link yang anda submit gagal dikirim", + err?.response?.data?.message || err?.message + // || "Link yang anda submit gagal dikirim", }), } ); diff --git a/src/Pages/internify/mentor/components/AddInternsToProjects.tsx b/src/Pages/internify/mentor/components/AddInternsToProjects.tsx index 5c4de51..2f3bd9c 100644 --- a/src/Pages/internify/mentor/components/AddInternsToProjects.tsx +++ b/src/Pages/internify/mentor/components/AddInternsToProjects.tsx @@ -19,8 +19,6 @@ export default function AddInternsModal({ isOpen, onClose, userId }: AddInternsM const { projects, loading: loadingProjects } = useProjects("active"); const { interns, loading: loadingInterns } = useAssignableInterns(); - console.log(projects) - useEffect(() => { const dialog = dialogRef.current; if (!dialog) return; diff --git a/src/Pages/internify/mentor/components/CreateProjectDialog.tsx b/src/Pages/internify/mentor/components/CreateProjectDialog.tsx index 9a9c6f7..cdcd3ff 100644 --- a/src/Pages/internify/mentor/components/CreateProjectDialog.tsx +++ b/src/Pages/internify/mentor/components/CreateProjectDialog.tsx @@ -33,6 +33,7 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat icon: PROJECT_ICON_MAP[id], })); + //open/close doalog komponen useEffect(() => { const dialog = dialogRef.current; if (!dialog) return; @@ -54,8 +55,22 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat }; }, [isOpen, onClose]); - const handleAddEmail = (emailToAdd?: string) => { - const email = (emailToAdd ?? emailInput).trim(); + // tutup dropdown email di luar kotak + useEffect(() => { + if (!showDropdown) return; + + const handleClickOutside = (e: MouseEvent) => { + if (emailSectionRef.current && !emailSectionRef.current.contains(e.target as Node)) { + setShowDropdown(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, [showDropdown]); + + + const handleAddEmail = (email: string) => { if (email && !invitedEmails.includes(email)) { setInvitedEmails([...invitedEmails, email]); setEmailInput(""); @@ -182,34 +197,23 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat - {/* Input email + dropdown sugesti intern */} + {/* filterisasi email */}
{ setEmailInput(e.target.value); setShowDropdown(true); }} onFocus={() => setShowDropdown(true)} onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - handleAddEmail(); - } - if (e.key === 'Escape') setShowDropdown(false); + if (e.key === 'Escape') setShowDropdown(false) }} - className="w-full pl-10 pr-20 py-2.5 bg-white border border-card-outline rounded-lg text-sm placeholder-gray-400 text-gray-800 focus:outline-none focus:border-red-600 focus:ring-1 focus:ring-red-600 font-medium" + className="w-full pl-10 pr-20 py-2.5 bg-white border border-card-outline rounded-lg text-sm placeholder-gray-400 text-gray-800 focus:outline-none focus:border-red-600 focus:ring-1 focus:ring-red-600 font-medium" /> -
{/* Dropdown daftar intern */} @@ -231,12 +235,16 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat )) diff --git a/src/Pages/internify/mentor/components/InternsTable.tsx b/src/Pages/internify/mentor/components/InternsTable.tsx index c6dfdc6..fe716cd 100644 --- a/src/Pages/internify/mentor/components/InternsTable.tsx +++ b/src/Pages/internify/mentor/components/InternsTable.tsx @@ -80,7 +80,7 @@ export default function InternsTable({ className="w-10 h-10 rounded-full object-cover border border-gray-100 shadow-sm hidden md:block" /> ) : ( -
+
{intern.name.charAt(0)}
)} diff --git a/src/Pages/internify/mentor/components/MentorTaskCard.tsx b/src/Pages/internify/mentor/components/MentorTaskCard.tsx index acb92ff..9f23adb 100644 --- a/src/Pages/internify/mentor/components/MentorTaskCard.tsx +++ b/src/Pages/internify/mentor/components/MentorTaskCard.tsx @@ -15,6 +15,11 @@ export default function MentorTaskCard({ task }: {task: InternTaskItem}) { navigate(`/mentor/projects/${slug}/${task.slug}?type=${task.submission_type}`) }; + function truncateText(text: string) { + if (text.length <= 230) return text; + return text.slice(0, 230) + "..."; + } + return (
- {task.description} + {truncateText(task.description)}
diff --git a/src/Pages/utils/showToast.tsx b/src/Pages/utils/showToast.tsx index bbb023b..6a7e6ca 100644 --- a/src/Pages/utils/showToast.tsx +++ b/src/Pages/utils/showToast.tsx @@ -3,6 +3,7 @@ import { FiX } from 'react-icons/fi'; import { FaCheck } from "react-icons/fa"; import { IoAlertCircleOutline } from "react-icons/io5"; +// Komponen Toast Card dengan Tailwind untuk pesan sukses dan pesan error function ToastCard({ t, type, title, description }: { t: Toast; type: 'success' | 'error'; @@ -27,13 +28,15 @@ function ToastCard({ t, type, title, description }: {

{description &&

{description}

}
-
); } + +// pemanggilan function ToastCard dengan params export const customToast = { success: (title: string, description?: string) => toast.custom((t) => ), @@ -55,19 +58,19 @@ export const customToast = { const isHookFailure = typeof data === 'object' && data !== null && 'success' in data && (data as { success?: boolean }).success === false; if (isHookFailure) { - toast.dismiss(loadingId); + toast.remove(loadingId); const result = data as { success: boolean; message?: string }; const { title, description } = messages.error(result); customToast.error(title, description ?? result.message); throw new Error(result.message ?? 'Operasi gagal.'); } - toast.dismiss(loadingId); + toast.remove(loadingId); const { title, description } = messages.success(data); customToast.success(title, description); return data; } catch (err) { - toast.dismiss(loadingId); + toast.remove(loadingId); const { title, description } = messages.error(err); customToast.error(title, description ?? (err as Error)?.message); throw err;