1
- import React from 'react'
1
+ import React , { useState , useEffect } from 'react'
2
2
import styled , { css } from 'styled-components'
3
-
4
- import { useRandomCharacters } from '../../utils/hooks'
5
3
import { Spinner } from '../shared'
6
4
import Card from './characterCard'
5
+ import { useSiteMeta } from '../../utils/hooks'
6
+ import { useRickAndMortyStats } from '../../utils/hooks'
7
7
8
8
const Wrapper = styled . section (
9
9
( { theme } ) => css `
10
- ${ theme . mixins . flex }
11
- padding : ${ theme . spacing . rem ( 72 ) } 0 ;
10
+ // ${ theme . mixins . flex }
11
+ padding : ${ theme . spacing . rem ( 40 ) } 0 ;
12
12
background : # 272b33 ;
13
13
min-height : calc (50vh - ${ theme . navHeight } px);
14
-
15
14
${ theme . media . phone ( css `
16
15
padding : ${ theme . spacing . _24 } ;
17
16
` ) }
@@ -20,18 +19,168 @@ const Wrapper = styled.section(
20
19
21
20
const Inner = styled . div (
22
21
( { theme } ) => css `
23
- ${ theme . mixins . flex } ;
22
+ ${ theme . mixins . flex }
24
23
flex-wrap : wrap;
25
24
max-width : 1920px ;
26
25
` ,
27
26
)
28
27
28
+ const Flex = styled . h1 (
29
+ ( { theme } ) => css `
30
+ z-index : 1 ;
31
+ display : flex;
32
+ justify-content : center;
33
+ margin : 0 0.75rem ;
34
+ max-width : 1920px ;
35
+ ${ theme . media . phone ( css `
36
+ justify-content : space-between;
37
+ margin : 0rem ;
38
+ ` ) }
39
+ ` ,
40
+ )
41
+
42
+ const Select = styled . select (
43
+ ( { theme } ) => css `
44
+ border : 1px solid rgb (255 , 152 , 0 );
45
+ border-radius : 8px ;
46
+ padding : 6px ;
47
+ width : 230px ;
48
+ margin : 0.75rem ;
49
+ color : # f5f5f5 ;
50
+ background : rgb (60 , 62 , 68 );
51
+ font-size : ${ theme . spacing . rem ( 16 ) } ;
52
+ ${ theme . media . phone ( css `
53
+ font-size : ${ theme . spacing . rem ( 14 ) } ;
54
+ width : 100% ;
55
+ ` ) }
56
+ ` ,
57
+ )
58
+
59
+
60
+
29
61
const Showcase = ( ) => {
30
- const { loading, data } = useRandomCharacters ( { total : 6 } )
62
+ const [ state , setState ] = useState ( {
63
+ status : 'all' ,
64
+ gender : 'all' ,
65
+ data :[ ] ,
66
+ loading :false ,
67
+ filteredData :[ ]
68
+ } )
69
+ const getRandomNums = ( { max, total } ) => {
70
+ const arr = [ ]
71
+ const randomNum = ( ) => Math . floor ( Math . random ( ) * max + 1 )
72
+
73
+ if ( total === 1 ) {
74
+ return randomNum ( )
75
+ }
76
+
77
+ while ( arr . length < total ) {
78
+ const num = randomNum ( )
79
+ if ( arr . indexOf ( num ) > - 1 ) {
80
+ continue
81
+ }
82
+ arr [ arr . length ] = num
83
+ }
84
+ return arr
85
+ }
86
+
87
+ const graphqlQuery = ( ) => ( {
88
+ query : `
89
+ query {
90
+ characters(page: 1) { # Start with page 1
91
+ info {
92
+ next
93
+ }
94
+ results {
95
+ id
96
+ name
97
+ status
98
+ gender
99
+ species
100
+ image
101
+ episode {
102
+ name
103
+ id
104
+ }
105
+ location {
106
+ name
107
+ id
108
+ }
109
+ }
110
+ }
111
+ }
112
+ ` ,
113
+ variables : { } ,
114
+ } )
115
+
116
+ const { siteUrl } = useSiteMeta ( )
117
+ const {
118
+ characters : { info } ,
119
+ } = useRickAndMortyStats ( )
120
+
121
+ const fetchFromAPI = async ( { status= state . status , gender= state . gender } ) => {
122
+ const res = await fetch ( `${ siteUrl } /graphql` , {
123
+ method : 'POST' ,
124
+ body : JSON . stringify ( graphqlQuery ( getRandomNums ( { max : info . count , total :20 } ) ) ) ,
125
+ headers : {
126
+ 'content-type' : 'application/json' ,
127
+ } ,
128
+ } ) . catch ( ( ) => {
129
+ setLoading ( false )
130
+ } )
131
+ if ( res && res . ok ) {
132
+ const { data } = await res . json ( )
133
+ let filteredCharacters = JSON . parse ( JSON . stringify ( data . characters . results ) )
134
+ if ( status !== "all" ) {
135
+ filteredCharacters = filteredCharacters . filter ( ( char ) => char . status === status )
136
+ }
137
+ if ( gender !== "all" ) {
138
+ filteredCharacters = filteredCharacters . filter ( ( char ) => char . gender === gender )
139
+ }
140
+ const characters = filteredCharacters . map ( ( item ) => ( {
141
+ ...item ,
142
+ url : `${ siteUrl } /api/character/${ item . id } ` ,
143
+ episode : {
144
+ name : item . episode [ 0 ] . name ,
145
+ url : `${ siteUrl } /api/episode/${ item . episode [ 0 ] . id } ` ,
146
+ } ,
147
+ location : {
148
+ name : item . location . name ,
149
+ url : `${ siteUrl } /api/location/${ item . location . id } ` ,
150
+ } ,
151
+ } ) )
152
+ //sessionStorage.setItem(CACHE_KEY, JSON.stringify(characters))
153
+ setState ( ( prev ) => ( { ...prev , data :data . characters . results , filteredData :characters , status, gender} ) )
154
+ }
155
+ }
156
+
157
+
158
+
159
+ useEffect ( ( ) => {
160
+ fetchFromAPI ( { } )
161
+ return ( ) => {
162
+ console . log ( "showcase unmounted" )
163
+ }
164
+ } , [ ] )
31
165
32
166
return (
33
167
< Wrapper >
34
- < Inner > { loading ? < Spinner /> : data . map ( ( char ) => < Card key = { char . id } { ...char } /> ) } </ Inner >
168
+ < Flex >
169
+ < Select name = "status" id = "status" onChange = { ( ) => fetchFromAPI ( { status :document . getElementById ( 'status' ) . value } ) } >
170
+ < option value = "all" > All</ option >
171
+ < option value = "Alive" > Alive</ option >
172
+ < option value = "Unknown" > Unknown</ option >
173
+ < option value = "Dead" > Dead</ option >
174
+ </ Select >
175
+ < Select name = "gender" id = "gender" onChange = { ( ) => fetchFromAPI ( { gender :document . getElementById ( 'gender' ) . value } ) } >
176
+ < option value = "all" > All</ option >
177
+ < option value = "Female" > Female</ option >
178
+ < option value = "Male" > Male</ option >
179
+ < option value = "Genderless" > Genderless</ option >
180
+ < option value = "Unknown" > Unknown</ option >
181
+ </ Select >
182
+ </ Flex >
183
+ < Inner > { state . loading ? < Spinner /> : state . filteredData . map ( ( char ) => < Card key = { char . id } { ...char } /> ) } </ Inner >
35
184
</ Wrapper >
36
185
)
37
186
}
0 commit comments