iticket-seatingplan-dev 1.6.7 → 1.6.9

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.
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _leaflet = _interopRequireDefault(require("leaflet"));
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactLeaflet = require("react-leaflet");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
12
+ const POSITION_CLASSES = {
13
+ bottomleft: "leaflet-bottom leaflet-left",
14
+ bottomright: "leaflet-bottom leaflet-right",
15
+ topleft: "leaflet-top leaflet-left",
16
+ topright: "leaflet-top leaflet-right"
17
+ };
18
+ const Control = props => {
19
+ var _props$container;
20
+ const [portalRoot, setPortalRoot] = _react.default.useState(document.createElement("div"));
21
+ const positionClass = props.position && POSITION_CLASSES[props.position] || POSITION_CLASSES.topright;
22
+ const controlContainerRef = /*#__PURE__*/_react.default.createRef();
23
+ const map = (0, _reactLeaflet.useMap)();
24
+
25
+ /**
26
+ * Whenever the control container ref is created,
27
+ * Ensure the click / scroll propagation is removed
28
+ * This way click/scroll events do not bubble down to the map
29
+ */
30
+ _react.default.useEffect(() => {
31
+ if (controlContainerRef.current !== null) {
32
+ _leaflet.default.DomEvent.disableClickPropagation(controlContainerRef.current);
33
+ _leaflet.default.DomEvent.disableScrollPropagation(controlContainerRef.current);
34
+ }
35
+ }, [controlContainerRef]);
36
+
37
+ /**
38
+ * Whenever the position is changed, go ahead and get the container of the map and the first
39
+ * instance of the position class in that map container
40
+ * Fixes #17
41
+ */
42
+ _react.default.useEffect(() => {
43
+ const mapContainer = map.getContainer();
44
+ const targetDiv = mapContainer.getElementsByClassName(positionClass);
45
+ setPortalRoot(targetDiv[0]);
46
+ }, [positionClass]);
47
+
48
+ /**
49
+ * Whenever the portal root is complete,
50
+ * append or prepend the control container to the portal root
51
+ */
52
+ _react.default.useEffect(() => {
53
+ if (portalRoot !== null) {
54
+ if (props.prepend !== undefined && props.prepend === true) {
55
+ portalRoot.prepend(controlContainerRef.current);
56
+ } else {
57
+ portalRoot.append(controlContainerRef.current);
58
+ }
59
+ }
60
+ }, [portalRoot, props.prepend, controlContainerRef]);
61
+
62
+ /**
63
+ * Concatenate the props.container className to the class of the control div
64
+ */
65
+ const className = (((_props$container = props.container) === null || _props$container === void 0 || (_props$container = _props$container.className) === null || _props$container === void 0 ? void 0 : _props$container.concat(" ")) || "") + "leaflet-control";
66
+
67
+ /**
68
+ * Render
69
+ */
70
+ return /*#__PURE__*/_react.default.createElement("div", _extends({}, props.container, {
71
+ ref: controlContainerRef,
72
+ className: className
73
+ }), props.children);
74
+ };
75
+ var _default = exports.default = Control;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = Map;
6
+ exports.default = SeatMap;
7
7
  require("./styles/gestureHandling.css");
8
8
  require("leaflet-draw/dist/leaflet.draw.css");
9
9
  var _react = _interopRequireWildcard(require("react"));
@@ -19,6 +19,7 @@ var _Flexi = _interopRequireDefault(require("./Flexi"));
19
19
  var _CloseIcon = _interopRequireDefault(require("./icons/CloseIcon"));
20
20
  var _TicketIcon = _interopRequireDefault(require("./icons/TicketIcon"));
21
21
  var _FlexiIcon = _interopRequireDefault(require("./icons/FlexiIcon"));
