@escapenavigator/hooks 1.10.146 → 1.10.148

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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './functional-popover';
2
+ export * from './input-tel';
2
3
  export * from './players-and-variation-picker';
3
4
  export * from './use-debounced-value';
4
5
  export * from './use-localstore-state';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./functional-popover"), exports);
18
+ __exportStar(require("./input-tel"), exports);
18
19
  __exportStar(require("./players-and-variation-picker"), exports);
19
20
  __exportStar(require("./use-debounced-value"), exports);
20
21
  __exportStar(require("./use-localstore-state"), exports);
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import 'react-phone-input-2/lib/style.css';
3
+ export type InputTelProps = {
4
+ value: string;
5
+ onChange: (props: {
6
+ phone: string;
7
+ isValid: boolean;
8
+ }) => void;
9
+ label?: string;
10
+ error?: string;
11
+ disabled?: boolean;
12
+ /** Organization / widget profile country — preferred default for new numbers. */
13
+ profileCountry?: string | null;
14
+ /** i18n.language or another BCP-47 tag. */
15
+ locale?: string | null;
16
+ /** @deprecated Use profileCountry — kept for gradual migration. */
17
+ initialCountry?: string;
18
+ /** Widget-specific tweaks (long SE numbers, empty mask). */
19
+ widgetMode?: boolean;
20
+ };
21
+ export declare const InputTel: React.FC<InputTelProps>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /* eslint-disable import/no-extraneous-dependencies */
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.InputTel = void 0;
41
+ const ui_1 = require("@alphakits/ui");
42
+ const phone_1 = require("@escapenavigator/utils/dist/phone");
43
+ const react_1 = __importStar(require("react"));
44
+ const react_phone_input_2_1 = __importDefault(require("react-phone-input-2"));
45
+ require("react-phone-input-2/lib/style.css");
46
+ const index_module_css_1 = __importDefault(require("./index.module.css"));
47
+ const normalizePhoneValue = (value) => `+${value.replace(/\D/g, '')}`;
48
+ const InputTel = ({ value, onChange, label, error, disabled, profileCountry, locale, initialCountry, widgetMode = false, }) => {
49
+ const resolvedCountry = (0, react_1.useMemo)(() => (0, phone_1.resolvePhoneCountry)({
50
+ phone: value,
51
+ profileCountry: profileCountry !== null && profileCountry !== void 0 ? profileCountry : initialCountry,
52
+ locale,
53
+ }), [value, profileCountry, initialCountry, locale]);
54
+ const [country, setCountry] = (0, react_1.useState)(resolvedCountry);
55
+ const onChangeRef = (0, react_1.useRef)(onChange);
56
+ onChangeRef.current = onChange;
57
+ (0, react_1.useEffect)(() => {
58
+ setCountry(resolvedCountry);
59
+ }, [resolvedCountry]);
60
+ (0, react_1.useEffect)(() => {
61
+ if (!value) {
62
+ return;
63
+ }
64
+ const phone = normalizePhoneValue(value);
65
+ onChangeRef.current({
66
+ phone,
67
+ isValid: (0, phone_1.validatePhoneNumber)(phone),
68
+ });
69
+ }, [value]);
70
+ const handleChange = (v, c) => {
71
+ const phone = `+${v}`;
72
+ const isValid = (0, phone_1.validatePhoneNumber)(phone);
73
+ setCountry(c.countryCode);
74
+ onChangeRef.current({ phone, isValid });
75
+ };
76
+ return (react_1.default.createElement(ui_1.FlexColumns, { columns: 1, gr: 4 },
77
+ !!label && (react_1.default.createElement(ui_1.Typography.Text, { view: 'caps', color: 'secondary' }, label)),
78
+ react_1.default.createElement(react_phone_input_2_1.default, { containerClass: index_module_css_1.default.container, buttonClass: index_module_css_1.default.dropdown, inputClass: index_module_css_1.default.input, country: country, disabled: disabled, enableClickOutside: false, value: value, onChange: handleChange, masks: widgetMode ? { se: '' } : undefined, enableLongNumbers: widgetMode }),
79
+ !!error && (react_1.default.createElement(ui_1.Typography.Text, { view: 'caps', color: 'negative' }, error))));
80
+ };
81
+ exports.InputTel = InputTel;
@@ -146,6 +146,35 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
146
146
  const effectiveMin = typeof minPlayers === 'number' && Number.isFinite(minPlayers)
