@escapenavigator/hooks 1.10.131 → 1.10.132
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.
|
@@ -80,6 +80,17 @@ export type PlayersAndVariationPickerProps = {
|
|
|
80
80
|
* excludes the current booking from occupancy calculations.
|
|
81
81
|
*/
|
|
82
82
|
orderId?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Fires whenever the internal `usePlayersAndVariationPicker` loading
|
|
85
|
+
* flag changes. Hosts can use it to show a full-screen busy overlay
|
|
86
|
+
* over their form (the player section + dependent UI like upsellings)
|
|
87
|
+
* while `/slots/details` is in flight on initial mount — without
|
|
88
|
+
* having to duplicate the hook call themselves.
|
|
89
|
+
*
|
|
90
|
+
* Starts `true` and flips to `false` once the first `/slots/details`
|
|
91
|
+
* resolves (success or error).
|
|
92
|
+
*/
|
|
93
|
+
onLoadingChange?: (loading: boolean) => void;
|
|
83
94
|
};
|
|
84
95
|
/**
|
|
85
96
|
* Single shared component that renders the "Variation + Players" picker used
|
|
@@ -62,9 +62,9 @@ const use_players_and_variation_picker_1 = require("../use-players-and-variation
|
|
|
62
62
|
* buttons, kids row, price hint, save button) was reimplemented in three
|
|
63
63
|
* places with subtle drift. This component is the single source of truth.
|
|
64
64
|
*/
|
|
65
|
-
const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loadSlotDetails, onVariationChange, onVariationResolved, onDetailsLoaded, players = 0, child = 0, tariff: tariffOverride, currency, minPlayers, maxPlayersLimit, slotDiscount, error, t, onChange, onSave, orderId, }) => {
|
|
65
|
+
const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loadSlotDetails, onVariationChange, onVariationResolved, onDetailsLoaded, players = 0, child = 0, tariff: tariffOverride, currency, minPlayers, maxPlayersLimit, slotDiscount, error, t, onChange, onSave, orderId, onLoadingChange, }) => {
|
|
66
66
|
var _a, _b;
|
|
67
|
-
const { options: pickerOptions, selectedOptionId, selectedVariation, buildVariationChange, selectVariation, details, } = (0, use_players_and_variation_picker_1.usePlayersAndVariationPicker)({
|
|
67
|
+
const { loading: pickerLoading, options: pickerOptions, selectedOptionId, selectedVariation, buildVariationChange, selectVariation, details, } = (0, use_players_and_variation_picker_1.usePlayersAndVariationPicker)({
|
|
68
68
|
slot,
|
|
69
69
|
currentTariffId,
|
|
70
70
|
currentDuration,
|
|
@@ -72,6 +72,17 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
|
|
|
72
72
|
t: t,
|
|
73
73
|
orderId,
|
|
74
74
|
});
|
|
75
|
+
/**
|
|
76
|
+
* Прокидываем loading-сигнал наверх через ref'нутый колбэк, чтобы
|
|
77
|
+
* не зависеть от референциальной стабильности `onLoadingChange`
|
|
78
|
+
* со стороны хоста.
|
|
79
|
+
*/
|
|
80
|
+
const onLoadingChangeRef = (0, react_1.useRef)(onLoadingChange);
|
|
81
|
+
onLoadingChangeRef.current = onLoadingChange;
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
var _a;
|
|
84
|
+
(_a = onLoadingChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onLoadingChangeRef, pickerLoading);
|
|
85
|
+
}, [pickerLoading]);
|
|
75
86
|
const onDetailsLoadedRef = (0, react_1.useRef)(onDetailsLoaded);
|
|
76
87
|
const onVariationResolvedRef = (0, react_1.useRef)(onVariationResolved);
|
|
77
88
|
onDetailsLoadedRef.current = onDetailsLoaded;
|
|
@@ -17,6 +17,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.usePlayersAndVariationPicker = void 0;
|
|
19
19
|
const use_api_method_1 = require("@escapenavigator/services/dist/hooks/use-api-method");
|
|
20
|
+
const format_flex_duration_label_1 = require("@escapenavigator/utils/dist/format-flex-duration-label");
|
|
20
21
|
const react_1 = require("react");
|
|
21
22
|
__exportStar(require("./types"), exports);
|
|
22
23
|
const variationKey = (variation) => { var _a; return (_a = variation.id) !== null && _a !== void 0 ? _a : `${variation.tariffId}-${variation.duration}`; };
|
|
@@ -35,8 +36,23 @@ const variationKey = (variation) => { var _a; return (_a = variation.id) !== nul
|
|
|
35
36
|
const usePlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loadSlotDetails, t, orderId, }) => {
|
|
36
37
|
const api = (0, use_api_method_1.useApiMethod)({ api: loadSlotDetails });
|
|
37
38
|
const data = api[`${loadSlotDetails.displayName}Data`];
|
|
38
|
-
const
|
|
39
|
+
const apiLoading = !!api[`${loadSlotDetails.displayName}Loading`];
|
|
39
40
|
const fetch = api[`${loadSlotDetails.displayName}Fetch`];
|
|
41
|
+
/**
|
|
42
|
+
* Guard against the one-frame visual flicker when the picker first
|
|
43
|
+
* mounts: `useApiMethod` initialises `loading` to `false`, so the
|
|
44
|
+
* very first render returns `loading=false` with empty `variations`
|
|
45
|
+
* — the host then briefly paints a "no options" / default-price
|
|
46
|
+
* row before our useEffect below fires the `/slots/details` request
|
|
47
|
+
* and `loading` flips to `true`.
|
|
48
|
+
*
|
|
49
|
+
* `firstFetchSettled` starts as `false` and only becomes `true` once
|
|
50
|
+
* the first `/slots/details` request actually resolves. Until then
|
|
51
|
+
* we report `loading=true` to the caller — the picker can render a
|
|
52
|
+
* skeleton/spinner for that entire window, with no empty-state
|
|
53
|
+
* flash.
|
|
54
|
+
*/
|
|
55
|
+
const [firstFetchSettled, setFirstFetchSettled] = (0, react_1.useState)(false);
|
|
40
56
|
(0, react_1.useEffect)(() => {
|
|
41
57
|
if (!(slot === null || slot === void 0 ? void 0 : slot.id) || !slot.questroomId || !slot.date || !slot.start)
|
|
42
58
|
return;
|
|
@@ -46,11 +62,16 @@ const usePlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration,
|
|
|
46
62
|
date: slot.date,
|
|
47
63
|
start: slot.start,
|
|
48
64
|
orderId,
|
|
49
|
-
})
|
|
65
|
+
})
|
|
66
|
+
.then(() => setFirstFetchSettled(true))
|
|
67
|
+
.catch(() => setFirstFetchSettled(true));
|
|
50
68
|
// Only primitive slot fields — callers often pass inline `{ id, date, ... }`
|
|
51
69
|
// objects that get a new reference every render; including `slot` here
|
|
52
70
|
// re-triggers `/slots/details` on every parent render (ERR_INSUFFICIENT_RESOURCES).
|
|
53
71
|
}, [slot === null || slot === void 0 ? void 0 : slot.id, slot === null || slot === void 0 ? void 0 : slot.questroomId, slot === null || slot === void 0 ? void 0 : slot.date, slot === null || slot === void 0 ? void 0 : slot.start, orderId, fetch]);
|
|
72
|
+
// До первого resolved-фетча — считаем `loading=true`, иначе host
|
|
73
|
+
// отрисует пустой picker в первый кадр.
|
|
74
|
+
const loading = !firstFetchSettled || apiLoading;
|
|
54
75
|
const variations = (0, react_1.useMemo)(() => (data === null || data === void 0 ? void 0 : data.variations) || [], [data === null || data === void 0 ? void 0 : data.variations]);
|
|
55
76
|
const isFlex = !!(data === null || data === void 0 ? void 0 : data.isFlex);
|
|
56
77
|
const findCurrentVariation = (rows) => {
|
|
@@ -111,7 +132,7 @@ const usePlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration,
|
|
|
111
132
|
const id = variationKey(variation);
|
|
112
133
|
const isCurrent = id === selectedOptionId;
|
|
113
134
|
const label = isFlex
|
|
114
|
-
?
|
|
135
|
+
? (0, format_flex_duration_label_1.formatFlexDurationLabel)(variation.duration, t)
|
|
115
136
|
: variation.isDefault
|
|
116
137
|
? 'Default'
|
|
117
138
|
: variation.title || `Tariff ${variation.tariffId}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@escapenavigator/hooks",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.132",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"test": "jest"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@escapenavigator/services": "^1.10.
|
|
18
|
-
"@escapenavigator/types": "^1.10.
|
|
19
|
-
"@escapenavigator/utils": "^1.10.
|
|
17
|
+
"@escapenavigator/services": "^1.10.140",
|
|
18
|
+
"@escapenavigator/types": "^1.10.131",
|
|
19
|
+
"@escapenavigator/utils": "^1.10.135",
|
|
20
20
|
"react": "19.2.6"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"ts-jest": "^29.1.1",
|
|
31
31
|
"typescript": "^5.6"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "cb2f3ab38ef5b8b2a38ab5b2c485e484a0cf9414"
|
|
34
34
|
}
|