Skip to content

Commit

Permalink
Merge pull request #32 from ItsukiKigoshi/31-release-000
Browse files Browse the repository at this point in the history
31 release 000
  • Loading branch information
ItsukiKigoshi authored Jan 31, 2024
2 parents 80db7f0 + b08b4df commit 8a354cc
Show file tree
Hide file tree
Showing 18 changed files with 624 additions and 297 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ next-env.d.ts
**/public/workbox-*.js
**/public/workbox-*.js.map

src/app/fetch/
.env
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const withPWA = require("next-pwa")({
dest: "public",
register: true,
skipWaiting: true,
disable: process.env.NODE_ENV === "development",
});

const nextConfig = withPWA({
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
"@mantine/dates": "^7.2.2",
"@mantine/dropzone": "^7.2.2",
"@mantine/ds": "^7.2.2",
"@mantine/form": "^7.2.2",
"@mantine/form": "^7.5.0",
"@mantine/hooks": "^7.2.2",
"@mantine/modals": "^7.2.2",
"@mantine/notifications": "^7.2.2",
"@mantine/nprogress": "^7.2.2",
"@mantine/spotlight": "^7.2.2",
"@mantine/spotlight": "^7.5.0",
"@mantine/tiptap": "^7.2.2",
"@tabler/icons-react": "^2.41.0",
"@tiptap/extension-link": "^2.1.12",
Expand Down
197 changes: 151 additions & 46 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"use client";
import { AppShell, Flex, Text } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { AppShell, Button, Flex, em } from "@mantine/core";
import { useDisclosure, useMediaQuery, useToggle } from "@mantine/hooks";
import { IconCalendar, IconList } from "@tabler/icons-react";
import { useEffect, useState } from "react";
import { Header } from "../components/Header";
import { Navbar } from "../components/Navbar";
import { Timetable } from "../components/Timetable";
Expand All @@ -9,26 +11,98 @@ import { Course } from "../type/Types";

export default function Page() {
const [opened, { toggle }] = useDisclosure(false);
const isMobile = useMediaQuery(`(max-width: ${em(750)})`);

const [weekdays, toggleSaturday] = useToggle([
["M", "TU", "W", "TH", "F"],
["M", "TU", "W", "TH", "F", "SA"],
]);

const terms = [
{ label: "2024S", ay: "2024", season: "Spring", value: "2024S" },
{ label: "2024A", ay: "2024", season: "Autumn", value: "2024A" },
{ label: "2024W", ay: "2024", season: "Winter", value: "2024W" },
];
const [selectedTermValue, setselectedTermValue] = useState(terms[0].value);

const selectedTerm = terms.find((term) => term.value === selectedTermValue);

const [displayMode, toggleDisplayMode] = useToggle(["list", "timetable"]);
useEffect(() => {
if (!isMobile) {
toggleDisplayMode("timetable");
}
}, [isMobile]);

// Get the list of courses from the local storage
const [courses, setCourses] = useLocalStorage<Course[]>("courses", [
{
regno: 99999,
regno: 99997,
season: "Spring",
ay: 2022,
ay: 2024,
no: "CS101",
lang: "E",
e: "Example Course",
e: "Example Spring Course",
j: "科目例",
schedule: ["3/M", "3/W", "3/F"],
instructor: "John Doe",
modified: new Date(2022, 5 - 1, 5, 6, 35, 20, 333),
unit: 3,
isEnrolled: true,
color: "#ff0000",
color: "orange 2",
},
{
regno: 99998,
season: "Autumn",
ay: 2024,
no: "CS101",
lang: "E",
e: "Example Autumn Course",
j: "科目例",
schedule: ["3/M", "3/W", "3/F"],
instructor: "John Doe",
modified: new Date(2022, 5 - 1, 5, 6, 35, 20, 333),
unit: 3,
isEnrolled: true,
color: "pink 2",
},
{
regno: 99999,
season: "Winter",
ay: 2024,
no: "CS101",
lang: "E",
e: "Example Winter Course",
j: "科目例",
schedule: ["3/M", "3/W", "3/F"],
instructor: "John Doe",
modified: new Date(2022, 5 - 1, 5, 6, 35, 20, 333),
unit: 3,
isEnrolled: true,
color: "green 2",
},
]);

const timetable: { [key: string]: Course[] } = {};
const coursesInSelectedTerm = courses.filter(
(course) =>
course.season === selectedTerm?.season &&
course.ay.toString() === selectedTerm?.ay
);

const enrolledCourses = coursesInSelectedTerm.filter(
(course) => course.isEnrolled
);
coursesInSelectedTerm.forEach((course) => {
course.schedule?.forEach((entry) => {
const [time, day] = entry.split("/");
if (!timetable[`${time}/${day}`]) {
timetable[`${time}/${day}`] = [];
}
timetable[`${time}/${day}`].push(course);
});
});

// Toggle the isEnrolled property of a certain course
// Usage: toggleIsEnrolled(regno)
const toggleIsEnrolled = (regno: number) => {
Expand Down Expand Up @@ -56,51 +130,82 @@ export default function Page() {
};

return (
<>
<AppShell
header={{ height: 60 }}
navbar={{
width: "400px",
breakpoint: "sm",
collapsed: { mobile: !opened },
}}
padding="md"
h="100vh"
>
<AppShell.Header>
<Header opened={opened} toggle={toggle} />
</AppShell.Header>
<AppShell.Navbar>
<AppShell
header={{ height: 60 }}
navbar={{
width: "400px",
breakpoint: "sm",
collapsed: { mobile: !opened },
}}
padding="0"
h="100vh"
w="100vw"
>
<AppShell.Header>
<Header
weekdays={weekdays}
toggleSaturday={() => {
toggleSaturday();
}}
terms={terms}
selectedTermValue={selectedTermValue}
setselectedTermValue={setselectedTermValue}
/>
</AppShell.Header>

<AppShell.Navbar>
<Navbar
courses={coursesInSelectedTerm}
toggleIsEnrolled={toggleIsEnrolled}
addCourse={addCourse}
deleteCourse={deleteCourse}
/>
</AppShell.Navbar>
<AppShell.Main h="100vh">
{displayMode === "timetable" ? (
<Timetable
timetable={timetable}
enrolledCourses={enrolledCourses}
toggleIsEnrolled={toggleIsEnrolled}
weekdays={weekdays}
/>
) : (
<Navbar
courses={courses}
courses={coursesInSelectedTerm}
toggleIsEnrolled={toggleIsEnrolled}
addCourse={addCourse}
deleteCourse={deleteCourse}
/>
</AppShell.Navbar>
<AppShell.Main>
{/* <Grid justify="flex-start" gutter="sm" align="stretch"> */}
{/* <Grid.Col span={{ base: "auto" }}> */}
<Timetable courses={courses} />
{/* </Grid.Col> */}
{/* <Grid.Col mt={{ base: 5, md: 0 }} span={{ base: 12, md: "content" }}>
<RequirementTable />
</Grid.Col> */}
{/* </Grid> */}
<Flex
gap="md"
justify="center"
align="center"
direction="row"
wrap="wrap"
)}
</AppShell.Main>
<AppShell.Footer
withBorder={false}
hiddenFrom="sm"
style={{ background: "rgba(0,0,0,0)" }}
>
<Flex gap="md" mih={50} justify="center" align="center" direction="row">
{/* <Button
variant="filled"
size="lg"
leftSection={<IconSearch />}
onClick={spotlight.open}
>
Search
</Button> */}
<Button
hiddenFrom="sm"
size="lg"
color="gray"
mr={3}
onClick={() => {
toggleDisplayMode();
}}
>
<Text fw="bold">
🚧 This App is still under development. Do not store any important
data here!
</Text>
</Flex>
</AppShell.Main>
</AppShell>
</>
{displayMode === "list" ? <IconList /> : <IconCalendar />}
</Button>
</Flex>
</AppShell.Footer>
{/* <SpotlightSearch /> */}
</AppShell>
);
}
19 changes: 0 additions & 19 deletions src/components/CourseCard/CourseCard.module.css

This file was deleted.

73 changes: 38 additions & 35 deletions src/components/CourseCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,72 @@ import { Course } from "@/src/type/Types";
import {
ActionIcon,
Card,
Checkbox,
Flex,
Divider,
Grid,
Stack,
Text,
UnstyledButton,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { IconTrash } from "@tabler/icons-react";
import classes from "./CourseCard.module.css";
import { IconEye, IconEyeOff, IconTrash } from "@tabler/icons-react";

export default function CourseCard(props: {
course: Course;
open: () => void;
toggleIsEnrolled: (regno: number) => void;
deleteCourse: (regno: number) => void;
}) {
const [modalOpened, { open, close }] = useDisclosure(false);
const [modalConfirmOpened, { open, close }] = useDisclosure(false);

return (
<Card key={props.course.regno} mb={8} className={classes.button}>
<Grid align="center">
<Card p={0} m="sm" withBorder>
<Grid>
<Grid.Col span="auto">
<UnstyledButton
onClick={() => {
props.toggleIsEnrolled(props.course.regno);
props.open();
}}
key={props.course.regno}
w="100%"
p="md"
>
<Flex align="center">
<Checkbox
checked={props.course.isEnrolled}
onChange={() => {
props.toggleIsEnrolled(props.course.regno);
}}
variant="default"
mr="xl"
/>
<div>
<Text size="xs" c="dimmed">
{props.course.no}{props.course.unit}
</Text>
<Text size="sm" lh={1} py={4}>
{props.course.e} ({props.course.lang})
</Text>
<Text size="xs" c="dimmed">
{props.course.schedule?.map((s, i) =>
i === props.course.schedule!.length - 1 ? s : s + ", "
)}
</Text>
</div>
</Flex>
<Stack h="100%" gap="sm">
<Text size="xs" c="dimmed">
{props.course.no}{props.course.unit}
</Text>
<Text size="sm" lh={1}>
{props.course.e} ({props.course.lang})
</Text>
<Text size="xs" c="dimmed">
{props.course.schedule?.map((s, i) =>
i === props.course.schedule!.length - 1 ? s : s + ", "
)}
</Text>
</Stack>
</UnstyledButton>
</Grid.Col>
<Divider orientation="vertical" my="md" mx={0} />
<Grid.Col span="content">
<Flex align="center">
<ActionIcon size="sm" onClick={open} color="red">
<Stack align="center" h="100%" p="md">
<ActionIcon
onClick={() => {
props.toggleIsEnrolled(props.course.regno);
}}
color="gray"
>
{props.course.isEnrolled ? <IconEye /> : <IconEyeOff />}
</ActionIcon>

<ActionIcon onClick={open} color="red">
<IconTrash />
</ActionIcon>
</Flex>
</Stack>
</Grid.Col>
</Grid>
<ModalConfirm
course={props.course}
deleteCourse={props.deleteCourse}
modalOpened={modalOpened}
modalConfirmOpened={modalConfirmOpened}
close={close}
/>
</Card>
Expand Down
Loading

0 comments on commit 8a354cc

Please sign in to comment.