From 6aad701a01afdf0941dd3c1f4421d7f6b36f3238 Mon Sep 17 00:00:00 2001 From: Mahika Date: Sat, 5 Oct 2024 20:18:42 -0400 Subject: [PATCH 1/2] Added pin/save schedule feature --- app/package-lock.json | 81 +++++++++-------- app/src/components/ScheduleDisplay.tsx | 118 +++++++++++-------------- 2 files changed, 99 insertions(+), 100 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index c882d1d..feccfaf 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1214,12 +1214,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1792,10 +1793,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2132,6 +2134,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2285,12 +2288,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2347,15 +2351,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2531,10 +2536,11 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -2567,9 +2573,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -2585,10 +2591,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -2917,10 +2924,11 @@ } }, "node_modules/rollup": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.0.tgz", - "integrity": "sha512-aOltLCrYZ0FhJDm7fCqwTjIUEVjWjcydKBV/Zeid6Mn8BWgDCUBBWT5beM5ieForYNo/1ZHuGJdka26kvQ3Gzg==", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -3022,10 +3030,11 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -3194,6 +3203,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3326,14 +3336,15 @@ "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==" }, "node_modules/vite": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.8.tgz", - "integrity": "sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", + "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", - "postcss": "^8.4.26", - "rollup": "^3.25.2" + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" diff --git a/app/src/components/ScheduleDisplay.tsx b/app/src/components/ScheduleDisplay.tsx index 3e317a6..f99640e 100644 --- a/app/src/components/ScheduleDisplay.tsx +++ b/app/src/components/ScheduleDisplay.tsx @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component, useState, useEffect } from "react"; import classNames from "classnames"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -25,14 +25,62 @@ type MeetTimeInfo = { sectionIsOnline: boolean; }; -export default class ScheduleDisplay extends Component { - // TODO: redo this (it is *disgusting*); maybe there is a library that does the work +// Pin/Save Feature Code (new) +const ScheduleDisplayWithPin = ({ schedule }) => { + const [pinnedSchedules, setPinnedSchedules] = useState([]); + + // Load pinned schedules from localStorage when component mounts + useEffect(() => { + const savedSchedules = JSON.parse(localStorage.getItem('pinnedSchedules')); + if (savedSchedules) { + setPinnedSchedules(savedSchedules); + } + }, []); + + const pinSchedule = (schedule) => { + const updatedPinned = [...pinnedSchedules, schedule]; + setPinnedSchedules(updatedPinned); + localStorage.setItem('pinnedSchedules', JSON.stringify(updatedPinned)); + }; + const removePinnedSchedule = (index) => { + const updatedPinned = pinnedSchedules.filter((_, i) => i !== index); + setPinnedSchedules(updatedPinned); + localStorage.setItem('pinnedSchedules', JSON.stringify(updatedPinned)); + }; + + return ( +
+ {/* Render the original schedule display */} + + + {/* Pin button */} + + + {/* Display pinned schedules */} +
+

Pinned Schedules

