iticket-seatingplan-dev 2.0.7 → 2.0.17

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.
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = Controls;
7
- var _reactLeafletCustomControl = _interopRequireDefault(require("react-leaflet-custom-control"));
7
+ var _Control = _interopRequireDefault(require("./Control"));
8
8
  var _reactLeafletDraw = require("react-leaflet-draw");
9
9
  var _reactLeaflet = require("react-leaflet");
10
10
  var _react = _interopRequireWildcard(require("react"));
@@ -35,7 +35,7 @@ function Controls(_ref) {
35
35
  } = _ref;
36
36
  const [isLegendOpen, setIsLegendOpen] = (0, _react.useState)(true);
37
37
  const map = (0, _reactLeaflet.useMap)();
38
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, preventOrphanedSeats && /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
38
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, preventOrphanedSeats && /*#__PURE__*/_react.default.createElement(_Control.default, {
39
39
  position: "topright"
40
40
  }, /*#__PURE__*/_react.default.createElement("div", {
41
41
  className: "extra-controls seat-quantity-control"
@@ -49,7 +49,7 @@ function Controls(_ref) {
49
49
  height: "16px",
50
50
  width: "16px",
51
51
  strokeWidth: "2"
52
- })))), /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
52
+ })))), /*#__PURE__*/_react.default.createElement(_Control.default, {
53
53
  position: "bottomright"
54
54
  }, /*#__PURE__*/_react.default.createElement("div", {
55
55
  className: "legendBox"
@@ -90,7 +90,7 @@ function Controls(_ref) {
90
90
  src: _encodedSvgs.userIcon,
91
91
  width: 15,
92
92
  height: 15
93
- }), /*#__PURE__*/_react.default.createElement("p", null, "membership seats"))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null)))), /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
93
+ }), /*#__PURE__*/_react.default.createElement("p", null, "membership seats"))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null)))), /*#__PURE__*/_react.default.createElement(_Control.default, {
94
94
  position: "topleft"
95
95
  }, /*#__PURE__*/_react.default.createElement("div", {
96
96
  className: "extra-controls"
@@ -120,7 +120,7 @@ function Controls(_ref) {
120
120
  style: {
121
121
  height: "17px"
122
122
  }
123
- })))), /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
123
+ })))), /*#__PURE__*/_react.default.createElement(_Control.default, {
124
124
  position: "topleft"
125
125
  }, /*#__PURE__*/_react.default.createElement("div", {
126
126
  className: "extra-controls full-screen-control"
@@ -135,7 +135,7 @@ function Controls(_ref) {
135
135
  style: {
136
136
  height: "24px"
137
137
  }
138
- })))), canMultiSelect && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
138
+ })))), canMultiSelect && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Control.default, {
139
139
  position: "bottomleft"
140
140
  }, /*#__PURE__*/_react.default.createElement("div", {
141
141
  className: "extra-controls multi-select-control"
@@ -215,7 +215,7 @@ function Controls(_ref) {
215
215
  onMounted: drawInstance => {
216
216
  drawRef.current = drawInstance;
217
217
  }
218
- }))), /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
218
+ }))), /*#__PURE__*/_react.default.createElement(_Control.default, {
219
219
  position: "topright"
220
220
  }, /*#__PURE__*/_react.default.createElement("button", {
221
221
  title: "Close full screen",
@@ -20,7 +20,8 @@ function HoverPopup(_ref) {
20
20
  show,
21
21
  availablePrices,
22
22
  prevHovered,
23
- isTouchScreen
23
+ isTouchScreen,
24
+ canUseHolds
24
25
  } = _ref;
25
26
  const map = (0, _reactLeaflet.useMap)();
26
27
  const ref = (0, _react.useRef)(null);
@@ -111,7 +112,16 @@ function HoverPopup(_ref) {
111
112
  key: "".concat(s).concat(i),
112
113
  className: "seat-name"
113
114
  }, s);
114
- })))), /*#__PURE__*/_react.default.createElement("div", {
115
+ })))), hoveredSeat !== null && hoveredSeat !== void 0 && hoveredSeat.ticketHold && canUseHolds ? /*#__PURE__*/_react.default.createElement("div", {
116
+ className: "hover-popup-ticket-hold"
117
+ }, /*#__PURE__*/_react.default.createElement("div", {
118
+ className: "held-by"
119
+ }, /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement("strong", null, "Held By:"), " ", hoveredSeat.ticketHold.CreatedBy), /*#__PURE__*/_react.default.createElement("p", {
120
+ className: "ticket-hold-category",
121
+ style: {
122
+ backgroundColor: "".concat(hoveredSeat.ticketHold.TicketHoldCategoryColor, "70")
123
+ }
124
+ }, hoveredSeat.ticketHold.TicketHoldCategory)), hoveredSeat.ticketHold.Note && /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement("strong", null, "Note:"), " ", hoveredSeat.ticketHold.Note)) : null, /*#__PURE__*/_react.default.createElement("div", {
115
125
  className: "hover-popup-price"
116
126
  }, /*#__PURE__*/_react.default.createElement("p", {
117
127
  className: "hover-popup-psname"
@@ -61,7 +61,9 @@ function SeatMap(_ref) {
61
61
  setSeatsToRemove,
62
62
  setRemoveMultipleSeatsPopupOpen,
63
63
  setInvalidSeatsPopupOpen,
64
- batchAddTicketsToCart
64
+ batchAddTicketsToCart,
65
+ canUseHolds,
66
+ bookingMode
65
67
  } = _ref;
66
68
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
67
69
  const [highlightedSeats, setHighlightedSeats] = (0, _react.useState)([]);
@@ -80,6 +82,7 @@ function SeatMap(_ref) {
80
82
  const resetTooltipTimeoutRef = (0, _react.useRef)(null);
81
83
  const hideTooltipTimeoutRef = (0, _react.useRef)(null);
82
84
  const map = (0, _reactLeaflet.useMap)();
85
+ const isPOS = bookingMode === _utils.bookingModes.POS;
83
86
  const imgBounds = [[0, 0], [-_constants.SCALE, width / height * _constants.SCALE]];
84
87
  const seatsMap = new Map(seats.seats.map(s => {
85
88
  const latlng = (0, _utils.getSeatCenterLatLng)(s, height, width, imgBounds);
@@ -87,7 +90,7 @@ function SeatMap(_ref) {
87
90
  center: latlng
88
91
  })];
89
92
  }));
90
- const isOrphanMode = (seats === null || seats === void 0 ? void 0 : seats.preventOrphanedSeats) && desiredSeatQuantity > 0;
93
+ const isOrphanMode = (seats === null || seats === void 0 ? void 0 : seats.preventOrphanedSeats) && desiredSeatQuantity > 0 && mode === _utils.modes.SINGLE;
91
94
  const isTouchScreen = (0, _utils.getIsTouchScreen)();
92
95
 
93
96
  // L.drawLocal.draw.toolbar.buttons.rectangle = "Box select";
@@ -119,7 +122,7 @@ function SeatMap(_ref) {
119
122
  } else if (mode === _utils.modes.REMOVE) {
120
123
  const seatsToRemove = [];
121
124
  selectedSeats.forEach(seat => {
122
- if (!seatsToRemove.find(s => s.ssId === seat.ssId) && seat.s === _utils.statuses.USER_PENDING) {
125
+ if (!seatsToRemove.some(s => s.ssId === seat.ssId) && seat.s === _utils.statuses.USER_PENDING) {
123
126
  seatsToRemove.push(seat);
124
127
  }
125
128
  });
@@ -223,7 +226,7 @@ function SeatMap(_ref) {
223
226
  lng: seat.x
224
227
  };
225
228
  const latlng = [seatCenter.lat, seatCenter.lng];
226
- if (boxBounds.contains(latlng) && !seatsToBook.find(s => s.ssId === seat.ssId) && seat.s === _utils.statuses.UNSOLD) {
229
+ if (boxBounds.contains(latlng) && !seatsToBook.some(s => s.ssId === seat.ssId) && (seat.s === _utils.statuses.UNSOLD || seat.s === _utils.statuses.RESERVED && canUseHolds)) {
227
230
  seatsToBook.push(seat);
228
231
  }
229
232
  });
@@ -234,7 +237,7 @@ function SeatMap(_ref) {
234
237
  (_drawLayersRef$curren = drawLayersRef.current) === null || _drawLayersRef$curren === void 0 || _drawLayersRef$curren.clearLayers();
235
238
  };
236
239
  const handleHighlightSeats = (0, _react.useCallback)((e, s) => {
237
- if (s.s === _utils.statuses.UNSOLD && mode === _utils.modes.SINGLE) {
240
+ if ((s.s === _utils.statuses.UNSOLD || s.s === _utils.statuses.RESERVED && canUseHolds) && mode === _utils.modes.SINGLE) {
238
241
  const seatsToBook = (0, _utils.getValidSeats)(s, seatsMap, desiredSeatQuantity);
239
242
  if (seatsToBook.valid) {
240
243
  setHighlightedSeats(seatsToBook.seats);
@@ -324,7 +327,7 @@ function SeatMap(_ref) {
324
327
  }
325
328
  };
326
329
  const onMouseDown = (0, _react.useCallback)((s, hasSeatPrices) => {
327
- if ((mode === _utils.modes.DRAG || mode === _utils.modes.REMOVE) && canMultiSelect && hasSeatPrices && !selectedSeats.find(seat => seat.ssId === s.ssId) && s.s === (mode === _utils.modes.DRAG ? _utils.statuses.UNSOLD : _utils.statuses.USER_PENDING)) {
330
+ if ((mode === _utils.modes.DRAG || mode === _utils.modes.REMOVE) && canMultiSelect && hasSeatPrices && !selectedSeats.some(seat => seat.ssId === s.ssId) && (s.s === (mode === _utils.modes.DRAG ? _utils.statuses.UNSOLD : _utils.statuses.USER_PENDING) || s.s === _utils.statuses.RESERVED && canUseHolds && mode === _utils.modes.DRAG)) {
328
331
  setSelectedSeats(prev => [...prev, s]);
329
332
  }
330
333
  }, [mode, canMultiSelect, selectedSeats, setSelectedSeats]);
@@ -335,7 +338,7 @@ function SeatMap(_ref) {
335
338
  if (hideTooltipTimeoutRef.current) {
336
339
  clearTimeout(hideTooltipTimeoutRef.current);
337
340
  }
338
- if ((mode === _utils.modes.DRAG || mode === _utils.modes.REMOVE) && isDragging && canMultiSelect && hasSeatPrices && !selectedSeats.find(seat => seat.ssId === s.ssId) && s.s === (mode === _utils.modes.DRAG ? _utils.statuses.UNSOLD : _utils.statuses.USER_PENDING)) {
341
+ if ((mode === _utils.modes.DRAG || mode === _utils.modes.REMOVE) && isDragging && canMultiSelect && hasSeatPrices && !selectedSeats.some(seat => seat.ssId === s.ssId) && (s.s === (mode === _utils.modes.DRAG ? _utils.statuses.UNSOLD : _utils.statuses.USER_PENDING) || s.s === _utils.statuses.RESERVED && canUseHolds && mode === _utils.modes.DRAG)) {
339
342
  setSelectedSeats(prev => [...prev, s]);
340
343
  return;
341
344
  }
@@ -367,7 +370,7 @@ function SeatMap(_ref) {
367
370
  infoVisible: false
368
371
  }));
369
372
  }
370
- if ((highlightedSeats === null || highlightedSeats === void 0 ? void 0 : highlightedSeats.length) > 0) {
373
+ if ((highlightedSeats === null || highlightedSeats === void 0 ? void 0 : highlightedSeats.length) > 0 && mode === _utils.modes.SINGLE) {
371
374
  setHighlightedSeats([]);
372
375
  }
373
376
  }, 400);
@@ -398,7 +401,8 @@ function SeatMap(_ref) {
398
401
  return ((_seats$pricing = seats.pricing) === null || _seats$pricing === void 0 ? void 0 : _seats$pricing.filter(p => p.psId === s.psId && (!priceSectionIds || priceSectionIds.includes(p.psId)) && (p.q === null || p.q > 0))) || [];
399
402
  }) : hoveredSeat ? ((_seats$pricing2 = seats.pricing) === null || _seats$pricing2 === void 0 ? void 0 : _seats$pricing2.filter(p => p.psId === hoveredSeat.psId && (!priceSectionIds || priceSectionIds.includes(p.psId)) && (p.q === null || p.q > 0))) || [] : undefined,
400
403
  prevHovered: prevHovered.current,
401
- isTouchScreen: isTouchScreen
404
+ isTouchScreen: isTouchScreen,
405
+ canUseHolds: canUseHolds
402
406
  }), /*#__PURE__*/_react.default.createElement(_Controls.default, {
403
407
  preventOrphanedSeats: seats === null || seats === void 0 ? void 0 : seats.preventOrphanedSeats,
404
408
  bounds: bounds,
@@ -467,7 +471,7 @@ function SeatMap(_ref) {
467
471
  bounds: iconBounds,
468
472
  opacity: s.loading || ticketPopupOpen && (chosenSeat === null || chosenSeat === void 0 || (_chosenSeat$seat2 = chosenSeat.seat) === null || _chosenSeat$seat2 === void 0 ? void 0 : _chosenSeat$seat2.ssId) === s.ssId ? 100 : 0,
469
473
  zIndex: 10
470
- }), !priceSectionIds || priceSectionIds.includes(s.psId) ? s.s === _utils.statuses.WHEELCHAIR_ACCESS ? /*#__PURE__*/_react.default.createElement(_reactLeaflet.ImageOverlay, {
474
+ }), !priceSectionIds || priceSectionIds.includes(s.psId) ? s.s === _utils.statuses.WHEELCHAIR_ACCESS && !isPOS ? /*#__PURE__*/_react.default.createElement(_reactLeaflet.ImageOverlay, {
471
475
  url: _encodedSvgs.wheelchairIcon,
472
476
  bounds: iconBounds,
473
477
  zIndex: 10
@@ -477,10 +481,14 @@ function SeatMap(_ref) {
477
481
  zIndex: 10
478
482
  }) : /*#__PURE__*/_react.default.createElement(_reactLeaflet.Circle, {
479
483
  center: [seatCenter.lat, seatCenter.lng],
480
- pathOptions: (0, _utils.getInitialColor)(s, price, s.loading || ticketPopupOpen && (chosenSeat === null || chosenSeat === void 0 || (_chosenSeat$seat3 = chosenSeat.seat) === null || _chosenSeat$seat3 === void 0 ? void 0 : _chosenSeat$seat3.ssId) === s.ssId, !hasSeatPrices, (selectedSeats.some(selectedSeat => selectedSeat.ssId === s.ssId) || highlightedSeats.some(hs => hs.ssId === s.ssId)) && isHoveringOnSeat, greyedOutSeats.some(gs => gs.ssId === s.ssId)),
484
+ pathOptions: (0, _utils.getInitialColor)(s, price, s.loading || ticketPopupOpen && (chosenSeat === null || chosenSeat === void 0 || (_chosenSeat$seat3 = chosenSeat.seat) === null || _chosenSeat$seat3 === void 0 ? void 0 : _chosenSeat$seat3.ssId) === s.ssId, canUseHolds, isPOS, !hasSeatPrices, (selectedSeats.some(selectedSeat => selectedSeat.ssId === s.ssId) || highlightedSeats.some(hs => hs.ssId === s.ssId)) && (isOrphanMode ? isHoveringOnSeat : true), greyedOutSeats.some(gs => gs.ssId === s.ssId)),
481
485
  radius: seatCenter.radius,
482
486
  eventHandlers: eventHandlers
483
- }, s.s === _utils.statuses.UNSOLD && hasSeatPrices ? /*#__PURE__*/_react.default.createElement(_reactLeaflet.Popup, {
487
+ }, (s.s === _utils.statuses.WHEELCHAIR_ACCESS || s.ost === _utils.statuses.WHEELCHAIR_ACCESS) && isPOS && /*#__PURE__*/_react.default.createElement(_reactLeaflet.ImageOverlay, {
488
+ url: _encodedSvgs.wheelchairIcon,
489
+ bounds: iconBounds,
490
+ zIndex: 10
491
+ }), (s.s === _utils.statuses.UNSOLD || s.s === _utils.statuses.RESERVED && canUseHolds || s.s === _utils.statuses.WHEELCHAIR_ACCESS && isPOS) && hasSeatPrices ? /*#__PURE__*/_react.default.createElement(_reactLeaflet.Popup, {
484
492
  className: "ticket-popup popup-".concat(s.sId)
485
493
  }, isSingleFlexi ? /*#__PURE__*/_react.default.createElement("div", {
486
494
  className: "single-flexi"
@@ -44,7 +44,16 @@ const SeatingPlan = _ref => {
44
44
  connectedShowings,
45
45
  areaName,
46
46
  promoCode,
47
- bookingMode = _utils.bookingModes.SHOPSITE
47
+ bookingMode = _utils.bookingModes.SHOPSITE,
48
+ theme = {
49
+ accent: "#6366f1",
50
+ accentDark: "#3730a3",
51
+ accentLight: "#e0e7ff",
52
+ flexiAccent: "#e32664",
53
+ flexiAccentDark: "#ffd3e2",
54
+ flexiAccentLight: "#be003f"
55
+ },
56
+ canManageHolds = false
48
57
  } = _ref;
49
58
  const [initialiseMessage, setInitialiseMessage] = (0, _react.useState)("Initialising seating plan...");
50
59
  const [isReloading, setIsReloading] = (0, _react.useState)(false);
@@ -70,7 +79,9 @@ const SeatingPlan = _ref => {
70
79
  const [invalidSeatsPopupOpen, setInvalidSeatsPopupOpen] = (0, _react.useState)(false);
71
80
  const [retrying, setRetrying] = (0, _react.useState)([]);
72
81
  const mapRef = (0, _react.useRef)(null);
73
- const canMultiSelect = bookingMode === _utils.bookingModes.POS;
82
+ const isPOS = bookingMode === _utils.bookingModes.POS;
83
+ const canMultiSelect = isPOS;
84
+ const canUseHolds = canManageHolds && isPOS;
74
85
  const apiUrl = "".concat(baseUrl, "/legacy/").concat(countryCode, "/shop/events/").concat(eventId, "/").concat(eventVenueId, "/showings/").concat(showingId, "/tickets/allocated/").concat(areaId);
75
86
  const setMap = map => {
76
87
  mapRef.current = map;
@@ -115,8 +126,9 @@ const SeatingPlan = _ref => {
115
126
  updateSeat(seatIndex, _objectSpread(_objectSpread({}, s), {}, {
116
127
  loading: true
117
128
  }));
118
- const isSeatAvailable = (s.s === _utils.statuses.UNSOLD || s.s === _utils.statuses.USER_PENDING) && !(bookedSeats.length >= quantity && s.s === _utils.statuses.UNSOLD) && (priceage.q === null || priceage.q > 0);
119
- if (!isSeatAvailable) {
129
+ const isSeatAvailable = s.s === _utils.statuses.UNSOLD || s.s === _utils.statuses.USER_PENDING || s.s === _utils.statuses.RESERVED && canUseHolds || s.s === _utils.statuses.WHEELCHAIR_ACCESS && isPOS;
130
+ const canInteract = !(bookedSeats.length >= quantity && isSeatAvailable) && (priceage.q === null || priceage.q > 0);
131
+ if (!canInteract) {
120
132
  if (bookedSeats.length >= quantity) {
121
133
  handleError({
122
134
  message: _utils.ERROR_MESSAGES.MAX_QUANTITY
@@ -219,10 +231,12 @@ const SeatingPlan = _ref => {
219
231
  };
220
232
  const removeTicketFromCart = async (s, e) => {
221
233
  const seatIndex = seats.seats.findIndex(seat => seat.ssId === s.ssId);
234
+ const isWheelchairSeat = s.ost === _utils.statuses.WHEELCHAIR_ACCESS;
222
235
  updateSeat(seatIndex, _objectSpread(_objectSpread({}, s), {}, {
223
236
  loading: true
224
237
  }));
225
238
  try {
239
+ var _s$ost;
226
240
  const response = await fetch("".concat(apiUrl, "/seat/").concat(s.ssId), {
227
241
  method: "DELETE",
228
242
  headers: {
@@ -234,7 +248,7 @@ const SeatingPlan = _ref => {
234
248
  }
235
249
  updateSeat(seatIndex, _objectSpread(_objectSpread({}, s), {}, {
236
250
  loading: false,
237
- s: _utils.statuses.UNSOLD,
251
+ s: s.ticketHold ? _utils.statuses.RESERVED : isWheelchairSeat ? _utils.statuses.WHEELCHAIR_ACCESS : (_s$ost = s.ost) !== null && _s$ost !== void 0 ? _s$ost : _utils.statuses.UNSOLD,
238
252
  bookedPrice: null
239
253
  }));
240
254
  setBookedSeats(prev => prev.filter(bs => bs.ssId !== s.ssId));
@@ -258,106 +272,179 @@ const SeatingPlan = _ref => {
258
272
  return;
259
273
  }
260
274
  setSeatsLoading(seatsToBook.map(seat => seat.seat), true);
261
- const succeeded = [];
262
- const _tryBook = async function tryBook(seatToBook) {
263
- let retryCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
275
+ if (isPOS) {
264
276
  try {
265
277
  const res = await fetch(apiUrl, {
266
278
  method: "POST",
267
- body: JSON.stringify({
279
+ body: JSON.stringify(seatsToBook.map(seatToBook => ({
268
280
  priceAgeId: seatToBook.priceage.paId,
269
281
  seatId: seatToBook.seat.ssId,
270
282
  price: seatToBook.priceage.p,
271
283
  connectedShowings: connectedShowings
272
- }),
284
+ }))),
273
285
  headers: {
274
286
  "content-type": "application/json",
275
287
  "basket-key": sessionId
276
288
  }
277
289
  });
278
- if (res.status === 429) {
279
- if (retryCount < _constants.BOOKING_MAX_RETRIES) {
280
- setRetrying(prev => [...prev, seatToBook.seat.ssId]);
281
- const delay = (0, _utils.getRetryDelay)(res);
282
- await new Promise(resolve => setTimeout(resolve, delay));
283
- return _tryBook(seatToBook, retryCount + 1);
284
- } else {
285
- throw new Error("429");
286
- }
287
- } else if (!res.ok) {
290
+ if (!res.ok) {
288
291
  throw new Error("".concat(res.status));
289
292
  }
290
- succeeded.push(seatToBook.seat);
291
- } catch (_unused3) {
292
- throw new Error("Booking failed for seat ".concat(seatToBook.seat.r, " ").concat(seatToBook.seat.c));
293
- }
294
- };
295
- try {
296
- for (const seatToBook of seatsToBook) {
297
- await _tryBook(seatToBook);
298
- }
299
- setRetrying(prev => prev.filter(id => !seatsToBook.some(s => s.seat.ssId === id)));
300
- setBookedSeats(prev => [...prev, ...seatsToBook.map(_ref2 => {
301
- let {
302
- seat,
303
- priceage
304
- } = _ref2;
305
- return _objectSpread(_objectSpread({}, seat), {}, {
306
- showingId: showingId,
307
- pId: priceage.paId,
308
- p: priceage.p,
309
- paName: priceage.paName
310
- });
311
- })]);
312
- setSeats(prev => {
313
- const updatedSeats = _objectSpread({}, prev);
314
- seatsToBook.forEach(_ref3 => {
293
+ setBookedSeats(prev => [...prev, ...seatsToBook.map(_ref2 => {
315
294
  let {
316
- seat
317
- } = _ref3;
318
- const seatIndex = updatedSeats.seats.findIndex(s => s.ssId === seat.ssId);
319
- if (seatIndex !== -1) {
320
- updatedSeats.seats[seatIndex] = _objectSpread(_objectSpread({}, updatedSeats.seats[seatIndex]), {}, {
321
- loading: false,
322
- s: _utils.statuses.USER_PENDING,
323
- bookedPrice: price
295
+ seat,
296
+ priceage
297
+ } = _ref2;
298
+ return _objectSpread(_objectSpread({}, seat), {}, {
299
+ showingId: showingId,
300
+ pId: priceage.paId,
301
+ p: priceage.p,
302
+ paName: priceage.paName
303
+ });
304
+ })]);
305
+ setSeats(prev => {
306
+ const updatedSeats = _objectSpread({}, prev);
307
+ seatsToBook.forEach(_ref3 => {
308
+ let {
309
+ seat
310
+ } = _ref3;
311
+ const seatIndex = updatedSeats.seats.findIndex(s => s.ssId === seat.ssId);
312
+ if (seatIndex !== -1) {
313
+ updatedSeats.seats[seatIndex] = _objectSpread(_objectSpread({}, updatedSeats.seats[seatIndex]), {}, {
314
+ loading: false,
315
+ s: _utils.statuses.USER_PENDING,
316
+ bookedPrice: price
317
+ });
318
+ }
319
+ });
320
+ return updatedSeats;
321
+ });
322
+ const event = {
323
+ type: "cart-change-add",
324
+ details: [...seatsToBook.map(_ref4 => {
325
+ let {
326
+ seat,
327
+ priceage
328
+ } = _ref4;
329
+ return _objectSpread(_objectSpread({}, seat), {}, {
330
+ showingId: showingId,
331
+ pId: priceage.paId,
332
+ p: priceage.p,
333
+ paName: priceage.paName
324
334
  });
325
- }
335
+ })]
336
+ };
337
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
338
+ } catch (error) {
339
+ console.error("Failed to book seats:", error);
340
+ setSeatsLoading(seatsToBook.map(seat => seat.seat), false);
341
+ handleError({
342
+ code: error === "429" ? 429 : 500,
343
+ message: _utils.ERROR_MESSAGES.GENERIC_ERROR
326
344
  });
327
- return updatedSeats;
328
- });
329
- const event = {
330
- type: "cart-change-add",
331
- details: [...seatsToBook.map(_ref4 => {
345
+ }
346
+ } else {
347
+ const succeeded = [];
348
+ const _tryBook = async function tryBook(seatToBook) {
349
+ let retryCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
350
+ try {
351
+ const res = await fetch(apiUrl, {
352
+ method: "POST",
353
+ body: JSON.stringify({
354
+ priceAgeId: seatToBook.priceage.paId,
355
+ seatId: seatToBook.seat.ssId,
356
+ price: seatToBook.priceage.p,
357
+ connectedShowings: connectedShowings
358
+ }),
359
+ headers: {
360
+ "content-type": "application/json",
361
+ "basket-key": sessionId
362
+ }
363
+ });
364
+ if (res.status === 429) {
365
+ if (retryCount < _constants.BOOKING_MAX_RETRIES) {
366
+ setRetrying(prev => [...prev, seatToBook.seat.ssId]);
367
+ const delay = (0, _utils.getRetryDelay)(res);
368
+ await new Promise(resolve => setTimeout(resolve, delay));
369
+ return _tryBook(seatToBook, retryCount + 1);
370
+ } else {
371
+ throw new Error("429");
372
+ }
373
+ } else if (!res.ok) {
374
+ throw new Error("".concat(res.status));
375
+ }
376
+ succeeded.push(seatToBook.seat);
377
+ } catch (_unused3) {
378
+ throw new Error("Booking failed for seat ".concat(seatToBook.seat.r, " ").concat(seatToBook.seat.c));
379
+ }
380
+ };
381
+ try {
382
+ for (const seatToBook of seatsToBook) {
383
+ await _tryBook(seatToBook);
384
+ }
385
+ setRetrying(prev => prev.filter(id => !seatsToBook.some(s => s.seat.ssId === id)));
386
+ setBookedSeats(prev => [...prev, ...seatsToBook.map(_ref5 => {
332
387
  let {
333
388
  seat,
334
389
  priceage
335
- } = _ref4;
390
+ } = _ref5;
336
391
  return _objectSpread(_objectSpread({}, seat), {}, {
337
392
  showingId: showingId,
338
393
  pId: priceage.paId,
339
394
  p: priceage.p,
340
395
  paName: priceage.paName
341
396
  });
342
- })]
343
- };
344
- callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
345
- } catch (error) {
346
- setRetrying(prev => prev.filter(id => !seatsToBook.some(s => s.seat.ssId === id)));
347
- console.error("Failed to book seats:", error);
348
- for (const seat of succeeded) {
349
- await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
350
- method: "DELETE",
351
- headers: {
352
- "basket-key": sessionId
353
- }
397
+ })]);
398
+ setSeats(prev => {
399
+ const updatedSeats = _objectSpread({}, prev);
400
+ seatsToBook.forEach(_ref6 => {
401
+ let {
402
+ seat
403
+ } = _ref6;
404
+ const seatIndex = updatedSeats.seats.findIndex(s => s.ssId === seat.ssId);
405
+ if (seatIndex !== -1) {
406
+ updatedSeats.seats[seatIndex] = _objectSpread(_objectSpread({}, updatedSeats.seats[seatIndex]), {}, {
407
+ loading: false,
408
+ s: _utils.statuses.USER_PENDING,
409
+ bookedPrice: price
410
+ });
411
+ }
412
+ });
413
+ return updatedSeats;
414
+ });
415
+ const event = {
416
+ type: "cart-change-add",
417
+ details: [...seatsToBook.map(_ref7 => {
418
+ let {
419
+ seat,
420
+ priceage
421
+ } = _ref7;
422
+ return _objectSpread(_objectSpread({}, seat), {}, {
423
+ showingId: showingId,
424
+ pId: priceage.paId,
425
+ p: priceage.p,
426
+ paName: priceage.paName
427
+ });
428
+ })]
429
+ };
430
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
431
+ } catch (error) {
432
+ setRetrying(prev => prev.filter(id => !seatsToBook.some(s => s.seat.ssId === id)));
433
+ console.error("Failed to book seats:", error);
434
+ for (const seat of succeeded) {
435
+ await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
436
+ method: "DELETE",
437
+ headers: {
438
+ "basket-key": sessionId
439
+ }
440
+ });
441
+ }
442
+ setSeatsLoading(seatsToBook.map(seat => seat.seat), false);
443
+ handleError({
444
+ code: error === "429" ? 429 : 500,
445
+ message: _utils.ERROR_MESSAGES.GENERIC_ERROR
354
446
  });
355
447
  }
356
- setSeatsLoading(seatsToBook.map(seat => seat.seat), false);
357
- handleError({
358
- code: error === "429" ? 429 : 500,
359
- message: _utils.ERROR_MESSAGES.GENERIC_ERROR
360
- });
361
448
  }
362
449
  };
363
450
  const batchRemoveTicketsFromCart = async seatsToRemove => {
@@ -395,9 +482,10 @@ const SeatingPlan = _ref => {
395
482
  seatsToRemove.forEach(s => {
396
483
  const seatIndex = updatedSeats.seats.findIndex(seat => seat.ssId === s.ssId);
397
484
  if (seatIndex !== -1) {
485
+ var _s$ost2;
398
486
  updatedSeats.seats[seatIndex] = _objectSpread(_objectSpread({}, updatedSeats.seats[seatIndex]), {}, {
399
487
  loading: false,
400
- s: succeededIds.includes(s.ssId) ? _utils.statuses.UNSOLD : s.s,
488
+ s: succeededIds.includes(s.ssId) ? s.ticketHold ? _utils.statuses.RESERVED : (_s$ost2 = s.ost) !== null && _s$ost2 !== void 0 ? _s$ost2 : _utils.statuses.UNSOLD : s.s,
401
489
  bookedPrice: null
402
490
  });
403
491
  }
@@ -418,7 +506,7 @@ const SeatingPlan = _ref => {
418
506
  circle: e,
419
507
  seat: s
420
508
  });
421
- if (s.s !== _utils.statuses.UNSOLD && s.s !== _utils.statuses.USER_PENDING || bookedSeats.length >= quantity && s.s === _utils.statuses.UNSOLD) {
509
+ if (s.s !== _utils.statuses.UNSOLD && s.s !== _utils.statuses.USER_PENDING && (s.s !== _utils.statuses.RESERVED || canUseHolds) && (s.s !== _utils.statuses.WHEELCHAIR_ACCESS || !isPOS) || bookedSeats.length >= quantity && s.s === _utils.statuses.UNSOLD) {
422
510
  if (bookedSeats.length >= quantity) {
423
511
  handleError({
424
512
  message: _utils.ERROR_MESSAGES.MAX_QUANTITY
@@ -426,7 +514,7 @@ const SeatingPlan = _ref => {
426
514
  }
427
515
  return;
428
516
  }
429
- if (s.s === _utils.statuses.UNSOLD) {
517
+ if (s.s === _utils.statuses.UNSOLD || s.s === _utils.statuses.RESERVED && canUseHolds || s.s === _utils.statuses.WHEELCHAIR_ACCESS && isPOS) {
430
518
  var _seats$pricing;
431
519
  const availablePrices = ((_seats$pricing = seats.pricing) === null || _seats$pricing === void 0 ? void 0 : _seats$pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && s.psId === price.psId)) || [];
432
520
  const isSingleFlexi = availablePrices.length === 1 && !!availablePrices[0].pMax && !!availablePrices[0].pMin && availablePrices[0].pMax > availablePrices[0].pMin;
@@ -540,19 +628,28 @@ const SeatingPlan = _ref => {
540
628
  // in full screen mode, render the map in the body, otherwise render in the seating-plan-root div
541
629
  const mapContainer = mounted && (isFullScreen ? (_document = document) === null || _document === void 0 ? void 0 : _document.body : (_document2 = document) === null || _document2 === void 0 ? void 0 : _document2.getElementById("seating-plan-root"));
542
630
  const backdropContainer = mounted && ((_document3 = document) === null || _document3 === void 0 ? void 0 : _document3.body);
543
-
544
- // return seating plan
631
+ const themeStyles = {
632
+ "--accent": theme.accent,
633
+ "--accent-dark": theme.accentDark,
634
+ "--accent-light": theme.accentLight,
635
+ "--flexi-accent": theme.flexiAccent,
636
+ "--flexi-accent-light": theme.flexiAccentLight,
637
+ "--flexi-accent-dark": theme.flexiAccentDark
638
+ };
545
639
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
546
640
  className: "seating-plan-root",
547
- id: "seating-plan-root"
641
+ id: "seating-plan-root",
642
+ style: themeStyles
548
643
  }, error ? /*#__PURE__*/_react.default.createElement("div", {
549
644
  className: "loading"
550
645
  }, /*#__PURE__*/_react.default.createElement("h1", null, "OOPS!"), /*#__PURE__*/_react.default.createElement("div", null, error.response.data.message)) : position && area === areaId ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, backdropContainer && /*#__PURE__*/(0, _reactDom.createPortal)(/*#__PURE__*/_react.default.createElement("div", {
551
646
  className: "seating-plan-backdrop ".concat(isFullScreen ? "full-screen" : ""),
552
- onClick: () => setIsFullScreen(false)
647
+ onClick: () => setIsFullScreen(false),
648
+ style: themeStyles
553
649
  }), backdropContainer), mapContainer && /*#__PURE__*/(0, _reactDom.createPortal)(/*#__PURE__*/_react.default.createElement("div", {
554
650
  className: "seating-plan-container ".concat(isFullScreen ? "full-screen" : ""),
555
- "data-mode": mode
651
+ "data-mode": mode,
652
+ style: themeStyles
556
653
  }, pricingPopupOpen && seats && seats.pricing && (canMultiSelect || seats.preventOrphanedSeats) ? /*#__PURE__*/_react.default.createElement(_PricingPopup.default, {
557
654
  onClose: () => {
558
655
  setPricingPopupOpen(false);
@@ -622,7 +719,9 @@ const SeatingPlan = _ref => {
622
719
  setSeatsToRemove: setSeatsToRemove,
623
720
  setRemoveMultipleSeatsPopupOpen: setRemoveMultipleSeatsPopupOpen,
624
721
  setInvalidSeatsPopupOpen: setInvalidSeatsPopupOpen,
625
- batchAddTicketsToCart: batchAddTicketsToCart
722
+ batchAddTicketsToCart: batchAddTicketsToCart,
723
+ canUseHolds: canUseHolds,
724
+ bookingMode: bookingMode
626
725
  }))), mapContainer)) : /*#__PURE__*/_react.default.createElement("div", {
627
726
  className: "loading"
628
727
  }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("svg", {
@@ -27,13 +27,15 @@ button {
27
27
  }
28
28
 
29
29
  .seating-plan-container {
30
- --accent: rgb(99 102 241);
30
+ /* --accent: rgb(99 102 241);
31
31
  --accent-dark: rgb(55 48 163);
32
32
  --accent-light: rgb(224 231 255);
33
33
  --flexi-accent: rgb(227 38 100);
34
34
  --flexi-accent-light: rgb(255 211 226);
35
- --flexi-accent-dark: rgb(190 0 63);
35
+ --flexi-accent-dark: rgb(190 0 63); */
36
36
  font-family: inherit;
37
+ height: 100%;
38
+ width: 100%;
37
39
  }
38
40
 
39
41
  .legendBox {
@@ -42,6 +44,7 @@ button {
42
44
  border-radius: 3px;
43
45
  text-align: left;
44
46
  backdrop-filter: blur(2px);
47
+ color: #333;
45
48
  }
46
49
 
47
50
  .legend-header {
@@ -1546,6 +1549,26 @@ svg.leaflet-image-layer.leaflet-interactive path {
1546
1549
  align-items: center;
1547
1550
  }
1548
1551
 
1552
+ .hover-popup-ticket-hold {
1553
+ padding: 0.5rem;
1554
+ padding-top: 0;
1555
+ font-size: 0.5rem;
1556
+ }
1557
+
1558
+ .hover-popup-ticket-hold .held-by {
1559
+ display: flex;
1560
+ gap: 0.25rem;
1561
+ align-items: center;
1562
+ }
1563
+
1564
+ .hover-popup-ticket-hold .ticket-hold-category {
1565
+ font-weight: 500;
1566
+ padding: 0.05rem 0.25rem;
1567
+ border-radius: 0.5rem;
1568
+ width: fit-content;
1569
+ font-size: 0.625rem;
1570
+ }
1571
+
1549
1572
  .hover-popup-price {
1550
1573
  padding: 0.5rem;
1551
1574
  font-size: 0.875rem;
@@ -18,7 +18,8 @@ const getIsTouchScreen = () => {
18
18
  return hasTouchScreen;
19
19
  };
20
20
  exports.getIsTouchScreen = getIsTouchScreen;
21
- const getInitialColor = (s, price, loading, disabled, selected, greyedOut) => {
21
+ const getInitialColor = (s, price, loading, canManageHolds, isPOS, disabled, selected, greyedOut) => {
22
+ const isWheelchairAccess = s.s === _enums.statuses.WHEELCHAIR_ACCESS || s.ost === _enums.statuses.WHEELCHAIR_ACCESS;
22
23
  // selected state for multiselect
23
24
  if (selected) {
24
25
  return {
@@ -37,9 +38,9 @@ const getInitialColor = (s, price, loading, disabled, selected, greyedOut) => {
37
38
  };
38
39
  }
39
40
  return {
40
- fillColor: s.s === _enums.statuses.UNSOLD && !disabled ? _enums.statusColors.available : s.s === _enums.statuses.USER_PENDING ? s.bookedPrice === price ? _enums.statusColors.booked : _enums.statusColors.bookedWithDifferentPrice : _enums.statusColors.sold,
41
+ fillColor: (s.s === _enums.statuses.UNSOLD || s.s === _enums.statuses.WHEELCHAIR_ACCESS && isPOS) && !disabled ? _enums.statusColors.available : s.s === _enums.statuses.USER_PENDING ? s.bookedPrice === price ? _enums.statusColors.booked : _enums.statusColors.bookedWithDifferentPrice : s.s === _enums.statuses.RESERVED && s.ticketHold && canManageHolds ? s.ticketHold.TicketHoldCategoryColor : _enums.statusColors.sold,
41
42
  color: "none",
42
- fillOpacity: loading ? 0 : 1,
43
+ fillOpacity: loading ? 0 : isWheelchairAccess && isPOS ? 0.5 : 1,
43
44
  stroke: false
44
45
  };
45
46
  };
package/package.json CHANGED
@@ -1,62 +1,61 @@
1
- {
2
- "name": "iticket-seatingplan-dev",
3
- "description": "Seating plan with FLEXi pricing",
4
- "author": "gedwyne",
5
- "version": "2.0.7",
6
- "private": false,
7
- "keywords": [
8
- "iticket",
9
- "seatingplan"
10
- ],
11
- "main": "dist/index.js",
12
- "module": "dist/index.js",
13
- "files": [
14
- "dist",
15
- "README.md"
16
- ],
17
- "dependencies": {
18
- "@babel/polyfill": "^7.12.1",
19
- "@types/leaflet": "^1.9.14",
20
- "@types/leaflet-draw": "^1.0.11",
21
- "leaflet": "^1.9.3",
22
- "leaflet-draw": "^1.0.4",
23
- "react": "^18.3.1",
24
- "react-dom": "^18.3.1",
25
- "react-leaflet": "^4.2.1",
26
- "react-leaflet-custom-control": "^1.3.5",
27
- "react-leaflet-draw": "^0.20.4",
28
- "react-scripts": "^5.0.1"
29
- },
30
- "codependencies": {
31
- "@babel/polyfill": "^7.12.1",
32
- "leaflet": "^1.9.3",
33
- "react-leaflet": "^4.2.1"
34
- },
35
- "scripts": {
36
- "build": "babel src/lib --out-dir dist --extensions '.tsx,.ts,.js' --copy-files",
37
- "start": "react-scripts start"
38
- },
39
- "browserslist": {
40
- "production": [
41
- ">0.2%",
42
- "not dead",
43
- "not op_mini all"
44
- ],
45
- "development": [
46
- "last 1 chrome version",
47
- "last 1 firefox version",
48
- "last 1 safari version"
49
- ]
50
- },
51
- "devDependencies": {
52
- "@babel/cli": "^7.22.5",
53
- "@babel/core": "^7.22.5",
54
- "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
55
- "@babel/preset-env": "^7.22.5",
56
- "@babel/preset-react": "^7.22.5",
57
- "@babel/preset-typescript": "^7.26.0",
58
- "@types/react": "^18.3.12",
59
- "@types/react-dom": "^18.3.1",
60
- "typescript": "^5.7.2"
61
- }
62
- }
1
+ {
2
+ "name": "iticket-seatingplan-dev",
3
+ "description": "Seating plan with FLEXi pricing",
4
+ "author": "gedwyne",
5
+ "version": "2.0.17",
6
+ "private": false,
7
+ "keywords": [
8
+ "iticket",
9
+ "seatingplan"
10
+ ],
11
+ "main": "dist/index.js",
12
+ "module": "dist/index.js",
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "dependencies": {
18
+ "@babel/polyfill": "^7.12.1",
19
+ "@types/leaflet": "^1.9.14",
20
+ "@types/leaflet-draw": "^1.0.11",
21
+ "leaflet": "^1.9.4",
22
+ "leaflet-draw": "^1.0.4",
23
+ "react": "^19.0.0",
24
+ "react-dom": "^19.0.0",
25
+ "react-leaflet": "^5.0.0-rc.2",
26
+ "react-leaflet-draw": "^0.20.4",
27
+ "react-scripts": "^5.0.1"
28
+ },
29
+ "codependencies": {
30
+ "@babel/polyfill": "^7.12.1",
31
+ "leaflet": "^1.9.3",
32
+ "react-leaflet": "^4.2.1"
33
+ },
34
+ "scripts": {
35
+ "build": "babel src/lib --out-dir dist --extensions '.tsx,.ts,.js' --copy-files",
36
+ "start": "react-scripts start"
37
+ },
38
+ "browserslist": {
39
+ "production": [
40
+ ">0.2%",
41
+ "not dead",
42
+ "not op_mini all"
43
+ ],
44
+ "development": [
45
+ "last 1 chrome version",
46
+ "last 1 firefox version",
47
+ "last 1 safari version"
48
+ ]
49
+ },
50
+ "devDependencies": {
51
+ "@babel/cli": "^7.22.5",
52
+ "@babel/core": "^7.22.5",
53
+ "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
54
+ "@babel/preset-env": "^7.22.5",
55
+ "@babel/preset-react": "^7.22.5",
56
+ "@babel/preset-typescript": "^7.26.0",
57
+ "@types/react": "^18.3.12",
58
+ "@types/react-dom": "^18.3.1",
59
+ "typescript": "^5.7.2"
60
+ }
61
+ }
@@ -1,17 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
- const Badge = props => {
10
- return /*#__PURE__*/_react.default.createElement("div", {
11
- className: "badge ".concat(!props.value ? 'badge--none' : '', " ")
12
- }, /*#__PURE__*/_react.default.createElement("h4", {
13
- className: "heavy"
14
- }, props.value || 0));
15
- };
16
- var _default = Badge;
17
- exports.default = _default;
@@ -1,21 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
- const Button = props => {
10
- return /*#__PURE__*/_react.default.createElement("button", {
11
- className: "btn btn--".concat(props.kind, " CTA"),
12
- "data-id": props.id,
13
- type: props.type,
14
- name: props.name,
15
- value: props.value,
16
- disabled: props.disabled,
17
- onClick: props.handleClick
18
- }, /*#__PURE__*/_react.default.createElement("h4", null, props.label));
19
- };
20
- var _default = Button;
21
- exports.default = _default;