diff --git a/public/help/ready-button.webp b/public/help/ready-button.webp new file mode 100644 index 0000000..c9a40c8 Binary files /dev/null and b/public/help/ready-button.webp differ diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 212df35..a5d8d4b 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,4 +1,4 @@ -import { Button, Tooltip } from '@nextui-org/react'; +import { Button, Tooltip, useDisclosure } from '@nextui-org/react'; import clsx from 'clsx'; import { useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -6,7 +6,11 @@ import { create } from 'zustand'; import { WEEK_DAYS } from '../constants/week-days'; import { YEAR } from '../constants/year'; -import { useCourseColor, useEnrolledCourse } from '../data/enrolled-courses'; +import { + useCourseColor, + useEnrolledCourse, + useEnrolledCourses, +} from '../data/enrolled-courses'; import { useCalendar, useOtherWeekCourseTimes } from '../helpers/calendar'; import { useCalendarHourHeight } from '../helpers/calendar-hour-height'; import { calcHoursDuration } from '../helpers/hours-duration'; @@ -15,6 +19,7 @@ import type dayjs from '../lib/dayjs'; import type { DateTimeRange, WeekCourse, WeekCourses } from '../types/course'; import { timeToDayjs } from '../utils/date'; import { useDrag, useDrop } from '../utils/dnd'; +import { EnrolmentModal } from './EnrolmentModal'; type DraggingCourseState = { isDragging: boolean; @@ -175,6 +180,38 @@ const CalendarHeader = ({ ); }; +const EndActions = () => { + const { t } = useTranslation(); + + const blockHeight = useCalendarHourHeight((s) => s.height); + + const { + isOpen: isReadyModalOpen, + onOpen: onReadyModalOpen, + onOpenChange: onReadyModalOpenChange, + } = useDisclosure(); + return ( +
+ {/* TODO: Share Button */} + + +
+ ); +}; + const CalendarBg = ({ currentWeek }: { currentWeek: dayjs.Dayjs }) => { const { t } = useTranslation(); @@ -373,6 +410,8 @@ export const Calendar = () => { }, }); + const noCourses = useEnrolledCourses((s) => s.courses.length === 0); + return (
{ {isDragging && } + {!noCourses && }
); diff --git a/src/components/EnrolmentModal.tsx b/src/components/EnrolmentModal.tsx new file mode 100644 index 0000000..9d385c8 --- /dev/null +++ b/src/components/EnrolmentModal.tsx @@ -0,0 +1,93 @@ +import { + Button, + Card, + CardBody, + CardHeader, + Divider, + Link, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + Tooltip, +} from '@nextui-org/react'; +import clsx from 'clsx'; +import { useTranslation } from 'react-i18next'; + +import { useDetailedEnrolledCourses } from '../data/enrolled-courses'; +import { useExportCalendar } from '../helpers/export-calendar'; + +type ReadyModalProps = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; +export const EnrolmentModal = ({ isOpen, onOpenChange }: ReadyModalProps) => { + const { t } = useTranslation(); + const { copyText } = useExportCalendar(); + + const enrolledCourses = useDetailedEnrolledCourses(); + const isOnlyCourse = enrolledCourses.length === 1; + + return ( + + + +
{t('calendar.end-actions.ready')}
+
+ Copy the numbers below and enter them on the enrollment page of + Access Adelaide. +
+
+ + {enrolledCourses.map((c) => ( + + +

+ {c.name.subject} {c.name.code} +

+

{c.name.title}

+
+ + + {c.classes.map((cls) => ( +
+
{cls.type}
+
{cls.classNumber}
+
+ ))} +
+
+ ))} +
+ + + + + + +
+
+ ); +}; diff --git a/src/components/HelpModal.tsx b/src/components/HelpModal.tsx index 1b67bb7..cdc909a 100644 --- a/src/components/HelpModal.tsx +++ b/src/components/HelpModal.tsx @@ -66,6 +66,13 @@ export const HelpModal = () => { alt: 'Course modal to change class time', }, }, + { + content: t('help.steps.ready-button'), + image: { + path: '/help/ready-button.webp', + alt: 'Ready button at bottom', + }, + }, { content: t('help.steps.access-adelaide'), image: { diff --git a/src/components/Tips.tsx b/src/components/Tips.tsx index a30bea6..154230d 100644 --- a/src/components/Tips.tsx +++ b/src/components/Tips.tsx @@ -44,6 +44,7 @@ const TIPS = [ CS Club Open Source Team to work on projects like this! , + <>You can search for courses using abbreviations, ]; const tips = shuffle(TIPS); diff --git a/src/helpers/export-calendar.ts b/src/helpers/export-calendar.ts new file mode 100644 index 0000000..b3d432d --- /dev/null +++ b/src/helpers/export-calendar.ts @@ -0,0 +1,24 @@ +import { useTranslation } from 'react-i18next'; +import { toast } from 'sonner'; + +import { useDetailedEnrolledCourses } from '../data/enrolled-courses'; + +export const useExportCalendar = () => { + const { t } = useTranslation(); + + const enrolledCourses = useDetailedEnrolledCourses(); + const copyText = async () => { + const res = enrolledCourses.map((c) => ({ + name: c.name.title + '\n' + c.name.subject + ' ' + c.name.code, + classes: c.classes + .map(({ type, classNumber }) => type + ': ' + classNumber) + .join('\n'), + })); + const resStr = res.map((d) => d.name + '\n\n' + d.classes).join('\n\n'); + const advertisement = + 'Planned with MyTimetable\nhttps://mytimetable.csclub.org.au/'; + await navigator.clipboard.writeText(resStr + '\n\n\n' + advertisement); + toast.success(t('calendar.end-actions.copy-success')); + }; + return { copyText }; +}; diff --git a/src/locales/en-au.json b/src/locales/en-au.json index 00f6d64..59758d0 100644 --- a/src/locales/en-au.json +++ b/src/locales/en-au.json @@ -39,7 +39,12 @@ "November", "December" ], - "immoveable-course": "Immoveable course" + "immoveable-course": "Immoveable course", + "end-actions": { + "copy": "Copy to clipboard", + "ready": "Ready for Enrolment", + "copy-success": "Copied to clipboard!" + } }, "help": { "title": "How to use MyTimetable", @@ -51,7 +56,8 @@ "change-week": "Change the calendar week to see more classes.", "course-details": "Click your enrolled course to see details of your enrolled classes.", "course-modal": "If you encounter any class clashes when using MyTimetable, you can open the modal to change the class.", - "access-adelaide": "You can enrol for courses in Access Adelaide by using the class numbers, once you are happy with your class times." + "ready-button": "Once you are satisfied with your class times, click the \"Ready for Enrollment\" button at the bottom of the calendar.", + "access-adelaide": "You can easily enroll in courses on Access Adelaide using the class numbers shown in the modal." }, "actions": { "next-step": "Next Step", diff --git a/src/locales/zh-cn.json b/src/locales/zh-cn.json index d9e410d..ff5288d 100644 --- a/src/locales/zh-cn.json +++ b/src/locales/zh-cn.json @@ -39,7 +39,12 @@ "十一月", "十二月" ], - "immoveable-course": "此课程无法移动" + "immoveable-course": "此课程无法移动", + "end-actions": { + "copy": "复制到剪切板", + "ready": "准备选课", + "copy-success": "已成功复制到剪切板!" + } }, "help": { "title": "如何使用 MyTimetable", @@ -51,7 +56,8 @@ "change-week": "切换周数查看更多课程", "course-details": "点击你的选课查看详情", "course-modal": "如果在使用 MyTimetable 时遇到任何课程冲突,可以随时打开详情弹窗来更改课程", - "access-adelaide": "课程调整完毕后,可以使用详情中的 Class Number 在 Access Adelaide 中进行选课" + "ready-button": "课程调整完毕后,点击日历底部的“准备选课”按钮", + "access-adelaide": "你可以用弹窗中的 Class Number 在 Access Adelaide 中进行选课" }, "actions": { "next-step": "下一步",