From 9e8c6315979c399d39db24f4351078e479242e73 Mon Sep 17 00:00:00 2001 From: Waver Velvet Date: Tue, 4 Jun 2024 23:52:26 +0800 Subject: [PATCH] refactor: remove calendar stuff temporarily due to compatibility --- app/api/calendar/route.tsx | 47 ---- app/api/cron/deploy/route.tsx | 29 --- app/faq/page.tsx | 17 -- app/layout.tsx | 1 - app/schedule/page.tsx | 169 -------------- app/schedule/sis-parser-dialog.tsx | 81 ------- components/component/calendar/course-card.tsx | 221 ------------------ data/schedule/calendar-event.ts | 56 ----- data/schedule/index.ts | 59 ----- data/schedule/path-advisor.ts | 64 ----- data/schedule/sis-parser.ts | 11 - scripts/update-data.mjs | 15 -- 12 files changed, 770 deletions(-) delete mode 100644 app/api/calendar/route.tsx delete mode 100644 app/api/cron/deploy/route.tsx delete mode 100644 app/schedule/page.tsx delete mode 100644 app/schedule/sis-parser-dialog.tsx delete mode 100644 components/component/calendar/course-card.tsx delete mode 100644 data/schedule/calendar-event.ts delete mode 100644 data/schedule/index.ts delete mode 100644 data/schedule/path-advisor.ts delete mode 100644 data/schedule/sis-parser.ts diff --git a/app/api/calendar/route.tsx b/app/api/calendar/route.tsx deleted file mode 100644 index 40932f5..0000000 --- a/app/api/calendar/route.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import {type NextRequest} from 'next/server'; -import {sectionMap} from '@/data/schedule'; -import * as ics from 'ics'; -import {PathAdvisor} from '@/data/schedule/path-advisor'; -import {generateEventAttributes} from '@/data/schedule/calendar-event'; - -export const dynamic = 'force-dynamic'; - -/** - * GET: /api/calendar - * Gets the iCalendar file for the given class (section) numbers. - * Example: webcal://ust-rankings.vercel.app/api/calendar?number=1023&number=1024 - */ -export async function GET(request: NextRequest) { - const numbers = request.nextUrl.searchParams - .getAll('number') - .map(it => Number.parseInt(it, 10)) - .filter(it => !Number.isNaN(it)); - - const webcal = Boolean(request.nextUrl.searchParams.get('webcal')); - - const sections = numbers.flatMap(it => sectionMap[it]); - const event = ics.createEvents(sections.map(it => ({ - ...generateEventAttributes(it), - description: `Path Advisor: ${PathAdvisor.findPathTo(it.room)!}`, - }))); - - if (event.error) { - console.error(event.error); - return new Response(event.error.message, {status: 500}); - } - - if (webcal) { - return new Response(event.value, { - headers: { - 'Content-Type': 'text/calendar; charset=utf-8', - }, - }); - } - - return new Response(event.value, { - headers: { - 'Content-Type': 'text/calendar; charset=utf-8', - 'Content-Disposition': 'attachment; filename="calendar.ics"', - }, - }); -} diff --git a/app/api/cron/deploy/route.tsx b/app/api/cron/deploy/route.tsx deleted file mode 100644 index 9d80f01..0000000 --- a/app/api/cron/deploy/route.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import {type NextRequest, NextResponse} from 'next/server'; - -export async function GET(request: NextRequest) { - if (request.headers.get('Authorization') !== `Bearer ${process.env.CRON_SECRET}`) { - return NextResponse.json({error: 'Unauthorized'}, {status: 401}); - } - - await redeploy(); - return NextResponse.json({}); -} - -async function redeploy() { - const API = `https://api.vercel.com/v13/deployments?${new URLSearchParams({forceNew: '1'}).toString()}`; - const resp = await fetch(API, { - method: 'POST', - headers: { - Authorization: `Bearer ${process.env.VERCEL_TOKEN}`, - }, - body: JSON.stringify({ - deploymentId: process.env.VERCEL_DEPLOYMENT_ID, - name: `Cron Deployment ${new Date().toISOString()}`, - target: 'production', - }), - }); - - if (!resp.ok) { - throw new Error(`Failed to redeploy: ${resp.status} ${resp.statusText} ${await resp.text()}`); - } -} diff --git a/app/faq/page.tsx b/app/faq/page.tsx index 90a2974..b83cdfa 100644 --- a/app/faq/page.tsx +++ b/app/faq/page.tsx @@ -98,23 +98,6 @@ export default function Faq() {

-

- FAQ - Schedule -

- -
-

Why not using the Timetable Planner?

-

- While it is true that Timetable Planner is able to export the schedule to the calendar, it is not flexible as - UST Schedule. Users are not allowed to add duplicate courses (except for using the "import to current - timetable" feature, but still, it is not flexible). Users are not allowed to add individual lectures, - tutorials or labs without adding the full course. -

-

- Additionally, UST Schedule is able to show the location of the venue via Path Advisor. -

-
-

Others

diff --git a/app/layout.tsx b/app/layout.tsx index 6a52d40..177ce94 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -33,7 +33,6 @@ export default function RootLayout({children}: Readonly<{children: React.ReactNo className='flex h-16 items-center px-8 gap-8 text-white bg-gradient-to-r from-[#003366] via-[#2b6297] to-[#003366] dark:from-[#003366] dark:via-[#224e77] dark:to-[#003366] text-lg font-medium'>
- Schedule FAQ diff --git a/app/schedule/page.tsx b/app/schedule/page.tsx deleted file mode 100644 index bdcf9c2..0000000 --- a/app/schedule/page.tsx +++ /dev/null @@ -1,169 +0,0 @@ -'use client'; - -import {Input} from '@/components/ui/input'; -import React, {type ChangeEvent} from 'react'; -import {WindowVirtualizer} from 'virtua'; -import {CourseCard} from '@/components/component/calendar/course-card'; -import {courses, searchCourses} from '@/data/schedule'; -import {Button} from '@/components/ui/button'; -import {CalendarPlus, Download, HelpCircle} from 'lucide-react'; -import {Collapsible, CollapsibleContent} from '@/components/ui/collapsible'; -import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs'; -import {NewDomainBanner} from '@/components/component/new-domain-banner'; -import {SisParserDialog} from '@/app/schedule/sis-parser-dialog'; -import {toast} from 'sonner'; - -export default function Home() { - const [shoppingCart, setShoppingCart] = React.useState>(new Set()); - - const isSectionInShoppingCart = (section: number) => shoppingCart.has(section); - - const addSectionToShoppingCart = (section: number) => { - shoppingCart.add(section); - setShoppingCart(new Set(shoppingCart)); - }; - - const removeSectionFromShoppingCart = (section: number) => { - shoppingCart.delete(section); - setShoppingCart(new Set(shoppingCart)); - }; - - const submitSisParserDialog = (classNumbers: number[]) => { - classNumbers.forEach(addSectionToShoppingCart); - }; - - const [showHelp, setShowHelp] = React.useState(false); - - const [query, setQuery] = React.useState(''); - const queryResult = query === '' ? courses : searchCourses(query); - - return ( - <> - - -

- UST Schedule -

- -
-
- ) => { - setQuery(e.target.value); - }} - - className='rounded-full focus-visible:ring-gray-700 text-md h-12' - placeholder='Search by...' type='search' - /> - - - -
- - - -
-

- Search for courses by their name, code, instructors, room or section number. -

-

- Features: -

-
    -
  • - Click (or tap) on sections to add them to (or remove them from) the shopping cart. -
  • -
  • - Click (or tap) on the calendar icon to import the schedules in the shopping cart into the - calendar. -
  • -
  • - Click (or tap) on the download icon to download the schedules in the shopping cart to the device. You - can import the downloaded file into the calendar app manually. -
  • -
  • - Click (or tap) on rooms to find their location by Path Advisor. -
  • -
-

- More features are coming soon...! -

-
-
-
-
- -
- - - All - Shopping Cart - - - - {queryResult - .filter(it => it.sections.length) - .map(course => ( -
- -
- ))} -
-
- - -
- - {queryResult - .filter(it => it.sections.length) - .filter(it => it.sections.some(section => shoppingCart.has(section.number))) - .map(it => ({...it, sections: it.sections.filter(section => shoppingCart.has(section.number))})) - .map(course => ( -
- -
- ))} -
-
-
-
- - ); -} diff --git a/app/schedule/sis-parser-dialog.tsx b/app/schedule/sis-parser-dialog.tsx deleted file mode 100644 index 0aa4615..0000000 --- a/app/schedule/sis-parser-dialog.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React, {type HTMLAttributes} from 'react'; -import {SisParser, SisUrl} from '@/data/schedule/sis-parser'; -import {findClass} from '@/data/schedule'; -import { - Dialog, DialogClose, - DialogContent, - DialogDescription, DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@/components/ui/dialog'; -import {Button} from '@/components/ui/button'; -import {Import} from 'lucide-react'; -import {Textarea} from '@/components/ui/textarea'; -import {Label} from '@/components/ui/label'; - -type SisParserDialogProps = { - callback: (classNumbers: number[]) => void; -} & HTMLAttributes; - -export function SisParserDialog({callback, ...props}: SisParserDialogProps) { - const [text, setText] = React.useState(''); - const classNumbers = SisParser.parse(text); - const classes = classNumbers.map(it => findClass(it)); - - function openSis() { - window.open(SisUrl, 'sis', 'popup=true'); - } - - function handleSubmit() { - callback(classNumbers); - } - - return - - - - - - Import from SIS - -
    -
  1. Go to SIS.
  2. -
  3. Press Ctrl/⌘ + A to select all text on the page.
  4. -
  5. Press Ctrl/⌘ + C to copy the text.
  6. -
  7. Press Ctrl/⌘ + V to paste the text here.
  8. -
-
-
-