esoftplay-event 0.0.2-s → 0.0.2-u

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  // withHooks
2
+ import { doc, getFirestore, runTransaction } from '@react-native-firebase/firestore';
2
3
  import { Canvas, Group, RoundedRect, Text, useFont } from '@shopify/react-native-skia';
3
4
  import { EventButton } from 'esoftplay/cache/event/button/import';
4
5
  import { EventHeader } from 'esoftplay/cache/event/header/import';
5
6
  import { EventMessage } from 'esoftplay/cache/event/message/import';
7
+ import { LibBackground_task } from 'esoftplay/cache/lib/background_task/import';
6
8
  import { LibCurl } from 'esoftplay/cache/lib/curl/import';
7
9
  import { LibIcon } from 'esoftplay/cache/lib/icon/import';
8
10
  import { LibNavigation } from 'esoftplay/cache/lib/navigation/import';
@@ -11,8 +13,9 @@ import { LibTextstyle } from 'esoftplay/cache/lib/textstyle/import';
11
13
  import { LibToastProperty } from 'esoftplay/cache/lib/toast/import';
12
14
  import { UseMap } from 'esoftplay/cache/use/map/import';
13
15
  import esp from 'esoftplay/esp';
16
+ import useLazyState from 'esoftplay/lazy';
14
17
  import useSafeState from 'esoftplay/state';
15
- import React, { useCallback, useEffect, useState } from 'react';
18
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
16
19
  import { Dimensions, Pressable, ScrollView, View } from 'react-native';
17
20
  import { TapGestureHandler, TapGestureHandlerStateChangeEvent } from 'react-native-gesture-handler';
18
21
 
