1
- import React , { Component } from "react" ;
1
+ import React , { useEffect , useState } from "react" ;
2
2
import { render } from 'react-dom' ;
3
3
import ButtonAppBar from './AppBar' ;
4
4
import LeadList from './LeadList' ;
@@ -8,6 +8,8 @@ import Alert from '@mui/material/Alert';
8
8
import Box from '@mui/material/Box' ;
9
9
import Grid from '@mui/material/Grid' ;
10
10
import Cookies from "universal-cookie" ;
11
+ import { stringAvatar } from "../utils" ;
12
+ import { AppContext } from "./AppContext" ;
11
13
12
14
const cookies = new Cookies ( ) ;
13
15
@@ -23,198 +25,142 @@ const lightTheme = createTheme({
23
25
} ,
24
26
} ) ;
25
27
26
- class App extends React . Component {
27
- constructor ( props ) {
28
- super ( props ) ;
29
28
30
- this . login = this . login . bind ( this ) ;
31
- this . clearError = this . clearError . bind ( this ) ;
32
-
33
- let defaultDark = false ;
34
- if ( window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ) {
35
- defaultDark = true ;
36
- }
37
-
38
- let darkMode = JSON . parse ( localStorage . getItem ( 'darkMode' ) ) ?? defaultDark ;
39
-
40
- this . state = {
41
- username : "" ,
42
- fullname : "Anonymous User" ,
43
- avatarProps : this . stringAvatar ( 'Anonymous User' ) ,
44
- email : "" ,
45
- password : "" ,
46
- error : "" ,
47
- isAuthenticated : false ,
48
- darkMode : darkMode ,
49
- } ;
50
- }
51
-
52
- stringToColor ( string ) {
53
- let hash = 0 ;
54
- let i ;
55
-
56
- /* eslint-disable no-bitwise */
57
- for ( i = 0 ; i < string . length ; i += 1 ) {
58
- hash = string . charCodeAt ( i ) + ( ( hash << 5 ) - hash ) ;
59
- }
60
-
61
- let color = '#' ;
62
-
63
- for ( i = 0 ; i < 3 ; i += 1 ) {
64
- const value = ( hash >> ( i * 8 ) ) & 0xff ;
65
- color += `00${ value . toString ( 16 ) } ` . slice ( - 2 ) ;
66
- }
67
- /* eslint-enable no-bitwise */
68
-
69
- return color ;
70
- }
29
+ // Figure out the default dark mode.
30
+ let osDark = false ;
31
+ let defaultDark = false ;
32
+ if ( window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ) {
33
+ osDark = true ;
34
+ }
35
+ defaultDark = JSON . parse ( localStorage . getItem ( 'darkMode' ) ) ?? osDark ;
71
36
72
- stringAvatar ( name ) {
73
- let children = '' ;
74
- if ( ! name . includes ( ' ' ) ) {
75
- children = name [ 0 ] . toUpperCase ( ) ;
76
- } else {
77
- children = name . split ( ' ' ) [ 0 ] [ 0 ] . toUpperCase ( ) + name . split ( ' ' ) [ 1 ] [ 0 ] . toUpperCase ( ) ;
78
- }
79
37
80
- return {
81
- sx : {
82
- bgcolor : this . stringToColor ( name ) ,
83
- } ,
84
- children : children ,
85
- } ;
86
- }
38
+ export function App ( ) {
39
+ const anonUser = {
40
+ username : '' ,
41
+ fullname : 'Anonymous User' ,
42
+ avatarProps : stringAvatar ( 'Anonymous User' ) ,
43
+ email : '' ,
44
+ password : '' ,
45
+ isAuthenticated : false
46
+ } ;
87
47
88
- componentDidMount = ( ) => {
89
- this . getSession ( ) ;
90
- }
48
+ const [ user , setUser ] = useState ( anonUser ) ;
49
+ const [ darkMode , setDarkMode ] = useState ( defaultDark ) ;
50
+ const [ error , setError ] = useState ( "" ) ;
91
51
92
- getSession = ( ) => {
52
+ // Retrieve any session details, or clear them if necessary
53
+ const getSession = ( ) => {
93
54
fetch ( "/api/session/" , {
94
55
credentials : "same-origin" ,
95
56
} )
96
- . then ( ( res ) => res . json ( ) )
97
- . then ( ( data ) => {
98
- console . log ( data ) ;
99
- if ( data . isAuthenticated ) {
100
- this . setState ( {
101
- isAuthenticated : true ,
102
- username : data . username ,
103
- fullname : data . fullname ,
104
- avatarProps : this . stringAvatar ( data . fullname ) ,
105
- email : data . email ,
106
- error : ''
107
- } ) ;
108
- } else {
109
- this . setState ( {
110
- isAuthenticated : false ,
111
- username : '' ,
112
- fullname : 'Anonymous User' ,
113
- avatarProps : this . stringAvatar ( 'Anonymous User' ) ,
114
- email : '' ,
115
- error : ''
116
- } ) ;
117
- }
118
- } )
119
- . catch ( ( err ) => {
120
- console . log ( err ) ;
121
- } ) ;
57
+ . then ( ( res ) => res . json ( ) )
58
+ . then ( ( data ) => {
59
+ console . log ( data ) ;
60
+ if ( data . isAuthenticated ) {
61
+ setUser ( {
62
+ username : data . username ,
63
+ fullname : data . fullname ,
64
+ avatarProps : stringAvatar ( data . fullname ) ,
65
+ email : data . email ,
66
+ password : '' ,
67
+ isAuthenticated : true
68
+ } ) ;
69
+ setError ( '' ) ;
70
+ } else {
71
+ setUser ( anonUser ) ;
72
+ setError ( '' ) ;
73
+ }
74
+ } )
75
+ . catch ( ( err ) => {
76
+ console . log ( err ) ;
77
+ } ) ;
122
78
}
123
79
124
- isResponseOk ( response ) {
80
+ // Did we get a good response from our request?
81
+ const isResponseOk = ( response ) => {
125
82
if ( response . status >= 200 && response . status <= 299 ) {
126
83
return response . json ( ) ;
127
84
} else {
128
85
throw Error ( response . statusText ) ;
129
86
}
130
87
}
131
88
132
- clearError ( ) {
133
- this . setState ( { error : '' } ) ;
89
+ // Clear any previous errors
90
+ const clearError = ( ) => {
91
+ setError ( '' ) ;
134
92
}
135
93
136
- login ( username , password , cbSuccess ) {
94
+ // Attempt to login
95
+ const login = ( username , password , cbSuccess ) => {
137
96
fetch ( "/api/login/" , {
138
- method : "POST" ,
139
- headers : {
140
- "Content-Type" : "application/json" ,
141
- "X-CSRFToken" : cookies . get ( "csrftoken" ) ,
142
- } ,
143
- credentials : "same-origin" ,
144
- body : JSON . stringify ( { username : username , password : password } ) ,
145
- } )
146
- . then ( this . isResponseOk )
147
- . then ( ( data ) => {
148
- this . getSession ( ) ;
149
- cbSuccess ( ) ;
97
+ method : "POST" , headers : {
98
+ "Content-Type" : "application/json" , "X-CSRFToken" : cookies . get ( "csrftoken" ) ,
99
+ } , credentials : "same-origin" , body : JSON . stringify ( { username : username , password : password } ) ,
150
100
} )
151
- . catch ( ( err ) => {
152
- console . log ( err ) ;
153
- this . setState ( { error : "Incorrect username or password." } ) ;
154
- } ) ;
101
+ . then ( isResponseOk )
102
+ . then ( ( ) => {
103
+ getSession ( ) ;
104
+ cbSuccess ( ) ;
105
+ } )
106
+ . catch ( ( err ) => {
107
+ console . log ( err ) ;
108
+ setError ( 'Incorrect username or password.' ) ;
109
+ } ) ;
155
110
}
156
111
157
- logout = ( ) => {
112
+ // Clear the session out
113
+ const logout = ( ) => {
158
114
fetch ( "/api/logout" , {
159
115
credentials : "same-origin" ,
160
116
} )
161
- . then ( this . isResponseOk )
162
- . then ( ( data ) => {
163
- console . log ( data ) ;
164
- this . setState ( {
165
- isAuthenticated : false ,
166
- username : '' ,
167
- fullname : 'Anonymous User' ,
168
- avatarProps : this . stringAvatar ( 'Anonymous User' ) ,
169
- email : '' ,
170
- error : ''
117
+ . then ( isResponseOk )
118
+ . then ( ( data ) => {
119
+ console . log ( data ) ;
120
+ setUser ( anonUser ) ;
121
+ setError ( '' ) ;
122
+ } )
123
+ . catch ( ( err ) => {
124
+ console . log ( err ) ;
171
125
} ) ;
172
- } )
173
- . catch ( ( err ) => {
174
- console . log ( err ) ;
175
- } ) ;
176
126
} ;
177
127
178
-
179
- changeTheme = ( ) => {
180
- const darkMode = this . state . darkMode ;
181
- this . setState ( { darkMode : ! darkMode } ) ;
128
+ // Toggle the theme
129
+ const changeTheme = ( ) => {
182
130
localStorage . setItem ( 'darkMode' , JSON . stringify ( ! darkMode ) ) ;
131
+ setDarkMode ( ! darkMode ) ;
183
132
}
184
133
185
- render ( ) {
186
- return (
187
- < ThemeProvider theme = { this . state . darkMode ? darkTheme : lightTheme } >
134
+ // See if we can get session data
135
+ useEffect ( ( ) => {
136
+ getSession ( )
137
+ } , [ ] ) ;
138
+
139
+ return ( < AppContext . Provider value = { { user, darkMode, error} } >
140
+ < ThemeProvider theme = { darkMode ? darkTheme : lightTheme } >
188
141
< CssBaseline />
189
- < ButtonAppBar appState = { this . state } handleLogin = { this . login } handleLogout = { this . logout } clearError = { this . clearError } onChangeTheme = { this . changeTheme } />
142
+ < ButtonAppBar appState = { user } handleLogin = { login } handleLogout = { logout } clearError = { clearError }
143
+ onChangeTheme = { changeTheme } />
190
144
< Box align = "center" sx = { { flexGrow : 1 } } style = { { marginLeft : 20 , marginRight : 20 } } >
191
145
< Grid container align = "left" maxWidth = "xl" spacing = { 1 } wrap = "wrap" >
192
- { ! this . state . isAuthenticated ?
146
+ { ! user . isAuthenticated ? < Grid item xs = { 12 } >
147
+ < h1 > Login</ h1 >
148
+ < Alert severity = "error" > Please login to see the lead list.</ Alert >
149
+ </ Grid > : < >
193
150
< Grid item xs = { 12 } >
194
- < h1 > Login</ h1 >
195
- < Alert severity = "error" > Please login to see the lead list.</ Alert >
151
+ < h1 > Lead List</ h1 >
196
152
</ Grid >
197
- :
198
- < >
199
- < Grid item xs = { 12 } >
200
- < h1 > Lead List</ h1 >
201
- </ Grid >
202
- < Grid item xs = { 12 } >
203
- < LeadList />
204
- </ Grid >
205
- </ >
206
- }
153
+ < Grid item xs = { 12 } >
154
+ < LeadList />
155
+ </ Grid >
156
+ </ > }
207
157
</ Grid >
208
158
</ Box >
209
159
</ ThemeProvider >
210
- )
211
- } ;
160
+ </ AppContext . Provider > )
212
161
}
213
162
214
163
const container = document . getElementById ( "app" ) ;
215
- render (
216
- < React . StrictMode >
217
- < App />
218
- </ React . StrictMode > ,
219
- container
220
- ) ;
164
+ render ( < React . StrictMode >
165
+ < App />
166
+ </ React . StrictMode > , container ) ;
0 commit comments