@@ -16,40 +16,117 @@ import {
16
16
Link ,
17
17
Divider ,
18
18
Box ,
19
+ Badge ,
19
20
} from "@chakra-ui/react" ;
20
21
import fs from "fs" ;
21
22
import path from "path" ;
22
23
import matter from "gray-matter" ;
23
24
import { CONTENT_PATH } from "@/lib/constants" ;
24
- import { useEffect , useState } from "react" ;
25
+ import { useMemo , useState } from "react" ;
26
+ import { api } from "@/utils/api" ;
27
+ import { useSession } from "next-auth/react" ;
25
28
26
- interface Lesson {
29
+ export interface Lesson {
27
30
frontMatter : any ;
28
31
slug : string ;
29
32
path : string ;
33
+ completed ?: boolean ;
30
34
}
31
- interface LessonProps {
35
+ export interface Lessons {
32
36
lessons : {
33
37
frontMatter : any ;
34
38
slug : string ;
35
39
} [ ] ;
36
40
}
37
41
38
- const GettingStarted : React . FC < LessonProps > = ( { lessons } ) => {
39
- const [ formattedLessons , setFormattedLessons ] = useState < LessonProps > ( {
40
- lessons : [ ] ,
41
- } ) ;
42
+ export interface LessonProps {
43
+ projects : Project [ ] ;
44
+ fundamentals : Fundamental [ ] ;
45
+ }
46
+
47
+ export interface Fundamental {
48
+ path : Path ;
49
+ frontMatter : FundamentalFrontMatter ;
50
+ slug : string ;
51
+ }
52
+
53
+ export interface FundamentalFrontMatter {
54
+ title : string ;
55
+ description : string ;
56
+ icons : string [ ] ;
57
+ authors ?: string [ ] ;
58
+ i18n ?: string ;
59
+ author ?: string [ ] | string ;
60
+ }
61
+
62
+ export enum Path {
63
+ Fundamentals = "fundamentals" ,
64
+ }
65
+
66
+ export interface Project {
67
+ path : string ;
68
+ frontMatter : ProjectFrontMatter ;
69
+ slug : string ;
70
+ completed : boolean ;
71
+ }
72
+
73
+ export interface ProjectFrontMatter {
74
+ title : string ;
75
+ description : string ;
76
+ icons : string [ ] ;
77
+ i18n ?: string ;
78
+ author ?: string ;
79
+ }
42
80
43
- useEffect ( ( ) => {
44
- const result : LessonProps = lessons . reduce ( ( acc : any , curr : any ) => {
45
- if ( ! acc [ curr . path ] ) acc [ curr . path ] = [ ] ;
81
+ const GettingStarted : React . FC < Lessons > = ( { lessons } ) => {
82
+ const [ formattedLessons , setFormattedLessons ] = useState < LessonProps > ( ) ;
83
+ const [ completedQuizzesSlugs , setCompletedQuizzesSlugs ] = useState < string [ ] > (
84
+ [ ]
85
+ ) ;
86
+
87
+ const [ fetchNow , setFetchNow ] = useState < boolean > ( true ) ;
88
+ const { data : sessionData } = useSession ( ) ;
89
+
90
+ // Requests
91
+ // - All
92
+ const {
93
+ data : completedQuizzesAllData ,
94
+ isLoading : completedQuizzesAllIsLoading ,
95
+ // refetch: completedQuizzesAllRefetch,
96
+ } = api . completedQuizzes . all . useQuery (
97
+ undefined , // no input
98
+ {
99
+ // Disable request if no session data
100
+ enabled : sessionData ?. user !== undefined && fetchNow ,
101
+ onSuccess : ( ) => {
102
+ // setNewTodo(""); // reset input form
103
+ } ,
104
+ }
105
+ ) ;
106
+
107
+ useMemo ( ( ) => {
108
+ if ( completedQuizzesAllData ?. length && fetchNow ) {
109
+ const result : LessonProps = lessons . reduce ( ( acc : any , curr : any ) => {
110
+ if ( ! acc [ curr . path ] ) acc [ curr . path ] = [ ] ;
46
111
47
- acc [ curr . path ] . push ( curr ) ;
48
- return acc ;
49
- } , { } ) ;
112
+ acc [ curr . path ] . push ( curr ) ;
113
+ return acc ;
114
+ } , { } ) ;
50
115
51
- setFormattedLessons ( result ) ;
52
- } , [ lessons ] ) ;
116
+ let completedQuizzes : Project [ ] = [ ] ;
117
+ const completedSlugs : string [ ] = completedQuizzesAllData ?. map (
118
+ ( quiz : any ) => quiz . lesson . replace ( "quiz-lesson-" , "" ) || [ ]
119
+ ) ;
120
+ completedQuizzes = result ?. projects ?. map ( ( project : Project ) => {
121
+ if ( completedSlugs . includes ( project . slug ) ) project . completed = true ;
122
+ else project . completed = false ;
123
+ return project ;
124
+ } ) ;
125
+
126
+ setFormattedLessons ( { ...result , projects : completedQuizzes } ) ;
127
+ setFetchNow ( false ) ;
128
+ }
129
+ } , [ completedQuizzesAllData , fetchNow , lessons ] ) ;
53
130
54
131
return (
55
132
< Flex
@@ -96,44 +173,65 @@ const GettingStarted: React.FC<LessonProps> = ({ lessons }) => {
96
173
>
97
174
Current Lessons
98
175
</ Heading >
99
- { Object . entries ( formattedLessons ) . map ( ( track : any , idx : number ) => {
100
- return (
101
- < UnorderedList
102
- listStyleType = "none"
103
- textAlign = "center"
104
- as = "div"
105
- key = { idx }
106
- >
107
- < Heading size = "md" color = "yellow.300" >
108
- { track [ 0 ] . toUpperCase ( ) }
109
- </ Heading >
110
- < >
111
- { track [ 1 ] . map ( ( lesson : Lesson , idx : number ) => (
112
- < ListItem key = { idx } my = "2" py = "2" maxW = "40vw" margin = "0 auto" >
113
- < Link
114
- as = { NextLink }
115
- href = { `/lessons/${ lesson . path } /${ lesson . slug } ` }
116
- passHref
117
- >
118
- < Button
119
- height = "auto"
120
- style = { {
121
- whiteSpace : "normal" ,
122
- wordWrap : "break-word" ,
123
- padding : "0.5rem" ,
124
- width : "100%" ,
125
- fontSize : "xl" ,
126
- } }
176
+ { formattedLessons
177
+ ? Object . entries ( formattedLessons ) . map ( ( track : any , idx : number ) => {
178
+ return (
179
+ < UnorderedList
180
+ listStyleType = "none"
181
+ textAlign = "center"
182
+ as = "div"
183
+ key = { idx }
184
+ >
185
+ < Heading size = "md" color = "yellow.300" >
186
+ { track [ 0 ] . toUpperCase ( ) }
187
+ </ Heading >
188
+ < >
189
+ { track [ 1 ] . map ( ( lesson : Lesson , idx : number ) => (
190
+ < ListItem
191
+ key = { idx }
192
+ my = "2"
193
+ py = "2"
194
+ maxW = "40vw"
195
+ margin = "0 auto"
127
196
>
128
- { lesson . frontMatter . title }
129
- </ Button >
130
- </ Link >
131
- </ ListItem >
132
- ) ) }
133
- </ >
134
- </ UnorderedList >
135
- ) ;
136
- } ) }
197
+ < Link
198
+ as = { NextLink }
199
+ href = { `/lessons/${ lesson . path } /${ lesson . slug } ` }
200
+ passHref
201
+ >
202
+ < Button
203
+ height = "auto"
204
+ style = { {
205
+ whiteSpace : "normal" ,
206
+ wordWrap : "break-word" ,
207
+ padding : "0.5rem" ,
208
+ width : "100%" ,
209
+ fontSize : "xl" ,
210
+ } }
211
+ >
212
+ { lesson . frontMatter . title }
213
+ { lesson &&
214
+ lesson . completed &&
215
+ lesson . completed === true ? (
216
+ < Badge
217
+ ml = "1"
218
+ alignItems = { "flex-end" }
219
+ colorScheme = "green"
220
+ position = "absolute"
221
+ right = { 3 }
222
+ >
223
+ Completed
224
+ </ Badge >
225
+ ) : null }
226
+ </ Button >
227
+ </ Link >
228
+ </ ListItem >
229
+ ) ) }
230
+ </ >
231
+ </ UnorderedList >
232
+ ) ;
233
+ } )
234
+ : null }
137
235
< Divider />
138
236
139
237
< Heading apply = "mdx.h3" as = "h3" fontSize = "2xl" textAlign = "center" p = { 5 } >
@@ -205,8 +303,6 @@ const GettingStarted: React.FC<LessonProps> = ({ lessons }) => {
205
303
) ;
206
304
} ;
207
305
208
- export default GettingStarted ;
209
-
210
306
export const getStaticProps = ( ) => {
211
307
const contentDir = path . join ( CONTENT_PATH ) ;
212
308
const directories = fs . readdirSync ( path . resolve ( contentDir ) ) ;
@@ -221,18 +317,30 @@ export const getStaticProps = () => {
221
317
) ;
222
318
223
319
const { data : frontMatter } = matter ( markdownWithMeta ) ;
224
- lessons . push ( {
225
- path : folder ,
226
- frontMatter,
227
- slug : file . replace ( ".mdx" , "" ) ,
228
- } ) ;
320
+ if ( folder === "fundamentals" ) {
321
+ lessons . push ( {
322
+ path : folder ,
323
+ frontMatter,
324
+ slug : file . replace ( ".mdx" , "" ) ,
325
+ } ) ;
326
+ } else {
327
+ lessons . push ( {
328
+ path : folder ,
329
+ frontMatter,
330
+ slug : file . replace ( ".mdx" , "" ) ,
331
+ completed : false ,
332
+ } ) ;
333
+ }
229
334
}
230
335
} ) ;
231
336
}
232
337
} ) ;
338
+
233
339
return {
234
340
props : {
235
341
lessons,
236
342
} ,
237
343
} ;
238
344
} ;
345
+
346
+ export default GettingStarted ;
0 commit comments