@redneckz/wildless-cms-uni-blocks 0.14.887 → 0.14.889

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.
Files changed (161) hide show
  1. package/bundle/api/LeadServiceAPI.d.ts +8 -0
  2. package/bundle/api/getSubmitBody.d.ts +494 -0
  3. package/bundle/blocks.schema.json +1 -1
  4. package/bundle/bundle.umd.js +663 -561
  5. package/bundle/bundle.umd.min.js +1 -1
  6. package/bundle/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  7. package/bundle/icons/IconName.d.ts +3 -7
  8. package/bundle/retail/api/checkCode.d.ts +9 -1
  9. package/bundle/retail/api/sendCode.d.ts +1 -1
  10. package/bundle/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  11. package/bundle/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  12. package/cosmos-static/icons/LogoIcon.svg +1 -1
  13. package/cosmos-static/icons/sprites.svg +1 -3
  14. package/dist/api/LeadServiceAPI.d.ts +8 -0
  15. package/dist/api/LeadServiceAPI.js +41 -49
  16. package/dist/api/LeadServiceAPI.js.map +1 -1
  17. package/dist/api/getSubmitBody.d.ts +494 -0
  18. package/dist/api/getSubmitBody.js +59 -0
  19. package/dist/api/getSubmitBody.js.map +1 -0
  20. package/dist/components/ApplicationForm/ApplicationForm.js +30 -5
  21. package/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
  22. package/dist/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  23. package/dist/icons/IconName.d.ts +3 -7
  24. package/dist/icons/IconName.js +2 -6
  25. package/dist/icons/IconName.js.map +1 -1
  26. package/dist/retail/api/checkCode.d.ts +9 -1
  27. package/dist/retail/api/checkCode.js +22 -1
  28. package/dist/retail/api/checkCode.js.map +1 -1
  29. package/dist/retail/api/sendCode.d.ts +1 -1
  30. package/dist/retail/api/sendCode.js +8 -2
  31. package/dist/retail/api/sendCode.js.map +1 -1
  32. package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  33. package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
  34. package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
  35. package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  36. package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +7 -4
  37. package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
  38. package/dist/retail/utils/mockLocalStorage.js +2 -2
  39. package/dist/retail/utils/mockLocalStorage.js.map +1 -1
  40. package/lib/api/LeadServiceAPI.d.ts +8 -0
  41. package/lib/api/LeadServiceAPI.js +41 -49
  42. package/lib/api/LeadServiceAPI.js.map +1 -1
  43. package/lib/api/getSubmitBody.d.ts +494 -0
  44. package/lib/api/getSubmitBody.js +54 -0
  45. package/lib/api/getSubmitBody.js.map +1 -0
  46. package/lib/components/ApplicationForm/ApplicationForm.fixture.d.ts +1 -0
  47. package/lib/components/ApplicationForm/ApplicationForm.js +30 -5
  48. package/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
  49. package/lib/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  50. package/lib/icons/IconName.d.ts +3 -7
  51. package/lib/icons/IconName.js +2 -6
  52. package/lib/icons/IconName.js.map +1 -1
  53. package/lib/retail/api/checkCode.d.ts +9 -1
  54. package/lib/retail/api/checkCode.js +22 -1
  55. package/lib/retail/api/checkCode.js.map +1 -1
  56. package/lib/retail/api/sendCode.d.ts +1 -1
  57. package/lib/retail/api/sendCode.js +7 -1
  58. package/lib/retail/api/sendCode.js.map +1 -1
  59. package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  60. package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
  61. package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
  62. package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  63. package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +6 -3
  64. package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
  65. package/lib/retail/utils/mockLocalStorage.js +2 -2
  66. package/lib/retail/utils/mockLocalStorage.js.map +1 -1
  67. package/mobile/bundle/api/LeadServiceAPI.d.ts +8 -0
  68. package/mobile/bundle/api/getSubmitBody.d.ts +494 -0
  69. package/mobile/bundle/bundle.umd.js +663 -561
  70. package/mobile/bundle/bundle.umd.min.js +1 -1
  71. package/mobile/bundle/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  72. package/mobile/bundle/icons/IconName.d.ts +3 -7
  73. package/mobile/bundle/retail/api/checkCode.d.ts +9 -1
  74. package/mobile/bundle/retail/api/sendCode.d.ts +1 -1
  75. package/mobile/bundle/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  76. package/mobile/bundle/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  77. package/mobile/dist/api/LeadServiceAPI.d.ts +8 -0
  78. package/mobile/dist/api/LeadServiceAPI.js +41 -49
  79. package/mobile/dist/api/LeadServiceAPI.js.map +1 -1
  80. package/mobile/dist/api/getSubmitBody.d.ts +494 -0
  81. package/mobile/dist/api/getSubmitBody.js +59 -0
  82. package/mobile/dist/api/getSubmitBody.js.map +1 -0
  83. package/mobile/dist/components/ApplicationForm/ApplicationForm.js +30 -5
  84. package/mobile/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
  85. package/mobile/dist/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  86. package/mobile/dist/icons/IconName.d.ts +3 -7
  87. package/mobile/dist/icons/IconName.js +2 -6
  88. package/mobile/dist/icons/IconName.js.map +1 -1
  89. package/mobile/dist/retail/api/checkCode.d.ts +9 -1
  90. package/mobile/dist/retail/api/checkCode.js +22 -1
  91. package/mobile/dist/retail/api/checkCode.js.map +1 -1
  92. package/mobile/dist/retail/api/sendCode.d.ts +1 -1
  93. package/mobile/dist/retail/api/sendCode.js +8 -2
  94. package/mobile/dist/retail/api/sendCode.js.map +1 -1
  95. package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  96. package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
  97. package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
  98. package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  99. package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +7 -4
  100. package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
  101. package/mobile/dist/retail/utils/mockLocalStorage.js +2 -2
  102. package/mobile/dist/retail/utils/mockLocalStorage.js.map +1 -1
  103. package/mobile/lib/api/LeadServiceAPI.d.ts +8 -0
  104. package/mobile/lib/api/LeadServiceAPI.js +41 -49
  105. package/mobile/lib/api/LeadServiceAPI.js.map +1 -1
  106. package/mobile/lib/api/getSubmitBody.d.ts +494 -0
  107. package/mobile/lib/api/getSubmitBody.js +54 -0
  108. package/mobile/lib/api/getSubmitBody.js.map +1 -0
  109. package/mobile/lib/components/ApplicationForm/ApplicationForm.js +30 -5
  110. package/mobile/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
  111. package/mobile/lib/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
  112. package/mobile/lib/icons/IconName.d.ts +3 -7
  113. package/mobile/lib/icons/IconName.js +2 -6
  114. package/mobile/lib/icons/IconName.js.map +1 -1
  115. package/mobile/lib/retail/api/checkCode.d.ts +9 -1
  116. package/mobile/lib/retail/api/checkCode.js +22 -1
  117. package/mobile/lib/retail/api/checkCode.js.map +1 -1
  118. package/mobile/lib/retail/api/sendCode.d.ts +1 -1
  119. package/mobile/lib/retail/api/sendCode.js +7 -1
  120. package/mobile/lib/retail/api/sendCode.js.map +1 -1
  121. package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
  122. package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
  123. package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
  124. package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
  125. package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +6 -3
  126. package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
  127. package/mobile/lib/retail/utils/mockLocalStorage.js +2 -2
  128. package/mobile/lib/retail/utils/mockLocalStorage.js.map +1 -1
  129. package/mobile/src/api/LeadServiceAPI.ts +64 -82
  130. package/mobile/src/api/getSubmitBody.ts +94 -0
  131. package/mobile/src/components/ApplicationForm/ApplicationForm.example.json +2 -2
  132. package/mobile/src/components/ApplicationForm/ApplicationForm.tsx +33 -4
  133. package/mobile/src/components/ApplicationForm/ApplicationFormContent.ts +1 -1
  134. package/mobile/src/icons/IconName.ts +5 -5
  135. package/mobile/src/icons/LogoIcon.svg +6 -27
  136. package/mobile/src/retail/api/checkCode.ts +47 -2
  137. package/mobile/src/retail/api/sendCode.ts +9 -1
  138. package/mobile/src/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.tsx +29 -8
  139. package/mobile/src/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.tsx +18 -5
  140. package/mobile/src/retail/utils/mockLocalStorage.ts +15 -9
  141. package/package.json +1 -1
  142. package/src/api/LeadServiceAPI.ts +64 -82
  143. package/src/api/getSubmitBody.ts +94 -0
  144. package/src/components/ApplicationForm/ApplicationForm.example.json +2 -2
  145. package/src/components/ApplicationForm/ApplicationForm.fixture.mobile.tsx +2 -2
  146. package/src/components/ApplicationForm/ApplicationForm.fixture.tsx +24 -2
  147. package/src/components/ApplicationForm/ApplicationForm.tsx +33 -4
  148. package/src/components/ApplicationForm/ApplicationFormContent.ts +1 -1
  149. package/src/icons/IconName.ts +5 -5
  150. package/src/icons/LogoIcon.svg +6 -27
  151. package/src/retail/api/checkCode.ts +47 -2
  152. package/src/retail/api/sendCode.ts +9 -1
  153. package/src/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.tsx +29 -8
  154. package/src/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.tsx +18 -5
  155. package/src/retail/utils/mockLocalStorage.ts +15 -9
  156. package/cosmos-static/icons/LogoIconBig.svg +0 -1
  157. package/cosmos-static/icons/LogoIconDefault.svg +0 -1
  158. package/mobile/src/icons/LogoIconBig.svg +0 -28
  159. package/mobile/src/icons/LogoIconDefault.svg +0 -7
  160. package/src/icons/LogoIconBig.svg +0 -28
  161. package/src/icons/LogoIconDefault.svg +0 -7
@@ -987,6 +987,9 @@
987
987
  });
988
988
  const randomNumber = (min = 0, max = 0) => Math.floor(Math.random() * (max - min) + min);
989
989
 
