Skip to content

Commit b686c49

Browse files
authored
Merge pull request #40 from mask-application/map-improvement
map: change loading - add vpn warning - fix zoomLevels bug
2 parents 62b5efc + b47c620 commit b686c49

File tree

7 files changed

+183
-169
lines changed

7 files changed

+183
-169
lines changed

.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ REACT_APP_BULK_EVENT=/api/v1/event/bulk
55
REACT_APP_GET_MAP_TYPE_LISTS=/map-cdn/maps.json
66
REACT_APP_MAP_CDN=/map-cdn/
77

8-
REACT_APP_GET_INFECTED_JSON_DATA=/data/infected.json
8+
REACT_APP_GET_INFECTED_JSON_DATA=/data/infected.json
9+
REACT_APP_MAP_TOKEN=web.VeNZSu3YdgN4YfaaI0AwLeoCRdi8oZ1jeOj6jm5x

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"@material-ui/core": "^4.9.7",
77
"@material-ui/icons": "^4.9.1",
8+
"@material-ui/lab": "^4.0.0-alpha.47",
89
"@testing-library/jest-dom": "^4.2.4",
910
"@testing-library/react": "^9.5.0",
1011
"@testing-library/user-event": "^7.2.1",

public/index.html

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<head>
44
<meta charset="utf-8" />
55
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6-
<!-- iOS 9 bug fix https://stackoverflow.com/q/33767533 -->
76
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
7+
<meta name="mobile-web-app-capable" content="yes">
88
<meta name="theme-color" content="#000000" />
99
<meta
1010
name="description"
@@ -43,14 +43,13 @@
4343
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
4444
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
4545

46-
ym(61518034, "init", {
46+
ym(61536613, "init", {
4747
clickmap:true,
4848
trackLinks:true,
49-
accurateTrackBounce:true,
50-
webvisor:true
49+
accurateTrackBounce:true
5150
});
5251
</script>
53-
<noscript><div><img src="https://mc.yandex.ru/watch/61518034" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
52+
<noscript><div><img src="https://mc.yandex.ru/watch/61536613" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
5453
<!-- /Yandex.Metrika counter -->
5554
</head>
5655
<body dir="rtl">

src/components/Map/Map.js

Lines changed: 99 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,29 @@
11
import React, { useEffect, useState } from 'react';
22
import './MapStyle.scss';
3-
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
4-
import MyLocationIcon from '@material-ui/icons/MyLocation';
3+
import * as utility from './utility';
54
import Papa from 'papaparse';
65
import * 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';
116
import 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

1313
export 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

Comments
 (0)