package com.rit.whatsapp.handler; import com.rit.whatsapp.model.UserState; import com.rit.whatsapp.service.ImsApiService; import com.rit.whatsapp.service.SessionService; import com.rit.whatsapp.service.WhatsAppMessageBuilder; import com.rit.whatsapp.service.WhatsAppMessageService; import com.rit.whatsapp.util.MessageFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class StudentMenuHandler { private final WhatsAppMessageService messageService; private final SessionService sessionService; private final GrievanceHandler grievanceHandler; private final ImsApiService imsApiService; @Autowired public StudentMenuHandler(WhatsAppMessageService messageService, SessionService sessionService, GrievanceHandler grievanceHandler, ImsApiService imsApiService) { this.messageService = messageService; this.sessionService = sessionService; this.grievanceHandler = grievanceHandler; this.imsApiService = imsApiService; } public void sendMainMenu(String phoneNumber) { sessionService.setUserState(phoneNumber, UserState.MAIN_MENU); String token = sessionService.getImsToken(phoneNumber); String studentName = "Student"; if (token != null) { studentName = sessionService.getStudentName(phoneNumber, token); } Map interactiveList = WhatsAppMessageBuilder.buildListMessage( "RIT Digital Assistant", "Welcome " + studentName + "! Please select an option from the menu below.", "Student Menu", getStudentMenuRows() ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); } public void handleMenuSelection(String phoneNumber, String selectedOptionId) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } switch (selectedOptionId) { case "student_attendance": String rawAttendance = imsApiService.getAttendance(token); String rawLeaves = imsApiService.getLeaves(token); sendResponseWithMenu(phoneNumber, MessageFormatter.formatAttendanceAndLeaves(rawAttendance, rawLeaves)); break; case "student_timetable": sendTimetableMenu(phoneNumber, token); break; case "student_internal_marks": sendInternalMarksMenu(phoneNumber); break; case "student_cat1_marks": handleCat1Marks(phoneNumber); break; case "student_cat2_marks": handleCat2Marks(phoneNumber); break; case "student_cat3_marks": handleCat3Marks(phoneNumber); break; case "student_assignment_marks": handleAssignmentMarks(phoneNumber); break; case "student_semester_results": sendSemesterSelection(phoneNumber, token); break; case "student_fee_details": sendFeeDetailsMenu(phoneNumber, token); break; case "student_raise_grievance": grievanceHandler.startGrievanceFlow(phoneNumber); break; case "student_help_menu": sendHelpMenu(phoneNumber); break; case "student_logout": sessionService.logoutUser(phoneNumber); messageService.sendMessage(phoneNumber, "You have been logged out successfully. Type 'Hi' to log in again."); break; case "student_contact_department": messageService.sendMessage(phoneNumber, "Contact Department is currently under development. Please check back later!"); sendMainMenu(phoneNumber); break; default: messageService.sendMessage(phoneNumber, "You selected an option that is currently under development. Please check back later!"); // Resend main menu sendMainMenu(phoneNumber); break; } } public void sendSemesterSelection(String phoneNumber, String token) { sessionService.setUserState(phoneNumber, UserState.AWAITING_SEMESTER_SELECTION); List> rows = new ArrayList<>(); for (int i = 1; i <= 8; i++) { rows.add(createRow("sem_" + i, "Semester " + i, "")); } String rawDashboard = imsApiService.getDashboard(token); String bodyText = MessageFormatter.formatDashboardCgpa(rawDashboard); Map interactiveList = WhatsAppMessageBuilder.buildListMessage( "Semester Results", bodyText, "Select Semester", rows ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); sendStudentMenuDirectly(phoneNumber); } public void handleSemesterSelection(String phoneNumber, String selectedOptionId) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } try { int semester = Integer.parseInt(selectedOptionId.replace("sem_", "")); byte[] pdfBytes = imsApiService.getResultsPdf(token, semester); if (pdfBytes != null) { String fileName = "Semester_" + semester + "_Results.pdf"; String mediaId = messageService.uploadMedia(pdfBytes, fileName, "application/pdf"); if (mediaId != null) { messageService.sendDocumentMessage(phoneNumber, mediaId, "Here are your Semester " + semester + " results!", fileName); sendSemesterSelection(phoneNumber, token); } else { messageService.sendMessage(phoneNumber, "Failed to upload the results document to WhatsApp."); sendSemesterSelection(phoneNumber, token); } } else { messageService.sendMessage(phoneNumber, "Failed to download your results. They may not be published yet."); sendSemesterSelection(phoneNumber, token); } } catch (Exception e) { messageService.sendMessage(phoneNumber, "Invalid semester selected."); sendSemesterSelection(phoneNumber, token); } sessionService.resetState(phoneNumber); // Reset state after fetching results } public void handleReceiptSelection(String phoneNumber, String selectedOptionId) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } try { byte[] pdfBytes = null; String fileName = "Receipt.pdf"; String docMessage = "Here is your Fee Receipt!"; if (selectedOptionId.startsWith("exam_")) { String longId = sessionService.getReceiptIdMapping(phoneNumber, selectedOptionId); pdfBytes = imsApiService.getExamFeeReceiptPdf(token, longId); fileName = "Exam_Receipt.pdf"; docMessage = "Here is your Exam Fee Receipt!"; } else if (selectedOptionId.startsWith("acad_")) { String longId = sessionService.getReceiptIdMapping(phoneNumber, selectedOptionId); pdfBytes = imsApiService.getAcademicFeeReceiptPdf(token, longId); fileName = "Academic_Receipt.pdf"; docMessage = "Here is your Academic Fee Receipt!"; } else if (selectedOptionId.startsWith("cons_")) { String longId = sessionService.getReceiptIdMapping(phoneNumber, selectedOptionId); pdfBytes = imsApiService.getConsolidatedAcademicFeeReceiptPdf(token, longId); fileName = "Consolidated_Receipt.pdf"; docMessage = "Here is your Consolidated Academic Fee Receipt!"; } if (pdfBytes != null) { String mediaId = messageService.uploadMedia(pdfBytes, fileName, "application/pdf"); if (mediaId != null) { messageService.sendDocumentMessage(phoneNumber, mediaId, docMessage, fileName); sendPaymentHistoryMenu(phoneNumber, token); } else { messageService.sendMessage(phoneNumber, "Failed to upload the receipt document to WhatsApp."); sendPaymentHistoryMenu(phoneNumber, token); } } else { messageService.sendMessage(phoneNumber, "Failed to download your receipt. It may not be available."); sendPaymentHistoryMenu(phoneNumber, token); } } catch (Exception e) { messageService.sendMessage(phoneNumber, "Invalid receipt selected."); sendPaymentHistoryMenu(phoneNumber, token); } sessionService.resetState(phoneNumber); // Reset state after fetching receipt } public void handleWeeklyTimetable(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawTimetable = imsApiService.getTimetable(token); String weeklyTimetable = MessageFormatter.formatWeeklyTimetable(rawTimetable); // Send weekly timetable as standard message (up to 4096 characters limit) messageService.sendMessage(phoneNumber, weeklyTimetable); // Follow up with Timetable sub-menu again sendTimetableMenu(phoneNumber, token); } public void handleExamFees(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawExamFees = imsApiService.getExamFees(token); String formattedExamFees = MessageFormatter.formatExamFees(rawExamFees); messageService.sendMessage(phoneNumber, formattedExamFees); sendFeeDetailsMenu(phoneNumber, token); } public void handlePaymentHistory(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } sendPaymentHistoryMenu(phoneNumber, token); } public void sendTimetableMenu(String phoneNumber, String token) { String rawTimetable = imsApiService.getTimetable(token); String todaySchedule = MessageFormatter.formatTimetable(rawTimetable); // Truncate to stay safely within WhatsApp 1024 character limit for button bodies if (todaySchedule.length() > 1020) { todaySchedule = todaySchedule.substring(0, 1017) + "..."; } List> buttons = new ArrayList<>(); Map weeklyBtn = new HashMap<>(); weeklyBtn.put("id", "student_weekly_timetable"); weeklyBtn.put("title", "Weekly Timetable"); buttons.add(weeklyBtn); Map menuBtn = new HashMap<>(); menuBtn.put("id", "student_show_menu"); menuBtn.put("title", "Student Menu"); buttons.add(menuBtn); System.out.println("FINAL TODAY TIMETABLE MESSAGE:\n" + todaySchedule); Map buttonMessage = WhatsAppMessageBuilder.buildButtonMessage(todaySchedule, buttons); messageService.sendInteractiveMessage(phoneNumber, buttonMessage); sendStudentMenuDirectly(phoneNumber); } public void sendFeeDetailsMenu(String phoneNumber, String token) { String rawFees = imsApiService.getFees(token); String bodyText = MessageFormatter.formatAcademicFeesOnly(rawFees); List> feeButtons = new ArrayList<>(); Map examBtn = new HashMap<>(); examBtn.put("id", "student_exam_fees"); examBtn.put("title", "Exam Fees"); feeButtons.add(examBtn); Map historyBtn = new HashMap<>(); historyBtn.put("id", "student_payment_history"); historyBtn.put("title", "Payment History"); feeButtons.add(historyBtn); if (bodyText.length() > 1020) { bodyText = bodyText.substring(0, 1017) + "..."; } Map feeButtonMessage = WhatsAppMessageBuilder.buildButtonMessage(bodyText, feeButtons); messageService.sendInteractiveMessage(phoneNumber, feeButtonMessage); sendStudentMenuDirectly(phoneNumber); } public void sendPaymentHistoryMenu(String phoneNumber, String token) { String rawExamFees = imsApiService.getExamFees(token); String rawFeesHistory = imsApiService.getAcademicFeesHistory(token); String formattedHistory = MessageFormatter.formatCombinedPaymentHistory(rawExamFees, rawFeesHistory); Map idMappings = new HashMap<>(); List> examRows = MessageFormatter.extractReceiptRows(rawExamFees, idMappings); List> acadRows = MessageFormatter.extractAcademicReceiptRows(rawFeesHistory, idMappings); List> consRows = MessageFormatter.extractConsolidatedReceiptRows(rawFeesHistory, idMappings); sessionService.storeReceiptIdMappings(phoneNumber, idMappings); List> receiptRows = new ArrayList<>(); receiptRows.addAll(examRows); receiptRows.addAll(acadRows); receiptRows.addAll(consRows); if (!receiptRows.isEmpty()) { if (receiptRows.size() > 10) receiptRows = receiptRows.subList(0, 10); sessionService.setUserState(phoneNumber, UserState.AWAITING_RECEIPT_SELECTION); if (formattedHistory.length() > 1024) { formattedHistory = formattedHistory.substring(0, 1021) + "..."; } Map listMessage = WhatsAppMessageBuilder.buildListMessage( "Receipts", formattedHistory, "Download Receipt", receiptRows ); messageService.sendInteractiveMessage(phoneNumber, listMessage); sendStudentMenuDirectly(phoneNumber); } else { sendResponseWithMenu(phoneNumber, formattedHistory); } } private void sendResponseWithMenu(String phoneNumber, String bodyText) { // Meta API interactive list body limit is 1024 characters if (bodyText.length() > 1024) { bodyText = bodyText.substring(0, 1021) + "..."; } Map interactiveList = WhatsAppMessageBuilder.buildListMessage( null, bodyText, "Student Menu", getStudentMenuRows() ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); } public void sendHelpMenu(String phoneNumber) { List> rows = new ArrayList<>(); rows.add(createRow("student_contact_department", "Contact department", "Faculty mentor, HOD, etc.")); rows.add(createRow("student_logout", "Logout", "Sign out of your account")); Map interactiveList = WhatsAppMessageBuilder.buildListMessage( "Help & Settings", "Please select an option below:", "Help Menu", rows ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); sendStudentMenuDirectly(phoneNumber); } public void sendStudentMenuDirectly(String phoneNumber) { sessionService.setUserState(phoneNumber, UserState.MAIN_MENU); Map interactiveList = WhatsAppMessageBuilder.buildListMessage( null, "Select an option from the menu below", "Student Menu", getStudentMenuRows() ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); } public void sendInternalMarksMenu(String phoneNumber) { List> rows = new ArrayList<>(); rows.add(createRow("student_cat1_marks", "CAT 1 Marks", "View CAT 1 (CO1) marks")); rows.add(createRow("student_cat2_marks", "CAT 2 Marks", "View CAT 2 (CO2) marks")); rows.add(createRow("student_cat3_marks", "CAT 3 Marks", "View CAT 3 (CO3) marks")); rows.add(createRow("student_assignment_marks", "Assignment Marks", "View assignments 1-5 marks")); Map interactiveList = WhatsAppMessageBuilder.buildListMessage( "Internal Marks", "Select which internal marks you want to view:", "Select Option", rows ); messageService.sendInteractiveMessage(phoneNumber, interactiveList); sendStudentMenuDirectly(phoneNumber); } public void handleCat1Marks(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawCatMarks = imsApiService.getCatMarks(token); String formatted = com.rit.whatsapp.util.MessageFormatter.formatCat1Marks(rawCatMarks); messageService.sendMessage(phoneNumber, formatted); sendInternalMarksMenu(phoneNumber); } public void handleCat2Marks(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawCatMarks = imsApiService.getCatMarks(token); String formatted = com.rit.whatsapp.util.MessageFormatter.formatCat2Marks(rawCatMarks); messageService.sendMessage(phoneNumber, formatted); sendInternalMarksMenu(phoneNumber); } public void handleCat3Marks(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawCatMarks = imsApiService.getCatMarks(token); String formatted = com.rit.whatsapp.util.MessageFormatter.formatCat3Marks(rawCatMarks); messageService.sendMessage(phoneNumber, formatted); sendInternalMarksMenu(phoneNumber); } public void handleAssignmentMarks(String phoneNumber) { String token = sessionService.getImsToken(phoneNumber); if (token == null) { messageService.sendMessage(phoneNumber, "Your session has expired. Please type 'Reset' to login again."); return; } String rawAssignmentMarks = imsApiService.getAssignmentMarks(token); String formatted = com.rit.whatsapp.util.MessageFormatter.formatAssignmentMarks(rawAssignmentMarks); messageService.sendMessage(phoneNumber, formatted); sendInternalMarksMenu(phoneNumber); } private List> getStudentMenuRows() { List> rows = new ArrayList<>(); rows.add(createRow("student_attendance", "Attendance", "Overall % and Subject-wise")); rows.add(createRow("student_timetable", "Timetable", "Today's classes and Weekly")); rows.add(createRow("student_internal_marks", "Internal marks", "CAT 1, CAT 2, Overall")); rows.add(createRow("student_semester_results", "Semester results", "Latest result and CGPA")); rows.add(createRow("student_fee_details", "Fee details & receipt", "Fee paid, Pending, Due date")); rows.add(createRow("student_academic_calendar", "Academic calendar", "Holidays and Important dates")); rows.add(createRow("student_exam_schedule", "Exam schedule", "Upcoming exams and Hall details")); rows.add(createRow("student_circulars", "Circulars & Notices", "Department circulars")); rows.add(createRow("student_raise_grievance", "Raise a grievance \u2B50", "Submit an issue ticket")); rows.add(createRow("student_help_menu", "Help & Settings", "Logout, Contact dept, etc.")); return rows; } private Map createRow(String id, String title, String description) { Map row = new HashMap<>(); row.put("id", id); row.put("title", title); row.put("description", description); return row; } }