diff --git a/src/Modules/Certificates/FeeStructureCertificate.jsx b/src/Modules/Certificates/FeeStructureCertificate.jsx index 541876e8e..2d94d89c0 100644 --- a/src/Modules/Certificates/FeeStructureCertificate.jsx +++ b/src/Modules/Certificates/FeeStructureCertificate.jsx @@ -10,6 +10,7 @@ import { Group, Loader, Paper, + Select, Stack, Text, TextInput, @@ -63,6 +64,17 @@ const filenameFrom = (header, fallback) => { return match?.[1] || fallback; }; +function ordinalWithSuperscript(value) { + const match = /^(\d+)(st|nd|rd|th)$/.exec((value ?? "").trim()); + if (!match) return value; + return ( + <> + {match[1]} + {match[2]} + + ); +} + const indianCurrency = (value) => { const [whole, fraction] = Number(value).toFixed(2).split("."); const head = whole.slice(0, -3); @@ -80,6 +92,8 @@ export default function FeeStructureCertificate() { const [rollNumber, setRollNumber] = useState(""); const [selectedStudent, setSelectedStudent] = useState(null); const [structure, setStructure] = useState(null); + const [financialYears, setFinancialYears] = useState([]); + const [selectedSemester, setSelectedSemester] = useState(null); const [certificateMeta, setCertificateMeta] = useState(null); const [preview, setPreview] = useState(null); const [fetchingStudent, setFetchingStudent] = useState(false); @@ -89,25 +103,31 @@ export default function FeeStructureCertificate() { const clearStudent = () => { setSelectedStudent(null); setStructure(null); + setFinancialYears([]); + setSelectedSemester(null); setCertificateMeta(null); setPreview(null); }; - const fetchStudent = async () => { - const normalizedRollNumber = rollNumber.trim().toUpperCase(); - if (!normalizedRollNumber || fetchingStudent) return; - - clearStudent(); - setRollNumber(normalizedRollNumber); + const fetchStudent = async (roll, semester) => { + if (!roll || fetchingStudent) return; setFetchingStudent(true); try { const { data } = await axios.get(feeStructureCertificateStudentRoute, { ...authConfig(), - params: { roll_number: normalizedRollNumber }, + params: { roll_number: roll, semester: semester || undefined }, }); setSelectedStudent(data.student || null); setStructure(data.structure || null); + setFinancialYears( + (data.financial_years || []).map((item) => ({ + value: String(item.value), + label: item.label, + })), + ); + setSelectedSemester(data.selected_semester ?? null); setCertificateMeta(data.certificate || null); + setPreview(null); } catch (error) { notifications.show({ color: "red", @@ -119,6 +139,21 @@ export default function FeeStructureCertificate() { } }; + const searchStudent = () => { + const normalizedRollNumber = rollNumber.trim().toUpperCase(); + if (!normalizedRollNumber) return; + clearStudent(); + setRollNumber(normalizedRollNumber); + fetchStudent(normalizedRollNumber); + }; + + const changeFinancialYear = (value) => { + const semester = Number(value); + setSelectedSemester(semester); + setPreview(null); + fetchStudent(rollNumber, semester); + }; + const showPreview = () => { if (!selectedStudent || !structure?.rows?.length || !certificateMeta) return; @@ -135,7 +170,7 @@ export default function FeeStructureCertificate() { try { const response = await axios.post( feeStructureCertificatePdfRoute, - { student_id: selectedStudent.student_id }, + { student_id: selectedStudent.student_id, semester: selectedSemester }, { ...authConfig(), responseType: "blob" }, ); const filename = filenameFrom( @@ -159,7 +194,9 @@ export default function FeeStructureCertificate() { } }; - const ready = Boolean(selectedStudent?.is_ready && structure?.rows?.length); + const ready = Boolean( + selectedStudent?.is_ready && structure?.rows?.length && selectedSemester, + ); return ( <> @@ -185,7 +222,7 @@ export default function FeeStructureCertificate() { onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); - fetchStudent(); + searchStudent(); } }} rightSection={ @@ -195,7 +232,7 @@ export default function FeeStructureCertificate() {