@snabcentr/client-ui 4.16.12-profstroy → 4.16.13-profstroy
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/esm2022/feedback/feedback-form/sc-feedback-form.component.mjs +21 -11
- package/esm2022/providers/cleanup-recaptcha-artifacts.mjs +30 -0
- package/esm2022/providers/index.mjs +2 -1
- package/esm2022/public-api.mjs +1 -2
- package/esm2022/samples/sc-sample.module.mjs +10 -3
- package/esm2022/services/index.mjs +1 -2
- package/feedback/feedback-form/sc-feedback-form.component.d.ts +1 -1
- package/fesm2022/snabcentr-client-ui.mjs +64 -367
- package/fesm2022/snabcentr-client-ui.mjs.map +1 -1
- package/package.json +2 -1
- package/providers/cleanup-recaptcha-artifacts.d.ts +7 -0
- package/providers/index.d.ts +1 -0
- package/public-api.d.ts +0 -1
- package/release_notes.tmp +2 -5
- package/samples/sc-sample.module.d.ts +2 -1
- package/services/index.d.ts +0 -1
- package/styles/tailwind/tailwind.scss +2 -40
- package/esm2022/services/sc-scripts.service.mjs +0 -106
- package/esm2022/smart-captcha/index.mjs +0 -5
- package/esm2022/smart-captcha/interfaces/index.mjs +0 -6
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-api.mjs +0 -2
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-event.mjs +0 -2
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-language.mjs +0 -2
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-render-params.mjs +0 -2
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-settings.mjs +0 -2
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-window.mjs +0 -2
- package/esm2022/smart-captcha/sc-smart-captcha.component.mjs +0 -167
- package/esm2022/smart-captcha/services/index.mjs +0 -2
- package/esm2022/smart-captcha/services/sc-smart-captcha-loader.service.mjs +0 -87
- package/esm2022/smart-captcha/tokens/index.mjs +0 -3
- package/esm2022/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.mjs +0 -8
- package/esm2022/smart-captcha/tokens/sc-smart-captcha-settings.token.mjs +0 -6
- package/services/sc-scripts.service.d.ts +0 -51
- package/smart-captcha/index.d.ts +0 -4
- package/smart-captcha/interfaces/index.d.ts +0 -5
- package/smart-captcha/interfaces/sc-smart-captcha-api.d.ts +0 -36
- package/smart-captcha/interfaces/sc-smart-captcha-event.d.ts +0 -4
- package/smart-captcha/interfaces/sc-smart-captcha-language.d.ts +0 -4
- package/smart-captcha/interfaces/sc-smart-captcha-render-params.d.ts +0 -16
- package/smart-captcha/interfaces/sc-smart-captcha-settings.d.ts +0 -16
- package/smart-captcha/interfaces/sc-smart-captcha-window.d.ts +0 -14
- package/smart-captcha/sc-smart-captcha.component.d.ts +0 -92
- package/smart-captcha/services/index.d.ts +0 -1
- package/smart-captcha/services/sc-smart-captcha-loader.service.d.ts +0 -50
- package/smart-captcha/tokens/index.d.ts +0 -2
- package/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.d.ts +0 -5
- package/smart-captcha/tokens/sc-smart-captcha-settings.token.d.ts +0 -6
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable, NgZone,
|
|
2
|
+
import { InjectionToken, inject, Injectable, NgZone, signal, EventEmitter, ChangeDetectorRef, Directive, Input, Output, untracked, Pipe, ElementRef, HostListener, Renderer2, ContentChildren, NgModule, input, computed, Component, ChangeDetectionStrategy, Inject, HostBinding, model, output, SkipSelf, DestroyRef, effect, ContentChild, ViewChild, viewChild, Optional, contentChild, TemplateRef, forwardRef, ViewEncapsulation, Injector, viewChildren, afterNextRender } from '@angular/core';
|
|
3
3
|
import * as i1 from '@snabcentr/client-core';
|
|
4
|
-
import { ScContactsService, ScUserService, ScLocationsService,
|
|
4
|
+
import { ScContactsService, ScUserService, ScLocationsService, ScAuthService, SEARCH_TERM, ScUnitsHelper, ScImageHelper, SC_PATH_IMAGE_NOT_FOUND, ScImage, ScSuggestionAddressQuality, ScPhoneService, ScUserMetrikaService, ScUserMetrikaGoalsEnum, IS_RUNNING_ON_TERMINAL, ScVCardService, ScVerificationService, ScISuggestionType, SC_MIN_LENGTH_SEARCH_TERM, ScConvertersService, ScNumberHelper, ScOpfList, ScReferencesService, ScContragentService, ScBannerService, ScMediaImageTransformerPipe, ScUploadedFile, ScCartService, loadingPlaceholder, SC_ORDER_LOADER, ScMimeTypes, ScCatalogService, SC_URLS, ScWarehouseService, SEARCH_TERM_PROVIDERS, ScPaginationService, SC_NEXT_PAGE_PAGINATION_CLICK, SC_PRODUCT_PAGINATION_OPTIONS, ScCatalogFilterService, ScIdOrSlugPipe, SC_CATEGORY_INFO, ScConfiguratorService, IS_SERVER, RESPONSE, ScIconTypesEnum, ScDocumentInfoTypesEnum, ScOrderItemsGroup, ScOrderItem, ScDeliveryAddressService, ScOrdersService, ScUIService, SC_USER_INFO as SC_USER_INFO$1, ScPaymentType, ScDeliveryType, TERMINAL_PROVIDERS, ScOrderDraft, SC_UPDATE_INTERVAL, ScOrderDraftsService, ScOrderDraftActualizationStatus, ScRouteKeys, ScSeoService, scOrderIsLoaded, SC_PAGE_QUERY_PARAM, ScFrequentlyAskedQuestionsService, SchemaOrgFactory, scGetPageQueryParamChanges, ScNewsService, SC_COMPANY_INFO, ScFeedbackService } from '@snabcentr/client-core';
|
|
5
5
|
import * as i5$1 from 'rxjs';
|
|
6
|
-
import { EMPTY, BehaviorSubject, switchMap, of, shareReplay, map,
|
|
6
|
+
import { EMPTY, BehaviorSubject, switchMap, of, shareReplay, map, Subject, filter, tap, catchError, finalize, startWith, share, timer, scan, takeWhile, endWith, distinctUntilChanged, debounceTime, throwError, combineLatest, pairwise, Observable, Subscription, merge, skip, from, concatMap, noop, first, retry, defaultIfEmpty, exhaustMap, fromEvent, animationFrames, take, takeUntil } from 'rxjs';
|
|
7
7
|
import { WA_WINDOW } from '@ng-web-apis/common';
|
|
8
8
|
import { takeUntilDestroyed, toSignal, outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
|
|
9
9
|
import * as i4$1 from '@taiga-ui/cdk';
|
|
10
|
-
import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, TuiValidationError, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TUI_WINDOW_SIZE, tuiClamp,
|
|
10
|
+
import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, TuiValidationError, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TUI_WINDOW_SIZE, tuiClamp, TUI_TRUE_HANDLER } from '@taiga-ui/cdk';
|
|
11
11
|
import * as i2$1 from '@taiga-ui/kit';
|
|
12
12
|
import { TUI_DATE_VALUE_TRANSFORMER, TuiPreview, TuiAvatar, TuiAccordionItem, TuiElasticContainer, TuiAccordion, TuiFieldErrorPipe, TuiFilterByInputPipe, TuiStringifyContentPipe, TuiDataListWrapper, TuiButtonLoading, TuiSortCountriesPipe, TuiStepper, TuiCarousel, TuiPush, TuiCheckbox, TUI_CONFIRM_WORDS, TuiFiles, TuiChip, TuiInputNumber, TuiBadge, TuiTooltip, TuiHighlight, TuiLineClamp, TuiFade, TuiRange, TuiBlock, tuiInputNumberOptionsProvider, TuiDataListWrapperComponent, TuiChevron, TuiSelect, TuiInputSlider, TuiTreeService, TuiTreeItemContent, TUI_TREE_START, TUI_TREE_CONTENT, TUI_TREE_LOADING, TUI_TREE_LOADER, TuiTree, TuiPreviewDialogService, TUI_CONFIRM, tuiFilesAccepted, TuiInputFiles, TuiInputFilesDirective, TuiFilesComponent, TuiFile, TuiFileRejectedPipe, TUI_INPUT_FILES_OPTIONS, tuiCreateFileFormatValidator, tuiCreateFileSizeValidator, TUI_INPUT_FILE_TEXTS, tuiItemsHandlersProvider as tuiItemsHandlersProvider$1, TUI_PAGINATION_TEXTS, TuiAccordionDirective, TuiAccordionItemContent } from '@taiga-ui/kit';
|
|
13
|
-
import * as i2$2 from '@angular/common';
|
|
14
|
-
import { DOCUMENT, CommonModule, NgIf, AsyncPipe, NgTemplateOutlet, NgFor, NgClass } from '@angular/common';
|
|
15
13
|
import { HttpClient, HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
|
16
14
|
import * as i1$1 from '@angular/forms';
|
|
17
|
-
import { FormControl, NgControl, FormGroupDirective, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule
|
|
15
|
+
import { FormControl, NgControl, FormGroupDirective, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
18
16
|
import * as i1$2 from '@taiga-ui/core';
|
|
19
17
|
import { TuiButton, TuiDialog, TuiDialogService, TuiLink, TuiFallbackSrcPipe, TuiInitialsPipe, TuiIcon, TuiAppearance, TuiWithAppearance, TuiIcons, TuiWithIcons, TUI_DATA_LIST_HOST, tuiDropdownOptionsProvider, TuiLabel, TuiError, TuiLoader, TuiDataList, TuiNotification, TuiTextfield, TuiTitle, TuiFormatNumberPipe, TuiNumberFormat, TuiHint, TUI_MONTHS, TuiScrollbar, tuiNumberFormatProvider, tuiItemsHandlersProvider, tuiTextfieldOptionsProvider, tuiHintOptionsProvider, TuiHintDriver, TuiHintHover, TuiHintPosition, TuiHintDirective, TuiAlertService, TuiDataListComponent, TuiOption, TuiIconPipe, TUI_BUTTON_OPTIONS, TUI_BUTTON_DEFAULT_OPTIONS, TUI_SPIN_ICONS, TuiSurface, tuiFadeIn } from '@taiga-ui/core';
|
|
20
18
|
import { isValidPhoneNumber } from 'libphonenumber-js/max';
|
|
@@ -26,6 +24,8 @@ import { isNil, isUndefined, isObject, isArray, isString } from 'lodash-es';
|
|
|
26
24
|
import * as i5 from '@taiga-ui/core/components/label';
|
|
27
25
|
import * as i8 from '@maskito/angular';
|
|
28
26
|
import { MaskitoDirective } from '@maskito/angular';
|
|
27
|
+
import * as i2$2 from '@angular/common';
|
|
28
|
+
import { DOCUMENT, CommonModule, NgIf, AsyncPipe, NgTemplateOutlet, NgFor, NgClass } from '@angular/common';
|
|
29
29
|
import * as i2$3 from '@taiga-ui/polymorpheus';
|
|
30
30
|
import { POLYMORPHEUS_CONTEXT, PolymorpheusComponent, PolymorpheusTemplate, PolymorpheusOutlet, injectContext } from '@taiga-ui/polymorpheus';
|
|
31
31
|
import * as i2 from 'angularx-qrcode';
|
|
@@ -55,6 +55,8 @@ import { Clipboard } from '@angular/cdk/clipboard';
|
|
|
55
55
|
import * as i2$5 from '@taiga-ui/experimental/components/expand';
|
|
56
56
|
import * as i3$3 from '@taiga-ui/kit/components/data-list-wrapper';
|
|
57
57
|
import { TuiGroup } from '@taiga-ui/core/directives/group';
|
|
58
|
+
import * as i4$3 from 'ng-recaptcha-2';
|
|
59
|
+
import { RecaptchaFormsModule, RecaptchaModule, RecaptchaComponent } from 'ng-recaptcha-2';
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
62
|
* Поток для закрытия уведомлений помощи.
|
|
@@ -354,6 +356,36 @@ const SC_HIDDEN_PRINT_ELEMENTS = new InjectionToken('SC_HIDDEN_PRINT_ELEMENTS',
|
|
|
354
356
|
providedIn: 'root',
|
|
355
357
|
});
|
|
356
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Селектор iframe reCAPTCHA.
|
|
361
|
+
*/
|
|
362
|
+
const RECAPTCHA_IFRAME_SELECTOR = 'iframe[src*="recaptcha"]';
|
|
363
|
+
/**
|
|
364
|
+
* Селектор хоста reCAPTCHA.
|
|
365
|
+
*/
|
|
366
|
+
const RECAPTCHA_HOST_SELECTOR = 're-captcha';
|
|
367
|
+
/**
|
|
368
|
+
* Освобождает ресурсы reCAPTCHA и удаляет осиротевшие iframe после смены маршрута.
|
|
369
|
+
*
|
|
370
|
+
* @param documentReference Объект документа.
|
|
371
|
+
* @param windowReference Объект окна браузера.
|
|
372
|
+
*/
|
|
373
|
+
function cleanupRecaptchaArtifacts(documentReference, windowReference) {
|
|
374
|
+
const windowWithRecaptcha = windowReference;
|
|
375
|
+
try {
|
|
376
|
+
windowWithRecaptcha.grecaptcha?.reset();
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
// Ошибки reCAPTCHA не должны блокировать навигацию.
|
|
380
|
+
}
|
|
381
|
+
documentReference.querySelectorAll(RECAPTCHA_IFRAME_SELECTOR).forEach((iframe) => {
|
|
382
|
+
if (iframe.closest(RECAPTCHA_HOST_SELECTOR)) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
iframe.remove();
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
357
389
|
/**
|
|
358
390
|
* Сервис по работе с печатью страницы.
|
|
359
391
|
*/
|
|
@@ -399,107 +431,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
399
431
|
}]
|
|
400
432
|
}] });
|
|
401
433
|
|
|
402
|
-
/**
|
|
403
|
-
* Сервис для вставки в {@link Document} внешних и дополнительных скриптов.
|
|
404
|
-
*/
|
|
405
|
-
class ScScriptsService {
|
|
406
|
-
constructor() {
|
|
407
|
-
/**
|
|
408
|
-
* Объект {@link Document}, предоставляющий доступ к DOM страницы.
|
|
409
|
-
*/
|
|
410
|
-
this.document = inject(DOCUMENT);
|
|
411
|
-
/**
|
|
412
|
-
* Объект {@link Renderer2}, предоставляющий доступ к DOM страницы.
|
|
413
|
-
*/
|
|
414
|
-
this.renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
415
|
-
/**
|
|
416
|
-
* Признак того, что скрипт выполняется в браузере.
|
|
417
|
-
*/
|
|
418
|
-
this.isBrowser = inject(IS_BROWSER);
|
|
419
|
-
/**
|
|
420
|
-
* {@link NgZone} для вставки скриптов вне зоны Angular.
|
|
421
|
-
*/
|
|
422
|
-
this.ngZone = inject(NgZone);
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Вставляет в конец {@link Document.body} скрипты, заданные строками HTML, вне зоны Angular. Из каждой строки берётся первый `<script>`. На сервере ничего не делает.
|
|
426
|
-
* Принимает только доверенные строки из конфигурации приложения: строка разбирается как HTML и может выполнить код.
|
|
427
|
-
*
|
|
428
|
-
* @param scriptStrings Строки HTML скриптов.
|
|
429
|
-
*/
|
|
430
|
-
appendScripts(scriptStrings) {
|
|
431
|
-
if (!this.isBrowser) {
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
this.ngZone.runOutsideAngular(() => {
|
|
435
|
-
scriptStrings.forEach((scriptString) => {
|
|
436
|
-
const script = this.createScript(scriptString);
|
|
437
|
-
if (script) {
|
|
438
|
-
this.renderer.appendChild(this.document.body, script);
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Загружает внешний скрипт: при подписке добавляет его в {@link Document.head}, после загрузки выдаёт элемент скрипта и завершается.
|
|
445
|
-
* Если скрипт не загрузился или подписка отменена раньше, удаляет его со страницы; удаление не отменяет загрузку и выполнение уже вставленного скрипта. На сервере завершается без загрузки.
|
|
446
|
-
*
|
|
447
|
-
* @param url Адрес скрипта.
|
|
448
|
-
*/
|
|
449
|
-
loadScript$(url) {
|
|
450
|
-
if (!this.isBrowser) {
|
|
451
|
-
return EMPTY;
|
|
452
|
-
}
|
|
453
|
-
return new Observable((subscriber) => {
|
|
454
|
-
const script = this.renderer.createElement('script');
|
|
455
|
-
let isLoaded = false;
|
|
456
|
-
const unlistenLoad = this.renderer.listen(script, 'load', () => {
|
|
457
|
-
isLoaded = true;
|
|
458
|
-
subscriber.next(script);
|
|
459
|
-
subscriber.complete();
|
|
460
|
-
});
|
|
461
|
-
const unlistenError = this.renderer.listen(script, 'error', () => {
|
|
462
|
-
subscriber.error(new Error(`Failed to load script ${url}`));
|
|
463
|
-
});
|
|
464
|
-
this.renderer.setProperty(script, 'src', url);
|
|
465
|
-
this.renderer.appendChild(this.document.head, script);
|
|
466
|
-
return () => {
|
|
467
|
-
unlistenLoad();
|
|
468
|
-
unlistenError();
|
|
469
|
-
if (!isLoaded) {
|
|
470
|
-
this.removeScript(script);
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Удаляет скрипт со страницы. При подключённых анимациях Angular узел удаляется при ближайшей проверке изменений.
|
|
477
|
-
*
|
|
478
|
-
* @param script Элемент скрипта.
|
|
479
|
-
*/
|
|
480
|
-
removeScript(script) {
|
|
481
|
-
this.renderer.removeChild(script.parentNode, script);
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Создаёт {@link HTMLScriptElement} из строки HTML скрипта.
|
|
485
|
-
*
|
|
486
|
-
* @param scriptString Строка HTML скрипта.
|
|
487
|
-
*/
|
|
488
|
-
createScript(scriptString) {
|
|
489
|
-
const range = this.document.createRange();
|
|
490
|
-
const fragment = range.createContextualFragment(scriptString);
|
|
491
|
-
return fragment.querySelector('script');
|
|
492
|
-
}
|
|
493
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
494
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, providedIn: 'root' }); }
|
|
495
|
-
}
|
|
496
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, decorators: [{
|
|
497
|
-
type: Injectable,
|
|
498
|
-
args: [{
|
|
499
|
-
providedIn: 'root',
|
|
500
|
-
}]
|
|
501
|
-
}] });
|
|
502
|
-
|
|
503
434
|
/**
|
|
504
435
|
* Проверяет корректность введенного номера телефона.
|
|
505
436
|
*/
|
|
@@ -12346,14 +12277,18 @@ class ScPreviewSampleModule {
|
|
|
12346
12277
|
TuiHovered,
|
|
12347
12278
|
TuiButton,
|
|
12348
12279
|
TuiButtonLoading,
|
|
12349
|
-
TuiLabel
|
|
12280
|
+
TuiLabel,
|
|
12281
|
+
RecaptchaFormsModule,
|
|
12282
|
+
RecaptchaModule], exports: [ScPreviewSampleComponent] }); }
|
|
12350
12283
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, imports: [CommonModule,
|
|
12351
12284
|
ReactiveFormsModule,
|
|
12352
12285
|
TuiError,
|
|
12353
12286
|
ScFormFieldsModule,
|
|
12354
12287
|
TuiInputModule,
|
|
12355
12288
|
TuiInputPhoneModule, i2$1.TuiCarouselComponent, TuiAvatar,
|
|
12356
|
-
TuiButtonLoading
|
|
12289
|
+
TuiButtonLoading,
|
|
12290
|
+
RecaptchaFormsModule,
|
|
12291
|
+
RecaptchaModule] }); }
|
|
12357
12292
|
}
|
|
12358
12293
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, decorators: [{
|
|
12359
12294
|
type: NgModule,
|
|
@@ -12373,6 +12308,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
12373
12308
|
TuiButton,
|
|
12374
12309
|
TuiButtonLoading,
|
|
12375
12310
|
TuiLabel,
|
|
12311
|
+
RecaptchaFormsModule,
|
|
12312
|
+
RecaptchaModule,
|
|
12376
12313
|
],
|
|
12377
12314
|
exports: [ScPreviewSampleComponent],
|
|
12378
12315
|
}]
|
|
@@ -12392,255 +12329,6 @@ const scGetCurrentRoute = (route) => {
|
|
|
12392
12329
|
return currentRoute;
|
|
12393
12330
|
};
|
|
12394
12331
|
|
|
12395
|
-
/**
|
|
12396
|
-
* Токен времени ожидания загрузки скрипта Yandex SmartCaptcha в миллисекундах.
|
|
12397
|
-
*/
|
|
12398
|
-
const SC_SMART_CAPTCHA_LOAD_TIMEOUT = new InjectionToken('SC_SMART_CAPTCHA_LOAD_TIMEOUT', {
|
|
12399
|
-
factory: () => 20_000,
|
|
12400
|
-
});
|
|
12401
|
-
|
|
12402
|
-
/**
|
|
12403
|
-
* Сервис загрузки скрипта Yandex SmartCaptcha.
|
|
12404
|
-
*/
|
|
12405
|
-
class ScSmartCaptchaLoaderService {
|
|
12406
|
-
constructor() {
|
|
12407
|
-
/**
|
|
12408
|
-
* Сервис для вставки внешних скриптов.
|
|
12409
|
-
*/
|
|
12410
|
-
this.scriptsService = inject(ScScriptsService);
|
|
12411
|
-
/**
|
|
12412
|
-
* Окно браузера с API Yandex SmartCaptcha.
|
|
12413
|
-
*/
|
|
12414
|
-
this.window = inject(WA_WINDOW);
|
|
12415
|
-
/**
|
|
12416
|
-
* Признак того, что приложение запущено в браузере.
|
|
12417
|
-
*/
|
|
12418
|
-
this.isBrowser = inject(IS_BROWSER);
|
|
12419
|
-
/**
|
|
12420
|
-
* Время ожидания загрузки скрипта в миллисекундах.
|
|
12421
|
-
*/
|
|
12422
|
-
this.loadTimeout = inject(SC_SMART_CAPTCHA_LOAD_TIMEOUT);
|
|
12423
|
-
/**
|
|
12424
|
-
* Имя функции окна, которую скрипт вызывает после загрузки.
|
|
12425
|
-
*/
|
|
12426
|
-
this.onloadCallbackName = 'scSmartCaptchaOnload';
|
|
12427
|
-
/**
|
|
12428
|
-
* Адрес скрипта.
|
|
12429
|
-
*/
|
|
12430
|
-
this.scriptUrl = `https://smartcaptcha.cloud.yandex.ru/captcha.js?render=onload&onload=${this.onloadCallbackName}`;
|
|
12431
|
-
/**
|
|
12432
|
-
* Загрузка API, общая для всех виджетов. Скрипт загружается один раз; отписка и истечение ожидания у подписчика загрузку не прерывают, после ошибки следующая подписка загружает скрипт заново.
|
|
12433
|
-
*/
|
|
12434
|
-
this.loading$ = defer(() => this.load$()).pipe(shareReplay(1));
|
|
12435
|
-
/**
|
|
12436
|
-
* {@link Observable} API Yandex SmartCaptcha. Значения и ошибки приходят вне зоны Angular, ожидание первого значения ограничено {@link SC_SMART_CAPTCHA_LOAD_TIMEOUT}.
|
|
12437
|
-
*/
|
|
12438
|
-
this.api$ = this.loading$.pipe(timeout({ first: this.loadTimeout }), tuiZonefree());
|
|
12439
|
-
}
|
|
12440
|
-
/**
|
|
12441
|
-
* Возвращает API Yandex SmartCaptcha, при необходимости загружая скрипт. На сервере ничего не возвращает.
|
|
12442
|
-
*/
|
|
12443
|
-
load$() {
|
|
12444
|
-
if (!this.isBrowser) {
|
|
12445
|
-
return EMPTY;
|
|
12446
|
-
}
|
|
12447
|
-
if (this.window.smartCaptcha) {
|
|
12448
|
-
return of(this.window.smartCaptcha);
|
|
12449
|
-
}
|
|
12450
|
-
return merge(this.onload$(), this.scriptsService.loadScript$(this.scriptUrl).pipe(ignoreElements()));
|
|
12451
|
-
}
|
|
12452
|
-
/**
|
|
12453
|
-
* Ждёт вызова функции из параметра `onload` адреса скрипта и возвращает API, которое скрипт к этому моменту создал.
|
|
12454
|
-
*/
|
|
12455
|
-
onload$() {
|
|
12456
|
-
return new Observable((subscriber) => {
|
|
12457
|
-
this.window[this.onloadCallbackName] = () => {
|
|
12458
|
-
if (this.window.smartCaptcha) {
|
|
12459
|
-
subscriber.next(this.window.smartCaptcha);
|
|
12460
|
-
subscriber.complete();
|
|
12461
|
-
}
|
|
12462
|
-
else {
|
|
12463
|
-
subscriber.error(new Error('Yandex SmartCaptcha API is unavailable'));
|
|
12464
|
-
}
|
|
12465
|
-
};
|
|
12466
|
-
return () => {
|
|
12467
|
-
this.window[this.onloadCallbackName] = undefined;
|
|
12468
|
-
};
|
|
12469
|
-
});
|
|
12470
|
-
}
|
|
12471
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
12472
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, providedIn: 'root' }); }
|
|
12473
|
-
}
|
|
12474
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, decorators: [{
|
|
12475
|
-
type: Injectable,
|
|
12476
|
-
args: [{
|
|
12477
|
-
providedIn: 'root',
|
|
12478
|
-
}]
|
|
12479
|
-
}] });
|
|
12480
|
-
|
|
12481
|
-
/**
|
|
12482
|
-
* Токен настроек Yandex SmartCaptcha. Задаётся приложением.
|
|
12483
|
-
*/
|
|
12484
|
-
const SC_SMART_CAPTCHA_SETTINGS = new InjectionToken('SC_SMART_CAPTCHA_SETTINGS');
|
|
12485
|
-
|
|
12486
|
-
/* eslint-disable no-use-before-define */
|
|
12487
|
-
/**
|
|
12488
|
-
* Виджет Yandex SmartCaptcha. Значение поля ввода - токен прохождения проверки, `null` пока проверка не пройдена или токен истёк.
|
|
12489
|
-
*/
|
|
12490
|
-
class ScSmartCaptchaComponent {
|
|
12491
|
-
/**
|
|
12492
|
-
* Инициализирует экземпляр класса {@link ScSmartCaptchaComponent}.
|
|
12493
|
-
*/
|
|
12494
|
-
constructor() {
|
|
12495
|
-
/**
|
|
12496
|
-
* Контейнер, в котором отрисовывается виджет.
|
|
12497
|
-
*/
|
|
12498
|
-
this.container = viewChild.required('container');
|
|
12499
|
-
/**
|
|
12500
|
-
* Настройки Yandex SmartCaptcha.
|
|
12501
|
-
*/
|
|
12502
|
-
this.settings = inject(SC_SMART_CAPTCHA_SETTINGS);
|
|
12503
|
-
/**
|
|
12504
|
-
* Сервис загрузки скрипта Yandex SmartCaptcha.
|
|
12505
|
-
*/
|
|
12506
|
-
this.loader = inject(ScSmartCaptchaLoaderService);
|
|
12507
|
-
/**
|
|
12508
|
-
* {@link NgZone} для отрисовки виджета вне зоны Angular и возврата его событий в зону.
|
|
12509
|
-
*/
|
|
12510
|
-
this.ngZone = inject(NgZone);
|
|
12511
|
-
/**
|
|
12512
|
-
* Ссылка для автоматического управления уничтожением зависимостей.
|
|
12513
|
-
*/
|
|
12514
|
-
this.destroyRef = inject(DestroyRef);
|
|
12515
|
-
/**
|
|
12516
|
-
* Признак того, что капчу не удалось загрузить.
|
|
12517
|
-
*/
|
|
12518
|
-
this.hasError = signal(false);
|
|
12519
|
-
/**
|
|
12520
|
-
* Функции отписки от событий виджета.
|
|
12521
|
-
*/
|
|
12522
|
-
this.unsubscribers = [];
|
|
12523
|
-
/**
|
|
12524
|
-
* Обработчик изменения значения поля ввода.
|
|
12525
|
-
*/
|
|
12526
|
-
this.onChange = noop;
|
|
12527
|
-
/**
|
|
12528
|
-
* Обработчик касания поля ввода.
|
|
12529
|
-
*/
|
|
12530
|
-
this.onTouched = noop;
|
|
12531
|
-
afterNextRender(() => {
|
|
12532
|
-
this.load();
|
|
12533
|
-
});
|
|
12534
|
-
this.destroyRef.onDestroy(() => {
|
|
12535
|
-
this.destroyWidget();
|
|
12536
|
-
});
|
|
12537
|
-
}
|
|
12538
|
-
/** @inheritDoc */
|
|
12539
|
-
writeValue(token) {
|
|
12540
|
-
const { api, widgetId } = this;
|
|
12541
|
-
if (!token && api && widgetId !== undefined) {
|
|
12542
|
-
this.ngZone.runOutsideAngular(() => {
|
|
12543
|
-
api.reset(widgetId);
|
|
12544
|
-
});
|
|
12545
|
-
}
|
|
12546
|
-
}
|
|
12547
|
-
/** @inheritDoc */
|
|
12548
|
-
registerOnChange(onChange) {
|
|
12549
|
-
this.onChange = onChange;
|
|
12550
|
-
}
|
|
12551
|
-
/** @inheritDoc */
|
|
12552
|
-
registerOnTouched(onTouched) {
|
|
12553
|
-
this.onTouched = onTouched;
|
|
12554
|
-
}
|
|
12555
|
-
/**
|
|
12556
|
-
* Повторяет загрузку капчи после ошибки.
|
|
12557
|
-
*/
|
|
12558
|
-
retry() {
|
|
12559
|
-
this.hasError.set(false);
|
|
12560
|
-
this.load();
|
|
12561
|
-
}
|
|
12562
|
-
/**
|
|
12563
|
-
* Загружает API Yandex SmartCaptcha и отрисовывает виджет (API приходит вне зоны Angular). При ошибке загрузки или отрисовки показывает сообщение.
|
|
12564
|
-
*/
|
|
12565
|
-
load() {
|
|
12566
|
-
this.loader.api$
|
|
12567
|
-
.pipe(tap((api) => {
|
|
12568
|
-
this.render(api);
|
|
12569
|
-
}), takeUntilDestroyed(this.destroyRef))
|
|
12570
|
-
.subscribe({
|
|
12571
|
-
error: () => {
|
|
12572
|
-
this.showError();
|
|
12573
|
-
},
|
|
12574
|
-
});
|
|
12575
|
-
}
|
|
12576
|
-
/**
|
|
12577
|
-
* Отрисовывает виджет и подписывается на его события.
|
|
12578
|
-
*
|
|
12579
|
-
* @param api API Yandex SmartCaptcha.
|
|
12580
|
-
*/
|
|
12581
|
-
render(api) {
|
|
12582
|
-
const widgetId = api.render(this.container().nativeElement, { sitekey: this.settings.sitekey, hl: this.settings.language });
|
|
12583
|
-
this.api = api;
|
|
12584
|
-
this.widgetId = widgetId;
|
|
12585
|
-
this.unsubscribers = [
|
|
12586
|
-
api.subscribe(widgetId, 'success', (token) => {
|
|
12587
|
-
this.updateValue(typeof token === 'string' ? token : null);
|
|
12588
|
-
}),
|
|
12589
|
-
api.subscribe(widgetId, 'token-expired', () => {
|
|
12590
|
-
this.updateValue(null);
|
|
12591
|
-
api.reset(widgetId);
|
|
12592
|
-
}),
|
|
12593
|
-
api.subscribe(widgetId, 'javascript-error', () => {
|
|
12594
|
-
this.showError();
|
|
12595
|
-
}),
|
|
12596
|
-
];
|
|
12597
|
-
}
|
|
12598
|
-
/**
|
|
12599
|
-
* Передаёт форме новое значение токена.
|
|
12600
|
-
*
|
|
12601
|
-
* @param token Токен прохождения проверки.
|
|
12602
|
-
*/
|
|
12603
|
-
updateValue(token) {
|
|
12604
|
-
this.ngZone.run(() => {
|
|
12605
|
-
this.onChange(token);
|
|
12606
|
-
this.onTouched();
|
|
12607
|
-
});
|
|
12608
|
-
}
|
|
12609
|
-
/**
|
|
12610
|
-
* Удаляет виджет, очищает токен и показывает сообщение об ошибке.
|
|
12611
|
-
*/
|
|
12612
|
-
showError() {
|
|
12613
|
-
this.destroyWidget();
|
|
12614
|
-
this.ngZone.run(() => {
|
|
12615
|
-
this.hasError.set(true);
|
|
12616
|
-
this.onChange(null);
|
|
12617
|
-
});
|
|
12618
|
-
}
|
|
12619
|
-
/**
|
|
12620
|
-
* Удаляет виджет вместе с созданными им элементами и обработчиками.
|
|
12621
|
-
*/
|
|
12622
|
-
destroyWidget() {
|
|
12623
|
-
this.unsubscribers.forEach((unsubscribe) => {
|
|
12624
|
-
unsubscribe();
|
|
12625
|
-
});
|
|
12626
|
-
this.unsubscribers = [];
|
|
12627
|
-
const { api, widgetId } = this;
|
|
12628
|
-
if (api && widgetId !== undefined) {
|
|
12629
|
-
this.ngZone.runOutsideAngular(() => {
|
|
12630
|
-
api.destroy(widgetId);
|
|
12631
|
-
});
|
|
12632
|
-
}
|
|
12633
|
-
this.api = undefined;
|
|
12634
|
-
this.widgetId = undefined;
|
|
12635
|
-
}
|
|
12636
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12637
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScSmartCaptchaComponent, isStandalone: true, selector: "sc-smart-captcha", providers: [tuiProvide(NG_VALUE_ACCESSOR, ScSmartCaptchaComponent, true)], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #container\n class=\"min-h-[7.375rem]\"\n [class.hidden]=\"hasError()\"\n></div>\n@if (hasError()) {\n <p\n role=\"alert\"\n class=\"text-body-s text-tui-text-negative\"\n >\n \u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u00AB\u042F \u043D\u0435 \u0440\u043E\u0431\u043E\u0442\u00BB.\n <button\n tuiLink\n type=\"button\"\n (click)=\"retry()\"\n >\n \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C\n </button>\n </p>\n}\n", dependencies: [{ kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12638
|
-
}
|
|
12639
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, decorators: [{
|
|
12640
|
-
type: Component,
|
|
12641
|
-
args: [{ standalone: true, selector: 'sc-smart-captcha', imports: [TuiLink], providers: [tuiProvide(NG_VALUE_ACCESSOR, ScSmartCaptchaComponent, true)], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #container\n class=\"min-h-[7.375rem]\"\n [class.hidden]=\"hasError()\"\n></div>\n@if (hasError()) {\n <p\n role=\"alert\"\n class=\"text-body-s text-tui-text-negative\"\n >\n \u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u00AB\u042F \u043D\u0435 \u0440\u043E\u0431\u043E\u0442\u00BB.\n <button\n tuiLink\n type=\"button\"\n (click)=\"retry()\"\n >\n \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C\n </button>\n </p>\n}\n" }]
|
|
12642
|
-
}], ctorParameters: () => [] });
|
|
12643
|
-
|
|
12644
12332
|
/**
|
|
12645
12333
|
* Компонент формы обратной связи.
|
|
12646
12334
|
*/
|
|
@@ -12712,7 +12400,7 @@ class ScFeedbackFormComponent {
|
|
|
12712
12400
|
}
|
|
12713
12401
|
}));
|
|
12714
12402
|
/**
|
|
12715
|
-
* Поле ввода
|
|
12403
|
+
* Поле ввода для recaptcha.
|
|
12716
12404
|
*/
|
|
12717
12405
|
this.recaptchaControl = new FormControl(null, Validators.required);
|
|
12718
12406
|
/**
|
|
@@ -12754,10 +12442,8 @@ class ScFeedbackFormComponent {
|
|
|
12754
12442
|
}),
|
|
12755
12443
|
// eslint-disable-next-line rxjs/no-implicit-any-catch
|
|
12756
12444
|
catchError((error) => {
|
|
12757
|
-
// Токен капчи одноразовый: для повторной отправки нужна новая проверка.
|
|
12758
|
-
this.recaptchaControl.reset();
|
|
12759
12445
|
this.form.markAllAsTouched();
|
|
12760
|
-
const { errors, message } =
|
|
12446
|
+
const { errors, message } = error.error;
|
|
12761
12447
|
if (errors) {
|
|
12762
12448
|
Object.keys(errors).forEach((key) => {
|
|
12763
12449
|
const control = this.form.get(key);
|
|
@@ -12794,6 +12480,16 @@ class ScFeedbackFormComponent {
|
|
|
12794
12480
|
* Список стран.
|
|
12795
12481
|
*/
|
|
12796
12482
|
this.countries = getCountries();
|
|
12483
|
+
/**
|
|
12484
|
+
* Это решение ошибки #4940, было @see [предложено](https://github.com/DethAriel/ng-recaptcha/issues/123#issuecomment-426112101) автором {@link RecaptchaComponent}.
|
|
12485
|
+
*/
|
|
12486
|
+
RecaptchaComponent.prototype.ngOnDestroy = function () {
|
|
12487
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
12488
|
+
if (this['subscription']) {
|
|
12489
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/dot-notation
|
|
12490
|
+
this['subscription'].unsubscribe();
|
|
12491
|
+
}
|
|
12492
|
+
};
|
|
12797
12493
|
merge(this.user$, this.accepted$.pipe(tap((files) => {
|
|
12798
12494
|
this.form.controls.files.reset([]);
|
|
12799
12495
|
this.onUploadFile(files);
|
|
@@ -12917,7 +12613,7 @@ class ScFeedbackFormComponent {
|
|
|
12917
12613
|
return ScPhoneService.isValidPhoneNumberForMessenger(value);
|
|
12918
12614
|
}
|
|
12919
12615
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFeedbackFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12920
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFeedbackFormComponent, isStandalone: true, selector: "sc-feedback-form", inputs: { slugInput: { classPropertyName: "slugInput", publicName: "slug", isSignal: true, isRequired: false, transformFunction: null }, fieldsInput: { classPropertyName: "fieldsInput", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickOffer: "clickOffer", sendSuccess: "sendSuccess" }, ngImport: i0, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- \u041A\u0430\u043F\u0447\u0430 -->\n @if (form.get('recaptcha'); as recaptcha) {\n <div\n class=\"mb-3 max-h-[7.5rem] overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': recaptcha.valid }\"\n [attr.inert]=\"recaptcha.valid ? '' : null\"\n >\n <sc-smart-captcha formControlName=\"recaptcha\" />\n </div>\n @if (recaptcha.getError('serverResponse'); as serverErrors) {\n <tui-error [error]=\"serverErrors.join(' ')\" />\n }\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: TuiError, selector: "tui-error", inputs: ["error"] }, { kind: "pipe", type: TuiFieldErrorPipe, name: "tuiFieldError" }, { kind: "ngmodule", type: ScFormFieldsModule }, { kind: "component", type: ScSuggestionFieldComponent, selector: "sc-suggestion-field", inputs: ["type"], outputs: ["selectedClick"] }, { kind: "ngmodule", type: TuiInputModule }, { kind: "component", type: i3.TuiInputComponent, selector: "tui-input" }, { kind: "directive", type: i3.TuiInputDirective, selector: "tui-input" }, { kind: "ngmodule", type: TuiInputPhoneModule }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: TuiButtonLoading, selector: "[tuiButton][loading],[tuiIconButton][loading]", inputs: ["size", "loading"] }, { kind: "directive", type: TuiLabel, selector: "label[tuiLabel]" }, { kind: "component", type: ScSmartCaptchaComponent, selector: "sc-smart-captcha" }, { kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TuiTextareaModule }, { kind: "component", type: i3.TuiTextareaComponent, selector: "tui-textarea", inputs: ["rows", "maxLength", "expandable"] }, { kind: "directive", type: i3.TuiTextareaDirective, selector: "tui-textarea" }, { kind: "component", type: TuiCheckbox, selector: "input[type=\"checkbox\"][tuiCheckbox]", inputs: ["size"] }, { kind: "directive", type: TuiTitle, selector: "[tuiTitle]", inputs: ["tuiTitle"] }, { kind: "component", type: i2$1.TuiFile, selector: "tui-file,a[tuiFile],button[tuiFile]", inputs: ["file", "state", "size", "showDelete", "showSize", "leftContent"], outputs: ["remove"] }, { kind: "component", type: i2$1.TuiInputFiles, selector: "label[tuiInputFiles]" }, { kind: "component", type: i2$1.TuiFilesComponent, selector: "tui-files", inputs: ["max", "expanded"], outputs: ["expandedChange"] }, { kind: "pipe", type: i2$1.TuiFileRejectedPipe, name: "tuiFileRejected" }, { kind: "directive", type: i2$1.TuiInputFilesDirective, selector: "input[tuiInputFiles]", outputs: ["reject"] }, { kind: "component", type: TuiInputPhoneInternational, selector: "input[tuiInputPhoneInternational]", inputs: ["countrySearch", "countries", "countryIsoCode"], outputs: ["countryIsoCodeChange"] }, { kind: "component", type: i1$2.TuiTextfieldComponent, selector: "tui-textfield:not([multi])" }, { kind: "pipe", type: TuiSortCountriesPipe, name: "tuiSortCountries" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12616
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFeedbackFormComponent, isStandalone: true, selector: "sc-feedback-form", inputs: { slugInput: { classPropertyName: "slugInput", publicName: "slug", isSignal: true, isRequired: false, transformFunction: null }, fieldsInput: { classPropertyName: "fieldsInput", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickOffer: "clickOffer", sendSuccess: "sendSuccess" }, ngImport: i0, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- recaptcha -->\n @if (form.get('recaptcha')) {\n <div\n class=\"mb-3 max-h-20 overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': form.get('recaptcha')?.valid }\"\n >\n <re-captcha formControlName=\"recaptcha\" />\n </div>\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: TuiError, selector: "tui-error", inputs: ["error"] }, { kind: "pipe", type: TuiFieldErrorPipe, name: "tuiFieldError" }, { kind: "ngmodule", type: ScFormFieldsModule }, { kind: "component", type: ScSuggestionFieldComponent, selector: "sc-suggestion-field", inputs: ["type"], outputs: ["selectedClick"] }, { kind: "ngmodule", type: TuiInputModule }, { kind: "component", type: i3.TuiInputComponent, selector: "tui-input" }, { kind: "directive", type: i3.TuiInputDirective, selector: "tui-input" }, { kind: "ngmodule", type: TuiInputPhoneModule }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: TuiButtonLoading, selector: "[tuiButton][loading],[tuiIconButton][loading]", inputs: ["size", "loading"] }, { kind: "directive", type: TuiLabel, selector: "label[tuiLabel]" }, { kind: "ngmodule", type: RecaptchaFormsModule }, { kind: "directive", type: i4$3.RecaptchaValueAccessorDirective, selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]" }, { kind: "ngmodule", type: RecaptchaModule }, { kind: "component", type: i4$3.RecaptchaComponent, selector: "re-captcha", inputs: ["id", "siteKey", "theme", "type", "size", "tabIndex", "badge", "errorMode"], outputs: ["resolved", "error", "errored"], exportAs: ["reCaptcha"] }, { kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TuiTextareaModule }, { kind: "component", type: i3.TuiTextareaComponent, selector: "tui-textarea", inputs: ["rows", "maxLength", "expandable"] }, { kind: "directive", type: i3.TuiTextareaDirective, selector: "tui-textarea" }, { kind: "component", type: TuiCheckbox, selector: "input[type=\"checkbox\"][tuiCheckbox]", inputs: ["size"] }, { kind: "directive", type: TuiTitle, selector: "[tuiTitle]", inputs: ["tuiTitle"] }, { kind: "component", type: i2$1.TuiFile, selector: "tui-file,a[tuiFile],button[tuiFile]", inputs: ["file", "state", "size", "showDelete", "showSize", "leftContent"], outputs: ["remove"] }, { kind: "component", type: i2$1.TuiInputFiles, selector: "label[tuiInputFiles]" }, { kind: "component", type: i2$1.TuiFilesComponent, selector: "tui-files", inputs: ["max", "expanded"], outputs: ["expandedChange"] }, { kind: "pipe", type: i2$1.TuiFileRejectedPipe, name: "tuiFileRejected" }, { kind: "directive", type: i2$1.TuiInputFilesDirective, selector: "input[tuiInputFiles]", outputs: ["reject"] }, { kind: "component", type: TuiInputPhoneInternational, selector: "input[tuiInputPhoneInternational]", inputs: ["countrySearch", "countries", "countryIsoCode"], outputs: ["countryIsoCodeChange"] }, { kind: "component", type: i1$2.TuiTextfieldComponent, selector: "tui-textfield:not([multi])" }, { kind: "pipe", type: TuiSortCountriesPipe, name: "tuiSortCountries" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
12921
12617
|
}
|
|
12922
12618
|
__decorate([
|
|
12923
12619
|
tuiPure
|
|
@@ -12937,7 +12633,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
12937
12633
|
TuiButton,
|
|
12938
12634
|
TuiButtonLoading,
|
|
12939
12635
|
TuiLabel,
|
|
12940
|
-
|
|
12636
|
+
RecaptchaFormsModule,
|
|
12637
|
+
RecaptchaModule,
|
|
12941
12638
|
TuiLink,
|
|
12942
12639
|
NgIf,
|
|
12943
12640
|
TuiTextareaModule,
|
|
@@ -12947,7 +12644,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
12947
12644
|
TuiInputPhoneInternational,
|
|
12948
12645
|
...TuiTextfield,
|
|
12949
12646
|
TuiSortCountriesPipe,
|
|
12950
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!--
|
|
12647
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- recaptcha -->\n @if (form.get('recaptcha')) {\n <div\n class=\"mb-3 max-h-20 overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': form.get('recaptcha')?.valid }\"\n >\n <re-captcha formControlName=\"recaptcha\" />\n </div>\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n" }]
|
|
12951
12648
|
}], ctorParameters: () => [], propDecorators: { isValidPhoneNumberForMessenger: [] } });
|
|
12952
12649
|
|
|
12953
12650
|
/**
|
|
@@ -13534,5 +13231,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
13534
13231
|
* Generated bundle index. Do not edit.
|
|
13535
13232
|
*/
|
|
13536
13233
|
|
|
13537
|
-
export { AbstractScPriceCard, AuthMethod, CURRENT_COUNTRY_ID, CostWithDiscountComponent, FilesAndDocumentsComponent, FilesAndDocumentsModule, FinishDateTimeTransformerDirective, IDLE_ITEM_STATE, IS_DEFAULT_COUNTRY, MAX_FILES_IN_FORM_INPUT, SC_ALLOW_SELECT_TERMINATED, SC_BANNER_DURATION, SC_BLOCK_INCOMPLETE_ADDRESS, SC_CATALOG_FILTER_PREVIEWS, SC_CATALOG_PRODUCTS_FILTERS, SC_CATALOG_SHOW_PRODUCTS_RECURSIVELY, SC_DATE_FORMATTER, SC_DEBOUNCE_TIME_DEFAULT, SC_DIALOG_SERVICE_TOKEN, SC_ERROR_CHANGE_HANDLER, SC_FAQ_GROUP_QUERY_PARAM, SC_FAQ_QUESTION_ANCHOR_PREFIX, SC_HELP_NOTIFICATION_CLOSE, SC_HELP_NOTIFICATION_LIMIT, SC_HIDDEN_PRINT_ELEMENTS, SC_MANAGER_QR_HANDLER, SC_NOTIFY_WHEN_IN_STOCK_REQUIRED_FIELDS, SC_ORDER_FORM_CONFIG, SC_ORDER_OPTIONS, SC_PAGE_SIZE_OPTIONS$1 as SC_PAGE_SIZE_OPTIONS, SC_SHOW_HELP_NOTIFICATION_IN_PHONE_INPUT,
|
|
13234
|
+
export { AbstractScPriceCard, AuthMethod, CURRENT_COUNTRY_ID, CostWithDiscountComponent, FilesAndDocumentsComponent, FilesAndDocumentsModule, FinishDateTimeTransformerDirective, IDLE_ITEM_STATE, IS_DEFAULT_COUNTRY, MAX_FILES_IN_FORM_INPUT, SC_ALLOW_SELECT_TERMINATED, SC_BANNER_DURATION, SC_BLOCK_INCOMPLETE_ADDRESS, SC_CATALOG_FILTER_PREVIEWS, SC_CATALOG_PRODUCTS_FILTERS, SC_CATALOG_SHOW_PRODUCTS_RECURSIVELY, SC_DATE_FORMATTER, SC_DEBOUNCE_TIME_DEFAULT, SC_DIALOG_SERVICE_TOKEN, SC_ERROR_CHANGE_HANDLER, SC_FAQ_GROUP_QUERY_PARAM, SC_FAQ_QUESTION_ANCHOR_PREFIX, SC_HELP_NOTIFICATION_CLOSE, SC_HELP_NOTIFICATION_LIMIT, SC_HIDDEN_PRINT_ELEMENTS, SC_MANAGER_QR_HANDLER, SC_NOTIFY_WHEN_IN_STOCK_REQUIRED_FIELDS, SC_ORDER_FORM_CONFIG, SC_ORDER_OPTIONS, SC_PAGE_SIZE_OPTIONS$1 as SC_PAGE_SIZE_OPTIONS, SC_SHOW_HELP_NOTIFICATION_IN_PHONE_INPUT, SC_USER_CITY_INFO, SC_USER_INFO, SC_USER_PROVIDERS, SC_VERIFICATION_CODE_TIMEOUT, ScAccordionComponent, ScAccordionContentDirective, ScAccordionModule, ScAddContactDialogComponent, ScAddContragentBankAccountsDialogComponent, ScAddContragentDialogComponent, ScAddDeliveryAddressDialogComponent, ScAddOrEditingCartItemDialogComponent, ScAddOrEditingCartItemFormComponent, ScAddressQualityDirective, ScAddressQualityService, ScAddressesSelectionFieldComponent, ScAuthModule, ScBannerComponent, ScBannerModule, ScBrandsListComponent, ScBrandsListModule, ScCartAddProductsFromCsvDialogComponent, ScCatalogFilterCollapsibleComponent, ScCatalogFiltersComponent, ScCatalogModule, ScCategoryCardComponent, ScConfirmAlertComponent, ScContactsAccordionComponent, ScContactsModule, ScContragentsAccordionComponent, ScContragentsAccordionItemComponent, ScContragentsModule, ScDeliveryAddressAccordionComponent, ScDeliveryAddressAccordionItemComponent, ScDeliveryAddressModule, ScDownloadPriceListComponent, ScDraftComponent, ScDraftExpirationClockService, ScDraftListHelper, ScDraftListUpdatesService, ScEmailLinkDirective, ScErrorBlockStatusComponent, ScErrorHandlerComponent, ScFavoriteButtonComponent, ScFeedbackFormComponent, ScFocusFirstInvalidFieldDirective, ScFormFieldsModule, ScFormatDatePipe, ScFrequentlyAskedQuestionsComponent, ScFrequentlyAskedQuestionsGroupSelectorComponent, ScFrequentlyAskedQuestionsWithGroupsComponent, ScGratitudeComponent, ScHelpNotificationService, ScHoverImageCarouselComponent, ScInputQuantityComponent, ScLinks, ScManagerCardComponent, ScManagerCardPushComponent, ScNewContactFormComponent, ScNewContragentBankAccountsFormComponent, ScNewContragentFormComponent, ScNewOrderItemsComponent, ScNewsCardComponent, ScNewsCardSkeletonComponent, ScNewsListComponent, ScNewsModule, ScNextInputFocusDirective, ScNextInputFocusModule, ScNoindexDirective, ScNoindexWrapperComponent, ScNotifyWhenInStockDialogComponent, ScOrderAccessorDirective, ScOrderFormComponent, ScOrderItemComponent, ScOrderItemsListByStockComponent, ScOrderItemsListComponent, ScOrderItemsListWithActionsComponent, ScOrderModule, ScPaginationLinksComponent, ScPaymentStatusComponent, ScPersonalDataProcessingPolicyComponent, ScPhoneFormatPipe, ScPreviewSampleComponent, ScPreviewSampleModule, ScPreviewSamplesMosquitoComponent, ScPriceCardComponent, ScPriceCardInlineComponent, ScPriceHistoryComponent, ScPriceListPaginationComponent, ScPriceWarehouseStockComponent, ScPrintDirective, ScPrintService, ScPrivacyPolicyComponent, ScProductInAllWarehousesPipe, ScProfileAccordionsContentComponent, ScProfileModule, ScProfstroyActualizationPanelComponent, ScProfstroyBadgeComponent, ScProfstroyDraftBadgesComponent, ScProfstroyDraftCreateDialogComponent, ScProfstroyDraftHelper, ScProfstroyDraftState, ScPublicOfferComponent, ScQRCodeDialogComponent, ScQRCodeModule, ScResetUserPasswordComponent, ScResourcePreviewComponent, ScSandwichComponent, ScSandwichM2Component, ScSandwichM2SkeletonComponent, ScSandwichSkeletonComponent, ScSelectOnFocusinDirective, ScSeoTagsComponent, ScShareButtonComponent, ScShareDialogComponent, ScShareMessengersLinksComponent, ScShareService, ScSignInFormByEmailComponent, ScSignInFormByPhoneComponent, ScSignInFormComponent, ScSignUpFormComponent, ScSimpleSignUpFormComponent, ScSuggestionFieldComponent, ScTelLinkDirective, ScTerminalLinkDirective, ScUpdateUserInfoDialogComponent, ScUserManagersComponent, ScUserModule, ScUserPhoneApproveDialogComponent, ScVerificationModule, ScVerificationPhoneCheckFormComponent, TreeDirective, TreeIconService, TreeLoaderService, TreeTopDirective, cleanupRecaptchaArtifacts, phoneValidator, scAtLeastOneRequiredValidator, scBicValidator, scClientUiIconsName, scCorrespondentAccountValidator, scGetCurrentRoute, scGetFaqGroupQueryParams, scGetFaqQuestionAnchor, scGetFaqQuestionIdFromAnchor, scPasswordConfirmMatchingValidator, stepValidator, tuiDateValueTransformerDefaultProvider };
|
|
13538
13235
|
//# sourceMappingURL=snabcentr-client-ui.mjs.map
|