22
+ var _EditIcon = _interopRequireDefault(require("./icons/EditIcon"));
22
23
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
23
24
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
24
25
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -27,7 +28,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
27
28
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
28
29
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
29
30
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
30
- function Map(_ref) {
31
+ function SeatMap(_ref) {
31
32
  let {
32
33
  seats,
33
34
  height,
@@ -53,7 +54,12 @@ function Map(_ref) {
53
54
  pricingPopupOpen,
54
55
  setPricingPopupOpen,
55
56
  selectedSeats,
56
- setSelectedSeats
57
+ setSelectedSeats,
58
+ selectQuantityPopupOpen,
59
+ setSelectQuantityPopupOpen,
60
+ desiredSeatQuantity,
61
+ setSeatsToRemove,
62
+ setRemoveMultipleSeatsPopupOpen
57
63
  } = _ref;
58
64
  const [isLegendOpen, setIsLegendOpen] = (0, _react.useState)(false);
59
65
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
@@ -195,7 +201,22 @@ function Map(_ref) {
195
201
  map.dragging.disable();
196
202
  }
197
203
  }, [mode, map]);
198
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
204
+ const seatsMap = (0, _react.useMemo)(() => new Map(seats.seats.map(s => [s.sId, s])), [seats.seats]);
205
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, seats.preventOrphanedSeats && /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
206
+ position: "topright"
207
+ }, /*#__PURE__*/_react.default.createElement("div", {
208
+ className: "extra-controls seat-quantity-control"
209
+ }, /*#__PURE__*/_react.default.createElement("button", {
210
+ title: "Quantity of seats to book",
211
+ onClick: () => {
212
+ setSelectQuantityPopupOpen(prev => !prev);
213
+ },
214
+ className: "leaflet-control-seat-quantity"
215
+ }, /*#__PURE__*/_react.default.createElement("span", null, "Selecting ", desiredSeatQuantity, " ", desiredSeatQuantity === 1 ? "seat" : "seats"), /*#__PURE__*/_react.default.createElement(_EditIcon.default, {
216
+ height: "16px",
217
+ width: "16px",
218
+ strokeWidth: "2"
219
+ })))), /*#__PURE__*/_react.default.createElement(_reactLeafletCustomControl.default, {
199
220
  position: "bottomright"
200
221
  }, /*#__PURE__*/_react.default.createElement("div", {
201
222
  className: "legendBox"
@@ -400,16 +421,23 @@ function Map(_ref) {
400
421
  zIndex: 10
401
422
  }) : /*#__PURE__*/_react.default.createElement(_reactLeaflet.Circle, {
402
423
  center: [s.r.includes("NORTH") ? getNorthSeatLat(s) : seatCenter.lat, seatCenter.lng],
403
- pathOptions: (0, _utils.getInitialColor)(s, price, !hasSeatPrices
424
+ pathOptions: (0, _utils.getInitialColor)(s, price, !hasSeatPrices,
404
425
  // TEST selected state for multiselect
405
- // !!selectedSeats.find(
406
- // (selectedSeat) => selectedSeat.ssId === s.ssId
407
- // )
408
- ),
426
+ !!selectedSeats.find(selectedSeat => selectedSeat.ssId === s.ssId)),
409
427
  radius: 12000,
410
428
  eventHandlers: {
411
429
  click: e => {
412
- if (mode === _utils.modes.SINGLE && hasSeatPrices) {
430
+ if (seats.preventOrphanedSeats && desiredSeatQuantity > 0) {
431
+ map.closePopup();
432
+ if (s.s === _utils.statuses.USER_PENDING) {
433
+ const newSeatsToRemove = (0, _utils.getAdjacentBookedSeats)(s, seatsMap);
434
+ setSeatsToRemove(newSeatsToRemove);
435
+ setRemoveMultipleSeatsPopupOpen(true);
436
+ }
437
+ if (selectedSeats.length > 0 && selectedSeats.length === desiredSeatQuantity) {
438
+ setPricingPopupOpen(true);
439
+ } else if (s.s === _utils.statuses.USER_PENDING) {}
440
+ } else if (mode === _utils.modes.SINGLE && hasSeatPrices) {
413
441
  handleClickSeat(e, s);
414
442
  }
415
443
  },
@@ -433,6 +461,12 @@ function Map(_ref) {
433
461
  if (!selectedSeats.find(seat => seat.ssId === s.ssId) && s.s === (mode === _utils.modes.DRAG ? _utils.statuses.UNSOLD : _utils.statuses.USER_PENDING)) {
434
462
  setSelectedSeats(prev => [...prev, s]);
435
463
  }
464
+ } else {
465
+ setSelectedSeats([]);
466
+ if (seats.preventOrphanedSeats && desiredSeatQuantity > 0 && s.s === _utils.statuses.UNSOLD) {
467
+ const seatsToBook = (0, _utils.getValidSeats)(s, seatsMap, desiredSeatQuantity);
468
+ setSelectedSeats(seatsToBook);
469
+ }
436
470
  }
437
471
  }
438
472
  }
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _utils = require("../utils");
9
9
  var _encodedSvgs = require("./assets/encodedSvgs");
10
10
  var _Flexi = _interopRequireDefault(require("./Flexi"));
11
+ var _TicketIcon = _interopRequireDefault(require("./icons/TicketIcon"));
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
13
14
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -61,34 +62,43 @@ const PriceSelect = _ref => {
61
62
  };
62
63
  function PricingPopup(_ref2) {
63
64
  let {
64
- cancelPriceSelect,
65
+ cancel,
65
66
  groupedSelectedSeats,
66
67
  pricing,
67
68
  priceSectionIds,
68
- batchAddTicketsToCart
69
+ batchAddTicketsToCart,
70
+ selectedSeatsWithPricing,
71
+ singleSeats
69
72
  } = _ref2;
70
- const [seatsToBook, setSeatsToBook] = (0, _react.useState)(groupedSelectedSeats);
73
+ const [seatGroupsToBook, setSeatGroupsToBook] = (0, _react.useState)(groupedSelectedSeats);
74
+ const [singleSeatsToBook, setSingleSeatsToBook] = (0, _react.useState)(selectedSeatsWithPricing);
71
75
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
72
76
  className: "pricing-popup-backdrop",
73
- onClick: cancelPriceSelect
77
+ onClick: cancel
74
78
  }), /*#__PURE__*/_react.default.createElement("div", {
75
79
  className: "pricing-popup",
76
80
  role: "dialog",
77
81
  "aria-modal": "true"
78
82
  }, /*#__PURE__*/_react.default.createElement("div", {
79
83
  className: "popup-header"
80
- }, /*#__PURE__*/_react.default.createElement("h3", null, "Choose prices"), /*#__PURE__*/_react.default.createElement("button", {
84
+ }, /*#__PURE__*/_react.default.createElement(_TicketIcon.default, {
85
+ className: "ticket-icon",
86
+ height: "86px",
87
+ width: "86px"
88
+ }), /*#__PURE__*/_react.default.createElement("button", {
81
89
  className: "close-button",
82
90
  "aria-label": "close popup",
83
- onClick: cancelPriceSelect
91
+ onClick: cancel
84
92
  }, /*#__PURE__*/_react.default.createElement("img", {
85
- src: _encodedSvgs.closeIcon,
93
+ src: _encodedSvgs.closeIconWhite,
86
94
  alt: "close",
87
95
  height: "20px",
88
96
  width: "20px"
89
- }))), /*#__PURE__*/_react.default.createElement("div", {
97
+ })), /*#__PURE__*/_react.default.createElement("h3", null, "Choose prices")), /*#__PURE__*/_react.default.createElement("div", {
98
+ className: "pricing-popup-content"
99
+ }, /*#__PURE__*/_react.default.createElement("div", {
90
100
  className: "seat-list"
91
- }, Object.entries(seatsToBook).map(_ref3 => {
101
+ }, !singleSeats && groupedSelectedSeats ? Object.entries(seatGroupsToBook).map(_ref3 => {
92
102
  let [id, seatGroup] = _ref3;
93
103
  const seatPriceages = pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && price.psId === parseInt(id));
94
104
  return /*#__PURE__*/_react.default.createElement("div", {
@@ -102,27 +112,55 @@ function PricingPopup(_ref2) {
102
112
  seatGroup: seatGroup,
103
113
  seatPriceages: seatPriceages,
104
114
  updateSeatGroupPriceage: newPriceage => {
105
- const newSeats = _objectSpread({}, seatsToBook);
115
+ const newSeats = _objectSpread({}, seatGroupsToBook);
106
116
  newSeats[id].priceage = newPriceage;
107
- setSeatsToBook(newSeats);
117
+ setSeatGroupsToBook(newSeats);
118
+ }
119
+ }) : /*#__PURE__*/_react.default.createElement("p", {
120
+ className: "no-prices-available"
121
+ }, "Oops, looks like there are no prices available for this section."));
122
+ }) : singleSeats && selectedSeatsWithPricing ? selectedSeatsWithPricing.map(_ref4 => {
123
+ let {
124
+ seat,
125
+ priceage
126
+ } = _ref4;
127
+ const seatPriceages = pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && price.psId === seat.psId);
128
+ return /*#__PURE__*/_react.default.createElement("div", {
129
+ key: seat.ssId,
130
+ className: "seat-group"
131
+ }, /*#__PURE__*/_react.default.createElement("div", {
132
+ className: "seat-group-header"
133
+ }, /*#__PURE__*/_react.default.createElement("h4", null, "Seat", " ".concat(seat.r, "-").concat(seat.c))), seatPriceages.filter(price => price.is_available !== false).length > 0 ? /*#__PURE__*/_react.default.createElement(PriceSelect, {
134
+ seatGroup: {
135
+ seats: [seat],
136
+ priceage
137
+ },
138
+ seatPriceages: seatPriceages,
139
+ updateSeatGroupPriceage: newPriceage => {
140
+ const newSeats = _objectSpread({}, singleSeatsToBook);
141
+ const currSeat = newSeats.find(s => s.seat.ssId === seat.ssId);
142
+ if (currSeat) {
143
+ currSeat.priceage = newPriceage;
144
+ }
145
+ setSingleSeatsToBook(newSeats);
108
146
  }
109
147
  }) : /*#__PURE__*/_react.default.createElement("p", {
110
148
  className: "no-prices-available"
111
149
  }, "Oops, looks like there are no prices available for this section."));
112
- })), /*#__PURE__*/_react.default.createElement("div", {
150
+ }) : null), /*#__PURE__*/_react.default.createElement("div", {
113
151
  className: "buttons"
114
152
  }, /*#__PURE__*/_react.default.createElement("button", {
115
153
  className: "cancel",
116
- onClick: cancelPriceSelect
154
+ onClick: cancel
117
155
  }, "Cancel"), /*#__PURE__*/_react.default.createElement("button", {
118
156
  className: "add-cart",
119
157
  onClick: () => {
120
- batchAddTicketsToCart(Object.values(seatsToBook).filter(v => !!v.priceage).flatMap(s => s.seats.map(seat => ({
158
+ singleSeats ? batchAddTicketsToCart(singleSeatsToBook) : batchAddTicketsToCart(Object.values(seatGroupsToBook).filter(v => !!v.priceage).flatMap(s => s.seats.map(seat => ({
121
159
  seat,
122
160
  priceage: s.priceage
123
161
  }))));
124
- cancelPriceSelect();
162
+ cancel();
125
163
  },
126
- disabled: Object.values(seatsToBook).every(v => !v.priceage)
127
- }, "Add to cart"))));
164
+ disabled: singleSeats ? singleSeatsToBook.every(v => !v.priceage) : Object.values(seatGroupsToBook).every(v => !v.priceage)
165
+ }, "Add to cart")))));
128
166
  }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = RemoveMultipleSeatsPopup;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _encodedSvgs = require("./assets/encodedSvgs");
