Your IP : 18.225.72.200


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/mail/sender-editor/src/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/mail/sender-editor/src/smtp-editor.js

import { Loc, Tag, Dom, ready, ajax, Type } from 'main.core';
import { Layout } from 'ui.sidepanel.layout';
import { LayoutForm } from 'ui.layout-form';
import './css/style.css';
import 'ui.hint';
import 'ui.alerts';
import { SaveButton } from "ui.buttons";
import { AliasEditor } from './alias-editor';

type SenderData = {
	name: string,
	isPublic: boolean;
	email: string,
	server: string,
	port: number,
	protocol: string,
	limit: null | number,
};

type Options = {
	senderId?: number,
	setSenderCallback?: Function,
	addSenderCallback?: Function,
	onClose?: Function,
};

const SidePanel = BX.SidePanel;
const emailRegularEx = /\S+@\S+\.\S+/;
const deleteMessage = 'mail-mailbox-config-delete';
const senderType = 'sender';

export class SmtpEditor
{
	constructor(options: Options)
	{
		if (options)
		{
			if (options.senderId && Type.isInteger(options.senderId) && options.senderId > 0)
			{
				this.title = Loc.getMessage('UI_MAIL_SMTP_SLIDER_EDIT_TITLE');
				this.senderId = options.senderId;
			}
			else
			{
				this.title = Loc.getMessage('UI_MAIL_SMTP_SLIDER_ADD_TITLE');
			}

			this.setSender = options.setSenderCallback ?? null;
			this.addSender = options.addSenderCallback ?? null;
		}
		this.onCloseAction = options.onClose ?? null;

		this.#createContentContainer();
		this.#prepareNecessaryFields();
	}

	static openSlider(options: Options): void {
		const instance = new SmtpEditor(options);
		SidePanel.Instance.open('smtpSender', {
			width: 760,
			cacheable: false,
			contentCallback: () => {
				return instance.getContentCallback();
			},
			events: {
				onLoad: () => {
					ready(() => {
						new LayoutForm({ container: instance.limitSection });
					});
				},
			},
		});
	}

	getContentCallback(): Layout
	{
		return Layout.createContent({
			extensions: [
				'ui.mail.sender-editor',
			],
			title: this.title,
			design: {
				section: false,
				margin: false,
			},
			content: () => {
				if (this.senderId > 0)
				{
					return this.loadSender(this.senderId);
				}

				return ajax.runAction('main.api.mail.sender.getDefaultSenderName')
					.then((response) => {
						this.#setUserName(response.data);

						return this.getContentContainer();
					})
					.catch(() => {
						return this.getContentContainer();
					})
				;
			},
			buttons: ({ cancelButton, Button }) => {
				const buttonArray = [];
				const saveButton = new SaveButton({
					onclick: () => {
						this.#save(saveButton);
					},
				});
				buttonArray.push(saveButton);

				if (this.senderId > 0)
				{
					this.disconnectButton = new Button({
						text: Loc.getMessage('UI_MAIL_SMTP_SLIDER_DISCONNECT_BUTTON'),
						color: BX.UI.Button.Color.DANGER,
						onclick: () => {
							this.#showDisconnectDialog();
						},
					});
					buttonArray.push(this.disconnectButton);
				}
				buttonArray.push(cancelButton);

				return buttonArray;
			},
		});
	}

	loadSender(senderId: number): Promise
	{
		return ajax.runAction(
			'main.api.mail.sender.getSenderData',
			{
				data: { senderId },
			},
		).then((response) => {
			this.#setFieldData(response.data);

			return this.getContentContainer();
		}).catch(() => {
			return this.getContentContainer();
		});
	}

	#setFieldData(senderData: SenderData): void
	{
		this.nameField.value = senderData.name;
		this.accessField.checked = senderData.isPublic;
		this.emailField.value = senderData.email;
		this.serverField.value = senderData.server;
		this.portField.value = senderData.port;
		if (senderData.protocol === 'smtps')
		{
			this.sslField.checked = true;
		}

		if (Type.isNumber(senderData.limit) && senderData.limit > 0)
		{
			this.senderLimitCheckbox.checked = true;
			this.senderLimitField.value = senderData.limit;
		}
	}

