@escapenavigator/hooks 2.0.50 → 2.1.1

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.
@@ -195,7 +195,7 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
195
195
  minPlayers,
196
196
  maxPlayersLimit,
197
197
  }), [tariff, categories, _composition, minPlayers, maxPlayersLimit]);
198
- const { capacityMax, pricingMax, effectiveMin, pricingHeads, totalHeads, levelUnavailable, belowMin, capacityReached, pricingFull, maxByCategory, baseLevelOptions, } = limits;
198
+ const { capacityMax, pricingMax, effectiveMin, pricingHeads, totalHeads, levelUnavailable, belowMin, capacityReached, maxByCategory, baseLevelOptions, } = limits;
199
199
  const baseCategory = categories.find((category) => category.mode === tariff_category_mode_enum_1.TariffCategoryModeEnum.BASE);
200
200
  const baseCategoryKey = baseCategory === null || baseCategory === void 0 ? void 0 : baseCategory.key;
201
201
  const applyComposition = (next) => {
@@ -284,13 +284,12 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
284
284
  const floorReached = minAmount > 0 && teamPriceBase <= minAmount && priceWithoutDiscounts > minAmount;
285
285
  const minAmountLabel = (0, format_amount_1.formatAmount)(minAmount, currency);
286
286
  /**
287
- * Есть ли в тарифе льготные строки — категории, которые занимают место в
288
- * цене, но платят не полную долю. Только ради них состав рисуется
289
- * степперами: гость должен разложить группу по строкам. Без них
290
- * раскладывать нечего, и работает прежний выбор числа тегами — он
291
- * компактнее и привычнее.
287
+ * Есть ли в тарифе строки кроме базовых взрослых — льготные места или
288
+ * надбавка сверх группы. Только тогда состав рисуется степперами: гость
289
+ * должен разложить группу по строкам. Без них раскладывать нечего, и
290
+ * работает прежний выбор числа тегами — он компактнее и привычнее.
292
291
  */
293
- const hasReducedCategories = categories.some((category) => category.countsInPrice && category.mode !== tariff_category_mode_enum_1.TariffCategoryModeEnum.BASE);
292
+ const hasExtraRows = (0, composition_price_1.hasExtraCategories)(categories);
294
293
  /** Категории сверх групповой цены — они всегда строка со степпером. */
295
294
  const addOnCategories = categories.filter((category) => !category.countsInPrice);
296
295
  const handleSelectLevel = (level) => {
@@ -352,10 +351,15 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
352
351
  const priceSummary = (react_1.default.createElement(react_1.default.Fragment, null,
353
352
  react_1.default.createElement(flex_1.Flex, { justify: 'start', gap: 'xs' },
354
353
  react_1.default.createElement(InfoMarkS_1.default, { style: { fill: 'var(--color-text-secondary)' } }),
355
- react_1.default.createElement(typography_1.Typography.Text, { view: 'caps', color: 'secondary' }, t('prices:totalPriceDescription', {
356
- teamPrice: (0, format_amount_1.formatAmount)(teamPrice, currency),
357
- personPrice: (0, format_amount_1.formatAmount)(personPrice, currency),
358
- }))),
354
+ react_1.default.createElement(typography_1.Typography.Text, { view: 'caps', color: 'secondary' }, hasExtraRows
355
+ ? t('prices:totalPriceTeam', {
356
+ teamPrice: (0, format_amount_1.formatAmount)(teamPrice, currency),
357
+ defaultValue: 'Стоимость за команду {{teamPrice}}',
358
+ })
359
+ : t('prices:totalPriceDescription', {
360
+ teamPrice: (0, format_amount_1.formatAmount)(teamPrice, currency),
361
+ personPrice: (0, format_amount_1.formatAmount)(personPrice, currency),
362
+ }))),
359
363
  minAmount > 0 && (react_1.default.createElement(typography_1.Typography.Text, { view: 'caps', color: 'secondary' }, floorReached
360
364
  ? t('prices:floorReached', {
361
365
  minAmount: minAmountLabel,
@@ -391,30 +395,33 @@ const PlayersAndVariationPicker = ({ slot, currentTariffId, currentDuration, loa
391
395
  !!variationDescription && (react_1.default.createElement(typography_1.Typography.Text, { view: 'caps', color: 'secondary' }, variationDescription)))),
392
396
  react_1.default.createElement(flex_columns_1.FlexColumns, { columns: 1, gr: 8 },
393
397
  react_1.default.createElement(flex_1.Flex, { gap: 'sm', align: 'center', justify: 'between' },
394
- react_1.default.createElement(typography_1.Typography.Text, { view: 'title', color: 'secondary' }, !hasReducedCategories && addOnCategories.length && baseCategory
398
+ react_1.default.createElement(typography_1.Typography.Text, { view: 'title', color: 'secondary' }, !hasExtraRows && addOnCategories.length && baseCategory
395
399
  ? categoryTitle(baseCategory)
396
400
  : t('prices:choosePlayersAmount')),
397
- !hasReducedCategories && !flexSelected && !!tariff[pricingHeads] && (react_1.default.createElement(typography_1.Typography.Text, { view: 'title', color: 'secondary' }, (0, format_amount_1.formatAmount)(tariff[pricingHeads], currency)))),
401
+ !hasExtraRows && !flexSelected && !!tariff[pricingHeads] && (react_1.default.createElement(typography_1.Typography.Text, { view: 'title', color: 'secondary' }, (0, format_amount_1.formatAmount)(tariff[pricingHeads], currency)))),
398
402
  !!flexPlayersOption && (react_1.default.createElement(flex_1.Flex, { gap: 'xs', wrap: true, justify: 'start' },
399
403
  react_1.default.createElement(tag_1.Tag, { key: 'flex-players', text: flexPlayersOption.label, onClick: handleSelectFlex, view: flexSelected ? 'primary-inverted' : 'primary' }))),
400
- !flexSelected && !hasReducedCategories && (react_1.default.createElement(flex_1.Flex, { gap: 'xs', wrap: true, justify: 'start' }, baseLevelOptions.map((level) => (react_1.default.createElement(tag_1.Tag, { key: `level-${level}`, text: `${level}`, onClick: () => handleSelectLevel(level), view: pricingHeads === level ? 'primary-inverted' : 'primary' }))))),
404
+ !flexSelected && !hasExtraRows && (react_1.default.createElement(flex_1.Flex, { gap: 'xs', wrap: true, justify: 'start' }, baseLevelOptions.map((level) => (react_1.default.createElement(tag_1.Tag, { key: `level-${level}`, text: `${level}`, onClick: () => handleSelectLevel(level), view: pricingHeads === level ? 'primary-inverted' : 'primary' }))))),
401
405
  !flexSelected &&
402
- (hasReducedCategories ? categories : addOnCategories).map((category) => {
406
+ (hasExtraRows ? categories : addOnCategories).map((category) => {
403
407
  var _a, _b;
404
408
  const value = Math.max(0, _composition[category.key] || 0);
409
+ const rowMax = (_a = maxByCategory[category.key]) !== null && _a !== void 0 ? _a : value;
410
+ const plusLimitHint = value >= rowMax
411
+ ? capacityReached
412
+ ? t('prices:capacityReached', {
413
+ count: capacityMax,
414
+ defaultValue: 'Максимум {{count}} участников',
415
+ })
416
+ : t('prices:pricingMaxReached', {
417
+ count: pricingMax,
418
+ defaultValue: 'Максимум {{count}} участников по этому тарифу',
419
+ })
420
+ : undefined;
405
421
  return (react_1.default.createElement(ticket_row_1.TicketRow, { key: category.key, title: categoryTitle(category), priceHint: categoryPriceHint(category), description: !hidePriceHints
406
- ? ((_a = category.description) === null || _a === void 0 ? void 0 : _a.trim()) || undefined
407
- : undefined, value: value, min: 0, max: (_b = maxByCategory[category.key]) !== null && _b !== void 0 ? _b : value, minusLabel: t('prices:minus', { defaultValue: 'На одного меньше' }), plusLabel: t('prices:plus', { defaultValue: 'На одного больше' }), onChange: (next) => handleChangeCategory(category.key, next) }));
408
- }),
409
- !flexSelected && (capacityReached || pricingFull) && (react_1.default.createElement(typography_1.Typography.Text, { view: 'caps', color: 'attention', weight: 'medium' }, capacityReached
410
- ? t('prices:capacityReached', {
411
- count: capacityMax,
412
- defaultValue: 'Максимум {{count}} участников',
413
- })
414
- : t('prices:pricingMaxReached', {
415
- count: pricingMax,
416
- defaultValue: 'Максимум {{count}} участников по этому тарифу',
417
- })))),
422
+ ? ((_b = category.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined
423
+ : undefined, value: value, min: 0, max: rowMax, minusLabel: t('prices:minus', { defaultValue: 'На одного меньше' }), plusLabel: t('prices:plus', { defaultValue: 'На одного больше' }), plusDisabledHint: plusLimitHint, onChange: (next) => handleChangeCategory(category.key, next) }));
424
+ })),
418
425
  !hidePriceHints && !flexSelected && bookable && (react_1.default.createElement(flex_columns_1.FlexColumns, { columns: 1, gr: 4, gc: 0 }, priceSummary)),
419
426
  hidePriceHints && !flexSelected && bookable && (react_1.default.createElement("div", { style: {
420
427
  display: 'flex',
@@ -8,6 +8,8 @@ type Props = {
8
8
  max: number;
9
9
  minusLabel: string;
10
10
  plusLabel: string;
11
+ /** Почему «плюс» больше не нажимается — показывается по клику на задисейбленную кнопку. */
12
+ plusDisabledHint?: string;
11
13
  onChange: (value: number) => void;
12
14
  };
13
15
  /**
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -6,15 +39,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.TicketRow = void 0;
7
40
  const MinusM_1 = __importDefault(require("@alphakits/icons/dist/MinusM"));
8
41
  const PlusM_1 = __importDefault(require("@alphakits/icons/dist/PlusM"));
42
+ const dist_1 = require("@alphakits/ui/dist");
9
43
  const typography_1 = require("@alphakits/ui/dist/typography");
10
- const react_1 = __importDefault(require("react"));
44
+ const functional_popover_panel_style_1 = require("@escapenavigator/utils/dist/functional-popover-panel-style");
45
+ const react_1 = __importStar(require("react"));
11
46
  const index_module_css_1 = __importDefault(require("./index.module.css"));
12
47
  /**
13
48
  * Строка спеццены: слева что это за места и сколько они снимают
14
49
  * с группового тарифа, справа сколько таких мест в брони.
15
50
  */
16
- const TicketRow = ({ title, priceHint, description, value, min, max, minusLabel, plusLabel, onChange, }) => {
51
+ const TicketRow = ({ title, priceHint, description, value, min, max, minusLabel, plusLabel, plusDisabledHint, onChange, }) => {
17
52
  const active = value > min;
53
+ const plusLocked = value >= max;
54
+ const plusWrapRef = (0, react_1.useRef)(null);
55
+ const [plusHintOpen, setPlusHintOpen] = (0, react_1.useState)(false);
56
+ (0, dist_1.useClickOutside)(plusWrapRef, () => setPlusHintOpen(false));
18
57
  return (react_1.default.createElement("div", { className: active ? `${index_module_css_1.default.ticket} ${index_module_css_1.default.ticketActive}` : index_module_css_1.default.ticket },
19
58
  react_1.default.createElement("div", { className: index_module_css_1.default.body },
20
59
  react_1.default.createElement(typography_1.Typography.Text, { view: 'primary-small', weight: 'medium' }, title),
@@ -24,7 +63,17 @@ const TicketRow = ({ title, priceHint, description, value, min, max, minusLabel,
24
63
  react_1.default.createElement("button", { type: 'button', className: index_module_css_1.default.stepperButton, "aria-label": minusLabel, disabled: value <= min, onClick: () => onChange(Math.max(min, value - 1)) },
25
64
  react_1.default.createElement(MinusM_1.default, null)),
26
65
  react_1.default.createElement("span", { className: index_module_css_1.default.stepperValue }, value),
27
- react_1.default.createElement("button", { type: 'button', className: index_module_css_1.default.stepperButton, "aria-label": plusLabel, disabled: value >= max, onClick: () => onChange(Math.min(max, value + 1)) },
28
- react_1.default.createElement(PlusM_1.default, null)))));
66
+ react_1.default.createElement("div", { ref: plusWrapRef, className: plusLocked ? `${index_module_css_1.default.plusWrap} ${index_module_css_1.default.plusWrapLocked}` : index_module_css_1.default.plusWrap, onClick: () => {
67
+ if (plusLocked && plusDisabledHint)
68
+ setPlusHintOpen((open) => !open);
69
+ } },
70
+ react_1.default.createElement("button", { type: 'button', className: index_module_css_1.default.stepperButton, "aria-label": plusLabel, disabled: plusLocked, onClick: (event) => {
71
+ event.stopPropagation();
72
+ onChange(Math.min(max, value + 1));
73
+ } },
74
+ react_1.default.createElement(PlusM_1.default, null)),
75
+ !!plusDisabledHint && (react_1.default.createElement(dist_1.Popover, { open: plusHintOpen, anchorElement: plusWrapRef.current, position: 'top', offset: [0, 8], withTransition: true },
76
+ react_1.default.createElement("div", { style: (0, functional_popover_panel_style_1.functionalPopoverPanel)({ padding: 8, maxWidth: 260 }) },
77
+ react_1.default.createElement(typography_1.Typography.Text, { view: 'caps' }, plusDisabledHint))))))));
29
78
  };
30
79
  exports.TicketRow = TicketRow;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/hooks",
3
- "version": "2.0.50",
3
+ "version": "2.1.1",
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": "^2.0.50",
18
- "@escapenavigator/types": "^2.0.48",
19
- "@escapenavigator/utils": "^2.0.50",
17
+ "@escapenavigator/services": "^2.1.1",
18
+ "@escapenavigator/types": "^2.1.1",
19
+ "@escapenavigator/utils": "^2.1.1",
20
20
  "libphonenumber-js": "^1.12.24",
21
21
  "react": "19.2.6",
22
22
  "react-phone-input-2": "^2.15.1"
@@ -32,5 +32,5 @@
32
32
  "ts-jest": "^29.1.1",
33
33
  "typescript": "^5.6"
34
34
  },
35
- "gitHead": "480174116c4a107d2db7e0a4ae92fd0b4e0c63e5"
35
+ "gitHead": "a12ec3a77f18fd9acd233aa2d15696c279b4137f"
36
36
  }