147
147
  ? Math.max(minFromTariff, minPlayers)
148
148
  : minFromTariff;
149
+ // Единственный источник истины «что реально можно выбрать»: ключи
150
+ // прайса тарифа, попадающие в [effectiveMin, effectiveMax] с учётом
151
+ // детей. Ровно те же числа рендерятся кнопками ниже.
152
+ const availablePlayerKeys = (0, react_1.useMemo)(() => playersOptions
153
+ .map((p) => p.key)
154
+ .filter((key) => {
155
+ const total = key + (_children || 0);
156
+ return total >= effectiveMin && total <= effectiveMax;
157
+ }), [playersOptions, effectiveMin, effectiveMax, _children]);
158
+ // Если уже выбранное (или засеянное хостом) число игроков выпало из
159
+ // доступного набора — например, после смены вариации/тарифа на более
160
+ // узкий диапазон — подтягиваем его к ближайшему валидному. Без этого
161
+ // `values.players` остаётся «залипшим» на count, которого в новом
162
+ // тарифе нет, и на бэке `tariff.price[players]` = undefined → NaN →
163
+ // 500 при создании заказа. `_players === 0/undefined` трактуем как
164
+ // «ещё не выбрано» и не трогаем (валидация формы заставит выбрать).
165
+ // biome-ignore lint/correctness/useExhaustiveDependencies: однонаправленный clamp, зависим только от набора и значения
166
+ (0, react_1.useEffect)(() => {
167
+ if (!availablePlayerKeys.length)
168
+ return;
169
+ if (!_players)
170
+ return;
171
+ if (availablePlayerKeys.includes(_players))
172
+ return;
173
+ const nearest = availablePlayerKeys.reduce((acc, key) => Math.abs(key - _players) < Math.abs(acc - _players) ? key : acc);
174
+ setPlayers(nearest);
175
+ onChange === null || onChange === void 0 ? void 0 : onChange('players', nearest);
176
+ // eslint-disable-next-line react-hooks/exhaustive-deps
177
+ }, [availablePlayerKeys, _players]);
149
178
  const childrenOptions = (0, react_1.useMemo)(() => {
150
179
  if (!tariff.child || !maxFromTariff)
151
180
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/hooks",
3
- "version": "1.10.146",
3
+ "version": "1.10.148",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,10 +14,12 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
- "@escapenavigator/services": "^1.10.154",
18
- "@escapenavigator/types": "^1.10.145",
19
- "@escapenavigator/utils": "^1.10.149",
20
- "react": "19.2.6"
17
+ "@escapenavigator/services": "^1.10.156",
18
+ "@escapenavigator/types": "^1.10.146",
19
+ "@escapenavigator/utils": "^1.10.151",
20
+ "libphonenumber-js": "^1.12.24",
21
+ "react": "19.2.6",
22
+ "react-phone-input-2": "^2.15.1"
21
23
  },
22
24
  "peerDependencies": {
23
25
  "@alphakits/icons": "*",
@@ -30,5 +32,5 @@
30
32
  "ts-jest": "^29.1.1",
31
33
  "typescript": "^5.6"
32
34
  },
33
- "gitHead": "4d5f85778c81f86f50c14fba7055dda83e1aafdd"
35
+ "gitHead": "b7cc49e197a4d4cda6337a2595d620dd88b7bd89"
34
36
  }