9
+ var _TicketIcon = _interopRequireDefault(require("./icons/TicketIcon"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ function RemoveMultipleSeatsPopup(_ref) {
12
+ let {
13
+ onConfirm,
14
+ onClose
15
+ } = _ref;
16
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
17
+ className: "pricing-popup-backdrop",
18
+ onClick: onClose
19
+ }), /*#__PURE__*/_react.default.createElement("div", {
20
+ className: "pricing-popup remove-multiple-seats-popup",
21
+ role: "dialog",
22
+ "aria-modal": "true"
23
+ }, /*#__PURE__*/_react.default.createElement("div", {
24
+ className: "popup-header"
25
+ }, /*#__PURE__*/_react.default.createElement(_TicketIcon.default, {
26
+ className: "ticket-icon",
27
+ height: "86px",
28
+ width: "86px"
29
+ }), /*#__PURE__*/_react.default.createElement("button", {
30
+ className: "close-button",
31
+ "aria-label": "close popup",
32
+ onClick: onClose
33
+ }, /*#__PURE__*/_react.default.createElement("img", {
34
+ src: _encodedSvgs.closeIconWhite,
35
+ alt: "close",
36
+ height: "20px",
37
+ width: "20px"
38
+ })), /*#__PURE__*/_react.default.createElement("h3", null, "Remove from cart")), /*#__PURE__*/_react.default.createElement("div", {
39
+ className: "pricing-popup-content"
40
+ }, /*#__PURE__*/_react.default.createElement("h4", {
41
+ className: "quantity-heading"
42
+ }, "This will remove all adjacent seats from your cart. Are you sure you want to proceed?"), /*#__PURE__*/_react.default.createElement("div", {
43
+ className: "buttons"
44
+ }, /*#__PURE__*/_react.default.createElement("button", {
45
+ className: "cancel",
46
+ onClick: onClose
47
+ }, "Cancel"), /*#__PURE__*/_react.default.createElement("button", {
48
+ className: "add-cart",
49
+ onClick: onConfirm
50
+ }, "Confirm")))));
51
+ }
@@ -13,6 +13,8 @@ var _reactLeaflet = require("react-leaflet");
13
13
  var _utils = require("../utils");
14
14
  var _reactDom = require("react-dom");
15
15
  var _PricingPopup = _interopRequireDefault(require("./PricingPopup"));
16
+ var _SelectQuantityPopup = _interopRequireDefault(require("./SelectQuantityPopup"));
17
+ var _RemoveMultipleSeatsPopup = _interopRequireDefault(require("./RemoveMultipleSeatsPopup"));
16
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
18
20
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -57,7 +59,11 @@ const SeatingPlan = _ref => {
57
59
  const [mounted, setMounted] = _react.default.useState(false);
58
60
  const [mode, setMode] = (0, _react.useState)(_utils.modes.SINGLE);
59
61
  const [pricingPopupOpen, setPricingPopupOpen] = (0, _react.useState)(false);
62
+ const [selectQuantityPopupOpen, setSelectQuantityPopupOpen] = (0, _react.useState)(false);
63
+ const [desiredSeatQuantity, setDesiredSeatQuantity] = (0, _react.useState)(2);
60
64
  const [selectedSeats, setSelectedSeats] = (0, _react.useState)([]);
65
+ const [seatsToRemove, setSeatsToRemove] = (0, _react.useState)([]);
66
+ const [removeMultipleSeatsPopupOpen, setRemoveMultipleSeatsPopupOpen] = (0, _react.useState)(false);
61
67
  const mapRef = (0, _react.useRef)(null);
62
68
  const canMultiSelect = bookingMode === _utils.bookingModes.POS;
63
69
  const apiUrl = "".concat(baseUrl, "/legacy/").concat(countryCode, "/shop/events/").concat(eventId, "/").concat(eventVenueId, "/showings/").concat(showingId, "/tickets/allocated/").concat(areaId);
@@ -269,7 +275,7 @@ const SeatingPlan = _ref => {
269
275
  });
270
276
  };
271
277
  const batchAddTicketsToCart = async seatsToBook => {
272
- if (!canMultiSelect || seatsToBook.length === 0) {
278
+ if (!canMultiSelect && !seats.preventOrphanedSeats || seatsToBook.length === 0) {
273
279
  return;
274
280
  }
275
281
  const updatedSeats = _objectSpread({}, seats);
@@ -280,33 +286,102 @@ const SeatingPlan = _ref => {
280
286
  }
281
287
  });
282
288
  setSeats(updatedSeats);
