1
1
"use client" ;
2
- import { AppShell , Flex , Text } from "@mantine/core" ;
3
- import { useDisclosure } from "@mantine/hooks" ;
2
+ import { AppShell , Button , Flex , em } from "@mantine/core" ;
3
+ import { useDisclosure , useMediaQuery , useToggle } from "@mantine/hooks" ;
4
+ import { IconCalendar , IconList } from "@tabler/icons-react" ;
5
+ import { useEffect , useState } from "react" ;
4
6
import { Header } from "../components/Header" ;
5
7
import { Navbar } from "../components/Navbar" ;
6
8
import { Timetable } from "../components/Timetable" ;
@@ -9,26 +11,98 @@ import { Course } from "../type/Types";
9
11
10
12
export default function Page ( ) {
11
13
const [ opened , { toggle } ] = useDisclosure ( false ) ;
14
+ const isMobile = useMediaQuery ( `(max-width: ${ em ( 750 ) } )` ) ;
15
+
16
+ const [ weekdays , toggleSaturday ] = useToggle ( [
17
+ [ "M" , "TU" , "W" , "TH" , "F" ] ,
18
+ [ "M" , "TU" , "W" , "TH" , "F" , "SA" ] ,
19
+ ] ) ;
20
+
21
+ const terms = [
22
+ { label : "2024S" , ay : "2024" , season : "Spring" , value : "2024S" } ,
23
+ { label : "2024A" , ay : "2024" , season : "Autumn" , value : "2024A" } ,
24
+ { label : "2024W" , ay : "2024" , season : "Winter" , value : "2024W" } ,
25
+ ] ;
26
+ const [ selectedTermValue , setselectedTermValue ] = useState ( terms [ 0 ] . value ) ;
27
+
28
+ const selectedTerm = terms . find ( ( term ) => term . value === selectedTermValue ) ;
29
+
30
+ const [ displayMode , toggleDisplayMode ] = useToggle ( [ "list" , "timetable" ] ) ;
31
+ useEffect ( ( ) => {
32
+ if ( ! isMobile ) {
33
+ toggleDisplayMode ( "timetable" ) ;
34
+ }
35
+ } , [ isMobile ] ) ;
12
36
13
37
// Get the list of courses from the local storage
14
38
const [ courses , setCourses ] = useLocalStorage < Course [ ] > ( "courses" , [
15
39
{
16
- regno : 99999 ,
40
+ regno : 99997 ,
17
41
season : "Spring" ,
18
- ay : 2022 ,
42
+ ay : 2024 ,
19
43
no : "CS101" ,
20
44
lang : "E" ,
21
- e : "Example Course" ,
45
+ e : "Example Spring Course" ,
22
46
j : "科目例" ,
23
47
schedule : [ "3/M" , "3/W" , "3/F" ] ,
24
48
instructor : "John Doe" ,
25
49
modified : new Date ( 2022 , 5 - 1 , 5 , 6 , 35 , 20 , 333 ) ,
26
50
unit : 3 ,
27
51
isEnrolled : true ,
28
- color : "#ff0000" ,
52
+ color : "orange 2" ,
53
+ } ,
54
+ {
55
+ regno : 99998 ,
56
+ season : "Autumn" ,
57
+ ay : 2024 ,
58
+ no : "CS101" ,
59
+ lang : "E" ,
60
+ e : "Example Autumn Course" ,
61
+ j : "科目例" ,
62
+ schedule : [ "3/M" , "3/W" , "3/F" ] ,
63
+ instructor : "John Doe" ,
64
+ modified : new Date ( 2022 , 5 - 1 , 5 , 6 , 35 , 20 , 333 ) ,
65
+ unit : 3 ,
66
+ isEnrolled : true ,
67
+ color : "pink 2" ,
68
+ } ,
69
+ {
70
+ regno : 99999 ,
71
+ season : "Winter" ,
72
+ ay : 2024 ,
73
+ no : "CS101" ,
74
+ lang : "E" ,
75
+ e : "Example Winter Course" ,
76
+ j : "科目例" ,
77
+ schedule : [ "3/M" , "3/W" , "3/F" ] ,
78
+ instructor : "John Doe" ,
79
+ modified : new Date ( 2022 , 5 - 1 , 5 , 6 , 35 , 20 , 333 ) ,
80
+ unit : 3 ,
81
+ isEnrolled : true ,
82
+ color : "green 2" ,
29
83
} ,
30
84
] ) ;
31
85
86
+ const timetable : { [ key : string ] : Course [ ] } = { } ;
87
+ const coursesInSelectedTerm = courses . filter (
88
+ ( course ) =>
89
+ course . season === selectedTerm ?. season &&
90
+ course . ay . toString ( ) === selectedTerm ?. ay
91
+ ) ;
92
+
93
+ const enrolledCourses = coursesInSelectedTerm . filter (
94
+ ( course ) => course . isEnrolled
95
+ ) ;
96
+ coursesInSelectedTerm . forEach ( ( course ) => {
97
+ course . schedule ?. forEach ( ( entry ) => {
98
+ const [ time , day ] = entry . split ( "/" ) ;
99
+ if ( ! timetable [ `${ time } /${ day } ` ] ) {
100
+ timetable [ `${ time } /${ day } ` ] = [ ] ;
101
+ }
102
+ timetable [ `${ time } /${ day } ` ] . push ( course ) ;
103
+ } ) ;
104
+ } ) ;
105
+
32
106
// Toggle the isEnrolled property of a certain course
33
107
// Usage: toggleIsEnrolled(regno)
34
108
const toggleIsEnrolled = ( regno : number ) => {
@@ -56,51 +130,82 @@ export default function Page() {
56
130
} ;
57
131
58
132
return (
59
- < >
60
- < AppShell
61
- header = { { height : 60 } }
62
- navbar = { {
63
- width : "400px" ,
64
- breakpoint : "sm" ,
65
- collapsed : { mobile : ! opened } ,
66
- } }
67
- padding = "md"
68
- h = "100vh"
69
- >
70
- < AppShell . Header >
71
- < Header opened = { opened } toggle = { toggle } />
72
- </ AppShell . Header >
73
- < AppShell . Navbar >
133
+ < AppShell
134
+ header = { { height : 60 } }
135
+ navbar = { {
136
+ width : "400px" ,
137
+ breakpoint : "sm" ,
138
+ collapsed : { mobile : ! opened } ,
139
+ } }
140
+ padding = "0"
141
+ h = "100vh"
142
+ w = "100vw"
143
+ >
144
+ < AppShell . Header >
145
+ < Header
146
+ weekdays = { weekdays }
147
+ toggleSaturday = { ( ) => {
148
+ toggleSaturday ( ) ;
149
+ } }
150
+ terms = { terms }
151
+ selectedTermValue = { selectedTermValue }
152
+ setselectedTermValue = { setselectedTermValue }
153
+ />
154
+ </ AppShell . Header >
155
+
156
+ < AppShell . Navbar >
157
+ < Navbar
158
+ courses = { coursesInSelectedTerm }
159
+ toggleIsEnrolled = { toggleIsEnrolled }
160
+ addCourse = { addCourse }
161
+ deleteCourse = { deleteCourse }
162
+ />
163
+ </ AppShell . Navbar >
164
+ < AppShell . Main h = "100vh" >
165
+ { displayMode === "timetable" ? (
166
+ < Timetable
167
+ timetable = { timetable }
168
+ enrolledCourses = { enrolledCourses }
169
+ toggleIsEnrolled = { toggleIsEnrolled }
170
+ weekdays = { weekdays }
171
+ />
172
+ ) : (
74
173
< Navbar
75
- courses = { courses }
174
+ courses = { coursesInSelectedTerm }
76
175
toggleIsEnrolled = { toggleIsEnrolled }
77
176
addCourse = { addCourse }
78
177
deleteCourse = { deleteCourse }
79
178
/>
80
- </ AppShell . Navbar >
81
- < AppShell . Main >
82
- { /* <Grid justify="flex-start" gutter="sm" align="stretch"> */ }
83
- { /* <Grid.Col span={{ base: "auto" }}> */ }
84
- < Timetable courses = { courses } />
85
- { /* </Grid.Col> */ }
86
- { /* <Grid.Col mt={{ base: 5, md: 0 }} span={{ base: 12, md: "content" }}>
87
- <RequirementTable />
88
- </Grid.Col> */ }
89
- { /* </Grid> */ }
90
- < Flex
91
- gap = "md"
92
- justify = "center"
93
- align = "center"
94
- direction = "row"
95
- wrap = "wrap"
179
+ ) }
180
+ </ AppShell . Main >
181
+ < AppShell . Footer
182
+ withBorder = { false }
183
+ hiddenFrom = "sm"
184
+ style = { { background : "rgba(0,0,0,0)" } }
185
+ >
186
+ < Flex gap = "md" mih = { 50 } justify = "center" align = "center" direction = "row" >
187
+ { /* <Button
188
+ variant="filled"
189
+ size="lg"
190
+ leftSection={<IconSearch />}
191
+ onClick={spotlight.open}
192
+ >
193
+ Search
194
+ </Button> */ }
195
+ < Button
196
+ hiddenFrom = "sm"
197
+ size = "lg"
198
+ color = "gray"
199
+ mr = { 3 }
200
+ onClick = { ( ) => {
201
+ toggleDisplayMode ( ) ;
202
+ } }
96
203
>
97
- < Text fw = "bold" >
98
- 🚧 This App is still under development. Do not store any important
99
- data here!
100
- </ Text >
101
- </ Flex >
102
- </ AppShell . Main >
103
- </ AppShell >
104
- </ >
204
+ { displayMode === "list" ? < IconList /> : < IconCalendar /> }
205
+ </ Button >
206
+ </ Flex >
207
+ </ AppShell . Footer >
208
+ { /* <SpotlightSearch /> */ }
209
+ </ AppShell >
105
210
) ;
106
211
}
0 commit comments