1
|
|
|
import React, { useEffect, useState, useCallback } from "react"; |
2
|
|
|
import { Map } from "../components"; |
3
|
|
|
import { useLocation } from "react-router-dom"; |
4
|
|
|
import { BsFillTrashFill } from "react-icons/bs"; |
5
|
|
|
import utils from "../utils/utils"; |
6
|
|
|
import cities from "../models/cities"; |
7
|
|
|
|
8
|
|
|
const Zones = () => { |
9
|
|
|
const location = useLocation(); |
10
|
|
|
const { id, coords } = location.state; |
11
|
|
|
const [selected, setSelected] = useState(); |
12
|
|
|
const [isCreate, setIsCreate] = useState(false); |
13
|
|
|
const [zoneMarkers, setZoneMarkers] = useState([]); |
14
|
|
|
const [zoneType, setZoneType] = useState("parkingZone"); |
15
|
|
|
const [zoneId, setZoneId] = useState(); |
16
|
|
|
const [reverse, setReverse] = useState([]); |
17
|
|
|
|
18
|
|
|
useEffect(() => { |
19
|
|
|
fetchData(); |
20
|
|
|
}, []); |
21
|
|
|
|
22
|
|
|
async function fetchData() { |
23
|
|
|
const res = await cities.getCityById(id); |
24
|
|
|
setSelected(res.city); |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
const handleCreate = async () => { |
28
|
|
|
const newZone = { |
29
|
|
|
zoneType: zoneType, |
30
|
|
|
type: "MultipPolygon", |
31
|
|
|
coordinates: zoneMarkers, |
32
|
|
|
}; |
33
|
|
|
|
34
|
|
|
setIsCreate(false); |
35
|
|
|
setZoneMarkers([]); |
36
|
|
|
setReverse([]); |
37
|
|
|
setZoneType("parkingZone"); |
38
|
|
|
await cities.registerZone(id, newZone); |
39
|
|
|
await fetchData(); |
40
|
|
|
}; |
41
|
|
|
|
42
|
|
|
const handleClickOnZone = (id) => { |
43
|
|
|
setZoneId(id); |
44
|
|
|
}; |
45
|
|
|
|
46
|
|
|
const handleDeleteZone = async (zoneID) => { |
47
|
|
|
await cities.deleteZone(zoneID, id); |
48
|
|
|
await fetchData(); |
49
|
|
|
}; |
50
|
|
|
|
51
|
|
|
const handleDeleteCoords = (coords) => { |
52
|
|
|
let allCoords = zoneMarkers; |
53
|
|
|
let revCoords = reverse; |
54
|
|
|
allCoords = allCoords.filter((element) => { |
55
|
|
|
if (element[0] !== coords[0] && element[1] !== coords[1]) { |
56
|
|
|
return element; |
57
|
|
|
} |
58
|
|
|
}); |
59
|
|
|
revCoords = revCoords.filter((element) => { |
60
|
|
|
if (element[0] !== coords[1] && element[1] !== coords[0]) { |
61
|
|
|
return element; |
62
|
|
|
} |
63
|
|
|
}); |
64
|
|
|
setZoneMarkers(allCoords); |
65
|
|
|
setReverse(revCoords); |
66
|
|
|
}; |
67
|
|
|
|
68
|
|
|
const zoneList = () => { |
69
|
|
|
return selected.zones.map((item, index) => { |
70
|
|
|
return ( |
71
|
|
|
<div |
72
|
|
|
className="p-3 border-b border-gray-300 |
73
|
|
|
flex flex-row justify-between" |
74
|
|
|
key={index} |
75
|
|
|
> |
76
|
|
|
<button |
77
|
|
|
onClick={(e) => { |
78
|
|
|
e.preventDefault(); |
79
|
|
|
handleClickOnZone(item._id); |
80
|
|
|
}} |
81
|
|
|
> |
82
|
|
|
{index} - {utils.zoneNameTranslate(item.zoneType)} |
83
|
|
|
</button> |
84
|
|
|
<button onClick={() => handleDeleteZone(item._id)} className="px-5"> |
85
|
|
|
<span className="text-slate-800 hover:text-red-600 transition-colors"> |
86
|
|
|
<BsFillTrashFill /> |
87
|
|
|
</span> |
88
|
|
|
</button> |
89
|
|
|
</div> |
90
|
|
|
); |
91
|
|
|
}); |
92
|
|
|
}; |
93
|
|
|
|
94
|
|
|
const createZoneList = () => { |
95
|
|
|
return zoneMarkers.map((item, index) => { |
96
|
|
|
return ( |
97
|
|
|
<div |
98
|
|
|
className="p-3 border-b border-gray-300 |
99
|
|
|
flex flex-row justify-between" |
100
|
|
|
key={index} |
101
|
|
|
> |
102
|
|
|
<div className="flex flex-row"> |
103
|
|
|
<h1 className="pr-7">{index}</h1> |
104
|
|
|
|
105
|
|
|
<div> |
106
|
|
|
<p>Lat - {item[1]}</p> |
107
|
|
|
<p>Lon - {item[0]}</p> |
108
|
|
|
</div> |
109
|
|
|
</div> |
110
|
|
|
<button |
111
|
|
|
onClick={() => { |
112
|
|
|
handleDeleteCoords(item); |
113
|
|
|
}} |
114
|
|
|
className="px-5" |
115
|
|
|
> |
116
|
|
|
<span className="text-slate-800 hover:text-red-600 transition-colors"> |
117
|
|
|
<BsFillTrashFill /> |
118
|
|
|
</span> |
119
|
|
|
</button> |
120
|
|
|
</div> |
121
|
|
|
); |
122
|
|
|
}); |
123
|
|
|
}; |
124
|
|
|
|
125
|
|
|
if (!selected) { |
126
|
|
|
return <div>loading...</div>; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return ( |
130
|
|
|
<div className="w-full"> |
131
|
|
|
<div className="w-full p-5 flex flex-row justify-between"> |
132
|
|
|
<h1 className="text-3xl">Zone Manager</h1> |
133
|
|
|
{isCreate ? ( |
134
|
|
|
<div className="flex flex-row "> |
135
|
|
|
<div className="px-2"> |
136
|
|
|
{/* <label className="text-xs">Zone type</label> */} |
137
|
|
|
<select |
138
|
|
|
name="zoneType" |
139
|
|
|
onChange={(e) => setZoneType(e.target.value)} |
140
|
|
|
className=" bg-gray-50 border border-gray-300 text-gray-900 |
141
|
|
|
text-sm rounded-lg block p-2.5" |
142
|
|
|
> |
143
|
|
|
<option value="parkingZone">Parking Zone</option> |
144
|
|
|
<option value="noParkingZone">No Parking Zone</option> |
145
|
|
|
<option value="chargingZone">Charging Zone</option> |
146
|
|
|
<option value="bonusParkingZone">Bonus Parking</option> |
147
|
|
|
</select> |
148
|
|
|
</div> |
149
|
|
|
<button |
150
|
|
|
onClick={handleCreate} |
151
|
|
|
className="py-3 w-32 transition-colors bg-sidebarHover |
152
|
|
|
hover:bg-sidebarBlue text-white rounded-full mx-2" |
153
|
|
|
> |
154
|
|
|
Add Zone |
155
|
|
|
</button> |
156
|
|
|
<button |
157
|
|
|
onClick={() => { |
158
|
|
|
setZoneMarkers([]); |
159
|
|
|
setReverse([]); |
160
|
|
|
setIsCreate(false); |
161
|
|
|
}} |
162
|
|
|
className="py-3 w-32 transition-colors bg-red-600 |
163
|
|
|
hover:bg-red-700 text-white rounded-full mx-2" |
164
|
|
|
> |
165
|
|
|
Cancel Create |
166
|
|
|
</button> |
167
|
|
|
</div> |
168
|
|
|
) : ( |
169
|
|
|
<button |
170
|
|
|
onClick={() => { |
171
|
|
|
setIsCreate(true); |
172
|
|
|
}} |
173
|
|
|
className="py-3 w-32 transition-colors bg-sidebarHover |
174
|
|
|
hover:bg-sidebarBlue text-white rounded-full" |
175
|
|
|
> |
176
|
|
|
Create Zone |
177
|
|
|
</button> |
178
|
|
|
)} |
179
|
|
|
</div> |
180
|
|
|
<div className="flex flex-row"> |
181
|
|
|
<div className="px-5 w-2/3"> |
182
|
|
|
<div className=" h-132 overflow-hidden shadow-md rounded-xl"> |
183
|
|
|
{selected ? ( |
184
|
|
|
<Map |
185
|
|
|
zoom={14} |
186
|
|
|
center={coords} |
187
|
|
|
cities={[selected]} |
188
|
|
|
zoneId={zoneId} |
189
|
|
|
add={isCreate} |
190
|
|
|
zoneMarkers={zoneMarkers} |
191
|
|
|
setZoneMarkers={setZoneMarkers} |
192
|
|
|
noPopup={isCreate} |
193
|
|
|
reverse={reverse} |
194
|
|
|
setReverse={setReverse} |
195
|
|
|
/> |
196
|
|
|
) : ( |
197
|
|
|
<> |
198
|
|
|
<div>No data...</div> |
199
|
|
|
</> |
200
|
|
|
)} |
201
|
|
|
</div> |
202
|
|
|
</div> |
203
|
|
|
<div className="w-1/3 shadow-md rounded-xl p-3 h-132"> |
204
|
|
|
{isCreate ? ( |
205
|
|
|
<div> |
206
|
|
|
<h1 className="text-xl pb-2">Create Zone</h1> |
207
|
|
|
<div className="overflow-scroll h-130">{createZoneList()}</div> |
208
|
|
|
</div> |
209
|
|
|
) : ( |
210
|
|
|
<div> |
211
|
|
|
<h1 className="text-xl pb-2">Area Overview</h1> |
212
|
|
|
<div className="overflow-scroll h-130">{zoneList()}</div> |
213
|
|
|
</div> |
214
|
|
|
)} |
215
|
|
|
</div> |
216
|
|
|
</div> |
217
|
|
|
</div> |
218
|
|
|
); |
219
|
|
|
}; |
220
|
|
|
|
221
|
|
|
export default Zones; |
222
|
|
|
|