iticket-seatingplan-dev 1.6.8 → 1.7.0

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,47 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = InvalidSeatsPopup;
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 InvalidSeatsPopup(_ref) {
12
+ let {
13
+ onClose
14
+ } = _ref;
15
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
16
+ className: "pricing-popup-backdrop",
17
+ onClick: onClose
18
+ }), /*#__PURE__*/_react.default.createElement("div", {
19
+ className: "pricing-popup remove-multiple-seats-popup",
20
+ role: "dialog",
21
+ "aria-modal": "true"
22
+ }, /*#__PURE__*/_react.default.createElement("div", {
23
+ className: "popup-header"
24
+ }, /*#__PURE__*/_react.default.createElement(_TicketIcon.default, {
25
+ className: "ticket-icon",
26
+ height: "86px",
27
+ width: "86px"
28
+ }), /*#__PURE__*/_react.default.createElement("button", {
29
+ className: "close-button",
30
+ "aria-label": "close popup",
31
+ onClick: onClose
32
+ }, /*#__PURE__*/_react.default.createElement("img", {
33
+ src: _encodedSvgs.closeIconWhite,
34
+ alt: "close",
35
+ height: "20px",
36
+ width: "20px"
37
+ })), /*#__PURE__*/_react.default.createElement("h3", null, "Seat selection")), /*#__PURE__*/_react.default.createElement("div", {
38
+ className: "pricing-popup-content"
39
+ }, /*#__PURE__*/_react.default.createElement("h4", {
40
+ className: "quantity-heading"
41
+ }, "The seats you've chosen aren't available. They may leave a single seat on its own, or there may not be enough seats in the row for your selection. Please select different seats to continue."), /*#__PURE__*/_react.default.createElement("div", {
42
+ className: "buttons buttons-single"
43
+ }, /*#__PURE__*/_react.default.createElement("button", {
44
+ className: "add-cart",
45
+ onClick: onClose
46
+ }, "Ok")))));
47
+ }
@@ -59,10 +59,13 @@ function SeatMap(_ref) {
59
59
  setSelectQuantityPopupOpen,
60
60
  desiredSeatQuantity,
61
61
  setSeatsToRemove,
62
- setRemoveMultipleSeatsPopupOpen
62
+ setRemoveMultipleSeatsPopupOpen,
63
+ setInvalidSeatsPopupOpen
63
64
  } = _ref;
64
65
  const [isLegendOpen, setIsLegendOpen] = (0, _react.useState)(false);
65
66
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
67
+ const [highlightedSeats, setHighlightedSeats] = (0, _react.useState)([]);
68
+ const [greyedOutSeats, setGreyedOutSeats] = (0, _react.useState)([]);
66
69
  const drawLayersRef = (0, _react.useRef)(null);
67
70
  const drawRef = (0, _react.useRef)(null);
68
71
  const popupRef = (0, _react.useRef)(null);
