UNPKG

@salla.sa/twilight-components

Version:
314 lines (308 loc) 14.2 kB
/*! * Crafted with ❤ by Salla */ import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client'; import { M as MailIcon } from './mail.js'; import { d as defineCustomElement$4 } from './salla-button2.js'; import { d as defineCustomElement$3 } from './salla-loading2.js'; import { d as defineCustomElement$2 } from './salla-modal2.js'; var AndroidPhoneIcon = `<!-- Generated by IcoMoon.io --> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <title>android-phone</title> <path d="M22.667 0h-13.333c-2.941 0-5.333 2.392-5.333 5.333v21.333c0 2.941 2.392 5.333 5.333 5.333h13.333c2.941 0 5.333-2.392 5.333-5.333v-21.333c0-2.941-2.392-5.333-5.333-5.333zM25.333 26.667c0 1.471-1.196 2.667-2.667 2.667h-13.333c-1.471 0-2.667-1.196-2.667-2.667v-2.667h18.667zM25.333 21.333h-18.667v-16c0-1.471 1.196-2.667 2.667-2.667h13.333c1.471 0 2.667 1.196 2.667 2.667zM13.333 28h5.333c0.736 0 1.333-0.597 1.333-1.333s-0.597-1.333-1.333-1.333h-5.333c-0.736 0-1.333 0.597-1.333 1.333s0.597 1.333 1.333 1.333z"></path> </svg> `; const sallaVerifyCss = "salla-verify{display:block}.s-verify-input{}.s-verify-input::-webkit-outer-spin-button,.s-verify-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.s-verify-input[type=number]{-moz-appearance:textfield}"; const SallaVerify$1 = /*@__PURE__*/ proxyCustomElement(class SallaVerify extends HTMLElement { constructor() { super(); this.__registerHost(); this.verified = createEvent(this, "verified", 7); this.translationLoaded = false; /** * Should render component without modal */ this.display = 'modal'; /** * Verifying method */ this.type = 'mobile'; /** * should auto reloading the page after success verification */ this.autoReload = true; /** * Once the api verify success, it will be login the customer in web pages */ this.supportWebAuth = true; this.resendAfter = 30; /** * to use: `salla.api.auth.verify` or `salla.profile.verify` */ this.isProfileVerify = false; salla.lang.onLoaded(() => { var _a; this.translationLoaded = true; this.title = salla.lang.get('pages.profile.verify_title') + salla.lang.get('common.elements.' + this.type); (_a = this.modal) === null || _a === void 0 ? void 0 : _a.setTitle(this.title); }); if (this.display == 'inline') { this.modal = { open: () => '', close: () => '', setTitle: () => '' }; return; } //todo:: change this way, now we fire the event from the backend, we should listen to salla.profile.event.onUpdated salla.event.on('profile::verification', data => { var _a; let payload = Array.isArray(data) ? data[0] : data; this.isProfileVerify = true; this.open(payload); this.title = salla.lang.get('pages.profile.verify_title') + salla.lang.get('common.elements.' + payload.type); (_a = this.modal) === null || _a === void 0 ? void 0 : _a.setTitle(this.title); }); salla.event.on('modalClosed', () => { this.resendAfter = 0; this.timer.innerHTML = '30 : 00'; }); } splitNumber(e) { this.resetError(); let data = e.data || e.target.value; // Chrome doesn't get the e.data, it's always empty, fallback to value then. if (!data) return; // Shouldn't happen, just in case. if (data.length === 1) return; // Here is a normal behavior, not a paste action. this.modifyNext(e.target, data); } modifyNext(el, data) { el.value = data[0]; // Apply first item to first input data = data.substring(1); // remove the first char. if (el.nextElementSibling && data.length) { // Do the same with the next element and next data this.modifyNext(el.nextElementSibling, data); } else if (!el.nextElementSibling && data.length === 0) { el.focus(); } else if (el.nextElementSibling && data.length === 0) { el.nextElementSibling.focus(); } } checkAllInputs() { let allFilled = true; for (let i = 0; i < this.otpInputs.length; i++) { if (this.otpInputs[i].value === '') { allFilled = false; } } return allFilled; } handleKeyUp(ev) { var _a, _b, _c, _d; this.resetError(); if (['Alt', 'Shift', 'Control', 'AltGraph', 'Ctrl'].includes(ev.key)) { return; } let key = ev.keyCode || ev.charCode; if (ev.target.value) { (_a = ev.target.nextElementSibling) === null || _a === void 0 ? void 0 : _a.focus(); (_b = ev.target.nextElementSibling) === null || _b === void 0 ? void 0 : _b.select(); } else if ([8, 46].includes(key)) { (_c = ev.target.previousElementSibling) === null || _c === void 0 ? void 0 : _c.focus(); (_d = ev.target.previousElementSibling) === null || _d === void 0 ? void 0 : _d.select(); } // If the target is populated to quickly, value length can be > 1 if (ev.target.value.length > 1) { this.splitNumber(ev); } } handlePaste(ev) { this.resetError(); const clipboardText = salla.helpers.number(ev.clipboardData.getData('text')) || ''; let text = clipboardText.replace(/[^0-9]/g, ''); text = text.substring(0, this.otpInputs.length); this.otpInputs.forEach(input => input.value = ''); this.modifyNext(this.otpInputs[0], text); } handleInput(ev) { this.resetError(); salla.helpers.inputDigitsOnly(ev.target); // check if all otpInputs has values then send the request if (this.checkAllInputs()) { setTimeout(() => { this.toggleOTPSubmit(); }, 100); } } resetError() { this.hasError = false; this.errorMessage = ''; } handleFocus(ev) { var _a; // If the focus element is the first one, do nothing if (ev.target === this.firstOtpInput) return; // If value of input 1 is empty, focus it. if (((_a = this.firstOtpInput) === null || _a === void 0 ? void 0 : _a.value) == '') { this.firstOtpInput.focus(); } // If value of a previous input is empty, focus it. // To remove if you don't wanna force user respecting the fields order. if (ev.target.previousElementSibling.value == '') { ev.target.previousElementSibling.focus(); } } /** * Get current code * @return {string} */ async getCode() { return this.code.value; } /** * Open verifying modal * @param data */ async open(data) { var _a, _b; this.data = data; this.data.type = this.data.type || this.type; this.type = this.data.type; this.resendTimer(); this.otpInputs = this.body.querySelectorAll('.s-verify-input'); this.firstOtpInput = this.body.querySelector('#otp-1'); this.reset(); this.resetError(); this.display == 'modal' && ((_a = this.modal) === null || _a === void 0 ? void 0 : _a.setTitle(this.title)); this.modal.open(); (_b = this.firstOtpInput) === null || _b === void 0 ? void 0 : _b.addEventListener('input', e => this.splitNumber(e)); // focus the first input after opening the modal setTimeout(() => this.otpInputs[0].focus(), 100); } toggleOTPSubmit() { let otp = []; this.otpInputs.forEach(input => input.value && otp.push(input.value)); this.code.value = otp.join(''); if (otp.length === 4) { this.btn.disable(); this.btn.click(); return; } this.btn.enable(); } reset() { this.otpInputs.forEach((input) => input.value = ''); this.code.value = ''; this.otpInputs[0].focus(); } resendTimer() { this.resendMessage.style.display = 'block'; this.resend.style.display = 'none'; this.resendAfter = 30; let timerId = setInterval(() => { if (this.resendAfter <= 0) { clearInterval(timerId); this.resend.style.display = 'block'; this.resendMessage.style.display = 'none'; } else { this.timer.innerHTML = `${this.resendAfter >= 10 ? this.resendAfter : '0' + this.resendAfter} : 00`; this.resendAfter--; } }, 1000); } resendCode() { return this.btn.stop() .then(() => this.btn.disable()) .then(() => { this.otpInputs.forEach(input => input.value = ''); this.otpInputs[0].focus(); }) .then(() => salla.api.auth.resend(this.data)) .finally(() => this.resendTimer()); } submit() { //if code not 4 digits, focus on the after filled input, if (this.code.value.length < 4) { this.otpInputs[this.code.value.length].focus(); salla.log('Trying to submit without 4 digits!'); return; } let data = Object.assign({ code: this.code.value }, this.data); return this.btn.load() .then(() => this.btn.disable()) .then(() => this.isProfileVerify ? salla.profile.verify(data) : salla.auth.verify(data, this.supportWebAuth)) .then(response => this.verified.emit(response)) .then(() => this.btn.stop() && this.btn.disable()) .then(() => this.modal.close()) .then(() => this.autoReload && window.location.reload()) .catch((error) => { var _a, _b, _c; this.hasError = true; this.errorMessage = ((_c = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.message) || salla.lang.get('common.errors.error_occurred'); if (!error.response) { console.log('Unexpected error', error); } else { salla.logger.error(error); } this.btn.stop() && this.btn.enable() && this.reset(); }); } render() { return this.display == 'inline' ? h(Host, null, this.myBody()) : h("salla-modal", { width: "xs", class: "s-verify", ref: modal => this.modal = modal, "modal-title": this.title }, h("span", { slot: 'icon', class: "s-verify-header-icon", innerHTML: this.type == "mobile" ? AndroidPhoneIcon : MailIcon }), this.myBody()); } myBody() { return (h("div", { class: "s-verify-body", ref: body => this.body = body }, h("div", { class: "s-verify-message", innerHTML: salla.lang.get('pages.profile.verify_message') }), h("slot", { name: "mobile" }), h("slot", { name: "email" }), h("input", { type: "hidden", name: "code", maxlength: "4", required: true, ref: code => this.code = code }), h("div", { class: { "s-verify-codes": true, "has-error": this.hasError }, dir: "ltr" }, [1, 2, 3, 4].map((i) => h("input", { type: "number", autocomplete: "one-time-code", pattern: "[0-9]*", inputmode: "numeric", maxlength: "1", value: "", id: `otp-${i}`, class: { "s-verify-input": true, "s-has-error": this.hasError }, onInput: e => this.handleInput(e), onPaste: e => this.handlePaste(e), onKeyUp: e => this.handleKeyUp(e), onFocus: e => this.handleFocus(e), required: true }))), this.hasError && this.errorMessage ? h("span", { class: "s-verify-error-message" }, this.errorMessage) : '', h("div", { slot: "footer", class: "s-verify-footer" }, h("salla-button", { class: "s-verify-submit", "loader-position": 'center', disabled: true, onClick: () => this.submit(), ref: b => this.btn = b }, salla.lang.get('pages.profile.verify')), h("p", { class: "s-verify-resend-message", ref: el => this.resendMessage = el }, salla.lang.get('blocks.header.resend_after'), h("b", { class: "s-verify-timer", ref: el => this.timer = el })), h("a", { href: "#", class: "s-verify-resend", onClick: () => this.resendCode(), ref: el => this.resend = el }, salla.lang.get('blocks.comments.submit'))), h("slot", { name: "after-footer" }))); } get host() { return this; } static get style() { return sallaVerifyCss; } }, [4, "salla-verify", { "display": [1], "type": [1025], "autoReload": [4, "auto-reload"], "supportWebAuth": [4, "support-web-auth"], "translationLoaded": [32], "title": [32], "resendAfter": [32], "hasError": [32], "errorMessage": [32], "isProfileVerify": [32], "getCode": [64], "open": [64] }]); function defineCustomElement$1() { if (typeof customElements === "undefined") { return; } const components = ["salla-verify", "salla-button", "salla-loading", "salla-modal"]; components.forEach(tagName => { switch (tagName) { case "salla-verify": if (!customElements.get(tagName)) { customElements.define(tagName, SallaVerify$1); } break; case "salla-button": if (!customElements.get(tagName)) { defineCustomElement$4(); } break; case "salla-loading": if (!customElements.get(tagName)) { defineCustomElement$3(); } break; case "salla-modal": if (!customElements.get(tagName)) { defineCustomElement$2(); } break; } }); } const SallaVerify = SallaVerify$1; const defineCustomElement = defineCustomElement$1; export { SallaVerify, defineCustomElement }; //# sourceMappingURL=salla-verify.js.map //# sourceMappingURL=salla-verify.js.map