990
+ const API_BASE_URI$1 = '/api/v1';
991
+ const RETAIL_API_BASE_URI = '/light-api-cash/v1';
992
+
990
993
  const formatDate = (date, toTimeStamp = false) => {
991
994
  if (typeof date === 'string') {
992
995
  return date.split('-').reverse().join('.');
@@ -1001,53 +1004,33 @@
1001
1004
 
1002
1005
  const formatPhone = (phone) => phone?.replace(/[^+\d]/g, '');
1003
1006
 
1004
- const API_BASE_URI$1 = '/api/v1';
1005
- const RETAIL_API_BASE_URI = '/light-api-cash/v1';
1006
-
1007
- function LeadServiceAPI() {
1008
- async function send(body, router, isIndividualType = false) {
1009
- const { typeForm, region, phone = '', email, birthday, desiredMeetingDate, inn, innDadata, fullRegion, addressBranch, secondaryPhone = '', bankEmpolee, applicationDate, serviceDirection, partnerSymbolCode, companyNameByInn, ...staticBody } = body;
1010
- const isNaturalPerson = isIndividualType && serviceDirection !== 'Юридическое лицо / ИП';
1011
- const url = `${API_BASE_URI$1}${isNaturalPerson ? '/lead' : '/sendcorporatelead'}`;
1012
- const submitBody = {
1013
- typeForm,
1014
- ...getRegion$1(region, isNaturalPerson),
1015
- ...getEmail(email, isNaturalPerson),
1016
- ...getPhone(phone),
1017
- ...getFormatDate(desiredMeetingDate, 'desiredMeetingDate'),
1018
- ...(isNaturalPerson ? getFormatDate(birthday) : { inn }),
1019
- ...(typeForm === 'FEEDBACK'
1020
- ? {}
1021
- : {
1022
- addressBranch,
1023
- bankEmpolee,
1024
- applicationDate,
1025
- ...getSecondaryPhone(secondaryPhone),
1026
- }),
1027
- ...addPageSlug(typeForm, router),
1028
- ...formatPFForm(typeForm, { innDadata, fullRegion, partnerSymbolCode, companyNameByInn }),
1029
- ...staticBody,
1030
- };
1031
- try {
1032
- const response = await fetch(url, {
1033
- method: 'POST',
1034
- headers: { 'Content-Type': 'application/json' },
1035
- mode: 'cors',
1036
- body: JSON.stringify(submitBody),
1037
- });
1038
- if (!response?.ok) {
1039
- return null;
1040
- }
1041
- return await response.json();
1042
- }
1043
- catch (e) {
1044
- return null;
1045
- }
1046
- }
1007
+ const getSubmitBody = (body, isNaturalPerson, router) => {
1008
+ const { typeForm, region, phone = '', email, birthday, desiredMeetingDate, inn, innDadata, fullRegion, addressBranch, secondaryPhone = '', bankEmpolee, applicationDate, partnerSymbolCode, companyNameByInn, ...staticBody } = body;
1047
1009
  return {
1048
- send,
1010
+ typeForm,
1011
+ ...getRegion$1(region, isNaturalPerson),
1012
+ ...getEmail(email, isNaturalPerson),
1013
+ ...getPhone(phone),
1014
+ ...getFormatDate(desiredMeetingDate, 'desiredMeetingDate'),
1015
+ ...(isNaturalPerson ? getFormatDate(birthday) : { inn }),
1016
+ ...(typeForm === 'FEEDBACK'
1017
+ ? {}
1018
+ : {
1019
+ addressBranch,
1020
+ bankEmpolee,
1021
+ applicationDate,
1022
+ ...getSecondaryPhone(secondaryPhone),
1023
+ }),
1024
+ ...addPageSlug(typeForm, router),
1025
+ ...formatPFForm(typeForm, { innDadata, fullRegion, partnerSymbolCode, companyNameByInn }),
1026
+ ...staticBody,
1049
1027
  };
1050
- }
1028
+ };
1029
+ const getPhoneBody = (phone) => {
1030
+ return {
1031
+ ...getPhone(phone),
1032
+ };
1033
+ };
1051
1034
  const getPhone = (phone) => (phone ? { phone: formatPhone(phone) } : {});
1052
1035
  const getFormatDate = (date, key = 'birthday') => date ? { [key]: formatDate(date) } : {};
1053
1036
  const getRegion$1 = (region, isNaturalPerson = true) => ({
@@ -1073,6 +1056,68 @@
1073
1056
  }
1074
1057
  : {};
1075
1058
 
1059
+ function LeadServiceAPI() {
1060
+ async function send(body, router, isIndividualType = false) {
1061
+ const { serviceDirection } = body;
1062
+ const isNaturalPerson = isIndividualType && serviceDirection !== 'Юридическое лицо / ИП';
1063
+ const url = `${API_BASE_URI$1}${isNaturalPerson ? '/lead' : '/sendcorporatelead'}`;
1064
+ const submitBody = getSubmitBody(body, isNaturalPerson, router);
1065
+ try {
1066
+ const response = await LeadServiceFetch(url, submitBody);
1067
+ if (!response?.ok) {
1068
+ return null;
1069
+ }
1070
+ return await response.json();
1071
+ }
1072
+ catch (e) {
1073
+ return null;
1074
+ }
1075
+ }
1076
+ async function sendCode({ phone }) {
1077
+ const submitBody = getPhoneBody(phone);
1078
+ try {
1079
+ const response = LeadServiceFetch(`${API_BASE_URI$1}/initCorporateLead`, submitBody).then(async (res) => {
1080
+ if (!res.ok) {
1081
+ throw new Error(`Ошибка HTTP: ${res.status}`);
1082
+ }
1083
+ return await res.text();
1084
+ });
1085
+ return await response;
1086
+ }
1087
+ catch (e) {
1088
+ return null;
1089
+ }
1090
+ }
1091
+ async function checkCode({ reqId, code, body }) {
1092
+ const submitBody = {
1093
+ requestId: reqId,
1094
+ confimationCode: code,
1095
+ leadRequest: getSubmitBody(body, false),
1096
+ };
1097
+ try {
1098
+ const response = await LeadServiceFetch(`${API_BASE_URI$1}/confirmCorporateLead`, submitBody);
1099
+ if (!response?.ok) {
1100
+ return null;
1101
+ }
1102
+ return await response.json();
1103
+ }
1104
+ catch (e) {
1105
+ return null;
1106
+ }
1107
+ }
1108
+ return {
1109
+ send,
1110
+ sendCode,
1111
+ checkCode,
1112
+ };
1113
+ }
1114
+ const LeadServiceFetch = (url, submitBody) => fetch(url, {
1115
+ method: 'POST',
1116
+ headers: { 'Content-Type': 'application/json' },
1117
+ mode: 'cors',
1118
+ body: JSON.stringify(submitBody),
1119
+ });
1120
+
1076
1121
  const handleAspects = async ({ aspectsAttributes, aspects, ev }) => {
1077
1122
  for (const { aspectName, params } of aspectsAttributes ?? []) {
1078
1123
  const aspectFn = aspects[aspectName ?? ''];
@@ -1238,11 +1283,183 @@
1238
1283
  return [formState, { errors, field, update, reset, onSubmit: handleSubmit }];
1239
1284
  }
1240
1285
 
1241
- const ApplicationFormLayout = JSX((props) => {
1242
- const { className, title, children, ...rest } = props;
1243
- return (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: jsxs("div", { className: "container space-y-lg", children: [title ? jsx(Heading, { headingType: "h3", title: title, className: "@xl:text-center" }) : null, children] }) }));
1286
+ function copy(source, target) {
1287
+ for (const [k, v] of source.entries()) {
1288
+ if (v !== null && v !== undefined) {
1289
+ target.setItem(k, v);
1290
+ }
1291
+ else {
1292
+ target.removeItem(k);
1293
+ }
1294
+ }
1295
+ }
1296
+
1297
+ function replicate(primary, secondary) {
1298
+ copy(primary, secondary);
1299
+ copy(secondary, primary);
1300
+ return primary.bus.watch(({ type, event }) => {
1301
+ if (event !== null && event !== undefined) {
1302
+ secondary.setItem(type, event);
1303
+ }
1304
+ else {
1305
+ secondary.removeItem(type);
1306
+ }
1307
+ });
1308
+ }
1309
+
1310
+ class StorageAdapter {
1311
+ storage;
1312
+ bus;
1313
+ get size() {
1314
+ return this.storage?.length ?? 0;
1315
+ }
1316
+ constructor(storage, bus = new EventBus()) {
1317
+ this.storage = storage;
1318
+ this.bus = bus;
1319
+ }
1320
+ hasItem(key) {
1321
+ return Boolean(this.storage?.getItem(String(key)));
1322
+ }
1323
+ getItem(key) {
1324
+ const _ = this.storage?.getItem(String(key)) ?? null;
1325
+ try {
1326
+ return JSON.parse(String(_));
1327
+ }
1328
+ catch (ex) {
1329
+ return null;
1330
+ }
1331
+ }
1332
+ entries() {
1333
+ return Array.from({ length: this.size }, (_, i) => {
1334
+ const k = String(this.storage?.key(i));
1335
+ return [k, this.getItem(k)];
1336
+ });
1337
+ }
1338
+ setItem(key, value) {
1339
+ if (value !== null) {
1340
+ this.storage?.setItem(String(key), JSON.stringify(value));
1341
+ }
1342
+ else {
1343
+ this.storage?.removeItem(String(key));
1344
+ }
1345
+ this.bus?.subject(key, value);
1346
+ }
1347
+ removeItem(key) {
1348
+ this.storage?.removeItem(String(key));
1349
+ this.bus?.subject(key, null);
1350
+ }
1351
+ }
1352
+
1353
+ class Store {
1354
+ bus;
1355
+ store = new Map();
1356
+ get size() {
1357
+ return this.store.size;
1358
+ }
1359
+ constructor(bus = new EventBus()) {
1360
+ this.bus = bus;
1361
+ }
1362
+ hasItem(key) {
1363
+ return this.store.has(key);
1364
+ }
1365
+ getItem(key) {
1366
+ return this.store.get(key);
1367
+ }
1368
+ entries() {
1369
+ return this.store.entries();
1370
+ }
1371
+ setItem(key, value) {
1372
+ this.store.set(key, value);
1373
+ this.bus.subject(key, value);
1374
+ }
1375
+ removeItem(key) {
1376
+ this.store.delete(key);
1377
+ this.bus.subject(key, null);
1378
+ }
1379
+ }
1380
+
1381
+ function useRerender() {
1382
+ const [, setCount] = useState(0);
1383
+ return useCallback(() => setCount(_ => (_ + 1) % (1 << 16)), []);
1384
+ }
1385
+
1386
+ const DEFAULT_METHODS = {};
1387
+ /**
1388
+ * MobX like reactivity (simplified).
1389
+ * Can be used to migrate from Redux/MobX or something else
1390
+ *
1391
+ * @param store
1392
+ * @returns reactive proxy backed by store
1393
+ */
1394
+ function useStore(store, methods = DEFAULT_METHODS) {
1395
+ const deps = useRef(null);
1396
+ const render = useRerender();
1397
+ useEffect(() => store.bus.watch(ev => {
1398
+ if (deps.current?.has(String(ev.type))) {
1399
+ render();
1400
+ }
1401
+ }), [store, render]);
1402
+ return useMemo(() => new Proxy(methods, {
1403
+ get(_, key) {
1404
+ deps.current ||= new Set();
1405
+ deps.current.add(key);
1406
+ return store.getItem(key);
1407
+ },
1408
+ has(_, key) {
1409
+ deps.current ||= new Set();
1410
+ deps.current.add(key);
1411
+ return store.hasItem(key);
1412
+ },
1413
+ set(_, key, value) {
1414
+ store.setItem(key, value);
1415
+ return true;
1416
+ },
1417
+ deleteProperty(_, key) {
1418
+ store.removeItem(key);
1419
+ return true;
1420
+ }
1421
+ }), [store]);
1422
+ }
1423
+
1424
+ const sessionStore = new Store(); // sessionStorage cache
1425
+ replicate(sessionStore, new StorageAdapter(globalThis?.sessionStorage));
1426
+ function useSessionStore() {
1427
+ return useStore(sessionStore);
1428
+ }
1429
+
1430
+ const noop = () => {
1431
+ // Do nothing
1432
+ };
1433
+
1434
+ const themeStyle$1 = {
1435
+ primary: style('text-white bg-primary-main hover:bg-primary-hover active:bg-primary-active', 'group-data-secondary:text-primary-main group-data-secondary:bg-white', 'group-data-secondary:hover:text-white group-data-secondary:hover:bg-primary-hover', 'group-data-secondary:active:bg-primary-active'),
1436
+ secondary: style('text-primary-main bg-main-divider hover:text-white hover:bg-primary-hover active:bg-primary-active', 'group-data-secondary:text-white group-data-secondary:bg-white/20', 'group-data-secondary:hover:bg-primary-hover', 'group-data-secondary:active:bg-primary-active'),
1437
+ };
1438
+ const embeddedStyle = style('group/btn-embedded', 'bg-transparent border border-transparent outline-none');
1439
+ const disabledStyle = style('bg-main-gray text-main-disabled cursor-not-allowed');
1440
+ const Button = JSX(({ className, type = 'button', version = 'primary', shape = 'default', embedded, disabled, role, ariaLabel, data, dataTheme, children, wcmsIgnore, onClick = noop, }) => {
1441
+ const handleClick = useCallback(role !== 'tab' ? handlerDecorator(onClick) : onClick, [
1442
+ role,
1443
+ onClick,
1444
+ ]);
1445
+ const aspectsAttrs = useMemo(() => getAspectsAttributes(data), [data]);
1446
+ const isRound = shape === 'round';
1447
+ return (jsx("button", { className: style('font-sans flex items-center gap-xs', {
1448
+ [themeStyle$1[version]]: !disabled && !embedded,
1449
+ [embeddedStyle]: embedded,
1450
+ [disabledStyle]: disabled,
1451
+ }, embedded ? 'justify-between' : 'justify-center', embedded || isRound ? 'p-0' : 'px-9 py-4', {
1452
+ 'rounded-md': shape === 'default',
1453
+ 'rounded-full': isRound,
1454
+ }, className), type: type, role: role, "aria-label": ariaLabel, disabled: disabled, "aria-disabled": disabled ? 'true' : undefined, "data-theme": dataTheme, "data-wcms-ignore": wcmsIgnore, ...aspectsAttrs, onClick: handleClick, children: children }));
1244
1455
  });
1245
1456
 
1457
+ const ButtonTitle = JSX(({ className, children }) => (jsx("span", { className: style('inline-flex items-center text-start gap-s group-[]/btn-embedded:text-primary-main', className), children: children })));
1458
+
1459
+ const CloseButton = JSX(({ className, onClose }) => (jsx("button", { className: style('flex justify-center items-center w-12 h-12 p-2xs bg-transparent border-none', className), onClick: onClose, title: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C", type: "button", children: jsx(Icon, { name: "CloseIcon", width: "20", height: "20", iconVersion: "gray" }) })));
1460
+
1461
+ const Dialog = JSX(({ className, head, children, onClose, onClick }) => (jsxs("div", { className: style('relative bg-white pt-0 p-lg', className), role: "dialog", title: "\u0414\u0438\u0430\u043B\u043E\u0433", onClick: onClick, children: [jsxs("div", { className: "sticky py-xl top-0 bg-white z-10", children: [jsx(CloseButton, { className: "absolute top-0 right-0", onClose: onClose }), jsx("div", { className: "container", children: head })] }), jsx("div", { className: "container pb-m mb-[74px] lg:mb-0", children: children })] })));
1462
+
1246
1463
  function useDialog(Dialog, initialProps = {}) {
1247
1464
  const { open, close, ...rest } = useDialogManager();
1248
1465
  const openDialog = useCallback((props, options = {}) => open({
@@ -1255,29 +1472,99 @@
1255
1472
  return { open: openDialog, close, ...rest };
1256
1473
  }
1257
1474
 
1258
- const getConsentDataProcessing = (inputs) => inputs?.find((_) => _?.name === 'consentDataProcessing');
1259
-
1260
- // TODO Базовая функицональность всех Control - надо вынести и привязать к required флагу
1261
- const getRequiredLabel = ({ label, errors }) => label && errors ? `${label}*` : label;
1475
+ const Loader = JSX(({ color = 'text-primary-main', position = 'absolute', blur = true, size = 'big' }) => (jsx("div", { className: style('flex justify-center items-center h-full w-full z-50', position, {
1476
+ 'backdrop-blur': blur,
1477
+ }), children: jsx("div", { className: style('inline-block', 'animate-spin rounded-full', 'border-solid border-current', 'border-r-transparent', size === 'extraSmall' && 'border-2 h-4 w-4', size === 'small' && 'border-4 h-8 w-8', size === 'big' && 'border-8 h-28 w-28', color), role: "status" }) })));
1262
1478
 
1263
- const renderErrorText = (error) => (jsx("div", { className: "min-h-6", children: error ? (jsx(Text, { size: "text-xs", font: "font-light", color: "text-error", children: error })) : null }));
1479
+ const Timer = JSX(({ className, seconds }) => (jsx("span", { className: className, children: formatTimer(seconds) })));
1480
+ const formatTimer = (seconds) => {
1481
+ const minutes = Math.floor(seconds / 60);
1482
+ return [minutes, seconds % 60].map((_) => String(_).padStart(2, '0')).join(':');
1483
+ };
1264
1484
 
1265
- const debounce = (fn, delay = 600) => {
1266
- let timerId;
1267
- const debouncedCallback = (...args) => {
1268
- debouncedCallback.dispose();
1269
- timerId = setTimeout(() => {
1270
- fn(...args);
1271
- }, delay);
1272
- };
1273
- debouncedCallback.dispose = () => {
1274
- if (timerId) {
1275
- clearTimeout(timerId);
1485
+ const useInterval = (handler, period) => {
1486
+ const timer = useRef(null);
1487
+ const stop = useCallback(() => clearInterval(timer.current), []);
1488
+ const start = useCallback(() => {
1489
+ stop();
1490
+ timer.current = setInterval(() => handler(stop), period);
1491
+ }, [handler, period, stop]);
1492
+ useEffect(() => {
1493
+ start();
1494
+ return stop;
1495
+ }, [start, stop]);
1496
+ return { start, stop };
1497
+ };
1498
+
1499
+ function useCountDownTimer({ seconds, period = 1000, onTick, onEnd }) {
1500
+ const counter = useRef(seconds);
1501
+ const handleTick = useCallback((stop) => {
1502
+ counter.current ||= 0;
1503
+ counter.current = Math.max(0, counter.current - 1);
1504
+ try {
1505
+ onTick?.(counter.current);
1276
1506
  }
1277
- };
1278
- return debouncedCallback;
1507
+ finally {
1508
+ if (counter.current <= 0) {
1509
+ stop();
1510
+ onEnd?.();
1511
+ }
1512
+ }
1513
+ }, [onTick, onEnd]);
1514
+ const { start } = useInterval(handleTick, period);
1515
+ return useCallback((_) => {
1516
+ counter.current = _;
1517
+ start();
1518
+ }, []);
1519
+ }
1520
+
1521
+ const getTraceId = () => {
1522
+ const result = new Uint8Array(8);
1523
+ globalThis.crypto.getRandomValues(result);
1524
+ return result.reduce((acc, _) => `${acc}${_.toString(16).padStart(2, '0')}`, '');
1279
1525
  };
1280
1526
 
1527
+ const fetchRetailJSON = async (url, method, body) => {
1528
+ try {
1529
+ const response = await doRequest(url, method, body);
1530
+ return response.json();
1531
+ }
1532
+ catch (err) {
1533
+ console.error(err);
1534
+ return null;
1535
+ }
1536
+ };
1537
+ async function doRequest(url, method, body) {
1538
+ const traceId = getTraceId();
1539
+ return globalThis?.fetch?.(`${RETAIL_API_BASE_URI}${url}`, {
1540
+ method,
1541
+ headers: {
1542
+ 'Content-Type': 'application/json',
1543
+ 'X-B3-Sampled': '1',
1544
+ 'X-B3-Spanid': traceId,
1545
+ 'X-B3-Traceid': traceId,
1546
+ ...getAuthorizationHeaders(),
1547
+ },
1548
+ credentials: 'include',
1549
+ body: body ? JSON.stringify(body) : null,
1550
+ });
1551
+ }
1552
+ const getAuthorizationHeaders = () => {
1553
+ const token = sessionStorage.getItem('accessToken');
1554
+ return token ? { Authorization: `Bearer ${token}` } : null;
1555
+ };
1556
+
1557
+ const API$2 = LeadServiceAPI();
1558
+ const sendCode = (body, isRetail) => {
1559
+ return isRetail ? fetchRetail(body) : fetchMain$1(body);
1560
+ };
1561
+ const fetchRetail = (body) => doRequest('/sms/sendCode', 'POST', body)
1562
+ .then((res) => res.text())
1563
+ .then((text) => text === 'OK');
1564
+ const fetchMain$1 = (body) => API$2.sendCode({ phone: body.phoneNumber });
1565
+
1566
+ const SubmitButton$1 = JSX(({ isLoading, disabled, children, className, ...rest }) => (jsxs(Button, { type: "submit", className: style('relative', className), disabled: isLoading || disabled, ...rest, children: [isLoading ? jsx(Loader, { blur: true, size: "small" }) : null, children] })));
1567
+
1281
1568
  const inputValidStyle = 'border border-solid outline-none border-gray hover:border-primary-hover active:border-primary-text focus:border-primary-text rounded';
1282
1569
 
1283
1570
  const getValidStyle = (valid) => (valid ? inputValidStyle : 'border-error');
@@ -1296,13 +1583,271 @@
1296
1583
  if (autoFocus) {
1297
1584
  inputRef.current?.focus();
1298
1585
  }
1299
- }, [autoFocus, inputRef]);
1300
- const paddingStyle = children ? 'pr-3xl' : '';
1301
- const validStyle = getValidStyle(valid);
1302
- const ariaLabel = label ?? name ?? id;
1303
- return (jsxs("div", { className: style('relative', className), children: [jsxs("label", { className: "space-y-xs", children: [renderLabel$1(label), isTextarea ? (jsx("textarea", { className: style('block resize-y min-h-24', defaultStyle$1, validStyle), id: style('textarea', id), value: value, name: name || id, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, onChange: handleChange, onFocus: onFocus, onBlur: onBlur }, key)) : (jsx("input", { ref: inputRef, className: style('h-14', defaultStyle$1, paddingStyle, validStyle), id: id, type: type, value: value, name: name || id, placeholder: placeholder, pattern: pattern, disabled: disabled, "aria-label": ariaLabel, onChange: handleChange, onFocus: onFocus, onBlur: onBlur }, key))] }), children] }));
1304
- });
1305
- const defaultStyle$1 = 'w-full border rounded-md text-primary-text outline-none p-m';
1586
+ }, [autoFocus, inputRef]);
1587
+ const paddingStyle = children ? 'pr-3xl' : '';
1588
+ const validStyle = getValidStyle(valid);
1589
+ const ariaLabel = label ?? name ?? id;
1590
+ return (jsxs("div", { className: style('relative', className), children: [jsxs("label", { className: "space-y-xs", children: [renderLabel$1(label), isTextarea ? (jsx("textarea", { className: style('block resize-y min-h-24', defaultStyle$1, validStyle), id: style('textarea', id), value: value, name: name || id, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, onChange: handleChange, onFocus: onFocus, onBlur: onBlur }, key)) : (jsx("input", { ref: inputRef, className: style('h-14', defaultStyle$1, paddingStyle, validStyle), id: id, type: type, value: value, name: name || id, placeholder: placeholder, pattern: pattern, disabled: disabled, "aria-label": ariaLabel, onChange: handleChange, onFocus: onFocus, onBlur: onBlur }, key))] }), children] }));
1591
+ });
1592
+ const defaultStyle$1 = 'w-full border rounded-md text-primary-text outline-none p-m';
1593
+
1594
+ const ICON_SIZE = { width: '118', height: '24' };
1595
+
1596
+ const logoTitleSizeStyle = '';
1597
+
1598
+ const ICON_VERSION_MAP = {
1599
+ 'bg-white': 'color',
1600
+ transparent: 'white',
1601
+ };
1602
+ const SVG_COLOR = {
1603
+ 'bg-white': 'text-primary-main',
1604
+ transparent: 'text-white',
1605
+ };
1606
+ const renderImage = (bgColor, image, size) => {
1607
+ const img = image?.src
1608
+ ? image
1609
+ : {
1610
+ icon: image?.icon || 'LogoIcon',
1611
+ iconVersion: ICON_VERSION_MAP[bgColor],
1612
+ };
1613
+ return (jsx(Img, { image: img, className: SVG_COLOR[bgColor], width: size?.width, height: size?.height }));
1614
+ };
1615
+
1616
+ const TEXT_COLOR = {
1617
+ 'bg-white': 'text-primary-text',
1618
+ transparent: 'text-white',
1619
+ };
1620
+ const Logo = JSX(({ className, href = '/', logo, children, targetBlank, bgColor = 'bg-white', showTitle = true, data, }) => (jsxs("a", { className: style('inline-flex items-center font-sans no-underline', className), href: logo?.href ?? href, target: targetBlank ? '_blank' : '_self', "aria-label": logo?.title ?? 'Россельхозбанк', ...getAspectsAttributes(data), children: [renderImage(bgColor, logo?.image, ICON_SIZE), showTitle
1621
+ ? children ?? (jsx("div", { className: "ml-s", children: jsx(Text, { font: "font-medium", color: TEXT_COLOR[bgColor], size: logoTitleSizeStyle, children: logo?.title ?? 'Россельхозбанк' }) }))
1622
+ : null] })));
1623
+
1624
+ const checkCaptcha = (body) => doRequest('/sms/checkCaptcha', 'POST', body)
1625
+ .then((res) => res.text())
1626
+ .then((text) => text !== 'ERROR');
1627
+
1628
+ const createCaptcha = (phoneNumber) => doRequest(`/sms/createCaptcha?phoneNumber=${encodeURIComponent(phoneNumber)}`, 'GET').then(async (res) => (res ? res.blob() : new Blob()));
1629
+
1630
+ const CaptchaDialog = JSX(({ phoneNumber, sendCode, onClose }) => {
1631
+ const [captcha, setCaptcha] = useState('');
1632
+ const [code, setCode] = useState('');
1633
+ const [hasError, setHasError] = useState(false);
1634
+ const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
1635
+ const { closeAll } = useDialogManager();
1636
+ const handleCheckCaptcha = useCallback(async () => {
1637
+ startLoading();
1638
+ const isValidCode = await checkCaptcha({ captchaText: code });
1639
+ if (isValidCode) {
1640
+ onClose?.();
1641
+ sendCode?.();
1642
+ }
1643
+ else {
1644
+ setHasError(true);
1645
+ }
1646
+ endLoading();
1647
+ }, [code, sendCode]);
1648
+ const handleCreateCaptcha = useCallback(() => {
1649
+ (async () => setCaptcha(URL.createObjectURL(await createCaptcha(phoneNumber))))();
1650
+ }, []);
1651
+ useEffect(handleCreateCaptcha, []);
1652
+ return (jsx(Dialog, { className: "my-6xl max-w-lg w-full min-h-fit mx-auto rounded-lg", head: jsx(Logo, {}), onClose: onClose, children: jsxs("div", { className: "flex flex-col gap-lg items-center", children: [jsxs("div", { className: "flex", children: [jsx("img", { className: "grow", src: captcha }), jsx(Button, { className: "w-8", embedded: true, onClick: handleCreateCaptcha, children: jsx(Icon, { iconVersion: "normal", name: "RefreshIcon" }) })] }), jsx(Input, { className: "w-80", onChange: setCode, value: code, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0434 \u0441 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438" }), hasError ? jsx("div", { className: "text-error", children: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043E\u0434" }) : null, jsxs("div", { className: "flex w-80 justify-between", children: [jsx(Button, { version: "secondary", onClick: closeAll, children: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F" }), jsx(SubmitButton$1, { version: "secondary", disabled: !code, onClick: handleCheckCaptcha, children: "\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C" })] }), isLoading ? jsx(Loader, { blur: false }) : null] }) }));
1653
+ });
1654
+
1655
+ const InputCode = JSX(({ values, setValues, hasError, errorText }) => {
1656
+ const [activeIndex, setActiveIndex] = useState(0);
1657
+ const inputRefs = useRef([]);
1658
+ useEffect(() => {
1659
+ inputRefs.current?.[activeIndex]?.focus();
1660
+ }, [activeIndex]);
1661
+ const handleChange = useCallback((index) => (event) => {
1662
+ const { value } = event.currentTarget;
1663
+ const oneValue = value.slice(0, 1);
1664
+ setValues(values.map((_, i) => (i === index ? oneValue : _)));
1665
+ setActiveIndex(index + 1);
1666
+ }, [values]);
1667
+ const handleKeyDown = useCallback((currentIndex) => (event) => {
1668
+ const { key } = event;
1669
+ if (key === 'Backspace' && !values[currentIndex]) {
1670
+ const previousIndex = currentIndex > 0 ? currentIndex - 1 : values.length - 1;
1671
+ const updatedValues = values.map((value, index) => (index === previousIndex ? '' : value));
1672
+ setValues(updatedValues);
1673
+ setActiveIndex(previousIndex);
1674
+ }
1675
+ }, [values]);
1676
+ const handlePaste = useCallback((event) => {
1677
+ event.preventDefault();
1678
+ const pastedData = event.clipboardData.getData('text');
1679
+ const updatedValues = values.map((_, idx) => (idx < pastedData.length ? pastedData[idx] : _));
1680
+ setValues(updatedValues);
1681
+ setActiveIndex(updatedValues.length - 1);
1682
+ }, [values]);
1683
+ return (jsxs("div", { className: "flex flex-col gap-2 text-center", children: [jsx("div", { children: values.map((value, index) => (jsx("input", { type: "number", maxLength: 1, value: value, onChange: handleChange(index), onPaste: handlePaste, ref: (ref) => {
1684
+ if (!inputRefs.current) {
1685
+ inputRefs.current = [];
1686
+ }
1687
+ inputRefs.current[index] = ref;
1688
+ }, onFocus: (event) => event.target.select(), onKeyDown: handleKeyDown(index), className: getInputStyle(index, values, hasError) }, index))) }), hasError ? jsx("div", { className: "text-error", children: errorText }) : null] }));
1689
+ });
1690
+ const getInputStyle = (index, values, hasError = false) => {
1691
+ const isInputEmpty = !values[index];
1692
+ return `w-16 sm:w-20 h-24 text-5xl text-center p-md m-2 border ${getValidStyle(!hasError || !isInputEmpty)} rounded-md caret-transparent outline-none`;
1693
+ };
1694
+
1695
+ const SubmitButton = JSX(({ disabled = false, onClick, text }) => (jsx(Button, { type: "button", onClick: onClick, disabled: disabled, children: jsx(Text, { font: "font-normal", children: text }) })));
1696
+
1697
+ const API$1 = LeadServiceAPI();
1698
+ const checkCode = async (body, isRetail) => {
1699
+ const transformedBody = transformBody(body, isRetail);
1700
+ return isRetail
1701
+ ? fetchRetailJSON('/sms/checkCode', 'POST', transformedBody).then(saveToken)
1702
+ : fetchMain(transformedBody).then((res) => {
1703
+ if (res === null) {
1704
+ throw new Error('Неверный код');
1705
+ }
1706
+ });
1707
+ };
1708
+ const saveToken = (data) => {
1709
+ if (data?.access_token && data?.refresh_token) {
1710
+ globalThis.sessionStorage.setItem('accessToken', data.access_token);
1711
+ globalThis.sessionStorage.setItem('refreshToken', data.refresh_token);
1712
+ }
1713
+ };
1714
+ const fetchMain = (body) => API$1.checkCode(body);
1715
+ const transformBody = ({ smsText, smsCodesSetName, body, reqId }, isRetail) => {
1716
+ if (isRetail) {
1717
+ return { smsText, smsCodesSetName };
1718
+ }
1719
+ if (!reqId || !body) {
1720
+ throw new Error('Произошла ошибка, попробуйте позднее');
1721
+ }
1722
+ return { code: smsText, reqId, body };
1723
+ };
1724
+
1725
+ const TIME_TO_RESEND = 180;
1726
+ const useVerifyPhoneDialogSubmit = ({ values, onSuccess, formatData, reqId, isRetail = true, }) => {
1727
+ const sessionStore = useSessionStore();
1728
+ const attempts = sessionStore.smsCode?.attempts || 0;
1729
+ const timer = Math.max(getTimer(sessionStore.smsCode?.sendTime || Date.now()), 0);
1730
+ const [errorText, setErrorText] = useState('');
1731
+ const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
1732
+ const [timeNextReq, setTimeNextReq] = useState(timer);
1733
+ const resetError = useCallback(() => setErrorText(''), []);
1734
+ const isTimeExpired = Boolean(timeNextReq === 0 && sessionStore.smsCode?.sendTime);
1735
+ const isSubmitButtonDisabled = attempts > 2 || isTimeExpired || !values.every(Boolean);
1736
+ const handleSubmit = useCallback(async () => {
1737
+ try {
1738
+ sessionStore.smsCode = {
1739
+ ...sessionStore.smsCode,
1740
+ attempts: attempts + 1,
1741
+ };
1742
+ startLoading();
1743
+ await checkCode({
1744
+ smsText: values.join(''),
1745
+ smsCodesSetName: { key: 'AUTHENTICATION' },
1746
+ body: isRetail ? undefined : formatData,
1747
+ reqId: isRetail ? undefined : reqId,
1748
+ }, isRetail);
1749
+ setTimeNextReq(0);
1750
+ resetError();
1751
+ sessionStore.smsCode = null;
1752
+ await onSuccess?.(values.join(''));
1753
+ }
1754
+ catch {
1755
+ setErrorText(attempts > 1 ? 'Исчерпан лимит ввода смс-кода' : 'Неверный код');
1756
+ }
1757
+ finally {
1758
+ endLoading();
1759
+ }
1760
+ }, [values, attempts]);
1761
+ useEffect(() => {
1762
+ if (isTimeExpired && isRetail) {
1763
+ setErrorText('Код просрочен');
1764
+ }
1765
+ else if (attempts > 2) {
1766
+ setErrorText('Исчерпан лимит ввода смс-кода');
1767
+ }
1768
+ }, [isTimeExpired]);
1769
+ return {
1770
+ handleSubmit,
1771
+ hasError: Boolean(errorText),
1772
+ errorText,
1773
+ isLoading,
1774
+ timeNextReq,
1775
+ isSubmitButtonDisabled,
1776
+ setTimeNextReq,
1777
+ setErrorText,
1778
+ };
1779
+ };
1780
+ const getTimer = (sendTime) => TIME_TO_RESEND - Math.floor((Date.now() - sendTime) / 1000);
1781
+
1782
+ const CODE_LENGTH = 4;
1783
+ const VerifyPhoneDialog = JSX(({ phone, withDescription = true, consents, onSuccess = noop, onClose = noop, formatData, reqId, isRetail = true, }) => {
1784
+ const [values, setValues] = useState(Array(CODE_LENGTH).fill(''));
1785
+ const sessionStore = useSessionStore();
1786
+ const { handleSubmit, hasError, errorText, isLoading, timeNextReq, isSubmitButtonDisabled, setTimeNextReq, setErrorText, } = useVerifyPhoneDialogSubmit({
1787
+ values,
1788
+ onSuccess,
1789
+ formatData,
1790
+ reqId,
1791
+ isRetail,
1792
+ });
1793
+ const captchaDialog = useDialog(CaptchaDialog);
1794
+ const phoneNumber = formatPhone(phone);
1795
+ const restartTimer = useCountDownTimer({ seconds: timeNextReq, onTick: setTimeNextReq });
1796
+ const handleSendCode = useCallback(async () => {
1797
+ const isSuccessSendCode = await sendCode({
1798
+ phoneNumber,
1799
+ smsCodesSetName: { key: 'AUTHENTICATION' },
1800
+ }, isRetail);
1801
+ if (isSuccessSendCode) {
1802
+ setTimeNextReq(TIME_TO_RESEND);
1803
+ restartTimer(TIME_TO_RESEND);
1804
+ setErrorText('');
1805
+ sessionStore.smsCode = {
1806
+ sendTime: Date.now(),
1807
+ attempts: 0,
1808
+ };
1809
+ }
1810
+ else {
1811
+ captchaDialog.open({ phoneNumber, sendCode: handleSendCode });
1812
+ }
1813
+ }, [phoneNumber, restartTimer, onClose]);
1814
+ useEffect(() => {
1815
+ if (!sessionStore.smsCode?.sendTime && isRetail) {
1816
+ handleSendCode();
1817
+ }
1818
+ }, []);
1819
+ return (jsx(Dialog, { className: "my-6xl max-w-3xl w-full min-h-fit mx-auto rounded-xl p-m", onClose: onClose, children: jsxs("div", { className: "flex flex-col gap-xl items-center rounded-md", children: [jsx(Headline, { className: "w-full", title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430", description: `Мы отправили код на ${phone}`, headlineVersion: "XS", isEmbedded: true, as: "h6" }), jsx(InputCode, { values: values, setValues: setValues, errorText: errorText, hasError: hasError }), renderText$3(timeNextReq, handleSendCode), withDescription ? (jsxs(RichText, { itemSize: "list-s", children: [jsx("span", { children: "\u0412\u0432\u043E\u0434\u044F \u043A\u043E\u0434, \u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044E, \u0447\u0442\u043E \u043E\u0437\u043D\u0430\u043A\u043E\u043C\u043B\u0435\u043D \u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044E: " }), jsx("ul", { children: consents?.map((_, i) => (jsx("li", { children: _ }, `${_}-${i}`))) })] })) : null, renderNextButton(isSubmitButtonDisabled, handleSubmit), isLoading ? jsx(Loader, { blur: false }) : null] }) }));
1820
+ });
1821
+ const renderNextButton = (disabled, onClick) => (jsx(SubmitButton, { text: "\u0414\u0430\u043B\u0435\u0435", disabled: disabled, onClick: onClick }));
1822
+ const renderText$3 = (timeNextReq, handleSendCode) => timeNextReq ? (jsxs("div", { className: "flex flex-row text-l font-light text-base", children: ["\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434 \u043C\u043E\u0436\u043D\u043E \u0447\u0435\u0440\u0435\u0437", jsx(Timer, { className: "pl-2xs", seconds: timeNextReq })] })) : (jsx(Button, { embedded: true, onClick: handleSendCode, children: jsx(ButtonTitle, { children: "\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434" }) }));
1823
+
1824
+ const ApplicationFormLayout = JSX((props) => {
1825
+ const { className, title, children, ...rest } = props;
1826
+ return (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: jsxs("div", { className: "container space-y-lg", children: [title ? jsx(Heading, { headingType: "h3", title: title, className: "@xl:text-center" }) : null, children] }) }));
1827
+ });
1828
+
1829
+ const getConsentDataProcessing = (inputs) => inputs?.find((_) => _?.name === 'consentDataProcessing');
1830
+
1831
+ // TODO Базовая функицональность всех Control - надо вынести и привязать к required флагу
1832
+ const getRequiredLabel = ({ label, errors }) => label && errors ? `${label}*` : label;
1833
+
1834
+ const renderErrorText = (error) => (jsx("div", { className: "min-h-6", children: error ? (jsx(Text, { size: "text-xs", font: "font-light", color: "text-error", children: error })) : null }));
1835
+
1836
+ const debounce = (fn, delay = 600) => {
1837
+ let timerId;
1838
+ const debouncedCallback = (...args) => {
1839
+ debouncedCallback.dispose();
1840
+ timerId = setTimeout(() => {
1841
+ fn(...args);
1842
+ }, delay);
1843
+ };
1844
+ debouncedCallback.dispose = () => {
1845
+ if (timerId) {
1846
+ clearTimeout(timerId);
1847
+ }
1848
+ };
1849
+ return debouncedCallback;
1850
+ };
1306
1851
 
1307
1852
  const formatOption = (_) => _?.text || _?.key || '';
1308
1853
 
@@ -1623,10 +2168,6 @@
1623
2168
  const ITEMS_CREDIT_AMOUNT = ['От 1 000 ₽', 'До 1 000 000 000 ₽'];
1624
2169
  const AmountField = JSX(({ field, input }) => (jsx(InputRange, { title: "\u0421\u0443\u043C\u043C\u0430, \u20BD", items: ITEMS_CREDIT_AMOUNT, min: MIN_CREDIT_AMOUNT, max: MAX_CREDIT_AMOUNT, ...field(input?.name ?? '') })));
1625
2170
 
1626
- const noop = () => {
1627
- // Do nothing
1628
- };
1629
-
1630
2171
  const InputWrapper = JSX(({ className, label, value = '', error, errors, type, isInteger, placeholder, maxLength, inputRef, isOpen, onOpen, onClose, onChange = noop, ...rest }) => {
1631
2172
  const popupRef = useOutsideClick(onClose);
1632
2173
  const handleChange = useCallback((v) => {
@@ -2109,9 +2650,9 @@
2109
2650
  onChange && onChange(!value);
2110
2651
  }, [onChange, disabled, value]);
2111
2652
  const icon = isRadio ? (jsx("div", { className: "absolute left-1 w-3 h-3 rounded-full bg-primary-main" })) : (jsx(SVG, { paths: CHECK_PATHS, className: "absolute left-1 ml-px block", width: "11", height: "9", fill: "white", viewBox: "0 0 11 9" }));
2112
- return (jsx("div", { className: className, children: jsxs("label", { className: style('flex items-center relative group/box', getCursorStyle(disabled)), onClick: handleChange, children: [jsx("div", { className: style(defaultCheckStyle, 'm-0', isRadio ? 'rounded-full border-2' : checkboxStyle(value), !disabled && value ? 'border-primary-main' : 'border-gray', disabled ? 'bg-main-disabled' : 'group-hover/box:border-primary-hover'), role: role(isRadio), "aria-checked": Boolean(value), "aria-disabled": Boolean(disabled), "aria-label": text }), value ? icon : null, renderText$3(text)] }) }));
2653
+ return (jsx("div", { className: className, children: jsxs("label", { className: style('flex items-center relative group/box', getCursorStyle(disabled)), onClick: handleChange, children: [jsx("div", { className: style(defaultCheckStyle, 'm-0', isRadio ? 'rounded-full border-2' : checkboxStyle(value), !disabled && value ? 'border-primary-main' : 'border-gray', disabled ? 'bg-main-disabled' : 'group-hover/box:border-primary-hover'), role: role(isRadio), "aria-checked": Boolean(value), "aria-disabled": Boolean(disabled), "aria-label": text }), value ? icon : null, renderText$2(text)] }) }));
2113
2654
  });
2114
- const renderText$3 = (text) => text ? (jsx("div", { className: "ml-s", children: jsx(Text, { size: "text-l", font: "font-light", children: text }) })) : null;
2655
+ const renderText$2 = (text) => text ? (jsx("div", { className: "ml-s", children: jsx(Text, { size: "text-l", font: "font-light", children: text }) })) : null;
2115
2656
  const getCursorStyle = (disabled = false) => (disabled ? 'cursor-not-allowed' : 'cursor-pointer');
2116
2657
  const role = (isRadio = false) => (isRadio ? 'radio' : 'checkbox');
2117
2658
  const checkboxStyle = (value = false) => style('rounded border', { 'bg-primary-main': value });
@@ -2435,33 +2976,6 @@
2435
2976
 
2436
2977
  const renderTitle = (title) => title ? (jsx("div", { className: "@xl:text-center @xl:col-span-2 mb-m", children: jsx(Text, { size: "text-h6", children: title }) })) : null;
2437
2978
 
2438
- const themeStyle$1 = {
2439
- primary: style('text-white bg-primary-main hover:bg-primary-hover active:bg-primary-active', 'group-data-secondary:text-primary-main group-data-secondary:bg-white', 'group-data-secondary:hover:text-white group-data-secondary:hover:bg-primary-hover', 'group-data-secondary:active:bg-primary-active'),
2440
- secondary: style('text-primary-main bg-main-divider hover:text-white hover:bg-primary-hover active:bg-primary-active', 'group-data-secondary:text-white group-data-secondary:bg-white/20', 'group-data-secondary:hover:bg-primary-hover', 'group-data-secondary:active:bg-primary-active'),
2441
- };
2442
- const embeddedStyle = style('group/btn-embedded', 'bg-transparent border border-transparent outline-none');
2443
- const disabledStyle = style('bg-main-gray text-main-disabled cursor-not-allowed');
2444
- const Button = JSX(({ className, type = 'button', version = 'primary', shape = 'default', embedded, disabled, role, ariaLabel, data, dataTheme, children, wcmsIgnore, onClick = noop, }) => {
2445
- const handleClick = useCallback(role !== 'tab' ? handlerDecorator(onClick) : onClick, [
2446
- role,
2447
- onClick,
2448
- ]);
2449
- const aspectsAttrs = useMemo(() => getAspectsAttributes(data), [data]);
2450
- const isRound = shape === 'round';
2451
- return (jsx("button", { className: style('font-sans flex items-center gap-xs', {
2452
- [themeStyle$1[version]]: !disabled && !embedded,
2453
- [embeddedStyle]: embedded,
2454
- [disabledStyle]: disabled,
2455
- }, embedded ? 'justify-between' : 'justify-center', embedded || isRound ? 'p-0' : 'px-9 py-4', {
2456
- 'rounded-md': shape === 'default',
2457
- 'rounded-full': isRound,
2458
- }, className), type: type, role: role, "aria-label": ariaLabel, disabled: disabled, "aria-disabled": disabled ? 'true' : undefined, "data-theme": dataTheme, "data-wcms-ignore": wcmsIgnore, ...aspectsAttrs, onClick: handleClick, children: children }));
2459
- });
2460
-
2461
- const CloseButton = JSX(({ className, onClose }) => (jsx("button", { className: style('flex justify-center items-center w-12 h-12 p-2xs bg-transparent border-none', className), onClick: onClose, title: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C", type: "button", children: jsx(Icon, { name: "CloseIcon", width: "20", height: "20", iconVersion: "gray" }) })));
2462
-
2463
- const Dialog = JSX(({ className, head, children, onClose, onClick }) => (jsxs("div", { className: style('relative bg-white pt-0 p-lg', className), role: "dialog", title: "\u0414\u0438\u0430\u043B\u043E\u0433", onClick: onClick, children: [jsxs("div", { className: "sticky py-xl top-0 bg-white z-10", children: [jsx(CloseButton, { className: "absolute top-0 right-0", onClose: onClose }), jsx("div", { className: "container", children: head })] }), jsx("div", { className: "container pb-m mb-[74px] lg:mb-0", children: children })] })));
2464
-
2465
2979
  const ResponseTypeDialog = JSX(({ ok, typeForm, onClose }) => {
2466
2980
  const statusIcon = ok ? 'ResponseOKIcon' : 'ResponseFailIcon';
2467
2981
  const responseOKDescription = typeForm === 'ANTIFRAUD'
@@ -2546,12 +3060,6 @@
2546
3060
  return { ...formState, typeForm: { key: typeForm, text: '' } };
2547
3061
  };
2548
3062
 
2549
- const Loader = JSX(({ color = 'text-primary-main', position = 'absolute', blur = true, size = 'big' }) => (jsx("div", { className: style('flex justify-center items-center h-full w-full z-50', position, {
2550
- 'backdrop-blur': blur,
2551
- }), children: jsx("div", { className: style('inline-block', 'animate-spin rounded-full', 'border-solid border-current', 'border-r-transparent', size === 'extraSmall' && 'border-2 h-4 w-4', size === 'small' && 'border-4 h-8 w-8', size === 'big' && 'border-8 h-28 w-28', color), role: "status" }) })));
2552
-
2553
- const SubmitButton$1 = JSX(({ isLoading, disabled, children, className, ...rest }) => (jsxs(Button, { type: "submit", className: style('relative', className), disabled: isLoading || disabled, ...rest, children: [isLoading ? jsx(Loader, { blur: true, size: "small" }) : null, children] })));
2554
-
2555
3063
  const themeStyle = {
2556
3064
  primary: themeStyle$1.primary,
2557
3065
  secondary: themeStyle$1.secondary,
@@ -2569,9 +3077,9 @@
2569
3077
  [themeStyle[version]]: Boolean(version),
2570
3078
  [aboveText ? 'px-9 py-2.5' : 'px-9 py-4']: buttonLike,
2571
3079
  'rounded-md': buttonLike,
2572
- }, className), href: href, target: target, rel: rel, "aria-label": ariaLabel ?? `Ссылка на ${text}`, role: href ? 'link' : 'button', onClick: onClick, ...getAspectsAttributes(data), children: children ?? renderText$2(text, aboveText) }));
3080
+ }, className), href: href, target: target, rel: rel, "aria-label": ariaLabel ?? `Ссылка на ${text}`, role: href ? 'link' : 'button', onClick: onClick, ...getAspectsAttributes(data), children: children ?? renderText$1(text, aboveText) }));
2573
3081
  });
2574
- const renderText$2 = (text, aboveText) => text || aboveText ? (jsxs("div", { className: "whitespace-pre", children: [aboveText ? jsx("div", { className: "font-light text-left text-xs", children: aboveText }) : null, jsx("div", { className: style('text-left', { 'text-s -mt-3xs': Boolean(aboveText) }), children: text })] })) : null;
3082
+ const renderText$1 = (text, aboveText) => text || aboveText ? (jsxs("div", { className: "whitespace-pre", children: [aboveText ? jsx("div", { className: "font-light text-left text-xs", children: aboveText }) : null, jsx("div", { className: style('text-left', { 'text-s -mt-3xs': Boolean(aboveText) }), children: text })] })) : null;
2575
3083
 
2576
3084
  const Footnote = JSX(({ text, link }) => (jsxs(Paragraph, { size: "text-l", font: "font-light", color: "text-secondary-text", children: [text ? jsx(Text, { children: text }) : null, link ? (jsx(Link, { ...link, ariaLabel: "\u0443\u0441\u043B\u043E\u0432\u0438\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043D\u043D\u044B\u0445", children: link.text })) : null] })));
2577
3085
 
@@ -2582,19 +3090,43 @@
2582
3090
  const renderContacts = () => (jsxs("div", { className: "space-y-m", children: [jsx(Heading, { headingType: "h6", title: "\u0418\u043B\u0438 \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u043D\u0430\u043C\u0438 \u0443\u0434\u043E\u0431\u043D\u044B\u043C \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C", className: "@xl:text-center" }), jsxs("div", { className: "flex sm:justify-center gap-xl", children: [jsxs("a", { className: "flex gap-s items-center text-primary-text no-underline", href: `tel:8 (800) 200-78-70`, "aria-label": "\u0442\u0435\u043B\u0435\u0444\u043E\u043D 8 (800) 200-78-70", children: [jsx(Img, { image: { icon: 'PhoneIcon' }, width: "24", height: "24" }), jsx("span", { children: "8 (800) 200-78-70" })] }), jsxs("a", { className: "flex gap-s items-center text-primary-text no-underline", "aria-label": "\u043F\u043E\u0447\u0442\u0430 ved@rshb.ru", href: `mailto:ved@rshb.ru`, children: [jsx(Img, { image: { icon: 'MailIcon' }, width: "24", height: "24" }), jsx("span", { children: "ved@rshb.ru" })] })] })] }));
2583
3091
 
2584
3092
  const API = LeadServiceAPI();
2585
- const ApplicationForm = UniBlock(({ className, title, typeForm = '', sections = [], button, link, endpoint, additionalParams, isContacts, data, ...rest }) => {
3093
+ const ApplicationForm = UniBlock(
3094
+ // eslint-disable-next-line max-lines-per-function
3095
+ ({ className, title, typeForm = '', sections = [], button, link, endpoint, additionalParams, isContacts, data, ...rest }) => {
2586
3096
  const inputs = useMemo(() => (sections?.flatMap((_) => _?.inputs) || []), [sections]);
2587
3097
  const initialFormState = useMemo(() => getInitialFormState$2(inputs, typeForm), [inputs, typeForm]);
2588
3098
  const router = useRouter();
2589
3099
  const formValidator = useMemo(() => getFormValidator(inputs), [inputs]);
2590
3100
  const responseTypeDialog = useDialog(ResponseTypeDialog);
2591
3101
  const aspects = useAspects();
3102
+ const verifyPhoneDialog = useDialog(VerifyPhoneDialog);
2592
3103
  const handleSubmit = useCallback(async (formData, ev) => {
2593
3104
  const formatData = getFormatData({ ...formData, ...additionalParams });
2594
- const ok = Boolean(await API.send(formatData, router, endpoint === 'lead'));
2595
- responseTypeDialog.open({ ok, typeForm });
2596
- if (ok) {
2597
- handleAspects({ aspectsAttributes: data, aspects, ev });
3105
+ if (endpoint === 'initcorporatelead') {
3106
+ const { phone } = formatData;
3107
+ const response = await API.sendCode({ phone: String(phone) });
3108
+ if (!response) {
3109
+ responseTypeDialog.open({ ok: Boolean(response), typeForm });
3110
+ return;
3111
+ }
3112
+ verifyPhoneDialog.open({
3113
+ phone,
3114
+ withDescription: false,
3115
+ formatData,
3116
+ reqId: String(response),
3117
+ isRetail: false,
3118
+ onSuccess: () => {
3119
+ verifyPhoneDialog.close();
3120
+ responseTypeDialog.open({ ok: true, typeForm });
3121
+ },
3122
+ });
3123
+ }
3124
+ else {
3125
+ const ok = Boolean(await API.send(formatData, router, endpoint === 'lead'));
3126
+ responseTypeDialog.open({ ok, typeForm });
3127
+ if (ok) {
3128
+ handleAspects({ aspectsAttributes: data, aspects, ev });
3129
+ }
2598
3130
  }
2599
3131
  }, [typeForm]);
2600
3132
  const [, { field, onSubmit }] = useForm(initialFormState, {
@@ -2885,42 +3417,6 @@
2885
3417
  EsiaStatuses["Pending"] = "PENDING";
2886
3418
  })(EsiaStatuses || (EsiaStatuses = {}));
2887
3419
 
2888
- const getTraceId = () => {
2889
- const result = new Uint8Array(8);
2890
- globalThis.crypto.getRandomValues(result);
2891
- return result.reduce((acc, _) => `${acc}${_.toString(16).padStart(2, '0')}`, '');
2892
- };
2893
-
2894
- const fetchRetailJSON = async (url, method, body) => {
2895
- try {
2896
- const response = await doRequest(url, method, body);
2897
- return response.json();
2898
- }
2899
- catch (err) {
2900
- console.error(err);
2901
- return null;
2902
- }
2903
- };
2904
- async function doRequest(url, method, body) {
2905
- const traceId = getTraceId();
2906
- return globalThis?.fetch?.(`${RETAIL_API_BASE_URI}${url}`, {
2907
- method,
2908
- headers: {
2909
- 'Content-Type': 'application/json',
2910
- 'X-B3-Sampled': '1',
2911
- 'X-B3-Spanid': traceId,
2912
- 'X-B3-Traceid': traceId,
2913
- ...getAuthorizationHeaders(),
2914
- },
2915
- credentials: 'include',
2916
- body: body ? JSON.stringify(body) : null,
2917
- });
2918
- }
2919
- const getAuthorizationHeaders = () => {
2920
- const token = sessionStorage.getItem('accessToken');
2921
- return token ? { Authorization: `Bearer ${token}` } : null;
2922
- };
2923
-
2924
3420
  const getLink = (body) => fetchRetailJSON('/esia/getLink', 'POST', body);
2925
3421
 
2926
3422
  const EsiaLoginBanner = JSX(({ onChangeEsiaStatus, productType }) => {
@@ -3273,8 +3769,6 @@
3273
3769
 
3274
3770
  const CardRow = JSX(({ className, children }) => (jsx("div", { className: style('flex flex-col sm:flex-row sm:border-t sm:border-solid sm:border-main-divider py-xl gap-x-6xl gap-y-xl', className), children: children })));
3275
3771
 
3276
- const ButtonTitle = JSX(({ className, children }) => (jsx("span", { className: style('inline-flex items-center text-start gap-s group-[]/btn-embedded:text-primary-main', className), children: children })));
3277
-
3278
3772
  const ToggleIcon = JSX(({ isUnfolded, ...rest }) => (jsx(Icon, { name: isUnfolded ? 'ArrowUpIcon' : 'ArrowDownIcon', size: "small", iconVersion: "", ...rest })));
3279
3773
 
3280
3774
  const DefaultFoldButton = JSX(({ className, isUnfolded, short, label = isUnfolded ? 'Скрыть' : 'Развернуть', embedded, ...rest }) => (jsxs(Button, { className: style({ 'w-full': !short }, className), embedded: embedded, shape: short ? 'default' : 'square', role: "tab", "aria-label": "\u041A\u043D\u043E\u043F\u043A\u0430 \u0441\u0432\u043E\u0440\u0430\u0447\u0438\u0432\u0430\u044E\u0449\u0435\u0439\u0441\u044F \u0441\u0435\u043A\u0446\u0438\u0438", ...rest, children: [jsx(ButtonTitle, { children: label }), jsx(ToggleIcon, { isUnfolded: isUnfolded, iconVersion: embedded ? 'color' : '' })] })));
@@ -3836,155 +4330,17 @@
3836
4330
  if (regionValue?.key) {
3837
4331
  addressField.onChange?.('');
3838
4332
  }
3839
- }, [regionValue.key]);
3840
- const { points } = useOfficesAtmsMapData({
3841
- data: offices,
3842
- filtrationState: {},
3843
- getBalloon: getOfficePoint,
3844
- });
3845
- return (jsxs("div", { children: [jsx(SelectControl, { label: "\u0410\u0434\u0440\u0435\u0441 \u043E\u0442\u0434\u0435\u043B\u0435\u043D\u0438\u044F", placeholder: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0442\u0434\u0435\u043B\u0435\u043D\u0438\u0435", options: offices.map(({ id, address = '' }) => ({
3846
- key: id?.toString() || '',
3847
- text: address,
3848
- })), ...addressField, isSearch: true }), jsx("div", { className: "h-[600px]", children: jsx(ClientOnly, { children: jsx(YandexMap, { points: points, isLoad: !data, className: "h-full", selectedAddress: addressField?.value?.text }) }) })] }));
3849
- });
3850
-
3851
- function copy(source, target) {
3852
- for (const [k, v] of source.entries()) {
3853
- if (v !== null && v !== undefined) {
3854
- target.setItem(k, v);
3855
- }
3856
- else {
3857
- target.removeItem(k);
3858
- }
3859
- }
3860
- }
3861
-
3862
- function replicate(primary, secondary) {
3863
- copy(primary, secondary);
3864
- copy(secondary, primary);
3865
- return primary.bus.watch(({ type, event }) => {
3866
- if (event !== null && event !== undefined) {
3867
- secondary.setItem(type, event);
3868
- }
3869
- else {
3870
- secondary.removeItem(type);
3871
- }
3872
- });
3873
- }
3874
-
3875
- class StorageAdapter {
3876
- storage;
3877
- bus;
3878
- get size() {
3879
- return this.storage?.length ?? 0;
3880
- }
3881
- constructor(storage, bus = new EventBus()) {
3882
- this.storage = storage;
3883
- this.bus = bus;
3884
- }
3885
- hasItem(key) {
3886
- return Boolean(this.storage?.getItem(String(key)));
3887
- }
3888
- getItem(key) {
3889
- const _ = this.storage?.getItem(String(key)) ?? null;
3890
- try {
3891
- return JSON.parse(String(_));
3892
- }
3893
- catch (ex) {
3894
- return null;
3895
- }
3896
- }
3897
- entries() {
3898
- return Array.from({ length: this.size }, (_, i) => {
3899
- const k = String(this.storage?.key(i));
3900
- return [k, this.getItem(k)];
3901
- });
3902
- }
3903
- setItem(key, value) {
3904
- if (value !== null) {
3905
- this.storage?.setItem(String(key), JSON.stringify(value));
3906
- }
3907
- else {
3908
- this.storage?.removeItem(String(key));
3909
- }
3910
- this.bus?.subject(key, value);
3911
- }
3912
- removeItem(key) {
3913
- this.storage?.removeItem(String(key));
3914
- this.bus?.subject(key, null);
3915
- }
3916
- }
3917
-
3918
- class Store {
3919
- bus;
3920
- store = new Map();
3921
- get size() {
3922
- return this.store.size;
3923
- }
3924
- constructor(bus = new EventBus()) {
3925
- this.bus = bus;
3926
- }
3927
- hasItem(key) {
3928
- return this.store.has(key);
3929
- }
3930
- getItem(key) {
3931
- return this.store.get(key);
3932
- }
3933
- entries() {
3934
- return this.store.entries();
3935
- }
3936
- setItem(key, value) {
3937
- this.store.set(key, value);
3938
- this.bus.subject(key, value);
3939
- }
3940
- removeItem(key) {
3941
- this.store.delete(key);
3942
- this.bus.subject(key, null);
3943
- }
3944
- }
3945
-
3946
- function useRerender() {
3947
- const [, setCount] = useState(0);
3948
- return useCallback(() => setCount(_ => (_ + 1) % (1 << 16)), []);
3949
- }
3950
-
3951
- const DEFAULT_METHODS = {};
3952
- /**
3953
- * MobX like reactivity (simplified).
3954
- * Can be used to migrate from Redux/MobX or something else
3955
- *
3956
- * @param store
3957
- * @returns reactive proxy backed by store
3958
- */
3959
- function useStore(store, methods = DEFAULT_METHODS) {
3960
- const deps = useRef(null);
3961
- const render = useRerender();
3962
- useEffect(() => store.bus.watch(ev => {
3963
- if (deps.current?.has(String(ev.type))) {
3964
- render();
3965
- }
3966
- }), [store, render]);
3967
- return useMemo(() => new Proxy(methods, {
3968
- get(_, key) {
3969
- deps.current ||= new Set();
3970
- deps.current.add(key);
3971
- return store.getItem(key);
3972
- },
3973
- has(_, key) {
3974
- deps.current ||= new Set();
3975
- deps.current.add(key);
3976
- return store.hasItem(key);
3977
- },
3978
- set(_, key, value) {
3979
- store.setItem(key, value);
3980
- return true;
3981
- },
3982
- deleteProperty(_, key) {
3983
- store.removeItem(key);
3984
- return true;
3985
- }
3986
- }), [store]);
3987
- }
4333
+ }, [regionValue.key]);
4334
+ const { points } = useOfficesAtmsMapData({
4335
+ data: offices,
4336
+ filtrationState: {},
4337
+ getBalloon: getOfficePoint,
4338
+ });
4339
+ return (jsxs("div", { children: [jsx(SelectControl, { label: "\u0410\u0434\u0440\u0435\u0441 \u043E\u0442\u0434\u0435\u043B\u0435\u043D\u0438\u044F", placeholder: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0442\u0434\u0435\u043B\u0435\u043D\u0438\u0435", options: offices.map(({ id, address = '' }) => ({
4340
+ key: id?.toString() || '',
4341
+ text: address,
4342
+ })), ...addressField, isSearch: true }), jsx("div", { className: "h-[600px]", children: jsx(ClientOnly, { children: jsx(YandexMap, { points: points, isLoad: !data, className: "h-full", selectedAddress: addressField?.value?.text }) }) })] }));
4343
+ });
3988
4344
 
3989
4345
  const localStore = new Store(); // localStorage cache
3990
4346
  replicate(localStore, new StorageAdapter(globalThis?.localStorage));
@@ -5209,12 +5565,6 @@
5209
5565
 
5210
5566
  const renderSubmitButton = (button, isSending = false) => (jsx(SubmitButton$1, { className: "w-full @xl:w-auto", isLoading: isSending, children: button?.text ? button.text : 'Отправить заявку' }));
5211
5567
 
5212
- const sessionStore = new Store(); // sessionStorage cache
5213
- replicate(sessionStore, new StorageAdapter(globalThis?.sessionStorage));
5214
- function useSessionStore() {
5215
- return useStore(sessionStore);
5216
- }
5217
-
5218
5568
  const createDraftTask = async (body) => {
5219
5569
  const res = await fetchRetailJSON('/user-data/createDraftTask', 'POST', body);
5220
5570
  return res || {};
@@ -5243,254 +5593,6 @@
5243
5593
 
5244
5594
  const updateUserTask = (body) => doRequest('/user-data/updateUserTask', 'PUT', body);
5245
5595
 
5246
- const Timer = JSX(({ className, seconds }) => (jsx("span", { className: className, children: formatTimer(seconds) })));
5247
- const formatTimer = (seconds) => {
5248
- const minutes = Math.floor(seconds / 60);
5249
- return [minutes, seconds % 60].map((_) => String(_).padStart(2, '0')).join(':');
5250
- };
5251
-
5252
- const useInterval = (handler, period) => {
5253
- const timer = useRef(null);
5254
- const stop = useCallback(() => clearInterval(timer.current), []);
5255
- const start = useCallback(() => {
5256
- stop();
5257
- timer.current = setInterval(() => handler(stop), period);
5258
- }, [handler, period, stop]);
5259
- useEffect(() => {
5260
- start();
5261
- return stop;
5262
- }, [start, stop]);
5263
- return { start, stop };
5264
- };
5265
-
5266
- function useCountDownTimer({ seconds, period = 1000, onTick, onEnd }) {
5267
- const counter = useRef(seconds);
5268
- const handleTick = useCallback((stop) => {
5269
- counter.current ||= 0;
5270
- counter.current = Math.max(0, counter.current - 1);
5271
- try {
5272
- onTick?.(counter.current);
5273
- }
5274
- finally {
5275
- if (counter.current <= 0) {
5276
- stop();
5277
- onEnd?.();
5278
- }
5279
- }
5280
- }, [onTick, onEnd]);
5281
- const { start } = useInterval(handleTick, period);
5282
- return useCallback((_) => {
5283
- counter.current = _;
5284
- start();
5285
- }, []);
5286
- }
5287
-
5288
- const sendCode = (body) => doRequest('/sms/sendCode', 'POST', body)
5289
- .then((res) => res.text())
5290
- .then((text) => text === 'OK');
5291
-
5292
- const ICON_SIZE = { width: '118', height: '24' };
5293
-
5294
- const logoTitleSizeStyle = '';
5295
-
5296
- const ICON_VERSION_MAP = {
5297
- 'bg-white': 'color',
5298
- transparent: 'white',
5299
- };
5300
- const SVG_COLOR = {
5301
- 'bg-white': 'text-primary-main',
5302
- transparent: 'text-white',
5303
- };
5304
- const renderImage = (bgColor, image, size) => {
5305
- const img = image?.src
5306
- ? image
5307
- : {
5308
- icon: image?.icon || 'LogoIcon',
5309
- iconVersion: ICON_VERSION_MAP[bgColor],
5310
- };
5311
- return (jsx(Img, { image: img, className: SVG_COLOR[bgColor], width: size?.width, height: size?.height }));
5312
- };
5313
-
5314
- const TEXT_COLOR = {
5315
- 'bg-white': 'text-primary-text',
5316
- transparent: 'text-white',
5317
- };
5318
- const Logo = JSX(({ className, href = '/', logo, children, targetBlank, bgColor = 'bg-white', showTitle = true, data, }) => (jsxs("a", { className: style('inline-flex items-center font-sans no-underline', className), href: logo?.href ?? href, target: targetBlank ? '_blank' : '_self', "aria-label": logo?.title ?? 'Россельхозбанк', ...getAspectsAttributes(data), children: [renderImage(bgColor, logo?.image, ICON_SIZE), showTitle
5319
- ? children ?? (jsx("div", { className: "ml-s", children: jsx(Text, { font: "font-medium", color: TEXT_COLOR[bgColor], size: logoTitleSizeStyle, children: logo?.title ?? 'Россельхозбанк' }) }))
5320
- : null] })));
5321
-
5322
- const checkCaptcha = (body) => doRequest('/sms/checkCaptcha', 'POST', body)
5323
- .then((res) => res.text())
5324
- .then((text) => text !== 'ERROR');
5325
-
5326
- const createCaptcha = (phoneNumber) => doRequest(`/sms/createCaptcha?phoneNumber=${encodeURIComponent(phoneNumber)}`, 'GET').then(async (res) => (res ? res.blob() : new Blob()));
5327
-
5328
- const CaptchaDialog = JSX(({ phoneNumber, sendCode, onClose }) => {
5329
- const [captcha, setCaptcha] = useState('');
5330
- const [code, setCode] = useState('');
5331
- const [hasError, setHasError] = useState(false);
5332
- const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
5333
- const { closeAll } = useDialogManager();
5334
- const handleCheckCaptcha = useCallback(async () => {
5335
- startLoading();
5336
- const isValidCode = await checkCaptcha({ captchaText: code });
5337
- if (isValidCode) {
5338
- onClose?.();
5339
- sendCode?.();
5340
- }
5341
- else {
5342
- setHasError(true);
5343
- }
5344
- endLoading();
5345
- }, [code, sendCode]);
5346
- const handleCreateCaptcha = useCallback(() => {
5347
- (async () => setCaptcha(URL.createObjectURL(await createCaptcha(phoneNumber))))();
5348
- }, []);
5349
- useEffect(handleCreateCaptcha, []);
5350
- return (jsx(Dialog, { className: "my-6xl max-w-lg w-full min-h-fit mx-auto rounded-lg", head: jsx(Logo, {}), onClose: onClose, children: jsxs("div", { className: "flex flex-col gap-lg items-center", children: [jsxs("div", { className: "flex", children: [jsx("img", { className: "grow", src: captcha }), jsx(Button, { className: "w-8", embedded: true, onClick: handleCreateCaptcha, children: jsx(Icon, { iconVersion: "normal", name: "RefreshIcon" }) })] }), jsx(Input, { className: "w-80", onChange: setCode, value: code, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0434 \u0441 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438" }), hasError ? jsx("div", { className: "text-error", children: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043E\u0434" }) : null, jsxs("div", { className: "flex w-80 justify-between", children: [jsx(Button, { version: "secondary", onClick: closeAll, children: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F" }), jsx(SubmitButton$1, { version: "secondary", disabled: !code, onClick: handleCheckCaptcha, children: "\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C" })] }), isLoading ? jsx(Loader, { blur: false }) : null] }) }));
5351
- });
5352
-
5353
- const InputCode = JSX(({ values, setValues, hasError, errorText }) => {
5354
- const [activeIndex, setActiveIndex] = useState(0);
5355
- const inputRefs = useRef([]);
5356
- useEffect(() => {
5357
- inputRefs.current?.[activeIndex]?.focus();
5358
- }, [activeIndex]);
5359
- const handleChange = useCallback((index) => (event) => {
5360
- const { value } = event.currentTarget;
5361
- const oneValue = value.slice(0, 1);
5362
- setValues(values.map((_, i) => (i === index ? oneValue : _)));
5363
- setActiveIndex(index + 1);
5364
- }, [values]);
5365
- const handleKeyDown = useCallback((currentIndex) => (event) => {
5366
- const { key } = event;
5367
- if (key === 'Backspace' && !values[currentIndex]) {
5368
- const previousIndex = currentIndex > 0 ? currentIndex - 1 : values.length - 1;
5369
- const updatedValues = values.map((value, index) => (index === previousIndex ? '' : value));
5370
- setValues(updatedValues);
5371
- setActiveIndex(previousIndex);
5372
- }
5373
- }, [values]);
5374
- const handlePaste = useCallback((event) => {
5375
- event.preventDefault();
5376
- const pastedData = event.clipboardData.getData('text');
5377
- const updatedValues = values.map((_, idx) => (idx < pastedData.length ? pastedData[idx] : _));
5378
- setValues(updatedValues);
5379
- setActiveIndex(updatedValues.length - 1);
5380
- }, [values]);
5381
- return (jsxs("div", { className: "flex flex-col gap-2 text-center", children: [jsx("div", { children: values.map((value, index) => (jsx("input", { type: "number", maxLength: 1, value: value, onChange: handleChange(index), onPaste: handlePaste, ref: (ref) => {
5382
- if (!inputRefs.current) {
5383
- inputRefs.current = [];
5384
- }
5385
- inputRefs.current[index] = ref;
5386
- }, onFocus: (event) => event.target.select(), onKeyDown: handleKeyDown(index), className: getInputStyle(index, values, hasError) }, index))) }), hasError ? jsx("div", { className: "text-error", children: errorText }) : null] }));
5387
- });
5388
- const getInputStyle = (index, values, hasError = false) => {
5389
- const isInputEmpty = !values[index];
5390
- return `w-16 sm:w-20 h-24 text-5xl text-center p-md m-2 border ${getValidStyle(!hasError || !isInputEmpty)} rounded-md caret-transparent outline-none`;
5391
- };
5392
-
5393
- const SubmitButton = JSX(({ disabled = false, onClick, text }) => (jsx(Button, { type: "button", onClick: onClick, disabled: disabled, children: jsx(Text, { font: "font-normal", children: text }) })));
5394
-
5395
- const checkCode = async (body) => fetchRetailJSON('/sms/checkCode', 'POST', body).then(saveToken);
5396
- const saveToken = (data) => {
5397
- if (data?.access_token && data?.refresh_token) {
5398
- globalThis.sessionStorage.setItem('accessToken', data.access_token);
5399
- globalThis.sessionStorage.setItem('refreshToken', data.refresh_token);
5400
- }
5401
- };
5402
-
5403
- const TIME_TO_RESEND = 180;
5404
- const useVerifyPhoneDialogSubmit = ({ values, onSuccess, }) => {
5405
- const sessionStore = useSessionStore();
5406
- const attempts = sessionStore.smsCode?.attempts || 0;
5407
- const timer = Math.max(getTimer(sessionStore.smsCode?.sendTime || Date.now()), 0);
5408
- const [errorText, setErrorText] = useState('');
5409
- const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
5410
- const [timeNextReq, setTimeNextReq] = useState(timer);
5411
- const resetError = useCallback(() => setErrorText(''), []);
5412
- const isTimeExpired = Boolean(timeNextReq === 0 && sessionStore.smsCode?.sendTime);
5413
- const isSubmitButtonDisabled = attempts > 2 || isTimeExpired || !values.every(Boolean);
5414
- const handleSubmit = useCallback(async () => {
5415
- try {
5416
- sessionStore.smsCode = {
5417
- ...sessionStore.smsCode,
5418
- attempts: attempts + 1,
5419
- };
5420
- startLoading();
5421
- await checkCode({
5422
- smsText: values.join(''),
5423
- smsCodesSetName: { key: 'AUTHENTICATION' },
5424
- });
5425
- setTimeNextReq(0);
5426
- resetError();
5427
- sessionStore.smsCode = null;
5428
- await onSuccess?.(values.join(''));
5429
- }
5430
- catch {
5431
- setErrorText(attempts > 1 ? 'Исчерпан лимит ввода смс-кода' : 'Неверный код');
5432
- }
5433
- finally {
5434
- endLoading();
5435
- }
5436
- }, [values, attempts]);
5437
- useEffect(() => {
5438
- if (isTimeExpired) {
5439
- setErrorText('Код просрочен');
5440
- }
5441
- else if (attempts > 2) {
5442
- setErrorText('Исчерпан лимит ввода смс-кода');
5443
- }
5444
- }, [isTimeExpired]);
5445
- return {
5446
- handleSubmit,
5447
- hasError: Boolean(errorText),
5448
- errorText,
5449
- isLoading,
5450
- timeNextReq,
5451
- isSubmitButtonDisabled,
5452
- setTimeNextReq,
5453
- setErrorText,
5454
- };
5455
- };
5456
- const getTimer = (sendTime) => TIME_TO_RESEND - Math.floor((Date.now() - sendTime) / 1000);
5457
-
5458
- const CODE_LENGTH = 4;
5459
- const VerifyPhoneDialog = JSX(({ phone, withDescription = true, consents, onSuccess = noop, onClose = noop }) => {
5460
- const [values, setValues] = useState(Array(CODE_LENGTH).fill(''));
5461
- const sessionStore = useSessionStore();
5462
- const { handleSubmit, hasError, errorText, isLoading, timeNextReq, isSubmitButtonDisabled, setTimeNextReq, setErrorText, } = useVerifyPhoneDialogSubmit({ values, onSuccess });
5463
- const captchaDialog = useDialog(CaptchaDialog);
5464
- const phoneNumber = formatPhone(phone);
5465
- const restartTimer = useCountDownTimer({ seconds: timeNextReq, onTick: setTimeNextReq });
5466
- const handleSendCode = useCallback(async () => {
5467
- const isSuccessSendCode = await sendCode({
5468
- phoneNumber,
5469
- smsCodesSetName: { key: 'AUTHENTICATION' },
5470
- });
5471
- if (isSuccessSendCode) {
5472
- setTimeNextReq(TIME_TO_RESEND);
5473
- restartTimer(TIME_TO_RESEND);
5474
- setErrorText('');
5475
- sessionStore.smsCode = {
5476
- sendTime: Date.now(),
5477
- attempts: 0,
5478
- };
5479
- }
5480
- else {
5481
- captchaDialog.open({ phoneNumber, sendCode: handleSendCode });
5482
- }
5483
- }, [phoneNumber, restartTimer, onClose]);
5484
- useEffect(() => {
5485
- if (!sessionStore.smsCode?.sendTime) {
5486
- handleSendCode();
5487
- }
5488
- }, []);
5489
- return (jsx(Dialog, { className: "my-6xl max-w-3xl w-full min-h-fit mx-auto rounded-xl p-m", onClose: onClose, children: jsxs("div", { className: "flex flex-col gap-xl items-center rounded-md", children: [jsx(Headline, { className: "w-full", title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430", description: `Мы отправили код на ${phone}`, headlineVersion: "XS", isEmbedded: true, as: "h6" }), jsx(InputCode, { values: values, setValues: setValues, errorText: errorText, hasError: hasError }), renderText$1(timeNextReq, handleSendCode), withDescription ? (jsxs(RichText, { itemSize: "list-s", children: [jsx("span", { children: "\u0412\u0432\u043E\u0434\u044F \u043A\u043E\u0434, \u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044E, \u0447\u0442\u043E \u043E\u0437\u043D\u0430\u043A\u043E\u043C\u043B\u0435\u043D \u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044E: " }), jsx("ul", { children: consents?.map((_, i) => (jsx("li", { children: _ }, `${_}-${i}`))) })] })) : null, renderNextButton(isSubmitButtonDisabled, handleSubmit), isLoading ? jsx(Loader, { blur: false }) : null] }) }));
5490
- });
5491
- const renderNextButton = (disabled, onClick) => (jsx(SubmitButton, { text: "\u0414\u0430\u043B\u0435\u0435", disabled: disabled, onClick: onClick }));
5492
- const renderText$1 = (timeNextReq, handleSendCode) => timeNextReq ? (jsxs("div", { className: "flex flex-row text-l font-light text-base", children: ["\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434 \u043C\u043E\u0436\u043D\u043E \u0447\u0435\u0440\u0435\u0437", jsx(Timer, { className: "pl-2xs", seconds: timeNextReq })] })) : (jsx(Button, { embedded: true, onClick: handleSendCode, children: jsx(ButtonTitle, { children: "\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434" }) }));
5493
-
5494
5596
  const defaultConsentText = {
5495
5597
  title: 'Подпишите согласие на запрос в БКИ',
5496
5598
  description: 'Согласие на запрос в Бюро кредитных историй (БКИ) ускорит решение по кредиту',
@@ -11537,7 +11639,7 @@
11537
11639
  slots: () => [HEADER_SLOT, FOOTER_SLOT, STICKY_FOOTER_SLOT],
11538
11640
  });
11539
11641
 
11540
- const packageVersion = "0.14.886";
11642
+ const packageVersion = "0.14.888";
11541
11643
 
11542
11644
  exports.Blocks = Blocks;
11543
11645
  exports.ContentPage = ContentPage;