diff --git a/client/src/data/examScheduleData.js b/client/src/data/examScheduleData.js new file mode 100644 index 00000000..c34858ca --- /dev/null +++ b/client/src/data/examScheduleData.js @@ -0,0 +1,767 @@ +const examScheduleData = { + "courseSlotMap": { + "BM5103H": "B", + "BM5105H": "D", + "BM5181H": "A1", + "BM6046H": "D1", + "BM5104H": "C", + "BM5101H": "A", + "BM5102H": "E", + "BM6014H": "B1", + "BM6043H": "C1", + "BM6003H": "F1", + "BM6047H": "E1", + "BT3001": "A1", + "CL2101": "E", + "CL2103": "F1", + "CL2091M": "F", + "BT3002": "B1", + "BT3003": "C1", + "BT3004": "D1", + "BT6005": "B1", + "BT6034": "C1", + "BT6045": "C1", + "CL3001": "C1", + "CL3002": "D1", + "CL3003": "A1", + "BT6004": "B1", + "BT6051": "E1", + "BT6037": "D1", + "BT6019": "A1", + "BT6041": "D1", + "BT2191M": "F", + "BT5101": "A", + "BT5102": "C", + "BT5103": "D", + "BT5104": "E", + "CL2102": "C", + "CL2104": "C", + "CL1101": "A1", + "CL1102": "A1", + "CL1103": "A1", + "CL5101": "C", + "CL5102": "B", + "CL6045": "A", + "PH0001": "A", + "BM5121H": "C", + "BM5122H": "D", + "BM5125H": "E", + "CL5201": "D", + "CL5202": "A", + "CL5203": "A", + "CL6014": "C1", + "CL6023": "F1", + "CL6043": "F", + "CL6013": "F", + "CL6029": "G", + "CL6030": "A1", + "CL6031": "D1", + "CL6040": "E1", + "CL6046": "G1", + "CL6049": "G1", + "CL6055": "B1", + "NT6002": "A", + "CH1101H": "C1", + "CH1102H": "C1", + "CH1103H": "C1", + "CH1105H": "C1", + "CH1104H": "C1", + "CH1106H": "C1", + "CH1107H": "C1", + "CH1108H": "C1", + "CH1112": "C1", + "CH2102": "E", + "CH2103H": "D", + "CH2101": "B", + "CH3121": "B1", + "CH3122": "C1", + "CH3123": "A1", + "CH4120": "B", + "CH4122": "C", + "CH4123": "D", + "CH4124": "D", + "CH4151": "A", + "CH4152": "B", + "CH4153": "C", + "CH4154": "D", + "CH5151": "A", + "CH5152": "B", + "CH5153": "C", + "CH5154": "D", + "CH7151": "A1", + "CH7152": "B1", + "CH7153": "C1", + "CH7154": "F", + "CH7155": "D1", + "CH7157": "G", + "BM5123H": "B", + "BM6006H": "A1", + "BM6001H": "B1", + "BM6048H": "C1", + "EE2101H": "B", + "EE2102H": "B", + "EE2103": "B", + "EE2100": "C", + "EE2104": "D", + "BM5124H": "A", + "EE3000": "A1", + "EE3001": "B1", + "EE3002": "C1", + "EE5000": "A", + "EE5001": "B", + "EE5002": "C", + "EE5102": "B", + "EE5103": "C", + "EE5100": "A", + "PH1110H": "E1", + "PH1112H": "E1", + "PH1113H": "E1", + "PH1111H": "E1", + "PH1114H": "E1", + "PH1115H": "E1", + "PH1116H": "E1", + "PH1310H": "E1", + "PH1312H": "E1", + "PH1311H": "E1", + "PH1313H": "E1", + "PH1314H": "E1", + "PH1315H": "E1", + "PH1130": "E1", + "PH2091M": "F", + "PH2510": "A", + "PH2520": "B", + "PH2530": "C", + "PH2540": "D", + "PH2110H": "E", + "PH3010": "A1", + "PH3030": "B1", + "PH3050": "C1", + "FT6001": "C", + "PH3070": "D1", + "FT6005": "E1", + "MA1221": "B", + "MA2091M": "F", + "MA2121": "C", + "MA2171": "D", + "MA2172": "E", + "MA4121": "A", + "FT6003": "B", + "EE5201": "C", + "EE5202": "B", + "EE5300": "A", + "EE5301": "B", + "EE5304": "D", + "EE5400": "A", + "EE5401": "B", + "EE5402": "C", + "EE5500": "D", + "EE5503": "C", + "FT6011": "F1", + "EE5501": "B", + "FT6007": "G", + "PH4150": "B", + "PH4130": "C", + "PH4010": "E", + "PH4030": "A", + "PH4050": "B", + "PH4070": "D", + "PH4090": "C", + "PH5350": "E1", + "PH5430": "G1", + "PH5220": "F1", + "MA4122": "B", + "MA4123": "C", + "MA4124": "D", + "MA4125": "A1", + "MA4126": "B1", + "MA4127": "C1", + "PH7010": "A", + "MA4128": "D1", + "PH7030": "B", + "PH7050": "D", + "PH7070": "C", + "MA4171": "E", + "MA4172": "C1", + "MA6001": "A1", + "MA6002": "B1", + "MA6003": "C1", + "MA6005": "B1", + "MA6004": "A1", + "BT2101": "B", + "BT2102": "C", + "BT2103": "D", + "BT2151H": "A", + "BT2161H": "A", + "BT4408": "A", + "BT4412": "C", + "BT6021": "B", + "BT4418": "C", + "BT4413": "D", + "BT4421": "E", + "BT6020": "F", + "BT6030": "B", + "BT6044": "E1", + "EE4032": "B", + "MA3911M": "E1", + "MA3921": "D1", + "MA3972": "A1", + "MA4923": "B", + "MA4973": "C", + "MA5022": "D", + "MA5055": "F", + "MA5074": "E1", + "MA6056": "E", + "MA6072": "D1", + "MA6026": "F1", + "MA2302H": "A", + "MA2306H": "A", + "MA2312H": "A", + "MA2310H": "A", + "MA2305H": "A", + "MA2307H": "A", + "MA2304H": "A", + "MA2309H": "A", + "MA2311H": "A", + "MA2502H": "A", + "MA2506H": "A", + "MA2512H": "A", + "MA2510H": "A", + "MA2505H": "A", + "MA2507H": "A", + "MA2504H": "A", + "MA2509H": "A", + "MA2511H": "A", + "MA5102": "A", + "MA5301H": "B", + "MA5501H": "B", + "EE3004": "D1", + "EE3005": "B1", + "EE5042": "F1", + "EE2091M": "F", + "EE3091M": "E1", + "EE3092M": "A", + "EE5003": "E", + "EE5031": "A1", + "EE5134": "A1", + "EE5235": "A1", + "EE5237": "E1", + "EE5334": "B1", + "EE5336": "C1", + "EE5340": "D1", + "EE5432": "D1", + "EE5434": "B1", + "EE5440": "A1", + "EE5536": "E1", + "EE5538": "C1", + "EE4033": "D", + "DA1102": "C1", + "DA1103": "D1", + "DA2141": "C", + "DA2121": "E", + "DA2151": "B", + "DA3021": "A1", + "DA3022": "B1", + "DA3031": "C1", + "DA3041": "D1", + "DA3051": "F1", + "DA3091M": "E1", + "DA4021": "E", + "DA4061": "B", + "DA4062": "C", + "DA6024": "D", + "DA6075": "D", + "DA6071": "D", + "DA4091M": "A", + "DA5011H": "C", + "DA5012H": "C", + "HS7005": "B", + "HS7045": "C", + "HS7060": "E", + "HS4002": "B", + "HS4003": "C", + "HS4004": "D", + "HS4005": "E", + "HS5206": "A1", + "HS5207": "B1", + "HS5208": "C1", + "HS6208": "D1", + "HS6224": "E1", + "HS6225": "F1", + "HS4011": "B", + "HS4012": "C", + "HS5213": "E", + "HS5215": "F", + "HS5001": "A1", + "HS5002": "D1", + "HS5203": "E1", + "CS1101": "A1", + "CS1109": "A1", + "CS1110": "A1", + "CS1102": "A1", + "CS1103": "A1", + "CS1104": "A1", + "CS1115": "A1", + "CS1116H": "C1", + "CS1113": "D1", + "CS2001": "A", + "CS2002": "D", + "CS2003": "E", + "CS2201": "C", + "CS3103": "B1", + "CS3105": "C1", + "CS3201M": "E1", + "CS4302M": "A", + "CS5001": "B", + "CS5003": "A", + "CS5005": "A", + "CS5006": "B", + "CS5201": "E1", + "CS5399": "F1", + "CS5396": "G1", + "CS6399": "G", + "CS5099": "F1", + "CS5097": "G", + "CS5191": "D1", + "DD1101S": "A", + "DD1103S": "B", + "DD1104": "C", + "DD1105": "D", + "DD2091M": "F", + "DD3301": "A", + "DD3302": "B", + "DD3304S": "C", + "DD3101M": "E1", + "DD4301": "A", + "DD4302S": "B", + "DD4101M": "A", + "DD5101": "A", + "DD5103": "B", + "DD5104": "C", + "DD5501": "A1", + "DD5503S": "B1", + "DD5510": "C1", + "DD5511": "D", + "DD5526": "E", + "BM6025H": "G1", + "DD5557": "E1", + "DD5514": "D1", + "DD5559": "F1", + "ME1101": "D1", + "ME1102": "D1", + "ME1103": "D1", + "ME1104": "D1", + "ME1105": "D1", + "ME1106": "D1", + "ME1107": "D1", + "ME1112": "C1", + "ME2091M": "F", + "ME2101": "B", + "ME2102": "C", + "ME2103": "D", + "ME2104": "E", + "ME2105": "D", + "ME3301M": "E1", + "ME3101": "A1", + "ME3312": "C1", + "ME3103": "D1", + "ME3104": "F1", + "ME4401M": "A", + "ME5501": "A", + "ME5510": "D", + "ME5512": "B1", + "ME5520": "A1", + "ME5521": "E1", + "ME5523": "D", + "ME5530": "D", + "ME5531": "A1", + "ME5532": "C", + "ME5543": "B1", + "ME5550": "D1", + "ME5551": "A1", + "ME6608": "E1", + "ME6609": "B", + "ME6644": "E1", + "ME6659": "B1", + "ME6660": "D1", + "ME6674": "F", + "ME6680": "C", + "ME6689": "E1", + "ME6690": "C", + "ME6692": "D1", + "ME6703": "D1", + "CE2101": "C", + "CE2103": "B", + "CE2105": "D", + "CE3102": "A1", + "CE3105": "B1", + "CE3116": "D1", + "CE3903": "C1", + "CE3904": "F1", + "CE4015": "B", + "CE4045": "D", + "CE5001": "A", + "CE5002": "C", + "CE5003": "D", + "CE5021": "A1", + "CE5022": "C1", + "CE5023": "B1", + "CE5031": "F", + "CE5032": "A1", + "CE5041": "A", + "CE5042": "E", + "CE5051": "A1", + "CE5053": "B1", + "CE5054": "E", + "CE5067": "C1", + "CE5081": "B1", + "CE5082": "A1", + "CE5087": "E", + "CE5091": "B", + "CE5092": "B1", + "CE5093": "C1", + "CE6001": "D1", + "CE6026": "B", + "CE6041": "D", + "CE6042": "C", + "CE6048": "B", + "CE6051": "D", + "CE6052": "C", + "CE6060": "E", + "CS5187": "A1", + "CS5393": "E", + "CS6398": "B1", + "CS6198": "A1", + "DD6501S": "G", + "DD6509": "G1", + "DD7501": "A1", + "DD2103": "A", + "DD2104": "B", + "DD2105": "C", + "HS4001": "A", + "HS4121": "D", + "DA2091M": "F", + "PH4101": "A1", + "PH4103": "B1", + "PH4105": "C1", + "PH4107": "D1", + "PH3091M": "E1", + "HT1101": "A1", + "HT1102": "D1", + "HT1103": "C1", + "HT1104": "B1", + "HT1105": "E1", + "HT1106": "F1", + "HT2301H": "A1", + "HT2501H": "A1", + "HT2101": "B1", + "HT2102": "F1", + "HT2103": "E1", + "HT2104": "D1", + "HT5001": "A", + "HT5002": "B", + "HT5003": "C", + "HT5004": "D", + "HT5005": "E", + "HS2008": "G", + "HS2011": "G", + "HS2018": "G", + "HS2022.": "G", + "HS2027": "G", + "HS2031": "G", + "HS2040": "G", + "HS2013": "G1", + "HS2022": "G1", + "HS2034": "G1", + "HS3004": "G1", + "HS2037": "G1", + "HS3006": "G1", + "HS3042": "G", + "HS3045": "G", + "HS3011": "G", + "HS3012": "G", + "HS3013": "G", + "HS3014": "G", + "HS3019": "G", + "HS3030": "G", + "EN2101": "C", + "EN2103": "B", + "EN2104": "D", + "EN3101": "A1", + "EN3102": "D1", + "EN3103": "B1", + "EN3104": "C1", + "EN5105": "D", + "EN5204": "E", + "EN5101": "B", + "EN5102": "C", + "EN5104": "C1", + "PH4190": "D", + "MA4911M": "A", + "DD5550": "F", + "BT4422": "D", + "DA2101H": "B", + "CS5291": "F1", + "EE5239": "C1", + "EE5341": "E1", + "EE5447": "B1", + "EE5540": "F", + "DA2142": "D", + "EE5303": "C", + "CS5290": "A1", + "HS5216": "F1", + "RT5001": "A", + "RT5002": "B", + "RT5003": "C", + "RT5004": "D", + "RT5020": "E", + "RT5021": "F", + "HS6205": "G1", + "HS7071": "C", + "HS7032": "A", + "HS7034": "B", + "HS7035": "C", + "HS7042": "D", + "HS7025": "A", + "HS7023": "B", + "HS5111": "B", + "HS7033": "A1", + "HS7036": "B1", + "SS5102": "B", + "SS5301": "E", + "SS5201": "C", + "SS5202": "D", + "LS5003": "A", + "LS5004": "B", + "LS5006": "C", + "HS7047": "E1", + "HS7029": "D1", + "HS6230": "D", + "HS4918M": "A", + "DA4022": "F", + "DA6021": "F", + "CS2091M": "F", + "EN1101": "A1", + "MA1301H": "B1", + "DA1101H": "G1", + "MA1302H": "B1", + "MA1303H": "B1", + "MA1304H": "B1", + "MA1305H": "B1", + "MA1306H": "B1", + "MA1307H": "B1", + "MA1308H": "B1", + "MA1309H": "B1", + "MA1310H": "B1", + "MA1311H": "B1", + "MA1312H": "B1", + "MA1501H": "B1", + "MA1502H": "B1", + "MA1503H": "B1", + "MA1504H": "B1", + "MA1505H": "B1", + "MA1506H": "B1", + "MA1507H": "B1", + "MA1508H": "B1", + "MA1509H": "B1", + "MA1510H": "B1", + "MA1511H": "B1", + "MA1512H": "B1", + "RT5022": "G", + "BT1101": "F1", + "EE1101H": "F1", + "EE1105H": "F1", + "EE1113": "C1", + "EE1115": "C1", + "EE1102H": "F1", + "EE1106H": "F1", + "EE1103H": "F1", + "EE1104H": "F1", + "EE1107H": "F1", + "EE1108H": "F1", + "CL6019": "B1", + "HS7048": "D1", + "PH3810M": "E1", + "CE6012": "C", + "CE4011": "F", + "CH4125": "F", + "CS4101": "F", + "MA4024": "F", + "PH4650": "F", + "CS3001": "F1", + "HS7046": "D", + "FT6016": "A", + "HS3041": "G1" + }, + "slotSchedule": { + "G": { + "midSem": { + "date": "13-09-2026", + "time": "9:00-11:00", + "raw": "13-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "14-11-2026", + "time": "9:00-12:00", + "raw": "14-11-2026 (9:00-12:00)" + } + }, + "G1": { + "midSem": { + "date": "13-09-2026", + "time": "14:00-16:00", + "raw": "13-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "14-11-2026", + "time": "14:00-17:00", + "raw": "14-11-2026 (14:00-17:00)" + } + }, + "A": { + "midSem": { + "date": "14-09-2026", + "time": "9:00-11:00", + "raw": "14-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "15-11-2026", + "time": "9:00-12:00", + "raw": "15-11-2026 (9:00-12:00)" + } + }, + "A1": { + "midSem": { + "date": "14-09-2026", + "time": "14:00-16:00", + "raw": "14-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "15-11-2026", + "time": "14:00-17:00", + "raw": "15-11-2026 (14:00-17:00)" + } + }, + "B": { + "midSem": { + "date": "15-09-2026", + "time": "9:00-11:00", + "raw": "15-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "16-11-2026", + "time": "9:00-12:00", + "raw": "16-11-2026 (9:00-12:00)" + } + }, + "B1": { + "midSem": { + "date": "15-09-2026", + "time": "14:00-16:00", + "raw": "15-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "16-11-2026", + "time": "14:00-17:00", + "raw": "16-11-2026 (14:00-17:00)" + } + }, + "C": { + "midSem": { + "date": "16-09-2026", + "time": "9:00-11:00", + "raw": "16-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "17-11-2026", + "time": "9:00-12:00", + "raw": "17-11-2026 (9:00-12:00)" + } + }, + "C1": { + "midSem": { + "date": "16-09-2026", + "time": "14:00-16:00", + "raw": "16-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "17-11-2026", + "time": "14:00-17:00", + "raw": "17-11-2026 (14:00-17:00)" + } + }, + "D": { + "midSem": { + "date": "18-09-2026", + "time": "9:00-11:00", + "raw": "18-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "19-11-2026", + "time": "9:00-12:00", + "raw": "19-11-2026 (9:00-12:00)" + } + }, + "D1": { + "midSem": { + "date": "18-09-2026", + "time": "14:00-16:00", + "raw": "18-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "19-11-2026", + "time": "14:00-17:00", + "raw": "19-11-2026 (14:00-17:00)" + } + }, + "E": { + "midSem": { + "date": "19-09-2026", + "time": "9:00-11:00", + "raw": "19-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "20-11-2026", + "time": "9:00-12:00", + "raw": "20-11-2026 (9:00-12:00)" + } + }, + "E1": { + "midSem": { + "date": "19-09-2026", + "time": "14:00-16:00", + "raw": "19-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "20-11-2026", + "time": "14:00-17:00", + "raw": "20-11-2026 (14:00-17:00)" + } + }, + "F": { + "midSem": { + "date": "20-09-2026", + "time": "9:00-11:00", + "raw": "20-09-2026 (9:00-11:00)" + }, + "endSem": { + "date": "21-11-2026", + "time": "9:00-12:00", + "raw": "21-11-2026 (9:00-12:00)" + } + }, + "F1": { + "midSem": { + "date": "20-09-2026", + "time": "14:00-16:00", + "raw": "20-09-2026 (14:00-16:00)" + }, + "endSem": { + "date": "21-11-2026", + "time": "14:00-17:00", + "raw": "21-11-2026 (14:00-17:00)" + } + } + } +}; + +export default examScheduleData; diff --git a/client/src/screens/dashboard/components/examschedule/index.jsx b/client/src/screens/dashboard/components/examschedule/index.jsx new file mode 100644 index 00000000..069f27a5 --- /dev/null +++ b/client/src/screens/dashboard/components/examschedule/index.jsx @@ -0,0 +1,152 @@ +import React, { useState, useEffect, useMemo } from "react"; +import { useSelector } from "react-redux"; +import Container from "../../../../components/container"; +import SubHeading from "../../../../components/subheading"; +import Space from "../../../../components/space"; +import { isUserExcluded, getExamScheduleForCourses } from "../../../../utils/examSchedule"; +import { getColors } from "../../../../utils/colors"; +import { capitalise } from "../../../../utils/capitalise"; +import formatLongText from "../../../../utils/formatLongText"; +import "./styles.scss"; + +/** + * Format a DD-MM-YYYY string into a clean readable format, e.g. "14 Sep 2026" + */ +function formatDisplayDate(dateStr) { + if (!dateStr) return ""; + const parts = dateStr.split("-").map(Number); + if (parts.length !== 3) return dateStr; + const [day, month, year] = parts; + const dateObj = new Date(year, month - 1, day); + if (isNaN(dateObj.getTime())) return dateStr; + return dateObj.toLocaleDateString("en-GB", { + day: "numeric", + month: "short", + year: "numeric", + }); +} + +const ExamScheduleWidget = () => { + const userState = useSelector((state) => state.user); + const currentUser = userState?.user; + + const [activeTab, setActiveTab] = useState("midSem"); // "midSem" | "endSem" + const [isLoading, setIsLoading] = useState(true); + const [hasError, setHasError] = useState(false); + + // Business Rule: Exclude B.Tech Semester 1 and Semester 2 users completely (return null) + const isExcluded = useMemo(() => isUserExcluded(currentUser), [currentUser]); + + useEffect(() => { + if (isExcluded) { + setIsLoading(false); + return; + } + + try { + setIsLoading(false); + setHasError(false); + } catch (err) { + setHasError(true); + setIsLoading(false); + } + }, [currentUser, isExcluded]); + + // Cross-reference user's registered courses with exam schedule + const scheduledExams = useMemo(() => { + if (!currentUser || isExcluded) return []; + const registeredCourses = Array.isArray(currentUser.courses) ? currentUser.courses : []; + return getExamScheduleForCourses(registeredCourses, undefined, activeTab); + }, [currentUser, isExcluded, activeTab]); + + // If user is B.Tech Sem 1 or 2, return null per specification (not an empty state) + if (isExcluded) { + return null; + } + + return ( + +
+
+ + +
+
setActiveTab("midSem")} + > + Mid-Sem +
+
setActiveTab("endSem")} + > + End-Sem +
+
+
+ + + + {/* State 1: Loading */} + {isLoading && ( +
+

Loading exam schedule...

+
+ )} + + {/* State 2: Error */} + {!isLoading && hasError && ( +
+

Failed to load exam schedule.

+
+ )} + + {/* State 3: Empty state (registered courses exist, but none scheduled yet) */} + {!isLoading && !hasError && scheduledExams.length === 0 && ( +
+

No {activeTab === "midSem" ? "Mid-Sem" : "End-Sem"} exams scheduled for your courses.

+
+
+ )} + + {/* State 4: Populated chronological schedule */} + {!isLoading && !hasError && scheduledExams.length > 0 && ( +
+ {scheduledExams.map((exam, index) => ( +
+
+ {exam.code} + Slot {exam.slot} +
+ +
+

+ {formatLongText(capitalise(exam.name || exam.code), 36)} +

+
+ +
+
+ DATE + {formatDisplayDate(exam.date)} +
+
+ TIME + {exam.time} +
+
+
+ ))} +
+ )} +
+
+ ); +}; + +export default ExamScheduleWidget; diff --git a/client/src/screens/dashboard/components/examschedule/styles.scss b/client/src/screens/dashboard/components/examschedule/styles.scss new file mode 100644 index 00000000..19465f39 --- /dev/null +++ b/client/src/screens/dashboard/components/examschedule/styles.scss @@ -0,0 +1,248 @@ +.exam-schedule-container { + width: 100%; + padding: 10px 0px; + + .schedule-header { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 15px; + + .schedule-toggle-group { + display: inline-flex; + background-color: #000; + padding: 3px; + gap: 2px; + + .toggle-tab { + padding: 6px 20px; + font-family: "Bold"; + font-size: 0.9rem; + color: #fff; + cursor: pointer; + text-align: center; + transition: 150ms ease; + user-select: none; + + &.active { + background-color: #FECF6F; + color: #000; + } + + &:not(.active):hover { + background-color: #222; + } + } + } + } + + .examcard-list { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + padding: 10px 0px; + gap: 0; + } + + .exam-item-card { + width: 210px; + height: 165px; + padding: 12px; + margin: 10px; + position: relative; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + transition: 150ms ease; + + &:hover { + transform: scale(1.04); + } + + .card-top { + display: flex; + justify-content: space-between; + align-items: center; + + .course-code { + background-color: #000; + color: #fff; + padding: 3px 6px; + font-family: "Bold"; + font-size: 0.8rem; + letter-spacing: 0.5px; + } + + .slot-pill { + background-color: rgba(0, 0, 0, 0.08); + color: #000; + border: 1px solid #000; + padding: 2px 6px; + font-family: "Bold"; + font-size: 0.75rem; + } + } + + .card-middle { + margin: 6px 0; + flex-grow: 1; + display: flex; + align-items: center; + + .course-name { + font-family: "Bold"; + font-size: 1.05rem; + color: #000; + line-height: 1.25; + } + } + + .card-bottom { + background-color: rgba(255, 255, 255, 0.65); + padding: 6px 8px; + display: flex; + flex-direction: column; + gap: 3px; + + .exam-detail-row { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.78rem; + + .label { + font-family: "Bold"; + color: #444; + font-size: 0.7rem; + letter-spacing: 0.5px; + } + + .value { + font-family: "Bold"; + color: #000; + } + } + } + } + + .schedule-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + padding: 20px 0; + + .empty-message { + width: 100%; + text-align: center; + font-weight: 530; + font-size: 1.3rem; + font-family: "Bold"; + color: #222; + margin-bottom: 16px; + } + + .no-exam-graphic { + width: 100%; + height: 280px; + background: url(../../graphic-cropped.svg); + background-position: center; + background-repeat: no-repeat; + background-size: contain; + margin-bottom: 24px; + opacity: 0.85; + } + } + + .schedule-state-box { + width: 100%; + text-align: center; + padding: 40px 0; + + .state-text { + font-family: "Bold"; + font-size: 1.1rem; + color: #555; + + &.error { + color: #d9534f; + } + } + } + + @media screen and (max-width: 768px) { + .examcard-list { + justify-content: center; + padding: 0 5px; + } + + .exam-item-card { + width: calc(50% - 10px); + min-width: 140px; + height: 155px; + margin: 5px; + padding: 10px; + + .card-middle .course-name { + font-size: 0.95rem; + } + + .card-bottom { + padding: 4px 6px; + .exam-detail-row { + font-size: 0.72rem; + } + } + } + + .schedule-empty-state .empty-message { + font-size: 1.1rem; + } + } + + @media screen and (max-width: 480px) { + .exam-item-card { + width: calc(50% - 8px); + min-width: 120px; + height: 145px; + margin: 4px; + padding: 8px; + + .card-top { + .course-code { + font-size: 0.68rem; + padding: 2px 4px; + } + .slot-pill { + font-size: 0.65rem; + padding: 1px 4px; + } + } + + .card-middle .course-name { + font-size: 0.85rem; + line-height: 1.15; + } + + .card-bottom .exam-detail-row { + font-size: 0.68rem; + .label { + font-size: 0.62rem; + } + } + } + } + + @media screen and (max-width: 360px) { + .exam-item-card { + width: calc(50% - 6px); + min-width: 100px; + height: 135px; + margin: 3px; + } + } +} diff --git a/client/src/screens/dashboard/index.jsx b/client/src/screens/dashboard/index.jsx index 10aff019..1716724a 100644 --- a/client/src/screens/dashboard/index.jsx +++ b/client/src/screens/dashboard/index.jsx @@ -9,6 +9,7 @@ import CourseCard from "./components/coursecard"; import ContributionBanner from "./components/contributionbanner"; import Footer from "../../components/footer"; import FavouriteCard from "./components/favouritecard"; +import ExamScheduleWidget from "./components/examschedule"; import { ChangeCurrentCourse, ResetFileBrowserState } from "../../actions/filebrowser_actions"; import { useDispatch, useSelector } from "react-redux"; @@ -239,30 +240,10 @@ const Dashboard = () => { )} - - - -
- {user?.favourites?.length > 0 ? ( - user.favourites.map((favourite) => ( - - )) - ) : ( - <> -
Coming Soon!
-
- - )} -
-
+ + +