@@ -421,9 +424,7 @@ function SeatMap(_ref) {
421
424
  zIndex: 10
422
425
  }) : /*#__PURE__*/_react.default.createElement(_reactLeaflet.Circle, {
423
426
  center: [s.r.includes("NORTH") ? getNorthSeatLat(s) : seatCenter.lat, seatCenter.lng],
424
- pathOptions: (0, _utils.getInitialColor)(s, price, !hasSeatPrices,
425
- // TEST selected state for multiselect
426
- !!selectedSeats.find(selectedSeat => selectedSeat.ssId === s.ssId)),
427
+ pathOptions: (0, _utils.getInitialColor)(s, price, !hasSeatPrices, selectedSeats.some(selectedSeat => selectedSeat.ssId === s.ssId) || highlightedSeats.some(hs => hs.ssId === s.ssId), greyedOutSeats.some(gs => gs.ssId === s.ssId)),
427
428
  radius: 12000,
428
429
  eventHandlers: {
429
430
  click: e => {
@@ -431,12 +432,18 @@ function SeatMap(_ref) {
431
432
  map.closePopup();
432
433
  if (s.s === _utils.statuses.USER_PENDING) {
433
434
  const newSeatsToRemove = (0, _utils.getAdjacentBookedSeats)(s, seatsMap);
434
- setSeatsToRemove(newSeatsToRemove);
435
- setRemoveMultipleSeatsPopupOpen(true);
436
- }
437
- if (selectedSeats.length > 0 && selectedSeats.length === desiredSeatQuantity) {
435
+ if (newSeatsToRemove.length === 1) {
436
+ handleClickSeat(e, s);
437
+ } else {
438
+ setSeatsToRemove(newSeatsToRemove);
439
+ setRemoveMultipleSeatsPopupOpen(true);
440
+ }
441
+ } else if (highlightedSeats.length > 0 && highlightedSeats.length === desiredSeatQuantity) {
442
+ setSelectedSeats([...highlightedSeats]);
438
443
  setPricingPopupOpen(true);
439
- } else if (s.s === _utils.statuses.USER_PENDING) {}
444
+ } else if (greyedOutSeats.some(gs => gs.ssId === s.ssId)) {
445
+ setInvalidSeatsPopupOpen(true);
446
+ }
440
447
  } else if (mode === _utils.modes.SINGLE && hasSeatPrices) {
441
448
  handleClickSeat(e, s);
442
449
  }
@@ -462,12 +469,23 @@ function SeatMap(_ref) {
462
469
  setSelectedSeats(prev => [...prev, s]);
463
470
  }
464
471
  } else {
465
- setSelectedSeats([]);
466
472
  if (seats.preventOrphanedSeats && desiredSeatQuantity > 0 && s.s === _utils.statuses.UNSOLD) {
467
473
  const seatsToBook = (0, _utils.getValidSeats)(s, seatsMap, desiredSeatQuantity);
468
- setSelectedSeats(seatsToBook);
474
+ if (seatsToBook.valid) {
475
+ setHighlightedSeats(seatsToBook.seats);
476
+ } else {
477
+ setGreyedOutSeats(seatsToBook.seats);
478
+ }
469
479
  }
470
480
  }
481
+ },
482
+ mouseout: () => {
483
+ if (highlightedSeats.length > 0) {
484
+ setHighlightedSeats([]);
485
+ }
486
+ if (greyedOutSeats.length > 0) {
487
+ setGreyedOutSeats([]);
488
+ }
471
489
  }
472
490
  }
473
491
  // value={s}
@@ -62,19 +62,19 @@ const PriceSelect = _ref => {
62
62
  };