283
- await new Promise(resolve => setTimeout(resolve, 1000));
284
- setBookedSeats(prev => [...prev, ...seatsToBook.map(_ref2 => {
285
- let {
286
- seat,
287
- priceage
288
- } = _ref2;
289
- return {
290
- ssId: seat.ssId,
291
- r: seat.r,
292
- c: seat.c,
293
- showingId: showingId,
294
- pId: priceage.paId,
295
- p: priceage.p,
296
- paName: priceage.paName
289
+ const succeeded = [];
290
+ try {
291
+ for (let seat of seatsToBook) {
292
+ try {
293
+ await fetch(apiUrl, {
294
+ method: "POST",
295
+ body: JSON.stringify({
296
+ priceAgeId: seat.priceage.paId,
297
+ seatId: seat.seat.ssId,
298
+ price: seat.priceage.p,
299
+ connectedShowings: connectedShowings
300
+ }),
301
+ headers: {
302
+ "content-type": "application/json",
303
+ "basket-key": sessionId
304
+ }
305
+ });
306
+ succeeded.push(seat);
307
+ } catch (error) {
308
+ console.error("Failed to book seat ".concat(seat, ":"), error);
309
+ throw new Error("Booking failed for seat ".concat(seat));
310
+ }
311
+ }
312
+ setBookedSeats(prev => [...prev, ...seatsToBook.map(_ref2 => {
313
+ let {
314
+ seat,
315
+ priceage
316
+ } = _ref2;
317
+ return {
318
+ ssId: seat.ssId,
319
+ r: seat.r,
320
+ c: seat.c,
321
+ showingId: showingId,
322
+ pId: priceage.paId,
323
+ p: priceage.p,
324
+ paName: priceage.paName
325
+ };
326
+ })]);
327
+ updatedSeats.seats.forEach(s => {
328
+ if (seatIds.includes(s.ssId)) {
329
+ s.s = _utils.statuses.USER_PENDING;
330
+ s.bookedPrice = price;
331
+ s.loading = false;
332
+ }
333
+ });
334
+ setSeats(updatedSeats);
335
+ const event = {
336
+ type: "cart-change-add",
337
+ details: [...bookedSeats, ...seatsToBook.map(_ref3 => {
338
+ let {
339
+ seat,
340
+ priceage
341
+ } = _ref3;
342
+ return {
343
+ ssId: seat.ssId,
344
+ r: seat.r,
345
+ c: seat.c,
346
+ showingId: showingId,
347
+ pId: priceage.paId,
348
+ p: priceage.p,
349
+ paName: priceage.paName
350
+ };
351
+ })]
297
352
  };
298
- })]);
299
- updatedSeats.seats.forEach(s => {
300
- if (seatIds.includes(s.ssId)) {
301
- s.s = _utils.statuses.USER_PENDING;
302
- s.bookedPrice = price;
303
- s.loading = false;
353
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
354
+ } catch (error) {
355
+ console.error("Failed to book seats:", error);
356
+ for (let seat of succeeded) {
357
+ await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
358
+ method: "DELETE",
359
+ headers: {
360
+ "basket-key": sessionId
361
+ }
362
+ });
304
363
  }
305
- });
306
- setSeats(updatedSeats);
364
+ updatedSeats.seats.forEach(s => {
365
+ if (seatIds.includes(s.ssId)) {
366
+ s.loading = false;
367
+ }
368
+ });
369
+ setSeats(updatedSeats);
370
+ const event = {
371
+ type: "error",
372
+ details: {
373
+ error: {
374
+ code: 500,
375
+ message: "Oops! Something went wrong. Please try again."
376
+ }
377
+ }
378
+ };
379
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
380
+ }
381
+ _initialFetch(true);
307
382
  };
308
383
  const batchRemoveTicketsFromCart = async seatsToRemove => {
309
- if (!canMultiSelect || seatsToRemove.length === 0) {
384
+ if (!canMultiSelect && !seats.preventOrphanedSeats || seatsToRemove.length === 0) {
310
385
  return;
311
386
  }
312
387
  const updatedSeats = _objectSpread({}, seats);
@@ -317,16 +392,53 @@ const SeatingPlan = _ref => {
317
392
  }
318
393
  });
319
394
  setSeats(updatedSeats);
320
- await new Promise(resolve => setTimeout(resolve, 1000));
321
- setBookedSeats(prev => [...prev.filter(v => !seatIds.includes(v.ssId))]);
395
+ const succeededIds = [];
396
+ try {
397
+ for (let seat of seatsToRemove) {
398
+ try {
399
+ await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
400
+ method: "DELETE",
401
+ headers: {
402
+ "basket-key": sessionId
403
+ }
404
+ });
405
+ succeededIds.push(seat.ssId);
406
+ } catch (error) {
407
+ console.error("Failed to remove seat ".concat(seat, ":"), error);
408
+ }
409
+ }
410
+ } catch (_unused) {
411
+ const event = {
412
+ type: "error",
413
+ details: {
414
+ error: {
415
+ code: 500,
416
+ message: "Oops! Something went wrong. Please try again."
417
+ }
418
+ }
419
+ };
420
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
421
+ }
422
+ setBookedSeats(prev => [...prev.filter(v => !succeededIds.includes(v.ssId))]);
322
423
  updatedSeats.seats.forEach(s => {
323
424
  if (seatIds.includes(s.ssId)) {
324
425
  s.loading = false;
325
- s.s = _utils.statuses.UNSOLD;
326
- s.bookedPrice = null;
426
+ if (succeededIds.includes(s.ssId)) {
427
+ s.s = _utils.statuses.UNSOLD;
428
+ s.bookedPrice = null;
429
+ }
327
430
  }
328
431
  });
329
432
  setSeats(updatedSeats);
433
+ setSeatsToRemove([]);
434
+ if (succeededIds.length > 0) {
435
+ const event = {
436
+ type: "cart-change-remove",
437
+ details: bookedSeats.filter(bs => succeededIds.includes(bs.ssId))
438
+ };
439
+ callbackFunction === null || callbackFunction === void 0 || callbackFunction(event);
440
+ }
441
+ _initialFetch(true);
330
442
  };
