1
- import React , { useState } from "react"
1
+ import React , { useEffect , useState } from "react"
2
2
import styled from "@emotion/styled"
3
3
import { graphql , PageProps } from "gatsby"
4
4
import { useIntl } from "react-intl"
@@ -22,11 +22,15 @@ import {
22
22
23
23
import { getLocaleTimestamp , INVALID_DATETIME } from "../../utils/time"
24
24
25
- import foreignTutorials from "../../data/externalTutorials.json"
25
+ import externalTutorials from "../../data/externalTutorials.json"
26
26
import FeedbackCard from "../../components/FeedbackCard"
27
27
import { getSkillTranslationId , Skill } from "../../components/TutorialMetadata"
28
28
import { Context } from "../../types"
29
29
import { Lang } from "../../utils/languages"
30
+ import {
31
+ filterTutorialsByLang ,
32
+ getSortedTutorialTagsForLang ,
33
+ } from "../../utils/tutorials"
30
34
31
35
const SubSlogan = styled . p `
32
36
font-size: 1.25rem;
@@ -217,7 +221,7 @@ const published = (locale: string, published: string) => {
217
221
) : null
218
222
}
219
223
220
- interface IExternalTutorial {
224
+ export interface IExternalTutorial {
221
225
url : string
222
226
title : string
223
227
description : string
@@ -230,7 +234,7 @@ interface IExternalTutorial {
230
234
publishDate : string
231
235
}
232
236
233
- interface ITutorial {
237
+ export interface ITutorial {
234
238
to : string
235
239
title : string
236
240
description : string
@@ -243,7 +247,7 @@ interface ITutorial {
243
247
isExternal : boolean
244
248
}
245
249
246
- interface ITutorialsState {
250
+ export interface ITutorialsState {
247
251
activeTagNames : Array < string >
248
252
filteredTutorials : Array < ITutorial >
249
253
}
@@ -253,130 +257,36 @@ const TutorialsPage = ({
253
257
pageContext,
254
258
} : PageProps < Queries . DevelopersTutorialsPageQuery , Context > ) => {
255
259
const intl = useIntl ( )
256
- // Filter tutorials by language and map to object
257
- const internalTutorials = data . allTutorials . nodes . map < ITutorial > (
258
- ( tutorial ) => ( {
259
- to :
260
- tutorial ?. fields ?. slug ?. substr ( 0 , 3 ) === "/en"
261
- ? tutorial . fields . slug . substr ( 3 )
262
- : tutorial . fields ?. slug || "/" ,
263
- title : tutorial ?. frontmatter ?. title || "" ,
264
- description : tutorial ?. frontmatter ?. description || "" ,
265
- author : tutorial ?. frontmatter ?. author || "" ,
266
- tags : tutorial ?. frontmatter ?. tags ?. map ( ( tag ) =>
267
- ( tag || "" ) . toLowerCase ( ) . trim ( )
268
- ) ,
269
- skill : tutorial ?. frontmatter ?. skill as Skill ,
270
- timeToRead : tutorial ?. fields ?. readingTime ?. minutes
271
- ? Math . round ( tutorial ?. fields ?. readingTime ?. minutes )
272
- : null ,
273
- published : tutorial ?. frontmatter ?. published ,
274
- lang : tutorial ?. frontmatter ?. lang || "en" ,
275
- isExternal : false ,
276
- } )
277
- )
278
-
279
- const externalTutorials = foreignTutorials . map < ITutorial > (
280
- ( tutorial : IExternalTutorial ) => ( {
281
- to : tutorial . url ,
282
- title : tutorial . title ,
283
- description : tutorial . description ,
284
- author : tutorial . author ,
285
- tags : tutorial . tags . map ( ( tag ) => tag . toLowerCase ( ) . trim ( ) ) ,
286
- skill : tutorial . skillLevel as Skill ,
287
- timeToRead : Number ( tutorial . timeToRead ) ,
288
- published : new Date ( tutorial . publishDate ) . toISOString ( ) ,
289
- lang : tutorial . lang || "en" ,
290
- isExternal : true ,
291
- } )
260
+ const filteredTutorialsByLang = filterTutorialsByLang (
261
+ data . allTutorials . nodes ,
262
+ externalTutorials ,
263
+ pageContext . locale
292
264
)
265
+ const allTags = getSortedTutorialTagsForLang ( filteredTutorialsByLang )
293
266
294
- const allTutorials : Array < ITutorial > = [
295
- ...externalTutorials ,
296
- ...internalTutorials ,
297
- ]
298
-
299
- const hasTutorialsCheck = allTutorials . some (
300
- ( tutorial ) => tutorial . lang === pageContext . language
267
+ const [ filteredTutorials , setFilteredTutorials ] = useState (
268
+ filteredTutorialsByLang
301
269
)
302
-
303
- const filteredTutorials = allTutorials
304
- . filter ( ( tutorial ) =>
305
- hasTutorialsCheck
306
- ? tutorial . lang === pageContext . language
307
- : tutorial . lang === "en"
308
- )
309
- . sort ( ( a , b ) => {
310
- if ( a . published && b . published ) {
311
- return new Date ( b . published ) . getTime ( ) - new Date ( a . published ) . getTime ( )
312
- }
313
- // Dont order if no published is present
314
- return 0
315
- } )
316
-
317
- // Tally all subject tag counts
318
- const tagsConcatenated : Array < string > = [ ]
319
- for ( const tutorial of filteredTutorials ) {
320
- if ( tutorial . tags ) {
321
- tagsConcatenated . push ( ...tutorial . tags )
322
- }
323
- }
324
-
325
- const allTags = tagsConcatenated . map ( ( tag ) => ( { name : tag , totalCount : 1 } ) )
326
- const sanitizedAllTags = Array . from (
327
- allTags . reduce (
328
- ( m , { name, totalCount } ) =>
329
- m . set (
330
- name . toLowerCase ( ) . trim ( ) ,
331
- ( m . get ( name . toLowerCase ( ) . trim ( ) ) || 0 ) + totalCount
332
- ) ,
333
- new Map ( )
334
- ) ,
335
- ( [ name , totalCount ] ) => ( { name, totalCount } )
336
- ) . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
337
-
338
- const [ state , setState ] = useState < ITutorialsState > ( {
339
- activeTagNames : [ ] ,
340
- filteredTutorials : filteredTutorials ,
341
- } )
342
-
343
- const clearActiveTags = ( ) => {
344
- setState ( {
345
- activeTagNames : [ ] ,
346
- filteredTutorials : filteredTutorials ,
347
- } )
348
- }
270
+ const [ selectedTags , setSelectedTags ] = useState < string [ ] > ( [ ] )
349
271
350
272
const handleTagSelect = ( tagName : string ) => {
351
- const activeTagNames = state . activeTagNames
273
+ const tempSelectedTags = selectedTags
352
274
353
- // Add or remove the selected tag
354
- const index = activeTagNames . indexOf ( tagName )
275
+ const index = tempSelectedTags . indexOf ( tagName )
355
276
if ( index > - 1 ) {
356
- activeTagNames . splice ( index , 1 )
277
+ tempSelectedTags . splice ( index , 1 )
357
278
} else {
358
- activeTagNames . push ( tagName )
279
+ tempSelectedTags . push ( tagName )
359
280
}
360
281
361
- // If no tags are active, show all tutorials, otherwise filter by active tag
362
- let filteredTutorials = allTutorials
363
- if ( activeTagNames . length > 0 ) {
364
- filteredTutorials = filteredTutorials . filter ( ( tutorial ) => {
365
- for ( const tag of activeTagNames ) {
366
- if ( ! tutorial . tags ?. includes ( tag ) ) {
367
- return false
368
- }
369
- }
370
- return hasTutorialsCheck
371
- ? tutorial . lang === pageContext . language
372
- : tutorial . lang === "en"
373
- } )
374
- }
375
- setState ( { activeTagNames, filteredTutorials } )
282
+ setSelectedTags ( [ ...tempSelectedTags ] )
376
283
}
377
284
378
- const hasActiveTags = state . activeTagNames . length > 0
379
- const hasNoTutorials = state . filteredTutorials . length === 0
285
+ // TODO: Update setFilteredTutorials with filteredTutorialsByLang filtered out by selectedTags
286
+ useEffect ( ( ) => {
287
+ console . log ( "CHANGE" )
288
+ } , [ selectedTags ] )
289
+
380
290
const [ isModalOpen , setModalOpen ] = useState ( false )
381
291
382
292
return (
@@ -456,28 +366,28 @@ const TutorialsPage = ({
456
366
< TutorialContainer >
457
367
< TagsContainer >
458
368
< TagContainer >
459
- { sanitizedAllTags . map ( ( tag ) => {
460
- const name = `${ tag . name } (${ tag . totalCount } )`
461
- const isActive = state . activeTagNames . includes ( tag . name )
369
+ { Object . entries ( allTags ) . map ( ( [ tagName , tagCount ] ) => {
370
+ const name = `${ tagName } (${ tagCount } )`
371
+ const isActive = selectedTags . includes ( tagName )
462
372
return (
463
373
< Tag
464
374
name = { name }
465
375
key = { name }
466
376
isActive = { isActive }
467
377
shouldShowIcon = { false }
468
378
onClick = { handleTagSelect }
469
- value = { tag . name }
379
+ value = { tagName }
470
380
/>
471
381
)
472
382
} ) }
473
- { hasActiveTags && (
474
- < ClearLink onClick = { clearActiveTags } >
383
+ { selectedTags . length > 0 && (
384
+ < ClearLink onClick = { ( ) => setSelectedTags ( [ ] ) } >
475
385
< Translation id = "page-find-wallet-clear" />
476
386
</ ClearLink >
477
387
) }
478
388
</ TagContainer >
479
389
</ TagsContainer >
480
- { hasNoTutorials && (
390
+ { filteredTutorials . length === 0 && (
481
391
< ResultsContainer >
482
392
< Emoji text = ":crying_face:" size = { 3 } mb = { `2em` } mt = { `2em` } />
483
393
< h2 >
@@ -488,7 +398,7 @@ const TutorialsPage = ({
488
398
</ p >
489
399
</ ResultsContainer >
490
400
) }
491
- { state . filteredTutorials . map ( ( tutorial ) => {
401
+ { filteredTutorials . map ( ( tutorial ) => {
492
402
return (
493
403
< TutorialCard
494
404
key = { tutorial . to }
0 commit comments