Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/js/catalog/product-selector/src/search-input/
Upload File :
Current File : /var/www/homesaver/www/bitrix/js/catalog/product-selector/src/search-input/input-barcode.js

import { Extension, Loc, Tag, Type, Text, Dom, Event, userOptions, ajax } from 'main.core';
import { EventEmitter } from 'main.core.events';
import { ProductModel } from 'catalog.product-model';
import { ProductSearchInputLimitedFooter } from './footer-limited';
import { ProductSearchInputDefault } from './input-default';
import { ProductSelector } from 'catalog.product-selector';
import { BarcodeScanner } from 'catalog.barcode-scanner';
import { ProductSearchInputBarcodeFooter } from './footer-barcode';
import { QrAuthorization } from 'ui.qrauthorization';
import { SelectorErrorCode } from '../selector-error-code';
import { Guide } from 'ui.tour';
import 'ui.notification';
import 'spotlight';

export class ProductSearchInputBarcode extends ProductSearchInputDefault
{
	onFocusHandler = this.handleFocusEvent.bind(this);
	onBlurHandler = this.handleBlurEvent.bind(this);

	constructor(id, options = {})
	{
		super(id, options);

		this.focused = false;
		this.settingsCollection = Extension.getSettings('catalog.product-selector');

		this.isInstalledMobileApp = (
			this.selector.getConfig('IS_INSTALLED_MOBILE_APP')
			|| this.settingsCollection.get('isInstallMobileApp')
		);

		if (
			!this.settingsCollection.get('isEnabledQrAuth')
			&& this.selector.getConfig('ENABLE_BARCODE_QR_AUTH', true)
		)
		{
			this.qrAuth = new QrAuthorization();
			this.qrAuth.createQrCodeImage();
		}
	}

