From ab98285f9145ead3be4656d9e11a7c9615c6c80f Mon Sep 17 00:00:00 2001 From: Billy Marcello <145271272+BeLieM@users.noreply.github.com> Date: Sun, 21 Dec 2025 22:27:19 +0700 Subject: [PATCH] fixed apply button to close after internship closed and added filter logic in internships list --- src/Pages/InternshipDetails.tsx | 21 +++- src/Pages/InternshipList.tsx | 168 ++++++++++++++++++++++---------- 2 files changed, 137 insertions(+), 52 deletions(-) diff --git a/src/Pages/InternshipDetails.tsx b/src/Pages/InternshipDetails.tsx index 00c5aab..bcfe559 100644 --- a/src/Pages/InternshipDetails.tsx +++ b/src/Pages/InternshipDetails.tsx @@ -28,6 +28,10 @@ const InternshipDetails = () => { if (!intern) return
Internship not found.
; + const isExpired = + new Date(intern.durasi_akhir) < new Date() || + intern.status_lowongan !== "dibuka"; + return (
{/* Navbar Section */} @@ -115,10 +119,21 @@ const InternshipDetails = () => { {/* Apply Button */}
diff --git a/src/Pages/InternshipList.tsx b/src/Pages/InternshipList.tsx index bd297e1..f7caabd 100644 --- a/src/Pages/InternshipList.tsx +++ b/src/Pages/InternshipList.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import SidebarAdmin from "../Layout/SidebarAdmin"; import NavbarAdmin from "../Layout/NavbarAdmin"; @@ -11,10 +11,17 @@ type Application = { status: string; }; +type StatusFilter = "all" | "diterima" | "ditolak"; + const InternshipList = () => { const [applications, setApplications] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [searchTerm, setSearchTerm] = useState(""); + + //FILTER STATE + const [selectedPosisi, setSelectedPosisi] = useState("all"); + const [selectedStatus, setSelectedStatus] = useState("all"); + const itemsPerPage = 10; const navigate = useNavigate(); @@ -66,18 +73,45 @@ const InternshipList = () => { } }; + // OPTIONS POSISI + const posisiOptions = useMemo(() => { + const set = new Set(); + applications.forEach((a) => { + const p = (a.posisi ?? "").trim(); + if (p) set.add(p); + }); + return ["all", ...Array.from(set).sort((a, b) => a.localeCompare(b))]; + }, [applications]); + + // FILTER + SEARCH + const filteredApplications = useMemo(() => { + const term = searchTerm.toLowerCase(); + + return applications.filter((app) => { + const nama = (app.nama_depan ?? "").toLowerCase(); + const posisi = (app.posisi ?? "").toLowerCase(); + const status = (app.status ?? "diproses").toLowerCase(); + + const matchSearch = nama.includes(term) || posisi.includes(term); + + const matchPosisi = + selectedPosisi === "all" ? true : app.posisi === selectedPosisi; + + const matchStatus = + selectedStatus === "all" ? true : status === selectedStatus; + + return matchSearch && matchPosisi && matchStatus; + }); + }, [applications, searchTerm, selectedPosisi, selectedStatus]); + + // Reset page kalau filter/search berubah biar ga nyangkut di page besar + useEffect(() => { + setCurrentPage(1); + }, [searchTerm, selectedPosisi, selectedStatus]); + // Pagination Logic const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; - - const filteredApplications = applications.filter((app) => { - const term = searchTerm.toLowerCase(); - const nama = (app.nama_depan ?? "").toLowerCase(); - const posisi = (app.posisi ?? "").toLowerCase(); - - return nama.includes(term) || posisi.includes(term); - }); - const currentItems = filteredApplications.slice( indexOfFirstItem, indexOfLastItem @@ -124,15 +158,11 @@ const InternshipList = () => { const handleUpdateBatch = async () => { const exportSuccess = await handleExportExcel(); - - if (!exportSuccess) { - return; - } + if (!exportSuccess) return; const confirmDelete = window.confirm( "Apakah Anda yakin ingin menghapus seluruh data pelamar setelah melakukan ekspor?" ); - if (!confirmDelete) return; const token = document.cookie @@ -158,15 +188,23 @@ const InternshipList = () => { } }; + const handleResetFilter = () => { + setSelectedPosisi("all"); + setSelectedStatus("all"); + setSearchTerm(""); + }; + return (
-
+

Daftar Pelamar

-
+ +
+ {/* SEARCH */} { onChange={(e) => setSearchTerm(e.target.value)} className="px-4 py-2 rounded-2xl w-[20rem] border border-slate-400" /> + + {/*FILTER POSISI*/} + + + {/*FILTER STATUS (diterima / ditolak)*/} + + + {/* RESET FILTER */} + + + {/* Update Batch dan Ekspor */} +
+ {/* INFO JUMLAH */} +
+ Menampilkan{" "} + {filteredApplications.length}{" "} + data (setelah filter). +
+
@@ -216,8 +298,8 @@ const InternshipList = () => { - {currentItems.map((app, idx) => ( - + {currentItems.map((app) => ( +
{app.nama_depan} {app.posisi} @@ -231,20 +313,6 @@ const InternshipList = () => { - {/* - - */} -
- {applications.length === 0 && ( + {filteredApplications.length === 0 && (

Tidak ada data.

)} {/* Pagination Controls */} -
- {Array.from({ length: totalPages }, (_, i) => ( - - ))} -
+ {totalPages > 1 && ( +
+ {Array.from({ length: totalPages }, (_, i) => ( + + ))} +
+ )}