From f0011b4af129c28a9bebdf55def5b9b90893364c Mon Sep 17 00:00:00 2001 From: Sidharth Prabhu Date: Thu, 20 Aug 2026 09:54:51 +0530 Subject: [PATCH] Time table feature initiated --- .../controller/WebhookController.java | 5 ++ .../whatsapp/handler/StudentMenuHandler.java | 33 +++++++- .../rit/whatsapp/util/MessageFormatter.java | 81 +++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rit/whatsapp/controller/WebhookController.java b/src/main/java/com/rit/whatsapp/controller/WebhookController.java index c3bdd10..6d85dce 100644 --- a/src/main/java/com/rit/whatsapp/controller/WebhookController.java +++ b/src/main/java/com/rit/whatsapp/controller/WebhookController.java @@ -186,6 +186,11 @@ public class WebhookController { return; } + if ("student_weekly_timetable".equals(selectedButtonId)) { + studentMenuHandler.handleWeeklyTimetable(phoneNumber); + return; + } + if (currentState == UserState.AWAITING_GRIEVANCE_CATEGORY) { grievanceHandler.handleCategorySelection(phoneNumber, selectedButtonId); } else { diff --git a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java index 72f25ae..e505abc 100644 --- a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java +++ b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java @@ -69,7 +69,21 @@ public class StudentMenuHandler { case "student_timetable": String rawTimetable = imsApiService.getTimetable(token); - sendResponseWithMenu(phoneNumber, MessageFormatter.formatTimetable(rawTimetable)); + 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 buttonMessage = WhatsAppMessageBuilder.buildButtonMessage(todaySchedule, buttons); + messageService.sendInteractiveMessage(phoneNumber, buttonMessage); break; case "student_internal_marks": @@ -217,6 +231,23 @@ public class StudentMenuHandler { 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 Student Menu list message + sendResponseWithMenu(phoneNumber, "Select an option from the menu below."); + } + private void sendResponseWithMenu(String phoneNumber, String bodyText) { // Meta API interactive list body limit is 1024 characters if (bodyText.length() > 1024) { diff --git a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java index 274dd3d..5f2d4bf 100644 --- a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java +++ b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java @@ -443,4 +443,85 @@ public class MessageFormatter { } catch (Exception e) {} return rows; } + + public static String formatWeeklyTimetable(String rawJson) { + if (rawJson == null) return "❌ Failed to retrieve weekly timetable data."; + + try { + JsonNode root = mapper.readTree(rawJson); + + if (!root.has("data") || !root.get("data").isObject() || !root.get("data").has("schedule")) { + return "❌ Weekly timetable details not available in the response."; + } + + JsonNode schedule = root.get("data").get("schedule"); + StringBuilder sb = new StringBuilder(); + sb.append("📅 *Weekly Class Timetable*\n\n"); + sb.append("```\n"); + sb.append(String.format("%-3s | %-11s | %s\n", "Day", "Time/Period", "Subject (Room)")); + sb.append("----+-------------+------------------------\n"); + + String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}; + String[] dayAbbrevs = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + boolean hasAnyClasses = false; + + for (int i = 0; i < days.length; i++) { + String day = days[i]; + String abbrev = dayAbbrevs[i]; + + if (schedule.has(day)) { + JsonNode daySchedule = schedule.get(day); + + if (daySchedule.isObject() && daySchedule.size() > 0) { + java.util.Iterator> fields = daySchedule.fields(); + while (fields.hasNext()) { + java.util.Map.Entry field = fields.next(); + String timeOrPeriod = field.getKey(); + JsonNode details = field.getValue(); + + String course = ""; + String room = ""; + if (details.isObject()) { + course = details.has("course_name") ? details.get("course_name").asText() : + (details.has("name") ? details.get("name").asText() : "Unknown"); + room = details.has("room") ? details.get("room").asText() : ""; + } else { + course = details.asText(); + } + + String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")"; + sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(timeOrPeriod, 11), subjectRoom)); + hasAnyClasses = true; + } + } else if (daySchedule.isArray() && daySchedule.size() > 0) { + for (JsonNode details : daySchedule) { + String time = details.has("time") ? details.get("time").asText() : "TBA"; + String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown"; + String room = details.has("room") ? details.get("room").asText() : ""; + + String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")"; + sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(time, 11), subjectRoom)); + hasAnyClasses = true; + } + } + } + } + + sb.append("```"); + + if (!hasAnyClasses) { + return "📅 *Weekly Class Timetable*\n\nNo classes scheduled for this week."; + } + + return sb.toString(); + } catch (Exception e) { + return "⚠️ Error formatting weekly timetable data."; + } + } + + private static String truncate(String text, int length) { + if (text == null) return ""; + if (text.length() <= length) return text; + return text.substring(0, length); + } }