331
443
  const handleClickSeat = (e, s) => {
332
444
  setChosenSeat({
@@ -406,6 +518,9 @@ const SeatingPlan = _ref => {
406
518
  setHeight(img.height * 0.5);
407
519
  setWidth(img.width * 0.5);
408
520
  setSeats(data);
521
+ if (data.preventOrphanedSeats && !isReload) {
522
+ setSelectQuantityPopupOpen(true);
523
+ }
409
524
  };
410
525
  setIsReloading(false);
411
526
  }).catch(error => {
@@ -443,6 +558,14 @@ const SeatingPlan = _ref => {
443
558
  // in full screen mode, render the map in the body, otherwise render in the seating-plan-root div
444
559
  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"));
445
560
  const backdropContainer = mounted && ((_document3 = document) === null || _document3 === void 0 ? void 0 : _document3.body);
561
+ const selectedSeatsWithPricing = selectedSeats.map(s => {
562
+ const priceages = seats.pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && price.psId === s.psId);
563
+ const availablePriceages = priceages.filter(p => p.is_available !== false);
564
+ return {
565
+ seat: s,
566
+ priceage: availablePriceages.length > 0 ? availablePriceages[0] : null
567
+ };
568
+ });
446
569
  const groupedSelectedSeats = selectedSeats.reduce((acc, curr) => {
447
570
  if (curr.psId) {
448
571
  const priceages = seats.pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && price.psId === curr.psId);
@@ -474,12 +597,27 @@ const SeatingPlan = _ref => {
474
597
  }), backdropContainer), mapContainer && /*#__PURE__*/(0, _reactDom.createPortal)(/*#__PURE__*/_react.default.createElement("div", {
475
598
  className: "seating-plan-container ".concat(isFullScreen ? "full-screen" : ""),
476
599
  "data-mode": mode
477
- }, pricingPopupOpen && canMultiSelect && /*#__PURE__*/_react.default.createElement(_PricingPopup.default, {
478
- cancelPriceSelect: cancelPriceSelect,
600
+ }, pricingPopupOpen && (canMultiSelect || seats.preventOrphanedSeats) ? /*#__PURE__*/_react.default.createElement(_PricingPopup.default, {
601
+ cancel: cancelPriceSelect,
479
602
  groupedSelectedSeats: groupedSelectedSeats,
603
+ selectedSeatsWithPricing: selectedSeatsWithPricing,
480
604
  priceSectionIds: priceSectionIds,
481
605
  pricing: seats.pricing,
482
- batchAddTicketsToCart: batchAddTicketsToCart
606
+ batchAddTicketsToCart: batchAddTicketsToCart,
607
+ singleSeats: seats.preventOrphanedSeats
608
+ }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), selectQuantityPopupOpen && /*#__PURE__*/_react.default.createElement(_SelectQuantityPopup.default, {
609
+ quantity: desiredSeatQuantity,
610
+ setQuantity: v => {
611
+ setDesiredSeatQuantity(v);
612
+ setSelectedSeats([]);
613
+ },
614
+ onClose: () => setSelectQuantityPopupOpen(false)
615
+ }), removeMultipleSeatsPopupOpen && /*#__PURE__*/_react.default.createElement(_RemoveMultipleSeatsPopup.default, {
616
+ onConfirm: () => {
617
+ batchRemoveTicketsFromCart(seatsToRemove);
618
+ setRemoveMultipleSeatsPopupOpen(false);
619
+ },
620
+ onClose: () => setRemoveMultipleSeatsPopupOpen(false)
483
621
  }), /*#__PURE__*/_react.default.createElement(_reactLeaflet.MapContainer, {
484
622
  zoomSnap: 0,
485
623
  zoomDelta: 1,
@@ -517,7 +655,12 @@ const SeatingPlan = _ref => {
517
655
  pricingPopupOpen: pricingPopupOpen,
518
656
  setPricingPopupOpen: setPricingPopupOpen,
519
657
  selectedSeats: selectedSeats,
520
- setSelectedSeats: setSelectedSeats
658
+ setSelectedSeats: setSelectedSeats,
659
+ selectQuantityPopupOpen: selectQuantityPopupOpen,
660
+ setSelectQuantityPopupOpen: setSelectQuantityPopupOpen,
661
+ desiredSeatQuantity: desiredSeatQuantity,
662
+ setSeatsToRemove: setSeatsToRemove,
663
+ setRemoveMultipleSeatsPopupOpen: setRemoveMultipleSeatsPopupOpen
521
664
  }))), mapContainer)) : /*#__PURE__*/_react.default.createElement("div", {
522
665
  className: "loading"
523
666
  }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("svg", {
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = SelectQuantityPopup;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _encodedSvgs = require("./assets/encodedSvgs");
9
+ var _TicketIcon = _interopRequireDefault(require("./icons/TicketIcon"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
12
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
+ const PriceSelect = _ref => {
14
+ let {
15
+ newQuantity,
16
+ setNewQuantity
17
+ } = _ref;
18
+ return /*#__PURE__*/_react.default.createElement("div", {
19
+ className: "price-select"
20
+ }, /*#__PURE__*/_react.default.createElement("select", {
21
+ onChange: e => {
22
+ setNewQuantity(parseInt(e.target.value));
23
+ },
24
+ value: newQuantity
25
+ }, Array.from({
26
+ length: 10
27
+ }, (_, i) => /*#__PURE__*/_react.default.createElement("option", {
28
+ key: i,
29
+ value: i + 1
30
+ }, i + 1))));
31
+ };
32
+ function SelectQuantityPopup(_ref2) {
33
+ let {
34
+ quantity,
35
+ setQuantity,
36
+ onClose
37
+ } = _ref2;
38
+ const [newQuantity, setNewQuantity] = (0, _react.useState)(quantity);
39
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
40
+ className: "pricing-popup-backdrop",
41
+ onClick: onClose
42
+ }), /*#__PURE__*/_react.default.createElement("div", {
43
+ className: "pricing-popup",
44
+ role: "dialog",
45
+ "aria-modal": "true"
46
+ }, /*#__PURE__*/_react.default.createElement("div", {
47
+ className: "popup-header"
48
+ }, /*#__PURE__*/_react.default.createElement(_TicketIcon.default, {
49
+ className: "ticket-icon",
50
+ height: "86px",
51
+ width: "86px"
52
+ }), /*#__PURE__*/_react.default.createElement("button", {
53
+ className: "close-button",
54
+ "aria-label": "close popup",
55
+ onClick: onClose
56
+ }, /*#__PURE__*/_react.default.createElement("img", {
57
+ src: _encodedSvgs.closeIconWhite,
58
+ alt: "close",
59
+ height: "20px",
60
+ width: "20px"
61
+ })), /*#__PURE__*/_react.default.createElement("h3", null, "Choose seats")), /*#__PURE__*/_react.default.createElement("div", {
62
+ className: "pricing-popup-content"
63
+ }, /*#__PURE__*/_react.default.createElement("h4", {
64
+ className: "quantity-heading"
65
+ }, "How many seats would you like to book?"), /*#__PURE__*/_react.default.createElement("div", {
66
+ className: "seat-list"
67
+ }, /*#__PURE__*/_react.default.createElement(PriceSelect, {
68
+ setNewQuantity: setNewQuantity,
69
+ newQuantity: newQuantity
70
+ })), /*#__PURE__*/_react.default.createElement("div", {
71
+ className: "buttons"
72
+ }, /*#__PURE__*/_react.default.createElement("button", {
73
+ className: "cancel",
74
+ onClick: onClose
75
+ }, "Cancel"), /*#__PURE__*/_react.default.createElement("button", {
76
+ className: "add-cart",
77
+ onClick: () => {
78
+ setQuantity(newQuantity);
79
+ onClose();
80
+ }
81
+ }, "Confirm")))));
82
+ }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.wheelchairIcon = exports.userIcon = exports.handIcon = exports.flexiIcon = exports.expandIcon = exports.editIcon = exports.cursorIcon = exports.collapseIcon = exports.closeIcon = void 0;
6
+ exports.wheelchairIcon = exports.userIcon = exports.handIcon = exports.flexiIcon = exports.expandIcon = exports.editIcon = exports.cursorIcon = exports.collapseIcon = exports.closeIconWhite = exports.closeIcon = void 0;
7
7
  const expandIcon = exports.expandIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgaGVpZ2h0PSIyNCIgd2lkdGg9IjI0IiBmaWxsPSJjdXJyZW50Q29sb3IiIHN0cm9rZT0iY3VycmVudENvbG9yIj4KIDxwYXRoIGQ9Ik03IDE0SDV2NWg1di0ySDd6bS0yLTRoMlY3aDNWNUg1em0xMiA3aC0zdjJoNXYtNWgtMnpNMTQgNXYyaDN2M2gyVjV6Ij48L3BhdGg+Cjwvc3ZnPgo=";
8
8
  const collapseIcon = exports.collapseIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgaGVpZ2h0PSIyNCIgd2lkdGg9IjI0IiBmaWxsPSJjdXJyZW50Q29sb3IiIHN0cm9rZT0iY3VycmVudENvbG9yIj4KPHBhdGggZD0iTTUgMTZoM3YzaDJ2LTVINXptMy04SDV2Mmg1VjVIOHptNiAxMWgydi0zaDN2LTJoLTV6bTItMTFWNWgtMnY1aDVWOHoiPjwvcGF0aD4KPC9zdmc+Cg==";
9
9
  const closeIcon = exports.closeIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxsaW5lIHgxPSIxOCIgeTE9IjYiIHgyPSI2IiB5Mj0iMTgiLz48bGluZSB4MT0iNiIgeTE9IjYiIHgyPSIxOCIgeTI9IjE4Ii8+PC9zdmc+";
@@ -12,4 +12,5 @@ const wheelchairIcon = exports.wheelchairIcon = "data:image/svg+xml;base64,PD94b
12
12
  const handIcon = exports.handIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik00NDggMjQwdjk2YzAgMy4xLS40IDYuMi0xLjEgOS4ybC0zMiAxMzZDNDEwLjcgNDk5LjIgMzk0LjYgNTEyIDM3NiA1MTJIMTY4YTQwIDQwIDAgMCAxIC0zMi40LTE2LjVsLTEyOC0xNzZjLTEzLTE3LjktOS00Mi45IDguOC01NS45IDE3LjktMTMgNDIuOS05IDU1LjkgOC44TDEwNCAzMTZWNDBjMC0yMi4xIDE3LjktNDAgNDAtNDBzNDAgMTcuOSA0MCA0MHYyMDBoOHYtNDBjMC0yMi4xIDE3LjktNDAgNDAtNDBzNDAgMTcuOSA0MCA0MHY0MGg4di0yNGMwLTIyLjEgMTcuOS00MCA0MC00MHM0MCAxNy45IDQwIDQwdjI0aDhjMC0yMi4xIDE3LjktNDAgNDAtNDBzNDAgMTcuOSA0MCA0MHptLTI1NiA4MGgtOHY5Nmg4di05NnptODggMGgtOHY5Nmg4di05NnptODggMGgtOHY5Nmg4di05NnoiLz48L3N2Zz4=";
13
13
  const cursorIcon = exports.cursorIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDMyMCA1MTIiPjwhLS0hRm9udCBBd2Vzb21lIEZyZWUgNi43LjEgYnkgQGZvbnRhd2Vzb21lIC0gaHR0cHM6Ly9mb250YXdlc29tZS5jb20gTGljZW5zZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tL2xpY2Vuc2UvZnJlZSBDb3B5cmlnaHQgMjAyNCBGb250aWNvbnMsIEluYy4tLT48cGF0aCBkPSJNMCA1NS4yTDAgNDI2YzAgMTIuMiA5LjkgMjIgMjIgMjJjNi4zIDAgMTIuNC0yLjcgMTYuNi03LjVMMTIxLjIgMzQ2bDU4LjEgMTE2LjNjNy45IDE1LjggMjcuMSAyMi4yIDQyLjkgMTQuM3MyMi4yLTI3LjEgMTQuMy00Mi45TDE3OS44IDMyMGwxMTguMSAwYzEyLjIgMCAyMi4xLTkuOSAyMi4xLTIyLjFjMC02LjMtMi43LTEyLjMtNy40LTE2LjVMMzguNiAzNy45QzM0LjMgMzQuMSAyOC45IDMyIDIzLjIgMzJDMTAuNCAzMiAwIDQyLjQgMCA1NS4yeiIvPjwvc3ZnPg==";
14
14
  const flexiIcon = exports.flexiIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDI0IDI0IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIGNsYXNzPSJzaXplLTYiPgogIDxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTIuMjUgMTggOSAxMS4yNWw0LjMwNiA0LjMwNmExMS45NSAxMS45NSAwIDAgMSA1LjgxNC01LjUxOGwyLjc0LTEuMjJtMCAwLTUuOTQtMi4yODFtNS45NCAyLjI4LTIuMjggNS45NDEiIC8+Cjwvc3ZnPg==";
15
- const editIcon = exports.editIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDI0IDI0IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIGNsYXNzPSJzaXplLTYiPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0ibTE2Ljg2MiA0LjQ4NyAxLjY4Ny0xLjY4OGExLjg3NSAxLjg3NSAwIDEgMSAyLjY1MiAyLjY1MkwxMC41ODIgMTYuMDdhNC41IDQuNSAwIDAgMS0xLjg5NyAxLjEzTDYgMThsLjgtMi42ODVhNC41IDQuNSAwIDAgMSAxLjEzLTEuODk3bDguOTMyLTguOTMxWm0wIDBMMTkuNSA3LjEyNU0xOCAxNHY0Ljc1QTIuMjUgMi4yNSAwIDAgMSAxNS43NSAyMUg1LjI1QTIuMjUgMi4yNSAwIDAgMSAzIDE4Ljc1VjguMjVBMi4yNSAyLjI1IDAgMCAxIDUuMjUgNkgxMCIgLz48L3N2Zz4=";
15
+ const editIcon = exports.editIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDI0IDI0IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIGNsYXNzPSJzaXplLTYiPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0ibTE2Ljg2MiA0LjQ4NyAxLjY4Ny0xLjY4OGExLjg3NSAxLjg3NSAwIDEgMSAyLjY1MiAyLjY1MkwxMC41ODIgMTYuMDdhNC41IDQuNSAwIDAgMS0xLjg5NyAxLjEzTDYgMThsLjgtMi42ODVhNC41IDQuNSAwIDAgMSAxLjEzLTEuODk3bDguOTMyLTguOTMxWm0wIDBMMTkuNSA3LjEyNU0xOCAxNHY0Ljc1QTIuMjUgMi4yNSAwIDAgMSAxNS43NSAyMUg1LjI1QTIuMjUgMi4yNSAwIDAgMSAzIDE4Ljc1VjguMjVBMi4yNSAyLjI1IDAgMCAxIDUuMjUgNkgxMCIgLz48L3N2Zz4=";
16
+ const closeIconWhite = exports.closeIconWhite = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48bGluZSB4MT0iMTgiIHkxPSI2IiB4Mj0iNiIgeTI9IjE4Ii8+PGxpbmUgeDE9IjYiIHkxPSI2IiB4Mj0iMTgiIHkyPSIxOCIvPjwvc3ZnPg==";
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = EditIcon;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ function EditIcon(_ref) {
10
+ let {
11
+ height = "18px",
12
+ width = "18px",
13
+ color = "currentColor",
14
+ strokeWidth = "1.5",
15
+ className
16
+ } = _ref;
17
+ return /*#__PURE__*/_react.default.createElement("svg", {
18
+ width: width,
19
+ height: height,
20
+ xmlns: "http://www.w3.org/2000/svg",
21
+ fill: "none",
22
+ viewBox: "0 0 24 24",
23
+ strokeWidth: strokeWidth,
24
+ stroke: color,
25
+ className: className
26
+ }, /*#__PURE__*/_react.default.createElement("path", {
27
+ strokeLinecap: "round",
28
+ strokeLinejoin: "round",
29
+ d: "m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
30
+ }));
31
+ }
@@ -676,6 +676,31 @@ svg.leaflet-image-layer.leaflet-interactive path {
676
676
  justify-content: center;
677
677
  }
678
678
 
679
+ .extra-controls.seat-quantity-control {
680
+ border: none;
681
+ transition: border-color 0.2s;
682
+ border-radius: 6px;
683
+ }
684
+
685
+ .extra-controls .leaflet-control-seat-quantity {
686
+ border: none;
687
+ background: var(--accent);
688
+ color: white;
689
+ cursor: pointer;
690
+ display: flex;
691
+ align-items: center;
692
+ font-size: 0.875rem;
693
+ gap: 0.25rem;
694
+ padding: 5px 10px;
695
+ transition: all 0.2s;
696
+ font-weight: bold;
697
+ }
698
+
699
+ .extra-controls .leaflet-control-seat-quantity:hover {
700
+ background: var(--accent-light);
701
+ color: var(--accent-dark);
702
+ }
703
+
679
704
  .leaflet-control-zoom-in.reload-seating-plan {
680
705
  border-radius: 0 0 0 0;
681
706
  border-top: 1px solid #ccc;
@@ -11,6 +11,12 @@
11
11
  animation: fade-in 400ms;
12
12
  }
13
13
 
14
+ .pricing-popup-content {
15
+ padding: 1rem;
16
+ flex: 1;
17
+ overflow-y: auto;
18
+ }
19
+
14
20
  .pricing-popup {
15
21
  position: absolute;
16
22
  z-index: 1002;
@@ -21,19 +27,39 @@
21
27
  background-color: #fff;
22
28
  /* font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; */
23
29
  font-family: inherit;
24
- padding: 1rem;
25
30
  color: #333;
26
31
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
27
32
  border-radius: 12px;
28
33
  min-width: 20rem;
34
+ max-height: 95%;
35
+ display: flex;
36
+ flex-direction: column;
37
+ }
38
+
39
+ @media screen and (max-width: 600px) {
40
+ .pricing-popup {
41
+ width: 100%;
42
+ min-width: unset;
43
+ }
44
+ }
45
+
46
+ .pricing-popup.remove-multiple-seats-popup {
47
+ min-width: unset;
48
+ max-width: 28rem;
29
49
  }
30
50
 
31
51
  .pricing-popup .popup-header {
32
52
  margin-top: 0;
53
+ padding: 1rem;
54
+ border-radius: 12px 12px 0px 0px;
55
+ flex-direction: column;
56
+ text-align: left;
57
+ gap: 0.5rem;
33
58
  }
34
59
 
35
60
  .pricing-popup .popup-header .close-button {
36
61
  margin: -2px -2px 0px 0px;
62
+ align-self: flex-end;
37
63
  }
38
64
 
39
65
  .pricing-popup h3,
@@ -42,6 +68,13 @@
42
68
  margin: 0;
43
69
  }
44
70
 
71
+ .pricing-popup .quantity-heading {
72
+ font-weight: normal;
73
+ text-align: left;
74
+ font-size: 0.875rem;
75
+ margin-bottom: 8px;
76
+ }
77
+
45
78
  .pricing-popup p {
46
79
  margin: 0;
47
80
  max-width: 30rem;
@@ -56,7 +89,6 @@
56
89
  display: flex;
57
90
  flex-direction: column;
58
91
  gap: 1rem;
59
- margin-top: 1rem;
60
92
  }
61
93
 
62
94
  .pricing-popup .seat-group {
@@ -76,6 +108,8 @@
76
108
  .pricing-popup select {
77
109
  flex: 1;
78
110
  padding: 0.3rem 0.2rem;
111
+ border: 1px solid #ccc;
112
+ border-radius: 0.25rem;
79
113
  }
80
114
 
81
115
  .pricing-popup .buttons {
@@ -98,6 +132,24 @@
98
132
  margin-bottom: 0;
99
133
  }
100
134
 
135
+ .pricing-popup .buttons button.add-cart {
136
+ background: var(--accent);
137
+ color: white;
138
+ font-weight: bold;
139
+ border: none;
140
+ }
141
+
142
+ .pricing-popup .buttons button.add-cart:hover:not(:disabled) {
143
+ background: var(--accent-light);
144
+ color: var(--accent-dark);
145
+ }
146
+
147
+ @media screen and (max-width: 600px) {
148
+ .pricing-popup .buttons button {
149
+ min-width: 8rem;
150
+ }
151
+ }
152
+
101
153
  .pricing-popup .buttons button:disabled {
102
154
  cursor: default;
103
155
  color: #bdc3c7;
@@ -115,7 +167,7 @@
115
167
  }
116
168
 
117
169
  .pricing-popup button.cancel {
118
- background: #ecf0f1;
170
+ background: #dcdcdc;
119
171
  border: none;
120
172
  }
121
173
 
@@ -12,7 +12,6 @@ const statusColors = exports.statusColors = {
12
12
  pending: "#e74c3c",
13
13
  booked: "#e74c3c",
14
14
  bookedWithDifferentPrice: "#fab1a0",
15
- // TODO temporary selected state
16
15
  selected: "#049CDB"
17
16
  };
18
17
  const statuses = exports.statuses = {
@@ -3,18 +3,24 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getInitialColor = exports.calculateCenterOfMap = exports.NZDollar = void 0;
6
+ exports.getValidSeats = exports.getRowSection = exports.getInitialColor = exports.getAdjacentBookedSeats = exports.createsOrphan = exports.canSelectSingleSeatGivenOrphanRules = exports.calculateCenterOfMap = exports.NZDollar = void 0;
7
7
  var _enums = require("./enums");
8
- const getInitialColor = (s, price, disabled, selected) => {
9
- // TEST selected state for multiselect
10
- // if (selected) {
11
- // return {
12
- // fillColor: statusColors.selected,
13
- // color: "none",
14
- // fillOpacity: s.loading ? 0 : 1,
15
- // };
16
- // }
17
-
8
+ const getInitialColor = (s, price, disabled, selected, greyedOut) => {
9
+ // selected state for multiselect
10
+ if (selected) {
11
+ return {
12
+ fillColor: _enums.statusColors.selected,
13
+ color: "none",
14
+ fillOpacity: s.loading ? 0 : 1
15
+ };
16
+ }
17
+ if (greyedOut) {
18
+ return {
19
+ fillColor: _enums.statusColors.unknown,
20
+ color: "none",
21
+ fillOpacity: s.loading ? 0 : 1
22
+ };
23
+ }
18
24
  return {
19
25
  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,
20
26
  color: "none",
@@ -37,4 +43,121 @@ exports.calculateCenterOfMap = calculateCenterOfMap;
37
43
  const NZDollar = exports.NZDollar = new Intl.NumberFormat("en-NZ", {
38
44
  style: "currency",
39
45
  currency: "NZD"
40
- });
46
+ });
47
+ const createsOrphan = (seat, seats, isRemove, selectedSeats) => {
48
+ const selectedIds = selectedSeats ? selectedSeats.map(s => s.sId) : null;
49
+ const filteredSeats = selectedIds ? seats.filter(s => !selectedIds.includes(s.sId)) : seats;
50
+ const sa = filteredSeats.find(s => s.sId === seat.sa);
51
+ const saa = filteredSeats.find(s => s.sId === (sa === null || sa === void 0 ? void 0 : sa.sa));
52
+ const sb = filteredSeats.find(s => s.sId === seat.sb);
53
+ const sbb = filteredSeats.find(s => s.sId === (sb === null || sb === void 0 ? void 0 : sb.sb));
54
+ if (isRemove) {
55
+ if (sa && sb && sa.s !== _enums.statuses.UNSOLD && sb.s === _enums.statuses.USER_PENDING || sa && sb && sa.s === _enums.statuses.USER_PENDING && sb.s !== _enums.statuses.UNSOLD || sa && !sb && sa.s === _enums.statuses.USER_PENDING || sb && !sa && sb.s === _enums.statuses.USER_PENDING) {
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ if (sb && sbb && sb.s === _enums.statuses.UNSOLD && sbb.s !== _enums.statuses.UNSOLD || sa && saa && sa.s === _enums.statuses.UNSOLD && saa.s !== _enums.statuses.UNSOLD || sb && !sbb && sb.s === _enums.statuses.UNSOLD || sa && !saa && sa.s === _enums.statuses.UNSOLD) {
61
+ return true;
62
+ }
63
+ return false;
64
+ };
65
+ exports.createsOrphan = createsOrphan;
66
+ const getRowSection = (startSeat, seatsMap) => {
67
+ const row = [];
68
+ let seat = startSeat;
69
+ while (seat && seat.sId !== undefined) {
70
+ row.unshift(seat);
71
+ seat = seatsMap.get(seat.sb);
72
+ }
73
+ seat = seatsMap.get(startSeat.sa);
74
+ while (seat && seat.sId !== undefined) {
75
+ row.push(seat);
76
+ seat = seatsMap.get(seat.sa);
77
+ }
78
+ return row;
79
+ };
80
+ exports.getRowSection = getRowSection;
81
+ const canSelectSingleSeatGivenOrphanRules = (seat, rowSection) => {
82
+ const isRemove = seat.s === _enums.statuses.USER_PENDING;
83
+ const selectedSeatCreatesOrphan = createsOrphan(seat, rowSection, isRemove);
84
+ if (selectedSeatCreatesOrphan) {
85
+ let hasOtherOptions = false;
86
+ for (let i = 0; i < rowSection.length; i++) {
87
+ if (rowSection[i].sId !== seat.sId && rowSection[i].s === (isRemove ? _enums.statuses.USER_PENDING : _enums.statuses.UNSOLD) && !createsOrphan(rowSection[i], rowSection, isRemove)) {
88
+ hasOtherOptions = true;
89
+ break;
90
+ }
91
+ }
92
+ return hasOtherOptions ? false : true;
93
+ }
94
+ return true;
95
+ };
96
+ exports.canSelectSingleSeatGivenOrphanRules = canSelectSingleSeatGivenOrphanRules;
97
+ const getValidSeats = (s, seatsMap, desiredSeatQuantity) => {
98
+ let seatsToBook = [s];
99
+ const rowSection = getRowSection(s, seatsMap);
100
+ if (seatsToBook.length < desiredSeatQuantity) {
101
+ const traverse = (seat, direction) => {
102
+ const nextSeatId = direction === "left" ? seat.sb : seat.sa;
103
+ if (nextSeatId) {
104
+ const nextSeat = rowSection.find(v => v.sId === nextSeatId);
105
+ if (nextSeat && nextSeat.s === _enums.statuses.UNSOLD && seatsToBook.length < desiredSeatQuantity && !(seatsToBook.length === desiredSeatQuantity - 1 && createsOrphan(nextSeat, rowSection, false, seatsToBook))) {
106
+ if (direction === "left") {
107
+ seatsToBook.unshift(nextSeat);
108
+ } else {
109
+ seatsToBook.push(nextSeat);
110
+ }
111
+ if (seatsToBook.length < desiredSeatQuantity) {
112
+ traverse(nextSeat, direction);
113
+ }
114
+ }
115
+ }
116
+ };
117
+ traverse(s, "right");
118
+ if (seatsToBook.length < desiredSeatQuantity) {
119
+ traverse(s, "left");
120
+ }
121
+ const firstSeat = seatsToBook[0];
122
+ const sb = rowSection.find(v => v.sId === firstSeat.sb);
123
+ const sbb = rowSection.find(v => v.sId === (sb === null || sb === void 0 ? void 0 : sb.sb));
124
+ const orphanToLeft = sb && sbb && sb.s === _enums.statuses.UNSOLD && sbb.s !== _enums.statuses.UNSOLD || sb && !sbb && sb.s === _enums.statuses.UNSOLD;
125
+ if (seatsToBook.length < desiredSeatQuantity || orphanToLeft) {
126
+ seatsToBook = [s];
127
+ traverse(s, "left");
128
+ if (seatsToBook.length < desiredSeatQuantity) {
129
+ traverse(s, "right");
130
+ }
131
+ }
132
+ }
133
+ if (seatsToBook.length === 1 && desiredSeatQuantity === 1) {
134
+ return canSelectSingleSeatGivenOrphanRules(s, rowSection) ? seatsToBook : [];
135
+ }
136
+ if (seatsToBook.length === desiredSeatQuantity && !(seatsToBook.length === 1 && createsOrphan(s, rowSection, false, seatsToBook))) {
137
+ return seatsToBook;
138
+ }
139
+ return [];
140
+ };
141
+ exports.getValidSeats = getValidSeats;
142
+ const getAdjacentBookedSeats = (seat, seatsMap) => {
143
+ const rowSection = getRowSection(seat, seatsMap);
144
+ const adjacentBookedSeats = [seat];
145
+ const traverse = (seat, direction) => {
146
+ const nextSeatId = direction === "left" ? seat.sb : seat.sa;
147
+ if (nextSeatId) {
148
+ const nextSeat = rowSection.find(v => v.sId === nextSeatId);
149
+ if (nextSeat && nextSeat.s === _enums.statuses.USER_PENDING) {
150
+ if (direction === "left") {
151
+ adjacentBookedSeats.unshift(nextSeat);
152
+ } else {
153
+ adjacentBookedSeats.push(nextSeat);
154
+ }
155
+ traverse(nextSeat, direction);
156
+ }
157
+ }
158
+ };
159
+ traverse(seat, "right");
160
+ traverse(seat, "left");
161
+ return adjacentBookedSeats;
162
+ };
163
+ exports.getAdjacentBookedSeats = getAdjacentBookedSeats;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "iticket-seatingplan-dev",
3
3
  "description": "Seating plan with FLEXi pricing",
4
4
  "author": "gedwyne",
5
- "version": "1.6.7",
5
+ "version": "1.6.9",
6
6
  "private": false,
7
7
  "keywords": [
8
8
  "iticket",