+ {pinnedSchedules.length === 0 ? ( +

No pinned schedules yet.

+ ) : ( + pinnedSchedules.map((schedule, index) => ( +
+

Pinned Schedule {index + 1}

+ +
+ )) + )} +
+
+ ); +}; + +// Original Schedule Display (unchanged, but now wrapped by ScheduleDisplayWithPin) +export default class ScheduleDisplay extends Component { render() { const schedule = this.props.schedule, periodCounts = PERIOD_COUNTS[schedule.term]; - // TODO: this is suspiciously similar to Meetings class const blockSchedule: Record = { [API_Day.Mon]: new Array(periodCounts.all).fill(null), [API_Day.Tue]: new Array(periodCounts.all).fill(null), @@ -64,14 +112,11 @@ export default class ScheduleDisplay extends Component { const divs = []; for (let p = 0; p < periodCounts.all; ++p) { for (const day of API_Days) { - // TODO: make this a checkbox or automatically change format to 6 days if schedule has a Saturday course if (day == API_Day.Sat) continue; - //TODO: make this not absolutely horrible :) const meetTimeInfo: MeetTimeInfo | null = blockSchedule[day][p]; if (meetTimeInfo == null) { - // No course divs.push(
{ blockSchedule[day][p - 1] == null || blockSchedule[day][p - 1]!.meetTime != mT) ) { - // TODO: why do I have to do this garbage?? const spanMap: Map = new Map< number, string @@ -114,7 +158,7 @@ export default class ScheduleDisplay extends Component { ]); const span: string = spanMap.get( Math.min(1 + (mT.periodEnd - mT.periodBegin), 6), - )!; // TODO: error handling for NaN + )!; divs.push(
{ {onlineSections.length > 0 && (
-
- ️ -
-
- )} -
-
- -
-
- {divs} - {onlineSections.length > 0 && ( -
-
-
- {onlineSections.map( - (sec: Section, ind: number) => ( -
- {sec.displayName} - - {1 + ind} - -
- ), - )} -
-
-
- )} -
-
- - - ); - } -} From 08f73d23f844b37b52675cf5381fdfb6ce35a217 Mon Sep 17 00:00:00 2001 From: Mahika Date: Sat, 5 Oct 2024 20:23:53 -0400 Subject: [PATCH 2/2] Added pin/save schedule feature --- app/src/components/ScheduleDisplay.tsx | 77 +++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/app/src/components/ScheduleDisplay.tsx b/app/src/components/ScheduleDisplay.tsx index f99640e..a902151 100644 --- a/app/src/components/ScheduleDisplay.tsx +++ b/app/src/components/ScheduleDisplay.tsx @@ -25,8 +25,8 @@ type MeetTimeInfo = { sectionIsOnline: boolean; }; -// Pin/Save Feature Code (new) -const ScheduleDisplayWithPin = ({ schedule }) => { +// Pin/Save Feature (new) +const PinScheduleFeature = ({ schedule }) => { const [pinnedSchedules, setPinnedSchedules] = useState([]); // Load pinned schedules from localStorage when component mounts @@ -51,10 +51,6 @@ const ScheduleDisplayWithPin = ({ schedule }) => { return (
- {/* Render the original schedule display */} - - - {/* Pin button */} {/* Display pinned schedules */} @@ -75,12 +71,14 @@ const ScheduleDisplayWithPin = ({ schedule }) => { ); }; -// Original Schedule Display (unchanged, but now wrapped by ScheduleDisplayWithPin) export default class ScheduleDisplay extends Component { + // TODO: redo this (it is *disgusting*); maybe there is a library that does the work + render() { const schedule = this.props.schedule, periodCounts = PERIOD_COUNTS[schedule.term]; + // TODO: this is suspiciously similar to Meetings class const blockSchedule: Record = { [API_Day.Mon]: new Array(periodCounts.all).fill(null), [API_Day.Tue]: new Array(periodCounts.all).fill(null), @@ -112,11 +110,14 @@ export default class ScheduleDisplay extends Component { const divs = []; for (let p = 0; p < periodCounts.all; ++p) { for (const day of API_Days) { + // TODO: make this a checkbox or automatically change format to 6 days if schedule has a Saturday course if (day == API_Day.Sat) continue; + //TODO: make this not absolutely horrible :) const meetTimeInfo: MeetTimeInfo | null = blockSchedule[day][p]; if (meetTimeInfo == null) { + // No course divs.push(
{ blockSchedule[day][p - 1] == null || blockSchedule[day][p - 1]!.meetTime != mT) ) { + // TODO: why do I have to do this garbage?? const spanMap: Map = new Map< number, string @@ -158,7 +160,7 @@ export default class ScheduleDisplay extends Component { ]); const span: string = spanMap.get( Math.min(1 + (mT.periodEnd - mT.periodBegin), 6), - )!; + )!; // TODO: error handling for NaN divs.push(
{ > Export Schedule + {/* Added pin/save feature below */} + +
{schedule.map((sec: Section, s: number) => ( @@ -280,3 +285,59 @@ export default class ScheduleDisplay extends Component { {onlineSections.length > 0 && (
+
+ ️ +
+
+ )} +
+
+ +
+
+ {divs} + {onlineSections.length > 0 && ( +
+
+
+ {onlineSections.map( + (sec: Section, ind: number) => ( +
+ {sec.displayName} + + {1 + ind} + +
+ ), + )} +
+
+
+ )} +
+
+
+
+ ); + } +}