63
63
  function PricingPopup(_ref2) {
64
64
  let {
65
- cancel,
65
+ onClose,
66
66
  groupedSelectedSeats,
67
67
  pricing,
68
68
  priceSectionIds,
69
69
  batchAddTicketsToCart,
70
70
  selectedSeatsWithPricing,
71
- singleSeats
71
+ isSingleSeats
72
72
  } = _ref2;
73
73
  const [seatGroupsToBook, setSeatGroupsToBook] = (0, _react.useState)(groupedSelectedSeats);
74
74
  const [singleSeatsToBook, setSingleSeatsToBook] = (0, _react.useState)(selectedSeatsWithPricing);
75
75
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
76
76
  className: "pricing-popup-backdrop",
77
- onClick: cancel
77
+ onClick: onClose
78
78
  }), /*#__PURE__*/_react.default.createElement("div", {
79
79
  className: "pricing-popup",
80
80
  role: "dialog",
@@ -88,7 +88,7 @@ function PricingPopup(_ref2) {
88
88
  }), /*#__PURE__*/_react.default.createElement("button", {
89
89
  className: "close-button",
90
90
  "aria-label": "close popup",
91
- onClick: cancel
91
+ onClick: onClose
92
92
  }, /*#__PURE__*/_react.default.createElement("img", {
93
93
  src: _encodedSvgs.closeIconWhite,
94
94
  alt: "close",
@@ -98,7 +98,7 @@ function PricingPopup(_ref2) {
98
98
  className: "pricing-popup-content"
99
99
  }, /*#__PURE__*/_react.default.createElement("div", {
100
100
  className: "seat-list"
101
- }, !singleSeats && groupedSelectedSeats ? Object.entries(seatGroupsToBook).map(_ref3 => {
101
+ }, !isSingleSeats && groupedSelectedSeats ? Object.entries(seatGroupsToBook).map(_ref3 => {
102
102
  let [id, seatGroup] = _ref3;
103
103
  const seatPriceages = pricing.filter(price => (!priceSectionIds || priceSectionIds.includes(price.psId)) && price.psId === parseInt(id));
104
104
  return /*#__PURE__*/_react.default.createElement("div", {
@@ -119,7 +119,7 @@ function PricingPopup(_ref2) {
119
119
  }) : /*#__PURE__*/_react.default.createElement("p", {
120
120
  className: "no-prices-available"
121
121
  }, "Oops, looks like there are no prices available for this section."));
122
- }) : singleSeats && selectedSeatsWithPricing ? selectedSeatsWithPricing.map(_ref4 => {
122
+ }) : isSingleSeats && selectedSeatsWithPricing ? selectedSeatsWithPricing.map(_ref4 => {
123
123
  let {
124
124
  seat,
125
125
  priceage
@@ -151,16 +151,16 @@ function PricingPopup(_ref2) {
151
151
  className: "buttons"
152
152
  }, /*#__PURE__*/_react.default.createElement("button", {
153
153
  className: "cancel",
154
- onClick: cancel
154
+ onClick: onClose
155
155
  }, "Cancel"), /*#__PURE__*/_react.default.createElement("button", {
156
156
  className: "add-cart",
157
157
  onClick: () => {
158
- singleSeats ? batchAddTicketsToCart(singleSeatsToBook) : batchAddTicketsToCart(Object.values(seatGroupsToBook).filter(v => !!v.priceage).flatMap(s => s.seats.map(seat => ({
158
+ isSingleSeats ? batchAddTicketsToCart(singleSeatsToBook) : batchAddTicketsToCart(Object.values(seatGroupsToBook).filter(v => !!v.priceage).flatMap(s => s.seats.map(seat => ({
159
159
  seat,
160
160
  priceage: s.priceage
161
161
  }))));
162
- cancel();
162
+ onClose();
163
163
  },
164
- disabled: singleSeats ? singleSeatsToBook.every(v => !v.priceage) : Object.values(seatGroupsToBook).every(v => !v.priceage)
164
+ disabled: isSingleSeats ? singleSeatsToBook.every(v => !v.priceage) : Object.values(seatGroupsToBook).every(v => !v.priceage)
165
165
  }, "Add to cart")))));
166
166
  }
@@ -15,6 +15,7 @@ var _reactDom = require("react-dom");
15
15
  var _PricingPopup = _interopRequireDefault(require("./PricingPopup"));
16
16
  var _SelectQuantityPopup = _interopRequireDefault(require("./SelectQuantityPopup"));
17
17
  var _RemoveMultipleSeatsPopup = _interopRequireDefault(require("./RemoveMultipleSeatsPopup"));
18
+ var _InvalidSeatsPopup = _interopRequireDefault(require("./InvalidSeatsPopup"));
18
19
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
20
  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); }
20
21
  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; }
@@ -64,6 +65,7 @@ const SeatingPlan = _ref => {
64
65
  const [selectedSeats, setSelectedSeats] = (0, _react.useState)([]);
65
66
  const [seatsToRemove, setSeatsToRemove] = (0, _react.useState)([]);
66
67
  const [removeMultipleSeatsPopupOpen, setRemoveMultipleSeatsPopupOpen] = (0, _react.useState)(false);
68
+ const [invalidSeatsPopupOpen, setInvalidSeatsPopupOpen] = (0, _react.useState)(false);
67
69
  const mapRef = (0, _react.useRef)(null);
68
70
  const canMultiSelect = bookingMode === _utils.bookingModes.POS;
69
71
  const apiUrl = "".concat(baseUrl, "/legacy/").concat(countryCode, "/shop/events/").concat(eventId, "/").concat(eventVenueId, "/showings/").concat(showingId, "/tickets/allocated/").concat(areaId);
@@ -290,7 +292,7 @@ const SeatingPlan = _ref => {
290
292
  try {
291
293
  for (let seat of seatsToBook) {
292
294
  try {
293
- await fetch(apiUrl, {
295
+ const res = await fetch(apiUrl, {
294
296
  method: "POST",
295
297
  body: JSON.stringify({
296
298
  priceAgeId: seat.priceage.paId,
@@ -303,6 +305,9 @@ const SeatingPlan = _ref => {
303
305
  "basket-key": sessionId
304
306
  }
305
307
  });
308
+ if (!res.ok) {
309
+ throw new Error("".concat(res.status));
310
+ }
306
311
  succeeded.push(seat);
307
312
  } catch (error) {
308
313
  console.error("Failed to book seat ".concat(seat, ":"), error);
@@ -396,12 +401,15 @@ const SeatingPlan = _ref => {
396
401
  try {
397
402
  for (let seat of seatsToRemove) {
398
403
  try {
399
- await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
404
+ const res = await fetch("".concat(apiUrl, "/seat/").concat(seat.ssId), {
400
405
  method: "DELETE",
401
406
  headers: {
402
407
  "basket-key": sessionId
403
408
  }
404
409
  });
410
+ if (!res.ok) {
411
+ throw new Error("".concat(res.status));
412
+ }
405
413
  succeededIds.push(seat.ssId);
406
414
  } catch (error) {
407
415
  console.error("Failed to remove seat ".concat(seat, ":"), error);
@@ -476,9 +484,8 @@ const SeatingPlan = _ref => {
476
484
  setIsReloading(true);
477
485
  }
478
486
  setInitialiseMessage("Initialising seating plan...");
479
- fetch("http://localhost:3155/api/legacy/shop/events/".concat(eventId, "/").concat(eventVenueId, "/showings/").concat(showingId, "/tickets/allocated/").concat(areaId),
480
- // `${apiUrl}${promoCode ? `?promo=${promoCode}` : ""}`,
481
- {
487
+ fetch(// `http://localhost:3155/api/legacy/shop/events/${eventId}/${eventVenueId}/showings/${showingId}/tickets/allocated/${areaId}`,
488
+ "".concat(apiUrl).concat(promoCode ? "?promo=".concat(promoCode) : ""), {
482
489
  headers: {
483
490
  "basket-key": sessionId,
484
491
  Authorization: "Bearer ".concat(apiKey)
@@ -581,10 +588,6 @@ const SeatingPlan = _ref => {
581
588
  }
582
589
  return acc;
583
590
  }, {});
584
- const cancelPriceSelect = () => {
585
- setPricingPopupOpen(false);
586
- setSelectedSeats([]);
587
- };
588
591
 
589
592
  // return seating plan
590
593
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
@@ -599,27 +602,32 @@ const SeatingPlan = _ref => {
599
602
  className: "seating-plan-container ".concat(isFullScreen ? "full-screen" : ""),
600
603
  "data-mode": mode
601
604
  }, pricingPopupOpen && (canMultiSelect || seats.preventOrphanedSeats) ? /*#__PURE__*/_react.default.createElement(_PricingPopup.default, {
602
- cancel: cancelPriceSelect,
605
+ onClose: () => {
606
+ setPricingPopupOpen(false);
607
+ setSelectedSeats([]);
608
+ },
603
609
  groupedSelectedSeats: groupedSelectedSeats,
604
610
  selectedSeatsWithPricing: selectedSeatsWithPricing,
605
611
  priceSectionIds: priceSectionIds,
606
612
  pricing: seats.pricing,
607
613
  batchAddTicketsToCart: batchAddTicketsToCart,
608
- singleSeats: seats.preventOrphanedSeats
609
- }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), selectQuantityPopupOpen && /*#__PURE__*/_react.default.createElement(_SelectQuantityPopup.default, {
614
+ isSingleSeats: seats.preventOrphanedSeats
615
+ }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), seats.preventOrphanedSeats && selectQuantityPopupOpen ? /*#__PURE__*/_react.default.createElement(_SelectQuantityPopup.default, {
610
616
  quantity: desiredSeatQuantity,
611
617
  setQuantity: v => {
612
618
  setDesiredSeatQuantity(v);
613
619
  setSelectedSeats([]);
614
620
  },
615
621
  onClose: () => setSelectQuantityPopupOpen(false)
616
- }), removeMultipleSeatsPopupOpen && /*#__PURE__*/_react.default.createElement(_RemoveMultipleSeatsPopup.default, {
622
+ }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), seats.preventOrphanedSeats && removeMultipleSeatsPopupOpen ? /*#__PURE__*/_react.default.createElement(_RemoveMultipleSeatsPopup.default, {
617
623
  onConfirm: () => {
618
624
  batchRemoveTicketsFromCart(seatsToRemove);
619
625
  setRemoveMultipleSeatsPopupOpen(false);
620
626
  },
621
627
  onClose: () => setRemoveMultipleSeatsPopupOpen(false)
622
- }), /*#__PURE__*/_react.default.createElement(_reactLeaflet.MapContainer, {
628
+ }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), seats.preventOrphanedSeats && invalidSeatsPopupOpen ? /*#__PURE__*/_react.default.createElement(_InvalidSeatsPopup.default, {
629
+ onClose: () => setInvalidSeatsPopupOpen(false)
630
+ }) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null), /*#__PURE__*/_react.default.createElement(_reactLeaflet.MapContainer, {
623
631
  zoomSnap: 0,
624
632
  zoomDelta: 1,
625
633
  center: (0, _utils.calculateCenterOfMap)(height, seats.seats),
@@ -661,7 +669,8 @@ const SeatingPlan = _ref => {
661
669
  setSelectQuantityPopupOpen: setSelectQuantityPopupOpen,
662
670
  desiredSeatQuantity: desiredSeatQuantity,
663
671
  setSeatsToRemove: setSeatsToRemove,
664
- setRemoveMultipleSeatsPopupOpen: setRemoveMultipleSeatsPopupOpen
672
+ setRemoveMultipleSeatsPopupOpen: setRemoveMultipleSeatsPopupOpen,
673
+ setInvalidSeatsPopupOpen: setInvalidSeatsPopupOpen
665
674
  }))), mapContainer)) : /*#__PURE__*/_react.default.createElement("div", {
666
675
  className: "loading"
667
676
  }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("svg", {
@@ -120,6 +120,10 @@
120
120
  margin-top: 1.2rem;
121
121
  }
122
122
 
123
+ .pricing-popup .buttons.buttons-single {
124
+ justify-content: center;
125
+ }
126
+
123
127
  .pricing-popup .buttons button {
124
128
  display: block;
125
129
  background: transparent;
@@ -132,6 +136,10 @@
132
136
  margin-bottom: 0;
133
137
  }
134
138
 
139
+ .pricing-popup .buttons.buttons-single button {
140
+ width: 100%;
141
+ }
142
+
135
143
  .pricing-popup .buttons button.add-cart {
136
144
  background: var(--accent);
137
145
  color: white;
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.statuses = exports.statusColors = exports.modes = exports.bookingModes = void 0;
7
7
  const statusColors = exports.statusColors = {
8
- unknown: "#95a5a6",
8
+ unknown: "#bdc3c7",
9
9
  available: "#00E640",
10
10
  sold: "#95a5a6",
11
11
  reserved: "#95a5a6",
@@ -11,7 +11,8 @@ const getInitialColor = (s, price, disabled, selected, greyedOut) => {
11
11
  return {
12
12
  fillColor: _enums.statusColors.selected,
13
13
  color: "none",
14
- fillOpacity: s.loading ? 0 : 1
14
+ fillOpacity: s.loading ? 0 : 1,
15
+ stroke: false
15
16
  };
16
17
  }
17
18
  if (greyedOut) {
@@ -94,55 +95,88 @@ const canSelectSingleSeatGivenOrphanRules = (seat, rowSection) => {
94
95
  return true;
95
96
  };
96
97
  exports.canSelectSingleSeatGivenOrphanRules = canSelectSingleSeatGivenOrphanRules;
98
+ const traverse = (arr, seat, direction, rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans) => {
99
+ const nextSeatId = direction === "left" ? seat.sb : seat.sa;
100
+ if (nextSeatId) {
101
+ const nextSeat = rowSectionMap.get(nextSeatId);
102
+ if (nextSeat && nextSeat.s === _enums.statuses.UNSOLD && arr.length < desiredSeatQuantity && !(!ignoreOrphans && arr.length === desiredSeatQuantity - 1 && createsOrphan(nextSeat, rowSection, false, arr)) && !arr.some(s => s.sId === nextSeat.sId)) {
103
+ if (direction === "left") {
104
+ arr.unshift(nextSeat);
105
+ } else {
106
+ arr.push(nextSeat);
107
+ }
108
+ if (arr.length < desiredSeatQuantity) {
109
+ traverse(arr, nextSeat, direction, rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans);
110
+ }
111
+ }
112
+ }
113
+ };
114
+ const getSeats = (seat, rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans) => {
115
+ let seats = [seat];
116
+ traverse(seats, seat, "right", rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans);
117
+ if (seats.length < desiredSeatQuantity) {
118
+ traverse(seats, seat, "left", rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans);
119
+ }
120
+ const firstSeat = seats[0];
121
+ const sb = rowSectionMap.get(firstSeat.sb);
122
+ const sbb = rowSectionMap.get(sb === null || sb === void 0 ? void 0 : sb.sb);
123
+ const orphanToLeft = sb && sbb && sb.s === _enums.statuses.UNSOLD && sbb.s !== _enums.statuses.UNSOLD || sb && !sbb && sb.s === _enums.statuses.UNSOLD;
124
+ if (seats.length < desiredSeatQuantity || orphanToLeft && !ignoreOrphans) {
125
+ seats = [seat];
126
+ traverse(seats, seat, "left", rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans);
127
+ if (seats.length < desiredSeatQuantity) {
128
+ traverse(seats, seat, "right", rowSectionMap, desiredSeatQuantity, rowSection, ignoreOrphans);
129
+ }
130
+ }
131
+ const lastSeat = seats[seats.length - 1];
132
+ const sa = rowSectionMap.get(lastSeat.sa);
133
+ const saa = rowSectionMap.get(sa === null || sa === void 0 ? void 0 : sa.sa);
134
+ const orphanToRight = sa && saa && sa.s === _enums.statuses.UNSOLD && saa.s !== _enums.statuses.UNSOLD || sa && !saa && sa.s === _enums.statuses.UNSOLD;
135
+ if (orphanToRight && !ignoreOrphans) {
136
+ return [];
137
+ }
138
+ return seats;
139
+ };
97
140
  const getValidSeats = (s, seatsMap, desiredSeatQuantity) => {
98
- let seatsToBook = [s];
99
141
  const rowSection = getRowSection(s, seatsMap);
142
+ const rowSectionMap = new Map(rowSection.map(seat => [seat.sId, seat]));
143
+ if (s && desiredSeatQuantity === 1) {
144
+ return {
145
+ seats: [s],
146
+ valid: canSelectSingleSeatGivenOrphanRules(s, rowSection) ? true : false
147
+ };
148
+ }
149
+ const seatsToBook = getSeats(s, rowSectionMap, desiredSeatQuantity, rowSection);
100
150
  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);
151
+ let hasOtherOptions = false;
152
+ const orphaningSeats = getSeats(s, rowSectionMap, desiredSeatQuantity, rowSection, true);
153
+ if (orphaningSeats.length === desiredSeatQuantity) {
154
+ const otherAvailableSeats = rowSection.filter(seat => seat.s === _enums.statuses.UNSOLD && seat.sId !== s.sId);
155
+ if (otherAvailableSeats.length > 0) {
156
+ for (const seat of otherAvailableSeats) {
157
+ const possibleSeats = getSeats(seat, rowSectionMap, desiredSeatQuantity, rowSection);
158
+ if (possibleSeats.length === desiredSeatQuantity) {
159
+ hasOtherOptions = true;
160
+ break;
113
161
  }
114
162
  }
115
163
  }
116
- };
117
- traverse(s, "right");
118
- if (seatsToBook.length < desiredSeatQuantity) {
119
- traverse(s, "left");
164
+ return {
165
+ seats: orphaningSeats,
166
+ valid: hasOtherOptions ? false : true
167
+ };
120
168
  }
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
169
  }
139
- return [];
170
+ return {
171
+ seats: seatsToBook,
172
+ valid: seatsToBook.length === desiredSeatQuantity ? true : false
173
+ };
140
174
  };
141
175
  exports.getValidSeats = getValidSeats;
142
176
  const getAdjacentBookedSeats = (seat, seatsMap) => {
143
177
  const rowSection = getRowSection(seat, seatsMap);
144
178
  const adjacentBookedSeats = [seat];
145
- const traverse = (seat, direction) => {
179
+ const traverseRow = (seat, direction) => {
146
180
  const nextSeatId = direction === "left" ? seat.sb : seat.sa;
147
181
  if (nextSeatId) {
148
182
  const nextSeat = rowSection.find(v => v.sId === nextSeatId);
@@ -152,12 +186,12 @@ const getAdjacentBookedSeats = (seat, seatsMap) => {
152
186
  } else {
153
187
  adjacentBookedSeats.push(nextSeat);
154
188
  }
155
- traverse(nextSeat, direction);
189
+ traverseRow(nextSeat, direction);
156
190
  }
157
191
  }
158
192
  };
159
- traverse(seat, "right");
160
- traverse(seat, "left");
193
+ traverseRow(seat, "right");
194
+ traverseRow(seat, "left");
161
195
  return adjacentBookedSeats;
162
196
  };
163
197
  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.8",
5
+ "version": "1.7.0",
6
6
  "private": false,
7
7
  "keywords": [
8
8
  "iticket",