@@ -23,10 +26,38 @@ export interface EventSeat_map_newArgs {
23
26
  export interface EventSeat_map_newProps {
24
27
 
25
28
  }
29
+
30
+ function getEventPath() {
31
+ return "event" + (esp.isDebug("") ? "BBT" : "BBO")
32
+ }
33
+
34
+ const mainPath = [getEventPath(), "event_seat", "seat_index"]
35
+ export function clearHoldedSeats() {
36
+ const app: any = esp.mod("firestore/index")().instance()
37
+ const firestoreUser = esp.mod("firestore/index")().getUserData(app.name)
38
+ esp.mod("firestore/index")().getCollectionIds(app, mainPath, [["uid", "==", firestoreUser?.uid], ["status", "==", "holding"]], [], (ids) => {
39
+ if (ids?.length > 0)
40
+ esp.mod("firestore/index")().deleteBatchDocument(app, mainPath, ids, () => {
41
+ }, console.log)
42
+ }, console.log)
43
+ }
44
+
26
45
  export default function m(props: any): any {
27
46
  const { dataTicket, url } = LibNavigation.getArgsAll<any>(props)
28
47
  const qty = dataTicket?.qty
29
48
 
49
+ const eventData = {
50
+ event_id: dataTicket?.event_id,
51
+ price_id: dataTicket?.selected_ticket?.price_id,
52
+ ondate: dataTicket?.ondate || dataTicket?.selected_ticket?.list?.ondate
53
+ }
54
+
55
+ const app: any = esp.mod("firestore/index")().instance()
56
+ const firestoreUser = esp.mod("firestore/index")().getUserData(app.name)
57
+
58
+ const [, setHoldedSeats, getHoldedSeats] = useLazyState<string[]>([])
59
+ const [, setLoadingSeats, getLoadingSeats] = useSafeState<string[]>([])
60
+
30
61
  const deviceWidth = Dimensions.get('window').width;
31
62
  const [scale, setScale] = useState(1);
32
63
  const [boundingBox, setBoundingBox] = useSafeState({ "x1": 1, "x2": 2, "y1": 1, "y2": 2 })
@@ -80,38 +111,161 @@ export default function m(props: any): any {
80
111
 
81
112
  const handleTap = useCallback((event: TapGestureHandlerStateChangeEvent) => {
82
113
  if (event.nativeEvent.state !== 5) return;
83
- // Adjust tap coordinates for scale
114
+
84
115
  const x = event.nativeEvent.x / scale;
85
116
  const y = event.nativeEvent.y / scale;
117
+
86
118
  for (let i = 0; i < getData()?.length; i++) {
87
119
  const [sx, sy, seatName, status] = getData()?.[i];
120
+
88
121
  const xSize = (boxSize / 2) + (sx * boxSize);
89
122
  const ySize = (boxSize / 2) + (sy * boxSize);
90
123
 
91
124
  if (x >= xSize && x <= xSize + boxSize && y >= ySize && y <= ySize + boxSize) {
92
- if (status == 0) {
93
- setSelectedSeat((prev: any) => {
94
- if (!prev?.includes(seatName)) {
95
- if (prev?.length < qty) {
96
- return [...prev, seatName];
97
- }
98
- LibToastProperty.show(esp.lang("event/seat_map", "max_seat", qty))
99
- return prev;
100
- }
101
- return prev.filter((s: string) => s != seatName);
102
- });
125
+ if (status != 0) return;
126
+ if (getLoadingSeats().includes(seatName)) return;
127
+
128
+ const isSelected = getSelectedSeat().includes(seatName);
129
+
130
+ const seat: any = getHoldedSeats().find((x: any) => x.id === seatName);
131
+ const isHolded = !!seat;
132
+ const isMine = seat?.uid === firestoreUser?.uid;
133
+
134
+ if (isHolded && !isMine) {
135
+ LibToastProperty.show(esp.lang("event/seat_map_new", "other_user"));
136
+ return;
103
137
  }
138
+
139
+ if (!isSelected && getSelectedSeat().length >= qty) {
140
+ LibToastProperty.show(esp.lang("event/seat_map", "max_seat", qty));
141
+ return;
142
+ }
143
+
144
+ const action = isSelected ? "release" : "hold";
145
+ setSelectedSeat((prev: any) => {
146
+ if (isSelected) {
147
+ return prev.filter((s: string) => s !== seatName);
148
+ } else {
149
+ return [...prev, seatName];
150
+ }
151
+ });
152
+
153
+ setLoadingSeats(prev => [...prev, seatName]);
154
+ handleSelectedSeat(seatName, action)
155
+ .then(() => { })
156
+ .catch((err: any) => {
157
+ // setSelectedSeat((prev: any) => {
158
+ // if (action === "hold") {
159
+ // return prev.filter((s: string) => s !== seatName);
160
+ // } else {
161
+ // return [...prev, seatName];
162
+ // }
163
+ // });
164
+ // LibToastProperty.show(err?.message || esp.lang("event/seat_map_new", "failed_sync"));
165
+ })
166
+ .finally(() => {
167
+ setLoadingSeats(prev => prev.filter(s => s !== seatName));
168
+ });
169
+
104
170
  return;
105
171
  }
172
+ }
173
+ }, [data, boxSize, scale, firestoreUser]);
106
174
 
175
+ async function handleSelectedSeat(seatName: string, action?: "hold" | "release") {
176
+ const pathKey = `${eventData?.event_id}_${eventData?.price_id}_${eventData?.ondate}_${seatName}`
177
+ const path = [...mainPath, pathKey]
178
+ const fixedPath = esp.mod("firestore/index")().castPathToString(path)
179
+
180
+ try {
181
+ await holdSeat(fixedPath, pathKey, action)
182
+ } catch (error) {
183
+ console.warn("Failed to hold seat:", error, firestoreUser.uid);
184
+ throw error
107
185
  }
108
- }, [data, boxSize, scale]);
186
+ }
187
+
188
+ const cat_id = `${eventData?.price_id}_${eventData?.ondate}`
189
+ async function holdSeat(path: string, pathKey: string, action?: "hold" | "release") {
190
+ const uid = firestoreUser?.uid
191
+
192
+ const db = getFirestore(app)
193
+ const seatRef = doc(db, path);
194
+
195
+ await runTransaction(db, async (tx) => {
196
+ const snap = await tx.get(seatRef);
197
+ const value = {
198
+ status: "holding",
199
+ id: pathKey,
200
+ cat_id,
201
+ uid,
202
+ updated: Date.now(),
203
+ }
204
+
205
+ if (!snap.exists()) {
206
+ tx.set(seatRef, value);
207
+ return;
208
+ }
209
+
210
+ const data: any = snap.data();
211
+ if (data.status === "holding" && data.uid === uid) {
212
+ if (action === "release") {
213
+ tx.update(seatRef, {
214
+ status: "available"
215
+ });
216
+ return;
217
+ } else {
218
+ return;
219
+ }
220
+ }
221
+ if (data.status === "available") {
222
+ tx.update(seatRef, value);
223
+ return;
224
+ }
225
+ throw new Error(esp.lang("event/seat_map_new", "seat_not_avail"));
226
+ });
227
+ }
109
228
 
110
229
  useEffect(() => {
111
230
  loadDataSeatmapBooked()
112
231
  return () => LibNavigation.cancelBackResult(LibNavigation.getResultKey(props))
113
232
  }, [])
114
233
 
234
+ useEffect(() => {
235
+ getAllHeldSeats()
236
+ updateTimestamp()
237
+ LibBackground_task.set("1", getAllHeldSeats, 2000)
238
+ LibBackground_task.set("2", updateTimestamp, 3000)
239
+ return () => {
240
+ LibBackground_task.clear("1")
241
+ LibBackground_task.clear("2")
242
+ }
243
+ }, [])
244
+
245
+ function getAllHeldSeats() {
246
+ esp.mod("firestore/index")().getCollectionWhere(app, mainPath, [
247
+ ["cat_id", "==", cat_id],
248
+ ["uid", "!=", firestoreUser?.uid],
249
+ ["status", "==", "holding"],
250
+ ], (docs) => {
251
+ const seats = docs.map((d: any) => ({ ...d.data, id: d.id.split("_").pop() }));
252
+ setHoldedSeats(seats)()
253
+ }, console.warn)
254
+ }
255
+
256
+ function updateTimestamp() {
257
+ esp.mod("firestore/index")().getCollectionIds(app, mainPath, [
258
+ ["cat_id", "==", cat_id],
259
+ ["uid", "==", firestoreUser?.uid],
260
+ ["status", "==", "holding"],
261
+ ], [], (ids) => {
262
+ esp.mod("firestore/index")().updateBatchDocument(app, mainPath, ids,
263
+ [{ key: "updated", value: Date.now() }],
264
+ () => { },
265
+ console.warn)
266
+ }, console.warn)
267
+ }
268
+
115
269
  function updateIndexByRes(data: any, res: any) {
116
270
  const resArr = res.split(",").map((item: any) => item.trim()); // biar aman dari spasi
117
271
  return data.map((row: any) => {
@@ -136,6 +290,14 @@ export default function m(props: any): any {
136
290
  })
137
291
  }
138
292
 
293
+ const holdedSeatsMap = useMemo(() => {
294
+ const map: any = {};
295
+ getHoldedSeats().forEach((x: any) => {
296
+ map[x.id] = x.uid;
297
+ });
298
+ return map;
299
+ }, [getHoldedSeats()]);
300
+
139
301
  function loadDataSeatmapBooked() {
140
302
  new LibCurl("v3/event_seat_booked", {
141
303
  event_id: dataTicket?.event_id,
@@ -204,7 +366,10 @@ export default function m(props: any): any {
204
366
  getData()?.map(([x, y, name, status], i) => {
205
367
  let newName = name?.replace(/^.*#/, "")
206
368
  const isSelected = getSelectedSeat()?.includes(name)
207
- const color = isSelected ? "#8EF67B" : getColorByStatus(status)
369
+ const uid = holdedSeatsMap[name];
370
+ const isHolded = !!uid;
371
+ const isMine = uid === firestoreUser?.uid;
372
+ const color = isSelected ? "#8EF67B" : (isHolded && !isMine) ? getColorByStatus(9) : getColorByStatus(status)
208
373
  const xSize = (boxSize / 2) + (x * boxSize)
209
374
  const ySize = (boxSize / 2) + (y * boxSize)
210
375
 
@@ -290,22 +455,22 @@ export default function m(props: any): any {
290
455
  function getLegends() {
291
456
  const colors: any = [
292
457
  ["#fff", esp.lang("event/seat_map", "available"), 0],
293
- ["#8EF67B", esp.lang("event/seat_map", "chosen"), "-1"],
458
+ // ["#8EF67B", esp.lang("event/seat_map", "chosen"), "-1"],
294
459
  ["#2EBBE8", esp.lang("event/seat_map", "reserved"), 3],
295
- ["#6C432C", esp.lang("event/seat_map", "chosen_by"), 7],
296
- ["#f1f2f3", esp.lang("event/seat_map", "way"), 5],
297
- ["#9FA1A4", esp.lang("event/seat_map", "not_sold"), 1],
460
+ // ["#6C432C", esp.lang("event/seat_map", "chosen_by"), 7],
461
+ // ["#f1f2f3", esp.lang("event/seat_map", "way"), 5],
462
+ // ["#9FA1A4", esp.lang("event/seat_map", "not_sold"), 1],
298
463
  ["#6B71E6", esp.lang("event/seat_map", "seat_hold"), 2],
299
- ["#FF4866", esp.lang("event/seat_map", "wall"), 6],
300
- ["#FFA601", esp.lang("event/seat_map", "other_type"), 4],
301
- ["purple", esp.lang("event/seat_map", "stage"), 8]
464
+ // ["#FF4866", esp.lang("event/seat_map", "wall"), 6],
465
+ // ["#FFA601", esp.lang("event/seat_map", "other_type"), 4],
466
+ // ["purple", esp.lang("event/seat_map", "stage"), 8]
467
+ ["#7e2a0c", esp.lang("event/seat_map_new", "picked_byother"), 9]
302
468
  ]
303
469
  return colors
304
470
  }
305
471
 
306
472
  function getColorByStatus(statuses: number) {
307
473
  const colors: any = {
308
- 8: 'purple',
309
474
  0: '#fff',
310
475
  1: "#9FA1A4",
311
476
  2: "#6B71E6",
@@ -313,7 +478,9 @@ function getColorByStatus(statuses: number) {
313
478
  4: "#FFA601",
314
479
  5: "#fff",
315
480
  6: "#FF4866",
316
- 7: "#6C432C"
481
+ 7: "#6C432C",
482
+ 8: 'purple',
483
+ 9: "#7e2a0c"
317
484
  }
318
485
  return colors[statuses]
319
486
  }
package/event/test.tsx CHANGED
@@ -142,7 +142,7 @@ export default function m(props: any): any {
142
142
  height: height * scale,
143
143
  padding: 10,
144
144
  backgroundColor: LibStyle.colorBgGrey,
145
-
145
+
146
146
  }}>
147
147
  {
148
148
  data.map(([x, y, name, status], i) => {
@@ -211,15 +211,15 @@ export default function m(props: any): any {
211
211
  function getLegends() {
212
212
  const colors: any = [
213
213
  ["#fff", esp.lang("event/seat_map", "available"), 0],
214
- ["#8EF67B", esp.lang("event/seat_map", "chosen"), "-1"],
214
+ // ["#8EF67B", esp.lang("event/seat_map", "chosen"), "-1"],
215
215
  ["#2EBBE8", esp.lang("event/seat_map", "reserved"), 3],
216
- ["#6C432C", esp.lang("event/seat_map", "chosen_by"), 7],
217
- ["#f1f2f3", esp.lang("event/seat_map", "way"), 5],
218
- ["#9FA1A4", esp.lang("event/seat_map", "not_sold"), 1],
216
+ // ["#6C432C", esp.lang("event/seat_map", "chosen_by"), 7],
217
+ // ["#f1f2f3", esp.lang("event/seat_map", "way"), 5],
218
+ // ["#9FA1A4", esp.lang("event/seat_map", "not_sold"), 1],
219
219
  ["#6B71E6", esp.lang("event/seat_map", "seat_hold"), 2],
220
- ["#FF4866", esp.lang("event/seat_map", "wall"), 6],
221
- ["#FFA601", esp.lang("event/seat_map", "other_type"), 4],
222
- ["purple", esp.lang("event/seat_map", "stage"), 8]
220
+ // ["#FF4866", esp.lang("event/seat_map", "wall"), 6],
221
+ // ["#FFA601", esp.lang("event/seat_map", "other_type"), 4],
222
+ // ["purple", esp.lang("event/seat_map", "stage"), 8]
223
223
  ]
224
224
  return colors
225
225
  }
package/id.json CHANGED
@@ -1020,6 +1020,9 @@
1020
1020
  "transfer_mbanking_instruction": "Petunjuk Transfer mBanking",
1021
1021
  "virtual_number_account": "No Virtual Account :"
1022
1022
  },
1023
+ "event/order_detail_return": {
1024
+ "send_back_ticket": "Kembalikan Tiket"
1025
+ },
1023
1026
  "event/order_detail_share": {
1024
1027
  "cancel": "Batal",
1025
1028
  "chose_ticket": "PILIH TIKET",
@@ -1369,6 +1372,12 @@
1369
1372
  "zoom_out": "Memperkecil denah..",
1370
1373
  "zoom_out_max": "Tidak dapat memperkecil lagi"
1371
1374
  },
1375
+ "event/seat_map_new": {
1376
+ "failed_sync": "Gagal sinkronisasi kursi",
1377
+ "other_user": "Seat sedang dipilih user lain",
1378
+ "picked_byother": "Dipilih orang lain",
1379
+ "seat_not_avail": "Seat tidak tersedia"
1380
+ },
1372
1381
  "event/seat_map_test": {
1373
1382
  "front": "DEPAN",
1374
1383
  "header_title": "Pilih Kursi"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esoftplay-event",
3
- "version": "0.0.2-s",
3
+ "version": "0.0.2-u",
4
4
  "description": "event module on esoftplay framework",
5
5
  "main": "index.js",
6
6
  "scripts": {