	layout(): HTMLElement
	{
		const block = super.layout();
		Dom.append(this.#getBarcodeIcon(), block);
		this.getNameInput().className += ' catalog-product-field-input-barcode';
		Event.bind(this.getNameInput(), 'focus', this.onFocusHandler);
		Event.bind(this.getNameInput(), 'blur', this.onBlurHandler);

		return block;
	}

	getDialogParams(): Object
	{
		const entity = {
			id: 'barcode',
			options: {
				iblockId: this.model.getIblockId(),
				basePriceId: this.model.getBasePriceId(),
				currency: this.model.getCurrency(),
			},
			dynamicLoad: true,
			dynamicSearch: true,
			searchFields: [
				{ name: 'title', type: 'string', system: true, searchable: false },
			],
		};

		const restrictedProductTypes = this.selector.getConfig('RESTRICTED_PRODUCT_TYPES', null);
		if (!Type.isNil(restrictedProductTypes))
		{
			entity.options.restrictedProductTypes = restrictedProductTypes;
		}

		const params = {
			id: `${this.id}_barcode`,
			height: 300,
			width: Math.max(this.getNameInput()?.offsetWidth, 565),
			context: null,
			targetNode: this.getNameInput(),
			enableSearch: false,
			multiple: false,
			dropdownMode: true,
			searchTabOptions: {
				stub: true,
				stubOptions: {
					title: Tag.message`${'CATALOG_SELECTOR_IS_EMPTY_TITLE'}`,
					subtitle: this.isAllowedCreateProduct()
						? Tag.message`${'CATALOG_SELECTOR_IS_EMPTY_SUBTITLE'}`
						: '',
					arrow: true,
				},
			},
			events: {
				'Item:onSelect': this.onProductSelect.bind(this),
				'Search:onItemCreateAsync': this.createProduct.bind(this),
				'ChangeItem:onClick': this.showChangeNotification.bind(this),
			},
			entities: [entity],
		};

		if (this.model.getSkuId() && !Type.isStringFilled(this.model.getField(this.inputName)))
		{
			params.preselectedItems = [['barcode', this.model.getSkuId()]];
		}

		if (Type.isObject(this.settingsCollection.get('limitInfo')))
		{
			params.footer = ProductSearchInputLimitedFooter;
		}
		else
		{
			params.footer = ProductSearchInputBarcodeFooter;
			params.footerOptions = {
				onScannerClick: this.#startMobileScanner.bind(this),
				isEmptyBarcode: !this.model || !this.model.isCatalogExisted(),
				inputName: this.inputName,
				errorAdminHint: this.settingsCollection.get('errorAdminHint'),
				allowEditItem: this.isAllowedEditProduct(),
				allowCreateItem: this.isAllowedCreateProduct(),
				creationLabel: Loc.getMessage('CATALOG_SELECTOR_SEARCH_POPUP_FOOTER_CREATE_WITH_BARCODE'),
				currentValue: this.getValue(),
				searchOptions: {
					allowCreateItem: this.isAllowedCreateProduct(),
					footerOptions: {
						label: Loc.getMessage('CATALOG_SELECTOR_SEARCH_POPUP_FOOTER_CREATE_WITH_BARCODE'),
					},
				},
			};
		}

		return params;
	}

	handleFocusEvent(): void
	{
		this.focused = true;
	}

	handleBlurEvent(): void
	{
		this.focused = false;
	}

	isSearchEnabled(): boolean
	{
		return true;
	}

	showDetailLink(): boolean
	{
		return false;
	}

	getNameTag(): ?HTMLElement
	{
		return null;
	}

	handleClickNameInput(event: UIEvent): void
	{
		if (this.qrAuth && this.getDialog().getContainer())
		{
			if (!Dom.hasClass(this.getDialog().getContainer(), 'qr-barcode-info'))
			{
				Dom.addClass(this.getDialog().getContainer(), 'qr-barcode-info');
			}

			if (this.getDialog().getContainer())
			{
				Dom.append(this.#layoutMobileQrPopup(), this.getDialog().getContainer());
			}
		}

		super.handleClickNameInput(event);
	}

	showItems(): void
	{
		this.searchInDialog();
	}

	onChangeValue(value: string): void
	{
		const fields = {};

		this.getNameInput().title = value;
		this.getNameInput().value = value;

		fields[this.inputName] = value;

		EventEmitter.emit('ProductSelector::onBarcodeChange', {
			rowId: this.selector.getRowId(),
			fields,
		});

		this.selector.emit('onBarcodeChange', { value });

		if (this.selector.isEnabledAutosave())
		{
			this.selector.getModel().setField(this.inputName, value);
			this.selector.getModel().showSaveNotifier(
				`barcodeChanger_${this.selector.getId()}`,
				{
					title: Loc.getMessage('CATALOG_SELECTOR_SAVING_NOTIFICATION_BARCODE'),
					disableCancel: true,
					events: {
						onSave: () => {
							if (this.selector)
							{
								this.selector.getModel().save([this.inputName]);
							}
						},
					},
				},
			);
		}
	}

	searchInDialog(): void
	{
		this.#searchByBarcode(this.getSearchQuery());
	}

	createProductModelFromSearchQuery(searchQuery: string): ProductModel
	{
		const model = super.createProductModelFromSearchQuery(searchQuery);
		model.setField(ProductSelector.INPUT_FIELD_NAME, Loc.getMessage('CATALOG_SELECTOR_NEW_BARCODE_PRODUCT_NAME'));
		model.setField(this.inputName, searchQuery);

		return model;
	}

	checkCreationModel(creationModel: ProductModel): boolean
	{
		if (!Type.isStringFilled(creationModel.getField(ProductSelector.INPUT_FIELD_NAME)))
		{
			this.model.getErrorCollection().setError(
				SelectorErrorCode.NOT_SELECTED_PRODUCT,
				Loc.getMessage('CATALOG_SELECTOR_EMPTY_TITLE'),
			);

			return false;
		}

		return true;
	}

	getPlaceholder(): string
	{
		return (
			this.isSearchEnabled() && this.model.isEmpty()
				? Loc.getMessage('CATALOG_SELECTOR_BEFORE_SEARCH_BARCODE_TITLE')
				: Loc.getMessage('CATALOG_SELECTOR_VIEW_BARCODE_TITLE')
		);
	}

	handleClearIconClick(event: UIEvent): void
	{
		this.toggleIcon(this.getClearIcon(), 'none');
		this.onChangeValue('');

		this.selector.focusName();

		event.stopPropagation();
		event.preventDefault();
	}

	applyScannerData(barcode: string): void
	{
		this.#getProductIdByBarcode(barcode)
			.then((response) => {
				const productId = response?.data;
				if (productId)
				{
					this.#selectScannedBarcodeProduct(productId);
				}
				else
				{
					this.#searchByBarcode(barcode);
				}
				this.getNameInput().value = Text.encode(barcode);
			})
			.catch((error) => console.error(error));
	}

	removeSpotlight(): void
	{
		if (this.spotlight)
		{
			this.spotlight.close();
		}
	}

	removeQrAuth(): void
	{
		const mobilePopup = this.getDialog().getContainer()?.querySelector('[data-role="mobile-popup"]');
		if (mobilePopup)
		{
			Dom.remove(mobilePopup);
			if (Dom.hasClass(this.getDialog().getContainer(), 'qr-barcode-info'))
			{
				Dom.removeClass(this.getDialog().getContainer(), 'qr-barcode-info');
			}
		}

		this.qrAuth = null;
	}

	destroy(): void
	{
		Event.unbind(this.getNameInput(), 'focus', this.onFocusHandler);
		Event.unbind(this.getNameInput(), 'blur', this.onBlurHandler);
	}

	#searchByBarcode(searchQuery: string = ''): void
	{
		if (!this.selector.isProductSearchEnabled())
		{
			return;
		}

		const dialog = this.getDialog();
		if (!dialog)
		{
			return;
		}

		dialog.removeItems();
		if (!Type.isStringFilled(searchQuery) && this.model && this.model.isCatalogExisted())
		{
			dialog.setPreselectedItems([['barcode', this.model.getSkuId()]]);
			dialog.loadState = 'UNSENT';
			dialog.load();
		}

		dialog.show();
		dialog.search(searchQuery);
	}

	#startMobileScanner(event): void
	{
		if (this.isInstalledMobileApp)
		{
			this.#sendMobilePush(event);

			return;
		}

		if (!this.qrAuth)
		{
			this.qrAuth = new QrAuthorization();
			this.qrAuth.createQrCodeImage();
		}

		if (this.getDialog().isOpen())
		{
			this.getDialog().hide();
			this.getDialog().subscribeOnce('onHide', this.handleClickNameInput.bind(this));
		}
		else
		{
			this.handleClickNameInput(event);
		}
	}

	#sendMobilePush(event): void
	{
		event?.preventDefault();
		this.getDialog().hide();
		this.getNameInput().focus();

		if (!this.selector.isEnabledMobileScanning())
		{
			return;
		}

		const token = this.selector.getMobileScannerToken();
		BarcodeScanner.open(token);

		const repeatLink = Tag.render`<span class='ui-notification-balloon-action'>${Loc.getMessage('CATALOG_SELECTOR_SEND_PUSH_ON_SCANNER_NOTIFICATION_REPEAT')}</span>`;
		Event.bind(repeatLink, 'click', this.#sendMobilePush.bind(this));

		const content = Tag.render`
			<div>
				<span>${Loc.getMessage('CATALOG_SELECTOR_SEND_PUSH_ON_SCANNER_NOTIFICATION')}</span>
				${repeatLink}
			</div>
		`;

		BX.UI.Notification.Center.notify({
			content,
			category: 'sending_push_barcode_scanner_notification',
			autoHideDelay: 5000,
		});
	}

	#getProductIdByBarcode(barcode: string): Promise
	{
		return ajax.runAction(
			'catalog.ProductSelector.#getProductIdByBarcode',
			{
				json: {
					barcode,
				},
			},
		);
	}

	#selectScannedBarcodeProduct(productId): void
	{
		this.toggleIcon(this.getSearchIcon(), 'none');
		this.clearErrors();
		if (this.selector)
		{
			this.selector.onProductSelect(
				productId,
				{
					isNew: false,
					immutableFields: [],
				},
			);

			this.selector.clearLayout();
			this.selector.layout();
		}

		this.cache.delete('dialog');
	}

	#getBarcodeIcon(): HTMLElement
	{
		return this.cache.remember('barcodeIcon', () => {
			const barcodeIcon = Tag.render`
				<button	class="ui-ctl-before warehouse-barcode-icon" title="${Loc.getMessage('CATALOG_SELECTOR_BARCODE_ICON_TITLE')}"></button>
			`;

			if (
				!this.settingsCollection.get('isShowedBarcodeSpotlightInfo')
				&& this.settingsCollection.get('isAllowedShowBarcodeSpotlightInfo')
				&& this.selector.getConfig('ENABLE_INFO_SPOTLIGHT', true)
			)
			{
				this.spotlight = new BX.SpotLight(
					{
						id: 'selector_barcode_scanner_info',
						targetElement: barcodeIcon,
						autoSave: true,
						targetVertex: 'middle-center',
						zIndex: 200,
					},
				);

				this.spotlight.show();

				EventEmitter.subscribe(this.spotlight, 'BX.SpotLight:onTargetEnter', () => {
					const guide = new Guide({
						steps: [
							{
								target: barcodeIcon,
								title: Loc.getMessage('CATALOG_SELECTOR_BARCODE_SCANNER_FIRST_TIME_HINT_TITLE'),
								text: Loc.getMessage('CATALOG_SELECTOR_BARCODE_SCANNER_FIRST_TIME_HINT_TEXT'),
							},
						],
						onEvents: true,
					});

					guide.getPopup().setAutoHide(true);
					guide.showNextStep();
					this.selector.setConfig('ENABLE_INFO_SPOTLIGHT', false);
					this.selector.emit('onSpotlightClose', {});
				});
			}

			Event.bind(barcodeIcon, 'click', (event) => {
				event.preventDefault();
				if (this.qrAuth)
				{
					this.handleClickNameInput(event);
				}
				else
				{
					this.#startMobileScanner(event);
				}
			});

			return barcodeIcon;
		});
	}

	#layoutMobileQrPopup(): HTMLElement
	{
		return this.cache.remember('qrMobilePopup', () => {
			const closeIcon = Tag.render`<span class="popup-window-close-icon"></span>`;
			Event.bind(closeIcon, 'click', this.#closeMobilePopup.bind(this));

			let sendButton = '';
			let helpButton = '';
			if (top.BX.Helper)
			{
				helpButton = Tag.render`
					<a class="product-selector-mobile-popup-link ui-btn ui-btn-light-border ui-btn-round">
						${Loc.getMessage('CATALOG_SELECTOR_MOBILE_POPUP_HELP_BUTTON')}
					</a>
				`;
				Event.bind(helpButton, 'click', () => {
					top.BX.Helper.show('redirect=detail&code=14956818');
				});

				sendButton = Tag.render`
					<a class="product-selector-mobile-popup-link ui-btn ui-btn-link">
						${Loc.getMessage('CATALOG_SELECTOR_MOBILE_POPUP_SEND_PUSH_BUTTON')}
					</a>
				`;

				Event.bind(sendButton, 'click', () => {
					top.BX.Helper.show('redirect=detail&code=15042444');
				});
			}

			return Tag.render`
				<div data-role="mobile-popup">
					<div class="product-selector-mobile-popup-overlay"></div>
					<div class="product-selector-mobile-popup-content">
						<div class="product-selector-mobile-popup-title">${Loc.getMessage('CATALOG_SELECTOR_MOBILE_POPUP_TITLE')}</div>
						<div class="product-selector-mobile-popup-text">${Loc.getMessage('CATALOG_SELECTOR_MOBILE_POPUP_INSTRUCTION')}</div>
						<div class="product-selector-mobile-popup-qr">
							${this.qrAuth.getQrNode()}
						</div>
						<div class="product-selector-mobile-popup-link-container">
							${helpButton}
							${sendButton}
						</div>
						${closeIcon}
					</div>
				</div>
			`;
		});
	}

	#closeMobilePopup(): void
	{
		this.removeQrAuth();

		ajax
			.runAction(
				'catalog.ProductSelector.isInstalledMobileApp',
				{
					json: {},
				},
			)
			.then((result) => {
				this.selector.emit('onBarcodeQrClose', {});

				if (result.data === true)
				{
					this.selector.emit('onBarcodeScannerInstallChecked', {});
					this.isInstalledMobileApp = true;
				}
			}).catch((error) => console.error(error))
		;

		userOptions.save('product-selector', 'barcodeQrAuth', 'showed', 'Y');
	}
}