11import React , { useEffect , useState } from 'react' ;
22import './MapStyle.scss' ;
3- import ExpandMoreIcon from '@material-ui/icons/ExpandMore' ;
4- import MyLocationIcon from '@material-ui/icons/MyLocation' ;
3+ import * as utility from './utility' ;
54import Papa from 'papaparse' ;
65import * as d3 from 'd3' ;
7- import Menu from '@material-ui/core/Menu' ;
8- import MenuItem from '@material-ui/core/MenuItem' ;
9- import * as constants from './constants/mapConstants' ;
10- import { Box , CircularProgress , Dialog } from '@material-ui/core' ;
116import logo from '../../logo1.png' ;
7+ import { Menu , MenuItem , IconButton , Collapse } from '@material-ui/core' ;
8+ import { Alert } from '@material-ui/lab' ;
9+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore' ;
10+ import MyLocationIcon from '@material-ui/icons/MyLocation' ;
11+ import CloseIcon from '@material-ui/icons/Close' ;
1212
1313export default function Map ( ) {
1414 // FIXME you are using leaflet but you haven't imported it in this component because you have put it in index.html
1515 // try to use react leaflet and help encapsulation components (and Separation of concerns)
1616
17- const [ type , setType ] = useState ( constants . types [ 'patients' ] . key ) ;
17+ const [ chosenMap , setChosenMap ] = useState ( null ) ;
1818 const [ map , setMap ] = useState ( null ) ;
1919 const [ data , setData ] = useState ( [ ] ) ;
2020 const [ zoomLevels , setZoomLevels ] = useState ( [ ] ) ;
21- const [ zoom , setZoom ] = useState ( 3 ) ;
21+ const [ zoom , setZoom ] = useState ( 0 ) ;
2222 const [ showData , setShowData ] = useState ( null ) ;
23- const [ list , setList ] = useState ( [ ] ) ;
23+ const [ list , setList ] = useState ( null ) ;
2424 const [ anchorEl , setAnchorEl ] = useState ( null ) ;
25- const [ isDialogOpen , setIsDialogOpen ] = useState ( false ) ;
26-
27- // #TODO move to a better Utility class
28- const getCurrentPosition = ( ) => {
29- return new Promise ( ( resolve , reject ) => {
30- if (
31- 'geolocation' in navigator &&
32- navigator . geolocation &&
33- typeof navigator . geolocation . getCurrentPosition === 'function'
34- ) {
35- try {
36- navigator . geolocation . getCurrentPosition (
37- ( position ) =>
38- resolve ( {
39- lat : position . coords . latitude ,
40- lng : position . coords . longitude ,
41- } ) ,
42- ( ) => {
43- reject ( {
44- message :
45- 'از طریق \n Settings > Privacy > Location Services > Safari Websites \n دسترسی موقعیت مکانی را فعال کنید.' ,
46- } ) ;
47- } ,
48- { timeout : 10000 }
49- ) ;
50- } catch ( error ) {
51- console . log (
52- 'Error when calling navigator.geolocation.getCurrentPosition: ' ,
53- error
54- ) ;
55- reject ( { message : 'مرورگر شما قابلیت مکانیابی را ندارد' } ) ;
56- }
57- } else {
58- reject ( { message : 'مرورگر شما قابلیت مکانیابی را ندارد' } ) ;
59- }
60- } ) ;
61- } ;
25+ const [ isMapFetching , setIsMapFetching ] = useState ( false ) ;
26+ const [ vpnAlert , setVpnAlert ] = useState ( true ) ;
6227
6328 // #TODO polygons -> points ot latLongs
6429 const drawPolygon = ( color , polygons ) => {
@@ -81,7 +46,8 @@ export default function Map() {
8146 // TODO explain about the code (Explain the goal for each section to help other developers).
8247 // Maybe a separate file would be better to include such these functions
8348 const getData = ( result ) => {
84- setIsDialogOpen ( false ) ;
49+ setIsMapFetching ( false ) ;
50+ setZoomLevels ( [ ] ) ;
8551 const line = result . data ;
8652 const lineNumber = line . length ;
8753 for ( let i = 0 ; i < lineNumber ; ) {
@@ -90,7 +56,7 @@ export default function Map() {
9056 let j = i + 1 ;
9157 let polygons = [ ] ;
9258 while ( j < lineNumber && line [ j ] . length > 1 ) {
93- polygons . push ( line [ j ] ) ;
59+ if ( ! isNaN ( line [ j ] [ 0 ] ) ) polygons . push ( line [ j ] ) ;
9460 j ++ ;
9561 }
9662 let sameColor = { } ;
@@ -118,20 +84,19 @@ export default function Map() {
11884
11985 const parseFile = ( url ) => {
12086 setData ( [ ] ) ;
121- setIsDialogOpen ( true ) ;
87+ setIsMapFetching ( true ) ;
12288 Papa . parse ( url , {
12389 download : true ,
12490 complete : getData ,
12591 } ) ;
12692 } ;
12793
12894 function getMapTypeLists ( ) {
129- // FIXME url ==> config file
130- setIsDialogOpen ( true ) ;
95+ setIsMapFetching ( true ) ;
13196 return fetch ( `${ process . env . REACT_APP_GET_MAP_TYPE_LISTS } ` )
13297 . then ( ( response ) => response . json ( ) )
13398 . then ( ( responseJson ) => {
134- setList ( responseJson ) ;
99+ setList ( Object . values ( responseJson ) [ 0 ] ) ;
135100 } )
136101 . catch ( ( error ) => {
137102 console . error ( error ) ;
@@ -144,7 +109,8 @@ export default function Map() {
144109 setMap (
145110 new window . L . Map ( 'map' , {
146111 // FIXME CRITICAL set token
147- key : 'web.VeNZSu3YdgN4YfaaI0AwLeoCRdi8oZ1jeOj6jm5x' ,
112+ key : process . env . REACT_APP_MAP_TOKEN ,
113+ // key: 'web.VeNZSu3YdgN4YfaaI0AwLeoCRdi8oZ1jeOj6jm5x',
148114 maptype : 'dreamy' ,
149115 poi : true ,
150116 traffic : false ,
@@ -155,46 +121,45 @@ export default function Map() {
155121 ) ;
156122 } , [ ] ) ;
157123
124+ useEffect ( ( ) => {
125+ list && setChosenMap ( list [ 0 ] ) ;
126+ } , [ list ] ) ;
127+
158128 useEffect ( ( ) => {
159129 let version ;
160130 if ( list ) {
161- const options = Object . values ( list ) [ 0 ] || [ ] ;
162- for ( let i = 0 ; i < options . length ; i ++ ) {
163- if ( ( options [ i ] || { } ) . id === type ) {
164- version = options [ i ] . version ;
131+ for ( let i = 0 ; i < list . length ; i ++ ) {
132+ if ( ( list [ i ] || { } ) . id === chosenMap . id ) {
133+ version = list [ i ] . version ;
165134 }
166135 }
167136 }
168- // FIXME config file
169137 version &&
170- parseFile ( `${ process . env . REACT_APP_MAP_CDN } ${ type } .${ version } .csv` ) ;
171- } , [ list , type ] ) ;
138+ parseFile (
139+ `${ process . env . REACT_APP_MAP_CDN } ${ chosenMap . id } .${ version } .csv`
140+ ) ;
141+ } , [ chosenMap ] ) ;
172142
173143 useEffect ( ( ) => {
174- data && setShowData ( data [ zoom ] ) ;
144+ setShowData ( ( ( data || { } ) [ zoom ] || [ ] ) [ 1 ] ) ;
175145 } , [ zoom , data ] ) ;
176146
177147 useEffect ( ( ) => {
178148 clearPolygon ( ) ;
179149 if ( showData )
180- for ( let key in showData [ 1 ] ) {
181- drawPolygon ( key , showData [ 1 ] [ key ] ) ;
150+ for ( let key in showData ) {
151+ drawPolygon ( key , showData [ key ] ) ;
182152 }
183153 } , [ map , showData ] ) ;
184154
185155 const handleLocate = async ( ) => {
186- const myLatLngLocation = await getCurrentPosition ( ) ;
156+ const myLatLngLocation = await utility . getCurrentPosition ( ) ;
187157 map . flyTo ( myLatLngLocation , 15 ) ;
188158 } ;
189159
190- const clickMenu = ( event ) => {
191- setAnchorEl ( event . currentTarget ) ;
192- } ;
193-
194- const closeMenu = ( value ) => {
195- value && setType ( value ) ;
196- setAnchorEl ( null ) ;
197- } ;
160+ useEffect ( ( ) => {
161+ setZoom ( zoomLevels . length - 1 ) ;
162+ } , [ zoomLevels ] ) ;
198163
199164 useEffect ( ( ) => {
200165 map &&
@@ -216,6 +181,15 @@ export default function Map() {
216181 } ) ;
217182 } ) ;
218183
184+ const clickMenu = ( event ) => {
185+ setAnchorEl ( event . currentTarget ) ;
186+ } ;
187+
188+ const closeMenu = ( value ) => {
189+ value && setChosenMap ( value ) ;
190+ setAnchorEl ( null ) ;
191+ } ;
192+
219193 const menu = (
220194 < Menu
221195 classes = { {
@@ -226,25 +200,61 @@ export default function Map() {
226200 open = { Boolean ( anchorEl ) }
227201 onClose = { ( ) => closeMenu ( ) }
228202 >
229- { Object . keys ( constants . types ) . map ( ( type ) => (
230- < MenuItem
231- classes = { { root : 'map-menu-item' } }
232- onClick = { ( ) => closeMenu ( constants . types [ type ] . key ) }
233- >
234- { constants . types [ type ] . text }
235- </ MenuItem >
236- ) ) }
237- < MenuItem classes = { { root : 'map-menu-item' } } disabled = { true } >
238- مراکز تشخیص کرونا
239- </ MenuItem >
240- < MenuItem classes = { { root : 'map-menu-item' } } disabled = { true } >
241- مراکز درمانی ۱۶ ساعته کرونا
242- </ MenuItem >
203+ { list &&
204+ list . map ( ( item ) => {
205+ return (
206+ < MenuItem
207+ classes = { { root : 'map-menu-item' } }
208+ onClick = { ( ) => closeMenu ( item ) }
209+ disabled = { item . id === 'testlabs' || item . id === 'hospitals' }
210+ >
211+ { item . name }
212+ </ MenuItem >
213+ ) ;
214+ } ) }
243215 </ Menu >
244216 ) ;
245217
246218 return (
247219 < div className = { `contentWrapper MapWrapper` } >
220+ < div className = "alerts" >
221+ < Collapse className = "map-alert-wrapper" in = { isMapFetching } >
222+ < Alert
223+ severity = "info"
224+ action = {
225+ < IconButton
226+ color = "inherit"
227+ size = "small"
228+ onClick = { ( ) => {
229+ setIsMapFetching ( false ) ;
230+ } }
231+ >
232+ < CloseIcon fontSize = "inherit" />
233+ </ IconButton >
234+ }
235+ >
236+ تا دریافت اطلاعات منتظر بمانید.
237+ </ Alert >
238+ </ Collapse >
239+ < Collapse className = "map-alert-wrapper" in = { vpnAlert } >
240+ < Alert
241+ severity = "warning"
242+ action = {
243+ < IconButton
244+ color = "inherit"
245+ size = "small"
246+ onClick = { ( ) => {
247+ setVpnAlert ( false ) ;
248+ } }
249+ >
250+ < CloseIcon fontSize = "inherit" />
251+ </ IconButton >
252+ }
253+ >
254+ در صورت اتصال، vpn دستگاه را قطع کنید.
255+ </ Alert >
256+ </ Collapse >
257+ </ div >
248258 < div className = "map-button-wrapper" >
249259 < button
250260 type = "button"
@@ -255,11 +265,11 @@ export default function Map() {
255265 </ button >
256266 < button
257267 type = "button"
258- name = "type "
268+ name = "chosenMap "
259269 className = "map-button type"
260270 onClick = { ( e ) => clickMenu ( e ) }
261271 >
262- < div > { constants . types [ type ] . text } </ div >
272+ < div > { ( chosenMap || { } ) . name } </ div >
263273 < ExpandMoreIcon />
264274 </ button >
265275 </ div >
@@ -276,18 +286,12 @@ export default function Map() {
276286 } }
277287 />
278288 < div className = "comment-wrapper" >
279- < div className = "map-comment" > { constants . types [ type ] . comment } </ div >
289+ < div className = "map-comment" > { ( chosenMap || { } ) . comment } </ div >
280290 </ div >
281291 < div className = "logo-wrapper" >
282292 < img src = { logo } alt = "" />
283293 </ div >
284294 { menu }
285- < Dialog open = { isDialogOpen } >
286- < div className = "dialog-content" >
287- < CircularProgress />
288- < Box ml = { 3 } > { 'لطفا کمی صبر کنید.' } </ Box >
289- </ div >
290- </ Dialog >
291295 </ div >
292296 ) ;
293297}
0 commit comments