@redneckz/wildless-cms-uni-blocks 0.14.888 → 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.
- package/bundle/api/LeadServiceAPI.d.ts +8 -0
- package/bundle/api/getSubmitBody.d.ts +494 -0
- package/bundle/bundle.umd.js +663 -561
- package/bundle/bundle.umd.min.js +1 -1
- package/bundle/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/bundle/retail/api/checkCode.d.ts +9 -1
- package/bundle/retail/api/sendCode.d.ts +1 -1
- package/bundle/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/bundle/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/dist/api/LeadServiceAPI.d.ts +8 -0
- package/dist/api/LeadServiceAPI.js +41 -49
- package/dist/api/LeadServiceAPI.js.map +1 -1
- package/dist/api/getSubmitBody.d.ts +494 -0
- package/dist/api/getSubmitBody.js +59 -0
- package/dist/api/getSubmitBody.js.map +1 -0
- package/dist/components/ApplicationForm/ApplicationForm.js +30 -5
- package/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
- package/dist/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/dist/retail/api/checkCode.d.ts +9 -1
- package/dist/retail/api/checkCode.js +22 -1
- package/dist/retail/api/checkCode.js.map +1 -1
- package/dist/retail/api/sendCode.d.ts +1 -1
- package/dist/retail/api/sendCode.js +8 -2
- package/dist/retail/api/sendCode.js.map +1 -1
- package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
- package/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
- package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +7 -4
- package/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
- package/dist/retail/utils/mockLocalStorage.js +2 -2
- package/dist/retail/utils/mockLocalStorage.js.map +1 -1
- package/lib/api/LeadServiceAPI.d.ts +8 -0
- package/lib/api/LeadServiceAPI.js +41 -49
- package/lib/api/LeadServiceAPI.js.map +1 -1
- package/lib/api/getSubmitBody.d.ts +494 -0
- package/lib/api/getSubmitBody.js +54 -0
- package/lib/api/getSubmitBody.js.map +1 -0
- package/lib/components/ApplicationForm/ApplicationForm.fixture.d.ts +1 -0
- package/lib/components/ApplicationForm/ApplicationForm.js +30 -5
- package/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
- package/lib/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/lib/retail/api/checkCode.d.ts +9 -1
- package/lib/retail/api/checkCode.js +22 -1
- package/lib/retail/api/checkCode.js.map +1 -1
- package/lib/retail/api/sendCode.d.ts +1 -1
- package/lib/retail/api/sendCode.js +7 -1
- package/lib/retail/api/sendCode.js.map +1 -1
- package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
- package/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
- package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +6 -3
- package/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
- package/lib/retail/utils/mockLocalStorage.js +2 -2
- package/lib/retail/utils/mockLocalStorage.js.map +1 -1
- package/mobile/bundle/api/LeadServiceAPI.d.ts +8 -0
- package/mobile/bundle/api/getSubmitBody.d.ts +494 -0
- package/mobile/bundle/bundle.umd.js +663 -561
- package/mobile/bundle/bundle.umd.min.js +1 -1
- package/mobile/bundle/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/mobile/bundle/retail/api/checkCode.d.ts +9 -1
- package/mobile/bundle/retail/api/sendCode.d.ts +1 -1
- package/mobile/bundle/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/mobile/bundle/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/mobile/dist/api/LeadServiceAPI.d.ts +8 -0
- package/mobile/dist/api/LeadServiceAPI.js +41 -49
- package/mobile/dist/api/LeadServiceAPI.js.map +1 -1
- package/mobile/dist/api/getSubmitBody.d.ts +494 -0
- package/mobile/dist/api/getSubmitBody.js +59 -0
- package/mobile/dist/api/getSubmitBody.js.map +1 -0
- package/mobile/dist/components/ApplicationForm/ApplicationForm.js +30 -5
- package/mobile/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
- package/mobile/dist/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/mobile/dist/retail/api/checkCode.d.ts +9 -1
- package/mobile/dist/retail/api/checkCode.js +22 -1
- package/mobile/dist/retail/api/checkCode.js.map +1 -1
- package/mobile/dist/retail/api/sendCode.d.ts +1 -1
- package/mobile/dist/retail/api/sendCode.js +8 -2
- package/mobile/dist/retail/api/sendCode.js.map +1 -1
- package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
- package/mobile/dist/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
- package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +7 -4
- package/mobile/dist/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
- package/mobile/dist/retail/utils/mockLocalStorage.js +2 -2
- package/mobile/dist/retail/utils/mockLocalStorage.js.map +1 -1
- package/mobile/lib/api/LeadServiceAPI.d.ts +8 -0
- package/mobile/lib/api/LeadServiceAPI.js +41 -49
- package/mobile/lib/api/LeadServiceAPI.js.map +1 -1
- package/mobile/lib/api/getSubmitBody.d.ts +494 -0
- package/mobile/lib/api/getSubmitBody.js +54 -0
- package/mobile/lib/api/getSubmitBody.js.map +1 -0
- package/mobile/lib/components/ApplicationForm/ApplicationForm.js +30 -5
- package/mobile/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
- package/mobile/lib/components/ApplicationForm/ApplicationFormContent.d.ts +1 -1
- package/mobile/lib/retail/api/checkCode.d.ts +9 -1
- package/mobile/lib/retail/api/checkCode.js +22 -1
- package/mobile/lib/retail/api/checkCode.js.map +1 -1
- package/mobile/lib/retail/api/sendCode.d.ts +1 -1
- package/mobile/lib/retail/api/sendCode.js +7 -1
- package/mobile/lib/retail/api/sendCode.js.map +1 -1
- package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.d.ts +4 -0
- package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js +10 -4
- package/mobile/lib/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.js.map +1 -1
- package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.d.ts +6 -1
- package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js +6 -3
- package/mobile/lib/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.js.map +1 -1
- package/mobile/lib/retail/utils/mockLocalStorage.js +2 -2
- package/mobile/lib/retail/utils/mockLocalStorage.js.map +1 -1
- package/mobile/src/api/LeadServiceAPI.ts +64 -82
- package/mobile/src/api/getSubmitBody.ts +94 -0
- package/mobile/src/components/ApplicationForm/ApplicationForm.example.json +2 -2
- package/mobile/src/components/ApplicationForm/ApplicationForm.tsx +33 -4
- package/mobile/src/components/ApplicationForm/ApplicationFormContent.ts +1 -1
- package/mobile/src/retail/api/checkCode.ts +47 -2
- package/mobile/src/retail/api/sendCode.ts +9 -1
- package/mobile/src/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.tsx +29 -8
- package/mobile/src/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.tsx +18 -5
- package/mobile/src/retail/utils/mockLocalStorage.ts +15 -9
- package/package.json +1 -1
- package/src/api/LeadServiceAPI.ts +64 -82
- package/src/api/getSubmitBody.ts +94 -0
- package/src/components/ApplicationForm/ApplicationForm.example.json +2 -2
- package/src/components/ApplicationForm/ApplicationForm.fixture.mobile.tsx +2 -2
- package/src/components/ApplicationForm/ApplicationForm.fixture.tsx +24 -2
- package/src/components/ApplicationForm/ApplicationForm.tsx +33 -4
- package/src/components/ApplicationForm/ApplicationFormContent.ts +1 -1
- package/src/retail/api/checkCode.ts +47 -2
- package/src/retail/api/sendCode.ts +9 -1
- package/src/retail/components/VerifyPhoneDialog/VerifyPhoneDialog.tsx +29 -8
- package/src/retail/components/VerifyPhoneDialog/useVerifyPhoneDialogSubmit.tsx +18 -5
- package/src/retail/utils/mockLocalStorage.ts +15 -9
|
@@ -995,6 +995,9 @@
|
|
|
995
995
|
});
|
|
996
996
|
const randomNumber = (min = 0, max = 0) => Math.floor(Math.random() * (max - min) + min);
|
|
997
997
|
|
|
998
|
+
const API_BASE_URI$1 = '/api/v1';
|
|
999
|
+
const RETAIL_API_BASE_URI = '/light-api-cash/v1';
|
|
1000
|
+
|
|
998
1001
|
const formatDate = (date, toTimeStamp = false) => {
|
|
999
1002
|
if (typeof date === 'string') {
|
|
1000
1003
|
return date.split('-').reverse().join('.');
|
|
@@ -1009,53 +1012,33 @@
|
|
|
1009
1012
|
|
|
1010
1013
|
const formatPhone = (phone) => phone?.replace(/[^+\d]/g, '');
|
|
1011
1014
|
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
function LeadServiceAPI() {
|
|
1016
|
-
async function send(body, router, isIndividualType = false) {
|
|
1017
|
-
const { typeForm, region, phone = '', email, birthday, desiredMeetingDate, inn, innDadata, fullRegion, addressBranch, secondaryPhone = '', bankEmpolee, applicationDate, serviceDirection, partnerSymbolCode, companyNameByInn, ...staticBody } = body;
|
|
1018
|
-
const isNaturalPerson = isIndividualType && serviceDirection !== 'Юридическое лицо / ИП';
|
|
1019
|
-
const url = `${API_BASE_URI$1}${isNaturalPerson ? '/lead' : '/sendcorporatelead'}`;
|
|
1020
|
-
const submitBody = {
|
|
1021
|
-
typeForm,
|
|
1022
|
-
...getRegion$1(region, isNaturalPerson),
|
|
1023
|
-
...getEmail(email, isNaturalPerson),
|
|
1024
|
-
...getPhone(phone),
|
|
1025
|
-
...getFormatDate(desiredMeetingDate, 'desiredMeetingDate'),
|
|
1026
|
-
...(isNaturalPerson ? getFormatDate(birthday) : { inn }),
|
|
1027
|
-
...(typeForm === 'FEEDBACK'
|
|
1028
|
-
? {}
|
|
1029
|
-
: {
|
|
1030
|
-
addressBranch,
|
|
1031
|
-
bankEmpolee,
|
|
1032
|
-
applicationDate,
|
|
1033
|
-
...getSecondaryPhone(secondaryPhone),
|
|
1034
|
-
}),
|
|
1035
|
-
...addPageSlug(typeForm, router),
|
|
1036
|
-
...formatPFForm(typeForm, { innDadata, fullRegion, partnerSymbolCode, companyNameByInn }),
|
|
1037
|
-
...staticBody,
|
|
1038
|
-
};
|
|
1039
|
-
try {
|
|
1040
|
-
const response = await fetch(url, {
|
|
1041
|
-
method: 'POST',
|
|
1042
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1043
|
-
mode: 'cors',
|
|
1044
|
-
body: JSON.stringify(submitBody),
|
|
1045
|
-
});
|
|
1046
|
-
if (!response?.ok) {
|
|
1047
|
-
return null;
|
|
1048
|
-
}
|
|
1049
|
-
return await response.json();
|
|
1050
|
-
}
|
|
1051
|
-
catch (e) {
|
|
1052
|
-
return null;
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1015
|
+
const getSubmitBody = (body, isNaturalPerson, router) => {
|
|
1016
|
+
const { typeForm, region, phone = '', email, birthday, desiredMeetingDate, inn, innDadata, fullRegion, addressBranch, secondaryPhone = '', bankEmpolee, applicationDate, partnerSymbolCode, companyNameByInn, ...staticBody } = body;
|
|
1055
1017
|
return {
|
|
1056
|
-
|
|
1018
|
+
typeForm,
|
|
1019
|
+
...getRegion$1(region, isNaturalPerson),
|
|
1020
|
+
...getEmail(email, isNaturalPerson),
|
|
1021
|
+
...getPhone(phone),
|
|
1022
|
+
...getFormatDate(desiredMeetingDate, 'desiredMeetingDate'),
|
|
1023
|
+
...(isNaturalPerson ? getFormatDate(birthday) : { inn }),
|
|
1024
|
+
...(typeForm === 'FEEDBACK'
|
|
1025
|
+
? {}
|
|
1026
|
+
: {
|
|
1027
|
+
addressBranch,
|
|
1028
|
+
bankEmpolee,
|
|
1029
|
+
applicationDate,
|
|
1030
|
+
...getSecondaryPhone(secondaryPhone),
|
|
1031
|
+
}),
|
|
1032
|
+
...addPageSlug(typeForm, router),
|
|
1033
|
+
...formatPFForm(typeForm, { innDadata, fullRegion, partnerSymbolCode, companyNameByInn }),
|
|
1034
|
+
...staticBody,
|
|
1057
1035
|
};
|
|
1058
|
-
}
|
|
1036
|
+
};
|
|
1037
|
+
const getPhoneBody = (phone) => {
|
|
1038
|
+
return {
|
|
1039
|
+
...getPhone(phone),
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1059
1042
|
const getPhone = (phone) => (phone ? { phone: formatPhone(phone) } : {});
|
|
1060
1043
|
const getFormatDate = (date, key = 'birthday') => date ? { [key]: formatDate(date) } : {};
|
|
1061
1044
|
const getRegion$1 = (region, isNaturalPerson = true) => ({
|
|
@@ -1081,6 +1064,68 @@
|
|
|
1081
1064
|
}
|
|
1082
1065
|
: {};
|
|
1083
1066
|
|
|
1067
|
+
function LeadServiceAPI() {
|
|
1068
|
+
async function send(body, router, isIndividualType = false) {
|
|
1069
|
+
const { serviceDirection } = body;
|
|
1070
|
+
const isNaturalPerson = isIndividualType && serviceDirection !== 'Юридическое лицо / ИП';
|
|
1071
|
+
const url = `${API_BASE_URI$1}${isNaturalPerson ? '/lead' : '/sendcorporatelead'}`;
|
|
1072
|
+
const submitBody = getSubmitBody(body, isNaturalPerson, router);
|
|
1073
|
+
try {
|
|
1074
|
+
const response = await LeadServiceFetch(url, submitBody);
|
|
1075
|
+
if (!response?.ok) {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
return await response.json();
|
|
1079
|
+
}
|
|
1080
|
+
catch (e) {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
async function sendCode({ phone }) {
|
|
1085
|
+
const submitBody = getPhoneBody(phone);
|
|
1086
|
+
try {
|
|
1087
|
+
const response = LeadServiceFetch(`${API_BASE_URI$1}/initCorporateLead`, submitBody).then(async (res) => {
|
|
1088
|
+
if (!res.ok) {
|
|
1089
|
+
throw new Error(`Ошибка HTTP: ${res.status}`);
|
|
1090
|
+
}
|
|
1091
|
+
return await res.text();
|
|
1092
|
+
});
|
|
1093
|
+
return await response;
|
|
1094
|
+
}
|
|
1095
|
+
catch (e) {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
async function checkCode({ reqId, code, body }) {
|
|
1100
|
+
const submitBody = {
|
|
1101
|
+
requestId: reqId,
|
|
1102
|
+
confimationCode: code,
|
|
1103
|
+
leadRequest: getSubmitBody(body, false),
|
|
1104
|
+
};
|
|
1105
|
+
try {
|
|
1106
|
+
const response = await LeadServiceFetch(`${API_BASE_URI$1}/confirmCorporateLead`, submitBody);
|
|
1107
|
+
if (!response?.ok) {
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
return await response.json();
|
|
1111
|
+
}
|
|
1112
|
+
catch (e) {
|
|
1113
|
+
return null;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
return {
|
|
1117
|
+
send,
|
|
1118
|
+
sendCode,
|
|
1119
|
+
checkCode,
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
const LeadServiceFetch = (url, submitBody) => fetch(url, {
|
|
1123
|
+
method: 'POST',
|
|
1124
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1125
|
+
mode: 'cors',
|
|
1126
|
+
body: JSON.stringify(submitBody),
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1084
1129
|
const handleAspects = async ({ aspectsAttributes, aspects, ev }) => {
|
|
1085
1130
|
for (const { aspectName, params } of aspectsAttributes ?? []) {
|
|
1086
1131
|
const aspectFn = aspects[aspectName ?? ''];
|
|
@@ -1246,11 +1291,183 @@
|
|
|
1246
1291
|
return [formState, { errors, field, update, reset, onSubmit: handleSubmit }];
|
|
1247
1292
|
}
|
|
1248
1293
|
|
|
1249
|
-
|
|
1250
|
-
const
|
|
1251
|
-
|
|
1294
|
+
function copy(source, target) {
|
|
1295
|
+
for (const [k, v] of source.entries()) {
|
|
1296
|
+
if (v !== null && v !== undefined) {
|
|
1297
|
+
target.setItem(k, v);
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
target.removeItem(k);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function replicate(primary, secondary) {
|
|
1306
|
+
copy(primary, secondary);
|
|
1307
|
+
copy(secondary, primary);
|
|
1308
|
+
return primary.bus.watch(({ type, event }) => {
|
|
1309
|
+
if (event !== null && event !== undefined) {
|
|
1310
|
+
secondary.setItem(type, event);
|
|
1311
|
+
}
|
|
1312
|
+
else {
|
|
1313
|
+
secondary.removeItem(type);
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
class StorageAdapter {
|
|
1319
|
+
storage;
|
|
1320
|
+
bus;
|
|
1321
|
+
get size() {
|
|
1322
|
+
return this.storage?.length ?? 0;
|
|
1323
|
+
}
|
|
1324
|
+
constructor(storage, bus = new EventBus()) {
|
|
1325
|
+
this.storage = storage;
|
|
1326
|
+
this.bus = bus;
|
|
1327
|
+
}
|
|
1328
|
+
hasItem(key) {
|
|
1329
|
+
return Boolean(this.storage?.getItem(String(key)));
|
|
1330
|
+
}
|
|
1331
|
+
getItem(key) {
|
|
1332
|
+
const _ = this.storage?.getItem(String(key)) ?? null;
|
|
1333
|
+
try {
|
|
1334
|
+
return JSON.parse(String(_));
|
|
1335
|
+
}
|
|
1336
|
+
catch (ex) {
|
|
1337
|
+
return null;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
entries() {
|
|
1341
|
+
return Array.from({ length: this.size }, (_, i) => {
|
|
1342
|
+
const k = String(this.storage?.key(i));
|
|
1343
|
+
return [k, this.getItem(k)];
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
setItem(key, value) {
|
|
1347
|
+
if (value !== null) {
|
|
1348
|
+
this.storage?.setItem(String(key), JSON.stringify(value));
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
this.storage?.removeItem(String(key));
|
|
1352
|
+
}
|
|
1353
|
+
this.bus?.subject(key, value);
|
|
1354
|
+
}
|
|
1355
|
+
removeItem(key) {
|
|
1356
|
+
this.storage?.removeItem(String(key));
|
|
1357
|
+
this.bus?.subject(key, null);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
class Store {
|
|
1362
|
+
bus;
|
|
1363
|
+
store = new Map();
|
|
1364
|
+
get size() {
|
|
1365
|
+
return this.store.size;
|
|
1366
|
+
}
|
|
1367
|
+
constructor(bus = new EventBus()) {
|
|
1368
|
+
this.bus = bus;
|
|
1369
|
+
}
|
|
1370
|
+
hasItem(key) {
|
|
1371
|
+
return this.store.has(key);
|
|
1372
|
+
}
|
|
1373
|
+
getItem(key) {
|
|
1374
|
+
return this.store.get(key);
|
|
1375
|
+
}
|
|
1376
|
+
entries() {
|
|
1377
|
+
return this.store.entries();
|
|
1378
|
+
}
|
|
1379
|
+
setItem(key, value) {
|
|
1380
|
+
this.store.set(key, value);
|
|
1381
|
+
this.bus.subject(key, value);
|
|
1382
|
+
}
|
|
1383
|
+
removeItem(key) {
|
|
1384
|
+
this.store.delete(key);
|
|
1385
|
+
this.bus.subject(key, null);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
function useRerender() {
|
|
1390
|
+
const [, setCount] = useState(0);
|
|
1391
|
+
return useCallback(() => setCount(_ => (_ + 1) % (1 << 16)), []);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
const DEFAULT_METHODS = {};
|
|
1395
|
+
/**
|
|
1396
|
+
* MobX like reactivity (simplified).
|
|
1397
|
+
* Can be used to migrate from Redux/MobX or something else
|
|
1398
|
+
*
|
|
1399
|
+
* @param store
|
|
1400
|
+
* @returns reactive proxy backed by store
|
|
1401
|
+
*/
|
|
1402
|
+
function useStore(store, methods = DEFAULT_METHODS) {
|
|
1403
|
+
const deps = useRef(null);
|
|
1404
|
+
const render = useRerender();
|
|
1405
|
+
useEffect(() => store.bus.watch(ev => {
|
|
1406
|
+
if (deps.current?.has(String(ev.type))) {
|
|
1407
|
+
render();
|
|
1408
|
+
}
|
|
1409
|
+
}), [store, render]);
|
|
1410
|
+
return useMemo(() => new Proxy(methods, {
|
|
1411
|
+
get(_, key) {
|
|
1412
|
+
deps.current ||= new Set();
|
|
1413
|
+
deps.current.add(key);
|
|
1414
|
+
return store.getItem(key);
|
|
1415
|
+
},
|
|
1416
|
+
has(_, key) {
|
|
1417
|
+
deps.current ||= new Set();
|
|
1418
|
+
deps.current.add(key);
|
|
1419
|
+
return store.hasItem(key);
|
|
1420
|
+
},
|
|
1421
|
+
set(_, key, value) {
|
|
1422
|
+
store.setItem(key, value);
|
|
1423
|
+
return true;
|
|
1424
|
+
},
|
|
1425
|
+
deleteProperty(_, key) {
|
|
1426
|
+
store.removeItem(key);
|
|
1427
|
+
return true;
|
|
1428
|
+
}
|
|
1429
|
+
}), [store]);
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
const sessionStore = new Store(); // sessionStorage cache
|
|
1433
|
+
replicate(sessionStore, new StorageAdapter(globalThis?.sessionStorage));
|
|
1434
|
+
function useSessionStore() {
|
|
1435
|
+
return useStore(sessionStore);
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
const noop = () => {
|
|
1439
|
+
// Do nothing
|
|
1440
|
+
};
|
|
1441
|
+
|
|
1442
|
+
const themeStyle$1 = {
|
|
1443
|
+
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'),
|
|
1444
|
+
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'),
|
|
1445
|
+
};
|
|
1446
|
+
const embeddedStyle = style('group/btn-embedded', 'bg-transparent border border-transparent outline-none');
|
|
1447
|
+
const disabledStyle = style('bg-main-gray text-main-disabled cursor-not-allowed');
|
|
1448
|
+
const Button = JSX(({ className, type = 'button', version = 'primary', shape = 'default', embedded, disabled, role, ariaLabel, data, dataTheme, children, wcmsIgnore, onClick = noop, }) => {
|
|
1449
|
+
const handleClick = useCallback(role !== 'tab' ? handlerDecorator(onClick) : onClick, [
|
|
1450
|
+
role,
|
|
1451
|
+
onClick,
|
|
1452
|
+
]);
|
|
1453
|
+
const aspectsAttrs = useMemo(() => getAspectsAttributes(data), [data]);
|
|
1454
|
+
const isRound = shape === 'round';
|
|
1455
|
+
return (jsx("button", { className: style('font-sans flex items-center gap-xs', {
|
|
1456
|
+
[themeStyle$1[version]]: !disabled && !embedded,
|
|
1457
|
+
[embeddedStyle]: embedded,
|
|
1458
|
+
[disabledStyle]: disabled,
|
|
1459
|
+
}, embedded ? 'justify-between' : 'justify-center', embedded || isRound ? 'p-0' : 'px-9 py-4', {
|
|
1460
|
+
'rounded-md': shape === 'default',
|
|
1461
|
+
'rounded-full': isRound,
|
|
1462
|
+
}, 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 }));
|
|
1252
1463
|
});
|
|
1253
1464
|
|
|
1465
|
+
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 })));
|
|
1466
|
+
|
|
1467
|
+
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" }) })));
|
|
1468
|
+
|
|
1469
|
+
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 })] })));
|
|
1470
|
+
|
|
1254
1471
|
function useDialog(Dialog, initialProps = {}) {
|
|
1255
1472
|
const { open, close, ...rest } = useDialogManager();
|
|
1256
1473
|
const openDialog = useCallback((props, options = {}) => open({
|
|
@@ -1263,29 +1480,99 @@
|
|
|
1263
1480
|
return { open: openDialog, close, ...rest };
|
|
1264
1481
|
}
|
|
1265
1482
|
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
const getRequiredLabel = ({ label, errors }) => label && errors ? `${label}*` : label;
|
|
1483
|
+
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, {
|
|
1484
|
+
'backdrop-blur': blur,
|
|
1485
|
+
}), 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" }) })));
|
|
1270
1486
|
|
|
1271
|
-
const
|
|
1487
|
+
const Timer = JSX(({ className, seconds }) => (jsx("span", { className: className, children: formatTimer(seconds) })));
|
|
1488
|
+
const formatTimer = (seconds) => {
|
|
1489
|
+
const minutes = Math.floor(seconds / 60);
|
|
1490
|
+
return [minutes, seconds % 60].map((_) => String(_).padStart(2, '0')).join(':');
|
|
1491
|
+
};
|
|
1272
1492
|
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
const
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1493
|
+
const useInterval = (handler, period) => {
|
|
1494
|
+
const timer = useRef(null);
|
|
1495
|
+
const stop = useCallback(() => clearInterval(timer.current), []);
|
|
1496
|
+
const start = useCallback(() => {
|
|
1497
|
+
stop();
|
|
1498
|
+
timer.current = setInterval(() => handler(stop), period);
|
|
1499
|
+
}, [handler, period, stop]);
|
|
1500
|
+
useEffect(() => {
|
|
1501
|
+
start();
|
|
1502
|
+
return stop;
|
|
1503
|
+
}, [start, stop]);
|
|
1504
|
+
return { start, stop };
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
function useCountDownTimer({ seconds, period = 1000, onTick, onEnd }) {
|
|
1508
|
+
const counter = useRef(seconds);
|
|
1509
|
+
const handleTick = useCallback((stop) => {
|
|
1510
|
+
counter.current ||= 0;
|
|
1511
|
+
counter.current = Math.max(0, counter.current - 1);
|
|
1512
|
+
try {
|
|
1513
|
+
onTick?.(counter.current);
|
|
1284
1514
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1515
|
+
finally {
|
|
1516
|
+
if (counter.current <= 0) {
|
|
1517
|
+
stop();
|
|
1518
|
+
onEnd?.();
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}, [onTick, onEnd]);
|
|
1522
|
+
const { start } = useInterval(handleTick, period);
|
|
1523
|
+
return useCallback((_) => {
|
|
1524
|
+
counter.current = _;
|
|
1525
|
+
start();
|
|
1526
|
+
}, []);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
const getTraceId = () => {
|
|
1530
|
+
const result = new Uint8Array(8);
|
|
1531
|
+
globalThis.crypto.getRandomValues(result);
|
|
1532
|
+
return result.reduce((acc, _) => `${acc}${_.toString(16).padStart(2, '0')}`, '');
|
|
1287
1533
|
};
|
|
1288
1534
|
|
|
1535
|
+
const fetchRetailJSON = async (url, method, body) => {
|
|
1536
|
+
try {
|
|
1537
|
+
const response = await doRequest(url, method, body);
|
|
1538
|
+
return response.json();
|
|
1539
|
+
}
|
|
1540
|
+
catch (err) {
|
|
1541
|
+
console.error(err);
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1545
|
+
async function doRequest(url, method, body) {
|
|
1546
|
+
const traceId = getTraceId();
|
|
1547
|
+
return globalThis?.fetch?.(`${RETAIL_API_BASE_URI}${url}`, {
|
|
1548
|
+
method,
|
|
1549
|
+
headers: {
|
|
1550
|
+
'Content-Type': 'application/json',
|
|
1551
|
+
'X-B3-Sampled': '1',
|
|
1552
|
+
'X-B3-Spanid': traceId,
|
|
1553
|
+
'X-B3-Traceid': traceId,
|
|
1554
|
+
...getAuthorizationHeaders(),
|
|
1555
|
+
},
|
|
1556
|
+
credentials: 'include',
|
|
1557
|
+
body: body ? JSON.stringify(body) : null,
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
const getAuthorizationHeaders = () => {
|
|
1561
|
+
const token = sessionStorage.getItem('accessToken');
|
|
1562
|
+
return token ? { Authorization: `Bearer ${token}` } : null;
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
const API$2 = LeadServiceAPI();
|
|
1566
|
+
const sendCode = (body, isRetail) => {
|
|
1567
|
+
return isRetail ? fetchRetail(body) : fetchMain$1(body);
|
|
1568
|
+
};
|
|
1569
|
+
const fetchRetail = (body) => doRequest('/sms/sendCode', 'POST', body)
|
|
1570
|
+
.then((res) => res.text())
|
|
1571
|
+
.then((text) => text === 'OK');
|
|
1572
|
+
const fetchMain$1 = (body) => API$2.sendCode({ phone: body.phoneNumber });
|
|
1573
|
+
|
|
1574
|
+
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] })));
|
|
1575
|
+
|
|
1289
1576
|
const inputValidStyle = 'border border-solid outline-none border-gray hover:border-primary-hover active:border-primary-text focus:border-primary-text rounded';
|
|
1290
1577
|
|
|
1291
1578
|
const getValidStyle = (valid) => (valid ? inputValidStyle : 'border-error');
|
|
@@ -1304,13 +1591,271 @@
|
|
|
1304
1591
|
if (autoFocus) {
|
|
1305
1592
|
inputRef.current?.focus();
|
|
1306
1593
|
}
|
|
1307
|
-
}, [autoFocus, inputRef]);
|
|
1308
|
-
const paddingStyle = children ? 'pr-3xl' : '';
|
|
1309
|
-
const validStyle = getValidStyle(valid);
|
|
1310
|
-
const ariaLabel = label ?? name ?? id;
|
|
1311
|
-
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] }));
|
|
1312
|
-
});
|
|
1313
|
-
const defaultStyle$1 = 'w-full border rounded-md text-primary-text outline-none p-m';
|
|
1594
|
+
}, [autoFocus, inputRef]);
|
|
1595
|
+
const paddingStyle = children ? 'pr-3xl' : '';
|
|
1596
|
+
const validStyle = getValidStyle(valid);
|
|
1597
|
+
const ariaLabel = label ?? name ?? id;
|
|
1598
|
+
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] }));
|
|
1599
|
+
});
|
|
1600
|
+
const defaultStyle$1 = 'w-full border rounded-md text-primary-text outline-none p-m';
|
|
1601
|
+
|
|
1602
|
+
const ICON_SIZE = { width: '103', height: '21' };
|
|
1603
|
+
|
|
1604
|
+
const logoTitleSizeStyle = 'text-s';
|
|
1605
|
+
|
|
1606
|
+
const ICON_VERSION_MAP = {
|
|
1607
|
+
'bg-white': 'color',
|
|
1608
|
+
transparent: 'white',
|
|
1609
|
+
};
|
|
1610
|
+
const SVG_COLOR = {
|
|
1611
|
+
'bg-white': 'text-primary-main',
|
|
1612
|
+
transparent: 'text-white',
|
|
1613
|
+
};
|
|
1614
|
+
const renderImage = (bgColor, image, size) => {
|
|
1615
|
+
const img = image?.src
|
|
1616
|
+
? image
|
|
1617
|
+
: {
|
|
1618
|
+
icon: image?.icon || 'LogoIcon',
|
|
1619
|
+
iconVersion: ICON_VERSION_MAP[bgColor],
|
|
1620
|
+
};
|
|
1621
|
+
return (jsx(Img, { image: img, className: SVG_COLOR[bgColor], width: size?.width, height: size?.height }));
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1624
|
+
const TEXT_COLOR = {
|
|
1625
|
+
'bg-white': 'text-primary-text',
|
|
1626
|
+
transparent: 'text-white',
|
|
1627
|
+
};
|
|
1628
|
+
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
|
|
1629
|
+
? children ?? (jsx("div", { className: "ml-s", children: jsx(Text, { font: "font-medium", color: TEXT_COLOR[bgColor], size: logoTitleSizeStyle, children: logo?.title ?? 'Россельхозбанк' }) }))
|
|
1630
|
+
: null] })));
|
|
1631
|
+
|
|
1632
|
+
const checkCaptcha = (body) => doRequest('/sms/checkCaptcha', 'POST', body)
|
|
1633
|
+
.then((res) => res.text())
|
|
1634
|
+
.then((text) => text !== 'ERROR');
|
|
1635
|
+
|
|
1636
|
+
const createCaptcha = (phoneNumber) => doRequest(`/sms/createCaptcha?phoneNumber=${encodeURIComponent(phoneNumber)}`, 'GET').then(async (res) => (res ? res.blob() : new Blob()));
|
|
1637
|
+
|
|
1638
|
+
const CaptchaDialog = JSX(({ phoneNumber, sendCode, onClose }) => {
|
|
1639
|
+
const [captcha, setCaptcha] = useState('');
|
|
1640
|
+
const [code, setCode] = useState('');
|
|
1641
|
+
const [hasError, setHasError] = useState(false);
|
|
1642
|
+
const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
|
|
1643
|
+
const { closeAll } = useDialogManager();
|
|
1644
|
+
const handleCheckCaptcha = useCallback(async () => {
|
|
1645
|
+
startLoading();
|
|
1646
|
+
const isValidCode = await checkCaptcha({ captchaText: code });
|
|
1647
|
+
if (isValidCode) {
|
|
1648
|
+
onClose?.();
|
|
1649
|
+
sendCode?.();
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
setHasError(true);
|
|
1653
|
+
}
|
|
1654
|
+
endLoading();
|
|
1655
|
+
}, [code, sendCode]);
|
|
1656
|
+
const handleCreateCaptcha = useCallback(() => {
|
|
1657
|
+
(async () => setCaptcha(URL.createObjectURL(await createCaptcha(phoneNumber))))();
|
|
1658
|
+
}, []);
|
|
1659
|
+
useEffect(handleCreateCaptcha, []);
|
|
1660
|
+
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] }) }));
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
const InputCode = JSX(({ values, setValues, hasError, errorText }) => {
|
|
1664
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
1665
|
+
const inputRefs = useRef([]);
|
|
1666
|
+
useEffect(() => {
|
|
1667
|
+
inputRefs.current?.[activeIndex]?.focus();
|
|
1668
|
+
}, [activeIndex]);
|
|
1669
|
+
const handleChange = useCallback((index) => (event) => {
|
|
1670
|
+
const { value } = event.currentTarget;
|
|
1671
|
+
const oneValue = value.slice(0, 1);
|
|
1672
|
+
setValues(values.map((_, i) => (i === index ? oneValue : _)));
|
|
1673
|
+
setActiveIndex(index + 1);
|
|
1674
|
+
}, [values]);
|
|
1675
|
+
const handleKeyDown = useCallback((currentIndex) => (event) => {
|
|
1676
|
+
const { key } = event;
|
|
1677
|
+
if (key === 'Backspace' && !values[currentIndex]) {
|
|
1678
|
+
const previousIndex = currentIndex > 0 ? currentIndex - 1 : values.length - 1;
|
|
1679
|
+
const updatedValues = values.map((value, index) => (index === previousIndex ? '' : value));
|
|
1680
|
+
setValues(updatedValues);
|
|
1681
|
+
setActiveIndex(previousIndex);
|
|
1682
|
+
}
|
|
1683
|
+
}, [values]);
|
|
1684
|
+
const handlePaste = useCallback((event) => {
|
|
1685
|
+
event.preventDefault();
|
|
1686
|
+
const pastedData = event.clipboardData.getData('text');
|
|
1687
|
+
const updatedValues = values.map((_, idx) => (idx < pastedData.length ? pastedData[idx] : _));
|
|
1688
|
+
setValues(updatedValues);
|
|
1689
|
+
setActiveIndex(updatedValues.length - 1);
|
|
1690
|
+
}, [values]);
|
|
1691
|
+
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) => {
|
|
1692
|
+
if (!inputRefs.current) {
|
|
1693
|
+
inputRefs.current = [];
|
|
1694
|
+
}
|
|
1695
|
+
inputRefs.current[index] = ref;
|
|
1696
|
+
}, onFocus: (event) => event.target.select(), onKeyDown: handleKeyDown(index), className: getInputStyle(index, values, hasError) }, index))) }), hasError ? jsx("div", { className: "text-error", children: errorText }) : null] }));
|
|
1697
|
+
});
|
|
1698
|
+
const getInputStyle = (index, values, hasError = false) => {
|
|
1699
|
+
const isInputEmpty = !values[index];
|
|
1700
|
+
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`;
|
|
1701
|
+
};
|
|
1702
|
+
|
|
1703
|
+
const SubmitButton = JSX(({ disabled = false, onClick, text }) => (jsx(Button, { type: "button", onClick: onClick, disabled: disabled, children: jsx(Text, { font: "font-normal", children: text }) })));
|
|
1704
|
+
|
|
1705
|
+
const API$1 = LeadServiceAPI();
|
|
1706
|
+
const checkCode = async (body, isRetail) => {
|
|
1707
|
+
const transformedBody = transformBody(body, isRetail);
|
|
1708
|
+
return isRetail
|
|
1709
|
+
? fetchRetailJSON('/sms/checkCode', 'POST', transformedBody).then(saveToken)
|
|
1710
|
+
: fetchMain(transformedBody).then((res) => {
|
|
1711
|
+
if (res === null) {
|
|
1712
|
+
throw new Error('Неверный код');
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
};
|
|
1716
|
+
const saveToken = (data) => {
|
|
1717
|
+
if (data?.access_token && data?.refresh_token) {
|
|
1718
|
+
globalThis.sessionStorage.setItem('accessToken', data.access_token);
|
|
1719
|
+
globalThis.sessionStorage.setItem('refreshToken', data.refresh_token);
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
const fetchMain = (body) => API$1.checkCode(body);
|
|
1723
|
+
const transformBody = ({ smsText, smsCodesSetName, body, reqId }, isRetail) => {
|
|
1724
|
+
if (isRetail) {
|
|
1725
|
+
return { smsText, smsCodesSetName };
|
|
1726
|
+
}
|
|
1727
|
+
if (!reqId || !body) {
|
|
1728
|
+
throw new Error('Произошла ошибка, попробуйте позднее');
|
|
1729
|
+
}
|
|
1730
|
+
return { code: smsText, reqId, body };
|
|
1731
|
+
};
|
|
1732
|
+
|
|
1733
|
+
const TIME_TO_RESEND = 180;
|
|
1734
|
+
const useVerifyPhoneDialogSubmit = ({ values, onSuccess, formatData, reqId, isRetail = true, }) => {
|
|
1735
|
+
const sessionStore = useSessionStore();
|
|
1736
|
+
const attempts = sessionStore.smsCode?.attempts || 0;
|
|
1737
|
+
const timer = Math.max(getTimer(sessionStore.smsCode?.sendTime || Date.now()), 0);
|
|
1738
|
+
const [errorText, setErrorText] = useState('');
|
|
1739
|
+
const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
|
|
1740
|
+
const [timeNextReq, setTimeNextReq] = useState(timer);
|
|
1741
|
+
const resetError = useCallback(() => setErrorText(''), []);
|
|
1742
|
+
const isTimeExpired = Boolean(timeNextReq === 0 && sessionStore.smsCode?.sendTime);
|
|
1743
|
+
const isSubmitButtonDisabled = attempts > 2 || isTimeExpired || !values.every(Boolean);
|
|
1744
|
+
const handleSubmit = useCallback(async () => {
|
|
1745
|
+
try {
|
|
1746
|
+
sessionStore.smsCode = {
|
|
1747
|
+
...sessionStore.smsCode,
|
|
1748
|
+
attempts: attempts + 1,
|
|
1749
|
+
};
|
|
1750
|
+
startLoading();
|
|
1751
|
+
await checkCode({
|
|
1752
|
+
smsText: values.join(''),
|
|
1753
|
+
smsCodesSetName: { key: 'AUTHENTICATION' },
|
|
1754
|
+
body: isRetail ? undefined : formatData,
|
|
1755
|
+
reqId: isRetail ? undefined : reqId,
|
|
1756
|
+
}, isRetail);
|
|
1757
|
+
setTimeNextReq(0);
|
|
1758
|
+
resetError();
|
|
1759
|
+
sessionStore.smsCode = null;
|
|
1760
|
+
await onSuccess?.(values.join(''));
|
|
1761
|
+
}
|
|
1762
|
+
catch {
|
|
1763
|
+
setErrorText(attempts > 1 ? 'Исчерпан лимит ввода смс-кода' : 'Неверный код');
|
|
1764
|
+
}
|
|
1765
|
+
finally {
|
|
1766
|
+
endLoading();
|
|
1767
|
+
}
|
|
1768
|
+
}, [values, attempts]);
|
|
1769
|
+
useEffect(() => {
|
|
1770
|
+
if (isTimeExpired && isRetail) {
|
|
1771
|
+
setErrorText('Код просрочен');
|
|
1772
|
+
}
|
|
1773
|
+
else if (attempts > 2) {
|
|
1774
|
+
setErrorText('Исчерпан лимит ввода смс-кода');
|
|
1775
|
+
}
|
|
1776
|
+
}, [isTimeExpired]);
|
|
1777
|
+
return {
|
|
1778
|
+
handleSubmit,
|
|
1779
|
+
hasError: Boolean(errorText),
|
|
1780
|
+
errorText,
|
|
1781
|
+
isLoading,
|
|
1782
|
+
timeNextReq,
|
|
1783
|
+
isSubmitButtonDisabled,
|
|
1784
|
+
setTimeNextReq,
|
|
1785
|
+
setErrorText,
|
|
1786
|
+
};
|
|
1787
|
+
};
|
|
1788
|
+
const getTimer = (sendTime) => TIME_TO_RESEND - Math.floor((Date.now() - sendTime) / 1000);
|
|
1789
|
+
|
|
1790
|
+
const CODE_LENGTH = 4;
|
|
1791
|
+
const VerifyPhoneDialog = JSX(({ phone, withDescription = true, consents, onSuccess = noop, onClose = noop, formatData, reqId, isRetail = true, }) => {
|
|
1792
|
+
const [values, setValues] = useState(Array(CODE_LENGTH).fill(''));
|
|
1793
|
+
const sessionStore = useSessionStore();
|
|
1794
|
+
const { handleSubmit, hasError, errorText, isLoading, timeNextReq, isSubmitButtonDisabled, setTimeNextReq, setErrorText, } = useVerifyPhoneDialogSubmit({
|
|
1795
|
+
values,
|
|
1796
|
+
onSuccess,
|
|
1797
|
+
formatData,
|
|
1798
|
+
reqId,
|
|
1799
|
+
isRetail,
|
|
1800
|
+
});
|
|
1801
|
+
const captchaDialog = useDialog(CaptchaDialog);
|
|
1802
|
+
const phoneNumber = formatPhone(phone);
|
|
1803
|
+
const restartTimer = useCountDownTimer({ seconds: timeNextReq, onTick: setTimeNextReq });
|
|
1804
|
+
const handleSendCode = useCallback(async () => {
|
|
1805
|
+
const isSuccessSendCode = await sendCode({
|
|
1806
|
+
phoneNumber,
|
|
1807
|
+
smsCodesSetName: { key: 'AUTHENTICATION' },
|
|
1808
|
+
}, isRetail);
|
|
1809
|
+
if (isSuccessSendCode) {
|
|
1810
|
+
setTimeNextReq(TIME_TO_RESEND);
|
|
1811
|
+
restartTimer(TIME_TO_RESEND);
|
|
1812
|
+
setErrorText('');
|
|
1813
|
+
sessionStore.smsCode = {
|
|
1814
|
+
sendTime: Date.now(),
|
|
1815
|
+
attempts: 0,
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
else {
|
|
1819
|
+
captchaDialog.open({ phoneNumber, sendCode: handleSendCode });
|
|
1820
|
+
}
|
|
1821
|
+
}, [phoneNumber, restartTimer, onClose]);
|
|
1822
|
+
useEffect(() => {
|
|
1823
|
+
if (!sessionStore.smsCode?.sendTime && isRetail) {
|
|
1824
|
+
handleSendCode();
|
|
1825
|
+
}
|
|
1826
|
+
}, []);
|
|
1827
|
+
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$4(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] }) }));
|
|
1828
|
+
});
|
|
1829
|
+
const renderNextButton = (disabled, onClick) => (jsx(SubmitButton, { text: "\u0414\u0430\u043B\u0435\u0435", disabled: disabled, onClick: onClick }));
|
|
1830
|
+
const renderText$4 = (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" }) }));
|
|
1831
|
+
|
|
1832
|
+
const ApplicationFormLayout = JSX((props) => {
|
|
1833
|
+
const { className, title, children, ...rest } = props;
|
|
1834
|
+
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] }) }));
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
const getConsentDataProcessing = (inputs) => inputs?.find((_) => _?.name === 'consentDataProcessing');
|
|
1838
|
+
|
|
1839
|
+
// TODO Базовая функицональность всех Control - надо вынести и привязать к required флагу
|
|
1840
|
+
const getRequiredLabel = ({ label, errors }) => label && errors ? `${label}*` : label;
|
|
1841
|
+
|
|
1842
|
+
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 }));
|
|
1843
|
+
|
|
1844
|
+
const debounce = (fn, delay = 600) => {
|
|
1845
|
+
let timerId;
|
|
1846
|
+
const debouncedCallback = (...args) => {
|
|
1847
|
+
debouncedCallback.dispose();
|
|
1848
|
+
timerId = setTimeout(() => {
|
|
1849
|
+
fn(...args);
|
|
1850
|
+
}, delay);
|
|
1851
|
+
};
|
|
1852
|
+
debouncedCallback.dispose = () => {
|
|
1853
|
+
if (timerId) {
|
|
1854
|
+
clearTimeout(timerId);
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
return debouncedCallback;
|
|
1858
|
+
};
|
|
1314
1859
|
|
|
1315
1860
|
const formatOption = (_) => _?.text || _?.key || '';
|
|
1316
1861
|
|
|
@@ -1631,10 +2176,6 @@
|
|
|
1631
2176
|
const ITEMS_CREDIT_AMOUNT = ['От 1 000 ₽', 'До 1 000 000 000 ₽'];
|
|
1632
2177
|
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 ?? '') })));
|
|
1633
2178
|
|
|
1634
|
-
const noop = () => {
|
|
1635
|
-
// Do nothing
|
|
1636
|
-
};
|
|
1637
|
-
|
|
1638
2179
|
const InputWrapper = JSX(({ className, label, value = '', error, errors, type, isInteger, placeholder, maxLength, inputRef, isOpen, onOpen, onClose, onChange = noop, ...rest }) => {
|
|
1639
2180
|
const popupRef = useOutsideClick(onClose);
|
|
1640
2181
|
const handleChange = useCallback((v) => {
|
|
@@ -2117,9 +2658,9 @@
|
|
|
2117
2658
|
onChange && onChange(!value);
|
|
2118
2659
|
}, [onChange, disabled, value]);
|
|
2119
2660
|
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" }));
|
|
2120
|
-
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$
|
|
2661
|
+
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)] }) }));
|
|
2121
2662
|
});
|
|
2122
|
-
const renderText$
|
|
2663
|
+
const renderText$3 = (text) => text ? (jsx("div", { className: "ml-s", children: jsx(Text, { size: "text-l", font: "font-light", children: text }) })) : null;
|
|
2123
2664
|
const getCursorStyle = (disabled = false) => (disabled ? 'cursor-not-allowed' : 'cursor-pointer');
|
|
2124
2665
|
const role = (isRadio = false) => (isRadio ? 'radio' : 'checkbox');
|
|
2125
2666
|
const checkboxStyle = (value = false) => style('rounded border', { 'bg-primary-main': value });
|
|
@@ -2443,33 +2984,6 @@
|
|
|
2443
2984
|
|
|
2444
2985
|
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;
|
|
2445
2986
|
|
|
2446
|
-
const themeStyle$1 = {
|
|
2447
|
-
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'),
|
|
2448
|
-
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'),
|
|
2449
|
-
};
|
|
2450
|
-
const embeddedStyle = style('group/btn-embedded', 'bg-transparent border border-transparent outline-none');
|
|
2451
|
-
const disabledStyle = style('bg-main-gray text-main-disabled cursor-not-allowed');
|
|
2452
|
-
const Button = JSX(({ className, type = 'button', version = 'primary', shape = 'default', embedded, disabled, role, ariaLabel, data, dataTheme, children, wcmsIgnore, onClick = noop, }) => {
|
|
2453
|
-
const handleClick = useCallback(role !== 'tab' ? handlerDecorator(onClick) : onClick, [
|
|
2454
|
-
role,
|
|
2455
|
-
onClick,
|
|
2456
|
-
]);
|
|
2457
|
-
const aspectsAttrs = useMemo(() => getAspectsAttributes(data), [data]);
|
|
2458
|
-
const isRound = shape === 'round';
|
|
2459
|
-
return (jsx("button", { className: style('font-sans flex items-center gap-xs', {
|
|
2460
|
-
[themeStyle$1[version]]: !disabled && !embedded,
|
|
2461
|
-
[embeddedStyle]: embedded,
|
|
2462
|
-
[disabledStyle]: disabled,
|
|
2463
|
-
}, embedded ? 'justify-between' : 'justify-center', embedded || isRound ? 'p-0' : 'px-9 py-4', {
|
|
2464
|
-
'rounded-md': shape === 'default',
|
|
2465
|
-
'rounded-full': isRound,
|
|
2466
|
-
}, 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 }));
|
|
2467
|
-
});
|
|
2468
|
-
|
|
2469
|
-
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" }) })));
|
|
2470
|
-
|
|
2471
|
-
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 })] })));
|
|
2472
|
-
|
|
2473
2987
|
const ResponseTypeDialog = JSX(({ ok, typeForm, onClose }) => {
|
|
2474
2988
|
const statusIcon = ok ? 'ResponseOKIcon' : 'ResponseFailIcon';
|
|
2475
2989
|
const responseOKDescription = typeForm === 'ANTIFRAUD'
|
|
@@ -2554,12 +3068,6 @@
|
|
|
2554
3068
|
return { ...formState, typeForm: { key: typeForm, text: '' } };
|
|
2555
3069
|
};
|
|
2556
3070
|
|
|
2557
|
-
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, {
|
|
2558
|
-
'backdrop-blur': blur,
|
|
2559
|
-
}), 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" }) })));
|
|
2560
|
-
|
|
2561
|
-
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] })));
|
|
2562
|
-
|
|
2563
3071
|
const themeStyle = {
|
|
2564
3072
|
primary: themeStyle$1.primary,
|
|
2565
3073
|
secondary: themeStyle$1.secondary,
|
|
@@ -2577,9 +3085,9 @@
|
|
|
2577
3085
|
[themeStyle[version]]: Boolean(version),
|
|
2578
3086
|
[aboveText ? 'px-9 py-2.5' : 'px-9 py-4']: buttonLike,
|
|
2579
3087
|
'rounded-md': buttonLike,
|
|
2580
|
-
}, className), href: href, target: target, rel: rel, "aria-label": ariaLabel ?? `Ссылка на ${text}`, role: href ? 'link' : 'button', onClick: onClick, ...getAspectsAttributes(data), children: children ?? renderText$
|
|
3088
|
+
}, 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) }));
|
|
2581
3089
|
});
|
|
2582
|
-
const renderText$
|
|
3090
|
+
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;
|
|
2583
3091
|
|
|
2584
3092
|
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] })));
|
|
2585
3093
|
|
|
@@ -2590,19 +3098,43 @@
|
|
|
2590
3098
|
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" })] })] })] }));
|
|
2591
3099
|
|
|
2592
3100
|
const API = LeadServiceAPI();
|
|
2593
|
-
const ApplicationForm = UniBlock(
|
|
3101
|
+
const ApplicationForm = UniBlock(
|
|
3102
|
+
// eslint-disable-next-line max-lines-per-function
|
|
3103
|
+
({ className, title, typeForm = '', sections = [], button, link, endpoint, additionalParams, isContacts, data, ...rest }) => {
|
|
2594
3104
|
const inputs = useMemo(() => (sections?.flatMap((_) => _?.inputs) || []), [sections]);
|
|
2595
3105
|
const initialFormState = useMemo(() => getInitialFormState$2(inputs, typeForm), [inputs, typeForm]);
|
|
2596
3106
|
const router = useRouter();
|
|
2597
3107
|
const formValidator = useMemo(() => getFormValidator(inputs), [inputs]);
|
|
2598
3108
|
const responseTypeDialog = useDialog(ResponseTypeDialog);
|
|
2599
3109
|
const aspects = useAspects();
|
|
3110
|
+
const verifyPhoneDialog = useDialog(VerifyPhoneDialog);
|
|
2600
3111
|
const handleSubmit = useCallback(async (formData, ev) => {
|
|
2601
3112
|
const formatData = getFormatData({ ...formData, ...additionalParams });
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
3113
|
+
if (endpoint === 'initcorporatelead') {
|
|
3114
|
+
const { phone } = formatData;
|
|
3115
|
+
const response = await API.sendCode({ phone: String(phone) });
|
|
3116
|
+
if (!response) {
|
|
3117
|
+
responseTypeDialog.open({ ok: Boolean(response), typeForm });
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
verifyPhoneDialog.open({
|
|
3121
|
+
phone,
|
|
3122
|
+
withDescription: false,
|
|
3123
|
+
formatData,
|
|
3124
|
+
reqId: String(response),
|
|
3125
|
+
isRetail: false,
|
|
3126
|
+
onSuccess: () => {
|
|
3127
|
+
verifyPhoneDialog.close();
|
|
3128
|
+
responseTypeDialog.open({ ok: true, typeForm });
|
|
3129
|
+
},
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
else {
|
|
3133
|
+
const ok = Boolean(await API.send(formatData, router, endpoint === 'lead'));
|
|
3134
|
+
responseTypeDialog.open({ ok, typeForm });
|
|
3135
|
+
if (ok) {
|
|
3136
|
+
handleAspects({ aspectsAttributes: data, aspects, ev });
|
|
3137
|
+
}
|
|
2606
3138
|
}
|
|
2607
3139
|
}, [typeForm]);
|
|
2608
3140
|
const [, { field, onSubmit }] = useForm(initialFormState, {
|
|
@@ -2893,42 +3425,6 @@
|
|
|
2893
3425
|
EsiaStatuses["Pending"] = "PENDING";
|
|
2894
3426
|
})(EsiaStatuses || (EsiaStatuses = {}));
|
|
2895
3427
|
|
|
2896
|
-
const getTraceId = () => {
|
|
2897
|
-
const result = new Uint8Array(8);
|
|
2898
|
-
globalThis.crypto.getRandomValues(result);
|
|
2899
|
-
return result.reduce((acc, _) => `${acc}${_.toString(16).padStart(2, '0')}`, '');
|
|
2900
|
-
};
|
|
2901
|
-
|
|
2902
|
-
const fetchRetailJSON = async (url, method, body) => {
|
|
2903
|
-
try {
|
|
2904
|
-
const response = await doRequest(url, method, body);
|
|
2905
|
-
return response.json();
|
|
2906
|
-
}
|
|
2907
|
-
catch (err) {
|
|
2908
|
-
console.error(err);
|
|
2909
|
-
return null;
|
|
2910
|
-
}
|
|
2911
|
-
};
|
|
2912
|
-
async function doRequest(url, method, body) {
|
|
2913
|
-
const traceId = getTraceId();
|
|
2914
|
-
return globalThis?.fetch?.(`${RETAIL_API_BASE_URI}${url}`, {
|
|
2915
|
-
method,
|
|
2916
|
-
headers: {
|
|
2917
|
-
'Content-Type': 'application/json',
|
|
2918
|
-
'X-B3-Sampled': '1',
|
|
2919
|
-
'X-B3-Spanid': traceId,
|
|
2920
|
-
'X-B3-Traceid': traceId,
|
|
2921
|
-
...getAuthorizationHeaders(),
|
|
2922
|
-
},
|
|
2923
|
-
credentials: 'include',
|
|
2924
|
-
body: body ? JSON.stringify(body) : null,
|
|
2925
|
-
});
|
|
2926
|
-
}
|
|
2927
|
-
const getAuthorizationHeaders = () => {
|
|
2928
|
-
const token = sessionStorage.getItem('accessToken');
|
|
2929
|
-
return token ? { Authorization: `Bearer ${token}` } : null;
|
|
2930
|
-
};
|
|
2931
|
-
|
|
2932
3428
|
const getLink = (body) => fetchRetailJSON('/esia/getLink', 'POST', body);
|
|
2933
3429
|
|
|
2934
3430
|
const EsiaLoginBanner = JSX(({ onChangeEsiaStatus, productType }) => {
|
|
@@ -3281,8 +3777,6 @@
|
|
|
3281
3777
|
|
|
3282
3778
|
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 })));
|
|
3283
3779
|
|
|
3284
|
-
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 })));
|
|
3285
|
-
|
|
3286
3780
|
const ToggleIcon = JSX(({ isUnfolded, ...rest }) => (jsx(Icon, { name: isUnfolded ? 'ArrowUpIcon' : 'ArrowDownIcon', size: "small", iconVersion: "", ...rest })));
|
|
3287
3781
|
|
|
3288
3782
|
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' : '' })] })));
|
|
@@ -3844,155 +4338,17 @@
|
|
|
3844
4338
|
if (regionValue?.key) {
|
|
3845
4339
|
addressField.onChange?.('');
|
|
3846
4340
|
}
|
|
3847
|
-
}, [regionValue.key]);
|
|
3848
|
-
const { points } = useOfficesAtmsMapData({
|
|
3849
|
-
data: offices,
|
|
3850
|
-
filtrationState: {},
|
|
3851
|
-
getBalloon: getOfficePoint,
|
|
3852
|
-
});
|
|
3853
|
-
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 = '' }) => ({
|
|
3854
|
-
key: id?.toString() || '',
|
|
3855
|
-
text: address,
|
|
3856
|
-
})), ...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 }) }) })] }));
|
|
3857
|
-
});
|
|
3858
|
-
|
|
3859
|
-
function copy(source, target) {
|
|
3860
|
-
for (const [k, v] of source.entries()) {
|
|
3861
|
-
if (v !== null && v !== undefined) {
|
|
3862
|
-
target.setItem(k, v);
|
|
3863
|
-
}
|
|
3864
|
-
else {
|
|
3865
|
-
target.removeItem(k);
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
}
|
|
3869
|
-
|
|
3870
|
-
function replicate(primary, secondary) {
|
|
3871
|
-
copy(primary, secondary);
|
|
3872
|
-
copy(secondary, primary);
|
|
3873
|
-
return primary.bus.watch(({ type, event }) => {
|
|
3874
|
-
if (event !== null && event !== undefined) {
|
|
3875
|
-
secondary.setItem(type, event);
|
|
3876
|
-
}
|
|
3877
|
-
else {
|
|
3878
|
-
secondary.removeItem(type);
|
|
3879
|
-
}
|
|
3880
|
-
});
|
|
3881
|
-
}
|
|
3882
|
-
|
|
3883
|
-
class StorageAdapter {
|
|
3884
|
-
storage;
|
|
3885
|
-
bus;
|
|
3886
|
-
get size() {
|
|
3887
|
-
return this.storage?.length ?? 0;
|
|
3888
|
-
}
|
|
3889
|
-
constructor(storage, bus = new EventBus()) {
|
|
3890
|
-
this.storage = storage;
|
|
3891
|
-
this.bus = bus;
|
|
3892
|
-
}
|
|
3893
|
-
hasItem(key) {
|
|
3894
|
-
return Boolean(this.storage?.getItem(String(key)));
|
|
3895
|
-
}
|
|
3896
|
-
getItem(key) {
|
|
3897
|
-
const _ = this.storage?.getItem(String(key)) ?? null;
|
|
3898
|
-
try {
|
|
3899
|
-
return JSON.parse(String(_));
|
|
3900
|
-
}
|
|
3901
|
-
catch (ex) {
|
|
3902
|
-
return null;
|
|
3903
|
-
}
|
|
3904
|
-
}
|
|
3905
|
-
entries() {
|
|
3906
|
-
return Array.from({ length: this.size }, (_, i) => {
|
|
3907
|
-
const k = String(this.storage?.key(i));
|
|
3908
|
-
return [k, this.getItem(k)];
|
|
3909
|
-
});
|
|
3910
|
-
}
|
|
3911
|
-
setItem(key, value) {
|
|
3912
|
-
if (value !== null) {
|
|
3913
|
-
this.storage?.setItem(String(key), JSON.stringify(value));
|
|
3914
|
-
}
|
|
3915
|
-
else {
|
|
3916
|
-
this.storage?.removeItem(String(key));
|
|
3917
|
-
}
|
|
3918
|
-
this.bus?.subject(key, value);
|
|
3919
|
-
}
|
|
3920
|
-
removeItem(key) {
|
|
3921
|
-
this.storage?.removeItem(String(key));
|
|
3922
|
-
this.bus?.subject(key, null);
|
|
3923
|
-
}
|
|
3924
|
-
}
|
|
3925
|
-
|
|
3926
|
-
class Store {
|
|
3927
|
-
bus;
|
|
3928
|
-
store = new Map();
|
|
3929
|
-
get size() {
|
|
3930
|
-
return this.store.size;
|
|
3931
|
-
}
|
|
3932
|
-
constructor(bus = new EventBus()) {
|
|
3933
|
-
this.bus = bus;
|
|
3934
|
-
}
|
|
3935
|
-
hasItem(key) {
|
|
3936
|
-
return this.store.has(key);
|
|
3937
|
-
}
|
|
3938
|
-
getItem(key) {
|
|
3939
|
-
return this.store.get(key);
|
|
3940
|
-
}
|
|
3941
|
-
entries() {
|
|
3942
|
-
return this.store.entries();
|
|
3943
|
-
}
|
|
3944
|
-
setItem(key, value) {
|
|
3945
|
-
this.store.set(key, value);
|
|
3946
|
-
this.bus.subject(key, value);
|
|
3947
|
-
}
|
|
3948
|
-
removeItem(key) {
|
|
3949
|
-
this.store.delete(key);
|
|
3950
|
-
this.bus.subject(key, null);
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
|
|
3954
|
-
function useRerender() {
|
|
3955
|
-
const [, setCount] = useState(0);
|
|
3956
|
-
return useCallback(() => setCount(_ => (_ + 1) % (1 << 16)), []);
|
|
3957
|
-
}
|
|
3958
|
-
|
|
3959
|
-
const DEFAULT_METHODS = {};
|
|
3960
|
-
/**
|
|
3961
|
-
* MobX like reactivity (simplified).
|
|
3962
|
-
* Can be used to migrate from Redux/MobX or something else
|
|
3963
|
-
*
|
|
3964
|
-
* @param store
|
|
3965
|
-
* @returns reactive proxy backed by store
|
|
3966
|
-
*/
|
|
3967
|
-
function useStore(store, methods = DEFAULT_METHODS) {
|
|
3968
|
-
const deps = useRef(null);
|
|
3969
|
-
const render = useRerender();
|
|
3970
|
-
useEffect(() => store.bus.watch(ev => {
|
|
3971
|
-
if (deps.current?.has(String(ev.type))) {
|
|
3972
|
-
render();
|
|
3973
|
-
}
|
|
3974
|
-
}), [store, render]);
|
|
3975
|
-
return useMemo(() => new Proxy(methods, {
|
|
3976
|
-
get(_, key) {
|
|
3977
|
-
deps.current ||= new Set();
|
|
3978
|
-
deps.current.add(key);
|
|
3979
|
-
return store.getItem(key);
|
|
3980
|
-
},
|
|
3981
|
-
has(_, key) {
|
|
3982
|
-
deps.current ||= new Set();
|
|
3983
|
-
deps.current.add(key);
|
|
3984
|
-
return store.hasItem(key);
|
|
3985
|
-
},
|
|
3986
|
-
set(_, key, value) {
|
|
3987
|
-
store.setItem(key, value);
|
|
3988
|
-
return true;
|
|
3989
|
-
},
|
|
3990
|
-
deleteProperty(_, key) {
|
|
3991
|
-
store.removeItem(key);
|
|
3992
|
-
return true;
|
|
3993
|
-
}
|
|
3994
|
-
}), [store]);
|
|
3995
|
-
}
|
|
4341
|
+
}, [regionValue.key]);
|
|
4342
|
+
const { points } = useOfficesAtmsMapData({
|
|
4343
|
+
data: offices,
|
|
4344
|
+
filtrationState: {},
|
|
4345
|
+
getBalloon: getOfficePoint,
|
|
4346
|
+
});
|
|
4347
|
+
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 = '' }) => ({
|
|
4348
|
+
key: id?.toString() || '',
|
|
4349
|
+
text: address,
|
|
4350
|
+
})), ...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 }) }) })] }));
|
|
4351
|
+
});
|
|
3996
4352
|
|
|
3997
4353
|
const localStore = new Store(); // localStorage cache
|
|
3998
4354
|
replicate(localStore, new StorageAdapter(globalThis?.localStorage));
|
|
@@ -5217,12 +5573,6 @@
|
|
|
5217
5573
|
|
|
5218
5574
|
const renderSubmitButton = (button, isSending = false) => (jsx(SubmitButton$1, { className: "w-full @xl:w-auto", isLoading: isSending, children: button?.text ? button.text : 'Отправить заявку' }));
|
|
5219
5575
|
|
|
5220
|
-
const sessionStore = new Store(); // sessionStorage cache
|
|
5221
|
-
replicate(sessionStore, new StorageAdapter(globalThis?.sessionStorage));
|
|
5222
|
-
function useSessionStore() {
|
|
5223
|
-
return useStore(sessionStore);
|
|
5224
|
-
}
|
|
5225
|
-
|
|
5226
5576
|
const createDraftTask = async (body) => {
|
|
5227
5577
|
const res = await fetchRetailJSON('/user-data/createDraftTask', 'POST', body);
|
|
5228
5578
|
return res || {};
|
|
@@ -5251,254 +5601,6 @@
|
|
|
5251
5601
|
|
|
5252
5602
|
const updateUserTask = (body) => doRequest('/user-data/updateUserTask', 'PUT', body);
|
|
5253
5603
|
|
|
5254
|
-
const Timer = JSX(({ className, seconds }) => (jsx("span", { className: className, children: formatTimer(seconds) })));
|
|
5255
|
-
const formatTimer = (seconds) => {
|
|
5256
|
-
const minutes = Math.floor(seconds / 60);
|
|
5257
|
-
return [minutes, seconds % 60].map((_) => String(_).padStart(2, '0')).join(':');
|
|
5258
|
-
};
|
|
5259
|
-
|
|
5260
|
-
const useInterval = (handler, period) => {
|
|
5261
|
-
const timer = useRef(null);
|
|
5262
|
-
const stop = useCallback(() => clearInterval(timer.current), []);
|
|
5263
|
-
const start = useCallback(() => {
|
|
5264
|
-
stop();
|
|
5265
|
-
timer.current = setInterval(() => handler(stop), period);
|
|
5266
|
-
}, [handler, period, stop]);
|
|
5267
|
-
useEffect(() => {
|
|
5268
|
-
start();
|
|
5269
|
-
return stop;
|
|
5270
|
-
}, [start, stop]);
|
|
5271
|
-
return { start, stop };
|
|
5272
|
-
};
|
|
5273
|
-
|
|
5274
|
-
function useCountDownTimer({ seconds, period = 1000, onTick, onEnd }) {
|
|
5275
|
-
const counter = useRef(seconds);
|
|
5276
|
-
const handleTick = useCallback((stop) => {
|
|
5277
|
-
counter.current ||= 0;
|
|
5278
|
-
counter.current = Math.max(0, counter.current - 1);
|
|
5279
|
-
try {
|
|
5280
|
-
onTick?.(counter.current);
|
|
5281
|
-
}
|
|
5282
|
-
finally {
|
|
5283
|
-
if (counter.current <= 0) {
|
|
5284
|
-
stop();
|
|
5285
|
-
onEnd?.();
|
|
5286
|
-
}
|
|
5287
|
-
}
|
|
5288
|
-
}, [onTick, onEnd]);
|
|
5289
|
-
const { start } = useInterval(handleTick, period);
|
|
5290
|
-
return useCallback((_) => {
|
|
5291
|
-
counter.current = _;
|
|
5292
|
-
start();
|
|
5293
|
-
}, []);
|
|
5294
|
-
}
|
|
5295
|
-
|
|
5296
|
-
const sendCode = (body) => doRequest('/sms/sendCode', 'POST', body)
|
|
5297
|
-
.then((res) => res.text())
|
|
5298
|
-
.then((text) => text === 'OK');
|
|
5299
|
-
|
|
5300
|
-
const ICON_SIZE = { width: '103', height: '21' };
|
|
5301
|
-
|
|
5302
|
-
const logoTitleSizeStyle = 'text-s';
|
|
5303
|
-
|
|
5304
|
-
const ICON_VERSION_MAP = {
|
|
5305
|
-
'bg-white': 'color',
|
|
5306
|
-
transparent: 'white',
|
|
5307
|
-
};
|
|
5308
|
-
const SVG_COLOR = {
|
|
5309
|
-
'bg-white': 'text-primary-main',
|
|
5310
|
-
transparent: 'text-white',
|
|
5311
|
-
};
|
|
5312
|
-
const renderImage = (bgColor, image, size) => {
|
|
5313
|
-
const img = image?.src
|
|
5314
|
-
? image
|
|
5315
|
-
: {
|
|
5316
|
-
icon: image?.icon || 'LogoIcon',
|
|
5317
|
-
iconVersion: ICON_VERSION_MAP[bgColor],
|
|
5318
|
-
};
|
|
5319
|
-
return (jsx(Img, { image: img, className: SVG_COLOR[bgColor], width: size?.width, height: size?.height }));
|
|
5320
|
-
};
|
|
5321
|
-
|
|
5322
|
-
const TEXT_COLOR = {
|
|
5323
|
-
'bg-white': 'text-primary-text',
|
|
5324
|
-
transparent: 'text-white',
|
|
5325
|
-
};
|
|
5326
|
-
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
|
|
5327
|
-
? children ?? (jsx("div", { className: "ml-s", children: jsx(Text, { font: "font-medium", color: TEXT_COLOR[bgColor], size: logoTitleSizeStyle, children: logo?.title ?? 'Россельхозбанк' }) }))
|
|
5328
|
-
: null] })));
|
|
5329
|
-
|
|
5330
|
-
const checkCaptcha = (body) => doRequest('/sms/checkCaptcha', 'POST', body)
|
|
5331
|
-
.then((res) => res.text())
|
|
5332
|
-
.then((text) => text !== 'ERROR');
|
|
5333
|
-
|
|
5334
|
-
const createCaptcha = (phoneNumber) => doRequest(`/sms/createCaptcha?phoneNumber=${encodeURIComponent(phoneNumber)}`, 'GET').then(async (res) => (res ? res.blob() : new Blob()));
|
|
5335
|
-
|
|
5336
|
-
const CaptchaDialog = JSX(({ phoneNumber, sendCode, onClose }) => {
|
|
5337
|
-
const [captcha, setCaptcha] = useState('');
|
|
5338
|
-
const [code, setCode] = useState('');
|
|
5339
|
-
const [hasError, setHasError] = useState(false);
|
|
5340
|
-
const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
|
|
5341
|
-
const { closeAll } = useDialogManager();
|
|
5342
|
-
const handleCheckCaptcha = useCallback(async () => {
|
|
5343
|
-
startLoading();
|
|
5344
|
-
const isValidCode = await checkCaptcha({ captchaText: code });
|
|
5345
|
-
if (isValidCode) {
|
|
5346
|
-
onClose?.();
|
|
5347
|
-
sendCode?.();
|
|
5348
|
-
}
|
|
5349
|
-
else {
|
|
5350
|
-
setHasError(true);
|
|
5351
|
-
}
|
|
5352
|
-
endLoading();
|
|
5353
|
-
}, [code, sendCode]);
|
|
5354
|
-
const handleCreateCaptcha = useCallback(() => {
|
|
5355
|
-
(async () => setCaptcha(URL.createObjectURL(await createCaptcha(phoneNumber))))();
|
|
5356
|
-
}, []);
|
|
5357
|
-
useEffect(handleCreateCaptcha, []);
|
|
5358
|
-
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] }) }));
|
|
5359
|
-
});
|
|
5360
|
-
|
|
5361
|
-
const InputCode = JSX(({ values, setValues, hasError, errorText }) => {
|
|
5362
|
-
const [activeIndex, setActiveIndex] = useState(0);
|
|
5363
|
-
const inputRefs = useRef([]);
|
|
5364
|
-
useEffect(() => {
|
|
5365
|
-
inputRefs.current?.[activeIndex]?.focus();
|
|
5366
|
-
}, [activeIndex]);
|
|
5367
|
-
const handleChange = useCallback((index) => (event) => {
|
|
5368
|
-
const { value } = event.currentTarget;
|
|
5369
|
-
const oneValue = value.slice(0, 1);
|
|
5370
|
-
setValues(values.map((_, i) => (i === index ? oneValue : _)));
|
|
5371
|
-
setActiveIndex(index + 1);
|
|
5372
|
-
}, [values]);
|
|
5373
|
-
const handleKeyDown = useCallback((currentIndex) => (event) => {
|
|
5374
|
-
const { key } = event;
|
|
5375
|
-
if (key === 'Backspace' && !values[currentIndex]) {
|
|
5376
|
-
const previousIndex = currentIndex > 0 ? currentIndex - 1 : values.length - 1;
|
|
5377
|
-
const updatedValues = values.map((value, index) => (index === previousIndex ? '' : value));
|
|
5378
|
-
setValues(updatedValues);
|
|
5379
|
-
setActiveIndex(previousIndex);
|
|
5380
|
-
}
|
|
5381
|
-
}, [values]);
|
|
5382
|
-
const handlePaste = useCallback((event) => {
|
|
5383
|
-
event.preventDefault();
|
|
5384
|
-
const pastedData = event.clipboardData.getData('text');
|
|
5385
|
-
const updatedValues = values.map((_, idx) => (idx < pastedData.length ? pastedData[idx] : _));
|
|
5386
|
-
setValues(updatedValues);
|
|
5387
|
-
setActiveIndex(updatedValues.length - 1);
|
|
5388
|
-
}, [values]);
|
|
5389
|
-
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) => {
|
|
5390
|
-
if (!inputRefs.current) {
|
|
5391
|
-
inputRefs.current = [];
|
|
5392
|
-
}
|
|
5393
|
-
inputRefs.current[index] = ref;
|
|
5394
|
-
}, onFocus: (event) => event.target.select(), onKeyDown: handleKeyDown(index), className: getInputStyle(index, values, hasError) }, index))) }), hasError ? jsx("div", { className: "text-error", children: errorText }) : null] }));
|
|
5395
|
-
});
|
|
5396
|
-
const getInputStyle = (index, values, hasError = false) => {
|
|
5397
|
-
const isInputEmpty = !values[index];
|
|
5398
|
-
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`;
|
|
5399
|
-
};
|
|
5400
|
-
|
|
5401
|
-
const SubmitButton = JSX(({ disabled = false, onClick, text }) => (jsx(Button, { type: "button", onClick: onClick, disabled: disabled, children: jsx(Text, { font: "font-normal", children: text }) })));
|
|
5402
|
-
|
|
5403
|
-
const checkCode = async (body) => fetchRetailJSON('/sms/checkCode', 'POST', body).then(saveToken);
|
|
5404
|
-
const saveToken = (data) => {
|
|
5405
|
-
if (data?.access_token && data?.refresh_token) {
|
|
5406
|
-
globalThis.sessionStorage.setItem('accessToken', data.access_token);
|
|
5407
|
-
globalThis.sessionStorage.setItem('refreshToken', data.refresh_token);
|
|
5408
|
-
}
|
|
5409
|
-
};
|
|
5410
|
-
|
|
5411
|
-
const TIME_TO_RESEND = 180;
|
|
5412
|
-
const useVerifyPhoneDialogSubmit = ({ values, onSuccess, }) => {
|
|
5413
|
-
const sessionStore = useSessionStore();
|
|
5414
|
-
const attempts = sessionStore.smsCode?.attempts || 0;
|
|
5415
|
-
const timer = Math.max(getTimer(sessionStore.smsCode?.sendTime || Date.now()), 0);
|
|
5416
|
-
const [errorText, setErrorText] = useState('');
|
|
5417
|
-
const [isLoading, { setTrue: startLoading, setFalse: endLoading }] = useBool(false);
|
|
5418
|
-
const [timeNextReq, setTimeNextReq] = useState(timer);
|
|
5419
|
-
const resetError = useCallback(() => setErrorText(''), []);
|
|
5420
|
-
const isTimeExpired = Boolean(timeNextReq === 0 && sessionStore.smsCode?.sendTime);
|
|
5421
|
-
const isSubmitButtonDisabled = attempts > 2 || isTimeExpired || !values.every(Boolean);
|
|
5422
|
-
const handleSubmit = useCallback(async () => {
|
|
5423
|
-
try {
|
|
5424
|
-
sessionStore.smsCode = {
|
|
5425
|
-
...sessionStore.smsCode,
|
|
5426
|
-
attempts: attempts + 1,
|
|
5427
|
-
};
|
|
5428
|
-
startLoading();
|
|
5429
|
-
await checkCode({
|
|
5430
|
-
smsText: values.join(''),
|
|
5431
|
-
smsCodesSetName: { key: 'AUTHENTICATION' },
|
|
5432
|
-
});
|
|
5433
|
-
setTimeNextReq(0);
|
|
5434
|
-
resetError();
|
|
5435
|
-
sessionStore.smsCode = null;
|
|
5436
|
-
await onSuccess?.(values.join(''));
|
|
5437
|
-
}
|
|
5438
|
-
catch {
|
|
5439
|
-
setErrorText(attempts > 1 ? 'Исчерпан лимит ввода смс-кода' : 'Неверный код');
|
|
5440
|
-
}
|
|
5441
|
-
finally {
|
|
5442
|
-
endLoading();
|
|
5443
|
-
}
|
|
5444
|
-
}, [values, attempts]);
|
|
5445
|
-
useEffect(() => {
|
|
5446
|
-
if (isTimeExpired) {
|
|
5447
|
-
setErrorText('Код просрочен');
|
|
5448
|
-
}
|
|
5449
|
-
else if (attempts > 2) {
|
|
5450
|
-
setErrorText('Исчерпан лимит ввода смс-кода');
|
|
5451
|
-
}
|
|
5452
|
-
}, [isTimeExpired]);
|
|
5453
|
-
return {
|
|
5454
|
-
handleSubmit,
|
|
5455
|
-
hasError: Boolean(errorText),
|
|
5456
|
-
errorText,
|
|
5457
|
-
isLoading,
|
|
5458
|
-
timeNextReq,
|
|
5459
|
-
isSubmitButtonDisabled,
|
|
5460
|
-
setTimeNextReq,
|
|
5461
|
-
setErrorText,
|
|
5462
|
-
};
|
|
5463
|
-
};
|
|
5464
|
-
const getTimer = (sendTime) => TIME_TO_RESEND - Math.floor((Date.now() - sendTime) / 1000);
|
|
5465
|
-
|
|
5466
|
-
const CODE_LENGTH = 4;
|
|
5467
|
-
const VerifyPhoneDialog = JSX(({ phone, withDescription = true, consents, onSuccess = noop, onClose = noop }) => {
|
|
5468
|
-
const [values, setValues] = useState(Array(CODE_LENGTH).fill(''));
|
|
5469
|
-
const sessionStore = useSessionStore();
|
|
5470
|
-
const { handleSubmit, hasError, errorText, isLoading, timeNextReq, isSubmitButtonDisabled, setTimeNextReq, setErrorText, } = useVerifyPhoneDialogSubmit({ values, onSuccess });
|
|
5471
|
-
const captchaDialog = useDialog(CaptchaDialog);
|
|
5472
|
-
const phoneNumber = formatPhone(phone);
|
|
5473
|
-
const restartTimer = useCountDownTimer({ seconds: timeNextReq, onTick: setTimeNextReq });
|
|
5474
|
-
const handleSendCode = useCallback(async () => {
|
|
5475
|
-
const isSuccessSendCode = await sendCode({
|
|
5476
|
-
phoneNumber,
|
|
5477
|
-
smsCodesSetName: { key: 'AUTHENTICATION' },
|
|
5478
|
-
});
|
|
5479
|
-
if (isSuccessSendCode) {
|
|
5480
|
-
setTimeNextReq(TIME_TO_RESEND);
|
|
5481
|
-
restartTimer(TIME_TO_RESEND);
|
|
5482
|
-
setErrorText('');
|
|
5483
|
-
sessionStore.smsCode = {
|
|
5484
|
-
sendTime: Date.now(),
|
|
5485
|
-
attempts: 0,
|
|
5486
|
-
};
|
|
5487
|
-
}
|
|
5488
|
-
else {
|
|
5489
|
-
captchaDialog.open({ phoneNumber, sendCode: handleSendCode });
|
|
5490
|
-
}
|
|
5491
|
-
}, [phoneNumber, restartTimer, onClose]);
|
|
5492
|
-
useEffect(() => {
|
|
5493
|
-
if (!sessionStore.smsCode?.sendTime) {
|
|
5494
|
-
handleSendCode();
|
|
5495
|
-
}
|
|
5496
|
-
}, []);
|
|
5497
|
-
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$2(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] }) }));
|
|
5498
|
-
});
|
|
5499
|
-
const renderNextButton = (disabled, onClick) => (jsx(SubmitButton, { text: "\u0414\u0430\u043B\u0435\u0435", disabled: disabled, onClick: onClick }));
|
|
5500
|
-
const renderText$2 = (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" }) }));
|
|
5501
|
-
|
|
5502
5604
|
const defaultConsentText = {
|
|
5503
5605
|
title: 'Подпишите согласие на запрос в БКИ',
|
|
5504
5606
|
description: 'Согласие на запрос в Бюро кредитных историй (БКИ) ускорит решение по кредиту',
|
|
@@ -11275,7 +11377,7 @@
|
|
|
11275
11377
|
slots: () => [HEADER_SLOT, FOOTER_SLOT, STICKY_FOOTER_SLOT],
|
|
11276
11378
|
});
|
|
11277
11379
|
|
|
11278
|
-
const packageVersion = "0.14.
|
|
11380
|
+
const packageVersion = "0.14.888";
|
|
11279
11381
|
|
|
11280
11382
|
exports.Blocks = Blocks;
|
|
11281
11383
|
exports.ContentPage = ContentPage;
|