1
1
import { useEffect , useState } from 'react' ;
2
- import { Button , Checkbox , Container , FormControlLabel , Grid , TextField , FormControl , InputLabel , Select , MenuItem } from
3
- '@mui/material' ;
2
+ import { Button , Checkbox , Container , FormControlLabel , Grid , TextField , FormControl , InputLabel , Select , MenuItem } from '@mui/material' ;
4
3
import { DataGrid } from '@mui/x-data-grid' ;
5
4
import Typography from '@mui/material/Typography' ;
6
-
7
5
import { NavLink } from 'react-router-dom' ;
8
6
const config = require ( '../config.json' ) ;
9
7
10
8
export default function ProductionSearchPage ( { type } ) {
11
9
const [ data , setData ] = useState ( [ ] ) ;
12
10
const [ pageSize , setPageSize ] = useState ( 25 ) ;
11
+ const [ loading , setLoading ] = useState ( true ) ; // New state for loading
13
12
14
13
const [ primaryTitle , setPrimaryTitle ] = useState ( '' ) ;
15
14
const [ isAdult , setIsAdult ] = useState ( false ) ;
@@ -19,15 +18,18 @@ export default function ProductionSearchPage({ type }) {
19
18
const [ averageRating , setAverageRating ] = useState ( [ 0 , 10 ] ) ;
20
19
21
20
useEffect ( ( ) => {
21
+ setLoading ( true ) ;
22
22
fetch ( `https://${ config . server_host } :${ config . server_port } /search_productions/${ type } ` )
23
23
. then ( res => res . json ( ) )
24
24
. then ( resJson => {
25
25
const productionsWithId = resJson . map ( ( production ) => ( { id : production . titleId , ...production } ) ) ;
26
26
setData ( productionsWithId ) ;
27
+ setLoading ( false ) ;
27
28
} ) ;
28
29
} , [ type ] ) ;
29
30
30
31
const search = ( ) => {
32
+ setLoading ( true ) ;
31
33
fetch ( `https://${ config . server_host } :${ config . server_port } /search_productions/${ type } ?primaryTitle=${ primaryTitle } ` +
32
34
`&isAdult=${ isAdult } &startYearLow=${ startYear [ 0 ] } &startYearHigh=${ startYear [ 1 ] } &runtimeMinutesLow=${ runtimeMinutes [ 0 ] } ` +
33
35
`&runtimeMinutesHigh=${ runtimeMinutes [ 1 ] } &genre=${ genre } &averageRatingLow=${ averageRating [ 0 ] } ` +
@@ -37,10 +39,10 @@ export default function ProductionSearchPage({ type }) {
37
39
. then ( resJson => {
38
40
const productionsWithId = resJson . map ( ( production ) => ( { id : production . titleId , ...production } ) ) ;
39
41
setData ( productionsWithId ) ;
42
+ setLoading ( false ) ;
40
43
} ) ;
41
44
} ;
42
45
43
- // This defines the columns of the table of productions. We use the DataGrid component for the table.
44
46
const columns = [
45
47
{ field : 'primaryTitle' , headerName : 'Title' , width : 490 , renderCell : ( params ) => (
46
48
< NavLink to = { `/production_info/${ params . row . titleId } ` } > { params . value } </ NavLink >
@@ -59,43 +61,82 @@ export default function ProductionSearchPage({ type }) {
59
61
typeDisplayed = 'Movies' ;
60
62
releaseYear = [ 1900 , 2023 ] ;
61
63
runtime = [ 0 , 1000 ] ;
62
- // ryWidth = 4;
63
- // rtWidth = 6;
64
64
ryWidth = 4 ;
65
65
rtWidth = 4 ;
66
66
} else if ( type === 'Short' ) {
67
67
typeDisplayed = 'Shorts' ;
68
68
releaseYear = [ 1900 , 2023 ] ;
69
69
runtime = [ 0 , 110 ] ;
70
- // ryWidth = 5;
71
- // rtWidth = 4;
72
70
ryWidth = 4 ;
73
71
rtWidth = 4 ;
74
72
} else {
75
73
typeDisplayed = 'TV Series' ;
76
74
releaseYear = [ 1930 , 2023 ] ;
77
75
runtime = [ 0 , 5300 ] ;
78
- // ryWidth = 3;
79
- // rtWidth = 7;
80
76
ryWidth = 4 ;
81
77
rtWidth = 4 ;
82
78
}
83
79
84
80
const genres = [ 'All' , 'Documentary' , 'Short' , 'Animation' , 'Comedy' , 'Romance' , 'Sport' , 'News' , 'Drama' , 'Fantasy' , 'Horror' ,
85
81
'Biography' , 'Music' , 'War' , 'Crime' , 'Western' , 'Family' , 'Adventure' , 'Action' , 'History' , 'Mystery' , 'Sci-Fi' , 'Musical' ,
86
82
'Thriller' , 'Film-Noir' , 'Talk-Show' , 'Game-Show' , 'Reality-TV' , 'Adult' ] ;
87
-
83
+
84
+ const rangeInputStyle = `
85
+ input[type="range"]::-webkit-slider-thumb {
86
+ -webkit-appearance: none;
87
+ width: 20px;
88
+ height: 20px;
89
+ background: gray;
90
+ cursor: pointer;
91
+ border-radius: 50%;
92
+ }
93
+ input[type="range"]::-moz-range-thumb {
94
+ width: 20px;
95
+ height: 20px;
96
+ background: gray;
97
+ cursor: pointer;
98
+ border-radius: 50%;
99
+ }
100
+ input[type="range"]::-ms-thumb {
101
+ width: 20px;
102
+ height: 20px;
103
+ background: gray;
104
+ cursor: pointer;
105
+ border-radius: 50%;
106
+ }
107
+ ` ;
108
+
109
+ const getRowClassName = ( params ) => {
110
+ if ( params . index === 0 ) {
111
+ return 'bold-row' ;
112
+ }
113
+ return '' ;
114
+ } ;
115
+
88
116
return (
89
117
< Container >
90
- < h2 > Search { typeDisplayed } </ h2 >
118
+ < style >
119
+ { rangeInputStyle }
120
+ { `
121
+ .bold-row {
122
+ font-weight: bold;
123
+ }
124
+ ` }
125
+ </ style >
126
+ < h2 style = { { textAlign : 'center' , fontSize : '32px' , marginBottom : '20px' } } > Search { typeDisplayed } </ h2 >
91
127
< Grid container spacing = { 6 } >
92
128
< Grid item xs = { 6 } >
93
- < TextField label = 'Title' value = { primaryTitle } onChange = { ( e ) => setPrimaryTitle ( e . target . value ) } style = { { width : "100%" } } />
129
+ < TextField
130
+ label = 'Title'
131
+ value = { primaryTitle }
132
+ onChange = { ( e ) => setPrimaryTitle ( e . target . value ) }
133
+ style = { { width : "100%" , border : '1px solid #ccc' , borderRadius : '4px' , marginBottom : '20px' } }
134
+ />
94
135
</ Grid >
95
136
< Grid item xs = { 4 } >
96
- < FormControl style = { { width : '100%' } } >
137
+ < FormControl style = { { width : '100%' , marginBottom : '20px' } } >
97
138
< InputLabel id = 'genre_label' > Genre</ InputLabel >
98
- < Select labelId = 'genre_label' label = 'Label ' value = { genre } onChange = { ( e ) => setGenre ( e . target . value ) } >
139
+ < Select labelId = 'genre_label' label = 'Genre ' value = { genre } onChange = { ( e ) => setGenre ( e . target . value ) } >
99
140
{ genres . map ( ( genre ) => (
100
141
< MenuItem key = { genre } value = { genre } > { genre } </ MenuItem >
101
142
) ) }
@@ -106,41 +147,9 @@ export default function ProductionSearchPage({ type }) {
106
147
< FormControlLabel
107
148
label = 'Adult'
108
149
control = { < Checkbox checked = { isAdult } onChange = { ( e ) => setIsAdult ( e . target . checked ) } /> }
150
+ style = { { marginBottom : '20px' } }
109
151
/>
110
152
</ Grid >
111
- { /* <Grid item xs={ryWidth}>
112
- <p>Release Year</p>
113
- <Slider style={{ color: 'black' }}
114
- value={startYear}
115
- min={releaseYear[0]}
116
- max={releaseYear[1]}
117
- step={1}
118
- onChange={(e, newValue) => setStartYear(newValue)}
119
- valueLabelDisplay='auto'
120
- />
121
- </Grid>
122
- <Grid item xs={rtWidth}>
123
- <p>Runtime (mins)</p>
124
- <Slider style={{ color: 'black' }}
125
- value={runtimeMinutes}
126
- min={runtime[0]}
127
- max={runtime[1]}
128
- step={1}
129
- onChange={(e, newValue) => setRuntimeMinutes(newValue)}
130
- valueLabelDisplay='auto'
131
- />
132
- </Grid>
133
- <Grid item xs={12-ryWidth-rtWidth}>
134
- <p>Average Rating</p>
135
- <Slider style={{ color: 'black' }}
136
- value={averageRating}
137
- min={0.0}
138
- max={10.0}
139
- step={0.1}
140
- onChange={(e, newValue) => setAverageRating(newValue)}
141
- valueLabelDisplay='auto'
142
- />
143
- </Grid> */ }
144
153
< Grid item xs = { ryWidth } >
145
154
< div style = { { display : 'flex' , flexDirection : 'column' , alignItems : 'center' } } >
146
155
< div style = { { backgroundColor : 'gray' , padding : '8px' , borderRadius : '4px' , display : 'flex' , alignItems : 'center' , justifyContent : 'center' } } >
@@ -232,12 +241,6 @@ export default function ProductionSearchPage({ type }) {
232
241
</ div >
233
242
</ Grid >
234
243
</ Grid >
235
- { /* <Button
236
- onClick={() => search()}
237
- style={{ backgroundColor: 'black', color: 'white', left: '50%',
238
- transform: 'translateX(-50%)', fontWeight: 'bold', marginTop: '25px' }}>
239
- Search
240
- </Button> */ }
241
244
< Button
242
245
onClick = { ( ) => search ( ) }
243
246
style = { {
@@ -246,22 +249,33 @@ export default function ProductionSearchPage({ type }) {
246
249
left : '50%' ,
247
250
transform : 'translateX(-50%)' ,
248
251
fontWeight : 'bold' ,
249
- marginTop : '60px' ,
250
- marginBottom : '200px' ,
251
- fontSize : '20px' , // Adjust the font size as needed
252
- padding : '15px 80px' // Adjust the padding as needed
253
- } } >
252
+ marginTop : '40px' ,
253
+ marginBottom : '60px' ,
254
+ fontSize : '20px' ,
255
+ padding : '15px 80px' ,
256
+ } }
257
+ >
254
258
Search
255
259
</ Button >
256
- < h2 > { typeDisplayed } YOU WOULD LIKE</ h2 >
257
- < DataGrid
258
- rows = { data }
259
- columns = { columns }
260
- pageSize = { pageSize }
261
- rowsPerPageOptions = { [ 10 , 25 , 50 , 100 ] }
262
- onPageSizeChange = { ( newPageSize ) => setPageSize ( newPageSize ) }
263
- autoHeight
264
- />
260
+ < h2 style = { { textAlign : 'center' , marginBottom : '20px' , fontSize : '28px' } } > { typeDisplayed } YOU WOULD LIKE</ h2 >
261
+ < div style = { { marginBottom : '40px' } } >
262
+ < DataGrid
263
+ rows = { loading ? [ ] : data } // Show empty rows if loading
264
+ columns = { columns }
265
+ pageSize = { pageSize }
266
+ rowsPerPageOptions = { [ 10 , 25 , 50 , 100 ] }
267
+ onPageSizeChange = { ( newPageSize ) => setPageSize ( newPageSize ) }
268
+ autoHeight
269
+ getRowClassName = { getRowClassName }
270
+ components = { {
271
+ NoRowsOverlay : ( ) => (
272
+ < div style = { { padding : '10px' , textAlign : 'center' } } >
273
+ { loading ? "Loading..." : "No rows" }
274
+ </ div >
275
+ )
276
+ } }
277
+ />
278
+ </ div >
265
279
</ Container >
266
280
) ;
267
- } ;
281
+ }
0 commit comments