	#showDisconnectDialog(): void
	{
		top.BX.UI.Dialogs.MessageBox.show({
			message: Loc.getMessage('UI_MAIL_SMTP_SLIDER_DISCONNECT_MESSAGE'),
			modal: true,
			buttons: BX.UI.Dialogs.MessageBoxButtons.OK_CANCEL,
			onOk: (messageBox) => {
				this.#disconnect();
				messageBox.close();
			},
			onCancel: (messageBox) => {
				messageBox.close();
			},
		});
	}

	#save(button: SaveButton): void
	{
		this.#clearInvalidFields();
		if (this.#hasInvalidFields())
		{
			return;
		}
		this.#hideAlertNode();
		button.setClocking();
		this.#saveSender()
			.then((response) => {
				const data = response.data;
				if (this.setSender)
				{
					this.setSender(data.senderId, data.name, this.email);
				}

				if (this.addSender)
				{
					const mailbox = [];
					mailbox.name = data.name;
					mailbox.email = this.email;
					this.addSender(mailbox);
				}

				BX.SidePanel.Instance.getTopSlider().close();
				if (!this.senderId && !this.addSender)
				{
					AliasEditor.openSlider({
						senderId: data.senderId,
						email: this.email,
						setSenderCallback: this.setSender,
						onClose: this.onCloseAction,
					});
				}
			})
			.catch((response) => {
				this.#showAlertNode(response.errors[0].message);
				button.setClocking(false);
			})
		;
	}

	#disconnect(): void
	{
		Dom.addClass(this.disconnectButton, 'ui-btn-wait');
		ajax.runAction(
			'main.api.mail.sender.deleteSender',
			{
				data: {
					senderId: this.senderId,
				},
			},
		).then(() => {
			Dom.removeClass(this.disconnectButton, 'ui-btn-wait');
			SidePanel.Instance.getTopSlider().close();
			top.BX.SidePanel.Instance.postMessage(
				window,
				deleteMessage,
				{
					id: this.senderId,
					type: senderType,
				},
			);
		}).catch(() => {
			Dom.removeClass(this.disconnectButton, 'ui-btn-wait');
		});
	}

	#saveSender(): Promise
	{
		this.email = this.emailField.value;

		const data = {
			id: this.senderId ?? null,
			name: this.nameField.value,
			email: this.email,
			smtp: {},
			public: this.accessField.checked ? 'Y' : 'N',
		};

		data.smtp = {
			server: this.serverField.value,
			port: this.portField.value,
			ssl: this.sslField.checked ? this.sslField.value : '',
			login: this.emailField.value,
			password: this.passwordField.value,
			limit: this.senderLimitCheckbox.checked ? this.senderLimitField.value : null,
		};

		return ajax.runAction('main.api.mail.sender.submitSender', {
			data: { data },
		}).then((response) => {
			return response;
		});
	}

	#createContentContainer(): void
	{
		this.#createAlertNode();
		this.#createSenderSection();
		this.#createSmtpServerSection();
		this.#createLimitSection();

		this.contentContainer = Tag.render`
			<div class="ui-form">
				${this.alertNode}
				${this.senderSection}
				${this.smtpServerSection}
				${this.limitSection}
			</div>
		`;
	}

	getContentContainer(): HTMLElement
	{
		return this.contentContainer;
	}

	#createAlertNode(): void
	{
		this.alertNode = Tag.render`
			<div class="ui-alert ui-alert-danger ui-alert-icon-warning" style="display: none">
				<span class="ui-alert-message"></span>
			</div>
		`;
	}

	#createSenderSection(): void
	{
		const { root, nameField, accessField } = Tag.render`
			<div class="ui-slider-section">
				<div class="ui-slider-content-box">
					<div class="ui-slider-heading-4">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_MAIN_SECTION_TITLE')}</div>
					<div class="ui-form-row">
						<div class="ui-ctl-top smtp-sender-name">
							<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_NAME')}</div>
							<span data-hint="${Loc.getMessage('UI_MAIL_SMTP_SLIDER_NAME_HINT')}"></span>
						</div>
						<div class="ui-form-row-inline ui-ctl-w100">
							<div class="ui-form-row">
								<div class="ui-ctl ui-ctl-textbox ui-ctl-w100">
									<input type="text" data-name="name" value="" class="ui-ctl-element" ref="nameField">
								</div>
							</div>
							<div class="ui-form-row">
								<label class="ui-ctl ui-ctl-checkbox">
									<input type="checkbox" class="ui-ctl-element" data-name="access" ref="accessField">
									<div class="ui-ctl-label-text">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_AVAILABLE_TOGGLE')}</div>
									<span data-hint="${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_AVAILABLE_TOGGLE_HINT')}"></span>
								</label>
							</div>
						</div>
					</div>
				</div>
			</div>
		`;
		this.senderSection = root;
		this.nameField = nameField;
		this.accessField = accessField;

		this.hintInstence = top.BX.UI.Hint?.createInstance();
		this.hintInstence.init(this.senderSection);
	}

	#createSmtpServerSection(): void
	{
		this.#createSmtpEmailRow();
		this.#createSmtpServerRow();
		this.#createSmtpPortAndSafeConnectionRow();
		this.#createSmtpPasswordRow();

		this.smtpServerSection = Tag.render`
			<div class="ui-slider-section">
				<div class="ui-slider-content-box">
					<div class="ui-slider-heading-4">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SMTP_SECTION_TITLE')}</div>
					${this.smtpServerRow}
					${this.smtpPortAndSafeConnectionRow}
					${this.smtpEmailRow}
					${this.smtpPasswordRow}
				</div>
			</div>
		`;
	}

	#createSmtpEmailRow(): void
	{
		const { root, emailField } = Tag.render`
			<div class="ui-form-row">
				<div class="ui-ctl-top">
					<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_EMAIL')}</div>
				</div>
				<div class="ui-ctl ui-ctl-textbox ui-ctl-w100">
					<input type="email" name="email" class="ui-ctl-element" data-name="email" placeholder="info@example.com" ref="emailField">
				</div>
			</div>
		`;

		this.smtpEmailRow = root;
		this.emailField = emailField;
	}

	#createSmtpServerRow(): void
	{
		const { root, serverField } = Tag.render`
			<div class="ui-form-row">
				<div class="ui-ctl-top">
					<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SERVER')}</div>
				</div>
				<div class="ui-ctl ui-ctl-textbox ui-ctl-w100">
					<input type="text" name="server" class="ui-ctl-element" data-name="server" placeholder="smtp.example.com" ref="serverField">
				</div>
			</div>
		`;

		this.smtpServerRow = root;
		this.serverField = serverField;
	}

	#createSmtpPortAndSafeConnectionRow(): void
	{
		const { root, portField, sslField } = Tag.render`
			<div class="ui-form-row">
				<div class="ui-ctl-top">
					<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_PORT')}</div>
				</div>
				<div class="ui-form-row-inline" style="margin-bottom: 0">
					<div class="ui-form-row">
						<div class="ui-ctl ui-ctl-textbox ui-ctl-w100">
						<input type="text" 
							class="ui-ctl-element" 
							data-name="port" 
							placeholder="555"
							ref="portField"
						>
						</div>
					</div>
					<div class="ui-form-row">
						<label class="ui-ctl ui-ctl-checkbox">
							<input type="checkbox" class="ui-ctl-element" value="Y" data-name="ssl" ref="sslField">
							<div class="ui-ctl-label-text">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SSL')}</div>
						</label>
					</div>
				</div>
			</div>
		`;

		this.smtpPortAndSafeConnectionRow = root;
		this.portField = portField;
		this.sslField = sslField;
	}

	#createSmtpPasswordRow(): void
	{
		const { root, passwordField } = Tag.render`
			<div class="ui-form-row">
				<div class="ui-ctl-top">
					<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_PASSWORD')}</div>
				</div>
				<div class="ui-ctl ui-ctl-textbox ui-ctl-w100">
					<input type="password" class="ui-ctl-element" data-name="password" ref="passwordField">
				</div>
			</div>
		`;

		this.smtpPasswordRow = root;
		this.passwordField = passwordField;
	}

	#createLimitSection(): void
	{
		const { root, senderLimitCheckbox, senderLimitField } = Tag.render`
			<div class="ui-slider-section">
				<div class="ui-slider-content-box">
					<div class="ui-slider-heading-4">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_LIMIT_SECTION_TITLE')}</div>
					<div class="ui-form-row">
						<div class="ui-form-label" data-form-row-hidden="">
							<label class="ui-ctl ui-ctl-checkbox smtp-editor-limit-checkbox">
								<input type="checkbox" class="ui-ctl-element" data-name="hasLimit" ref="senderLimitCheckbox">
								<div class="ui-ctl-label-text">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_LIMIT_SETTINGS')}</div>
							</label>
						</div>
						<div class="ui-form-row-hidden">
							<div class="ui-form-row">
								<div class="ui-ctl-top">
									<div class="ui-form-label">${Loc.getMessage('UI_MAIL_SMTP_SLIDER_SENDER_LIMIT_TITLE')}</div>
								</div>
								<div class="ui-ctl ui-ctl-textbox ui-ctl-w25">
									<input type="number" class="ui-ctl-element" data-name="limit" value="250" min="0" ref="senderLimitField">
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
		`;

		this.limitSection = root;
		this.senderLimitCheckbox = senderLimitCheckbox;
		this.senderLimitField = senderLimitField;
	}

	#showAlertNode(message: string = null): void
	{
		if (message)
		{
			const spanNode = this.alertNode.querySelector('span');
			spanNode.textContent = message;
		}

		Dom.style(this.alertNode, 'display', 'block');
	}

	#hideAlertNode(): void
	{
		Dom.style(this.alertNode, 'display', 'none');
	}

	#prepareNecessaryFields(): void
	{
		this.requiredFields = [
			{ row: this.smtpEmailRow, input: this.emailField, type: 'email' },
			{ row: this.smtpServerRow, input: this.serverField, type: 'server' },
			{ row: this.smtpPortAndSafeConnectionRow, input: this.portField, type: 'port' },
		];

		if (!this.senderId)
		{
			this.requiredFields.push({
				row: this.smtpPasswordRow,
				input: this.passwordField,
				type: 'pass',
			});
		}
	}

	#hasInvalidFields(): boolean
	{
		let count = 0;
		this.requiredFields.forEach((field) => {
			if (!this.#isInvalidField(field.type, field.input.value))
			{
				return;
			}
			count++;
			Dom.addClass(field.row, 'ui-ctl-warning');
			const errorMessage = this.#getErrorMessage(field.type, field.input.value);
			const invalidField = Tag.render`
				<div class="ui-mail-field-error-message ui-ctl-bottom">${errorMessage}</div>
			`;
			Dom.append(invalidField, field.row);

			if (this.topEmptyNode)
			{
				return;
			}
			this.topEmptyNode = field.row;
			this.topEmptyNode.scrollIntoView();
		});

		return count > 0;
	}

	#clearInvalidFields(): void
	{
		if (!this.requiredFields)
		{
			return;
		}

		this.requiredFields.forEach((field) => {
			Dom.removeClass(field.row, 'ui-ctl-warning');
			const errorMessageFiled = field.row.querySelector('.ui-mail-field-error-message');
			if (Type.isDomNode(errorMessageFiled))
			{
				Dom.remove(errorMessageFiled);
			}
		});
		this.topEmptyNode = null;
		this.invalidFieldNode?.remove();
	}

	#isInvalidField(type: string, input: string | number): boolean
	{
		if (input.length === 0)
		{
			return true;
		}

		if (type === 'port'
			&& (
				!Number.isInteger(Number(input))
				|| input < 0
				|| input > 65535
			)
		)
		{
			return true;
		}

		return type === 'email' && !emailRegularEx.test(input);
	}

	#getErrorMessage(type: string, input: string | number): string
	{
		switch (type)
		{
			case 'email':
				if (Type.isString(input) && input.length > 0)
				{
					return Loc.getMessage('UI_MAIL_SMTP_SLIDER_INVALID_EMAIL');
				}

				return Loc.getMessage('UI_MAIL_SMTP_SLIDER_EMPTY_EMAIL');
			case 'server':
				return Loc.getMessage('UI_MAIL_SMTP_SLIDER_EMPTY_SERVER');
			case 'port':
				return Loc.getMessage('UI_MAIL_SMTP_SLIDER_INVALID_PORT');
			default:
				return Loc.getMessage('UI_MAIL_SMTP_SLIDER_EMPTY_PASSWORD');
		}
	}

	#setUserName(name: string)
	{
		this.nameField.value = name;
	}
}