You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
7.9 KiB
JavaScript
226 lines
7.9 KiB
JavaScript
import './lib/gt.js';
|
|
import './lib/tom-select.complete.min.js';
|
|
import { PhoneProviderGeetestCaptcha } from './lib/gtutils.js';
|
|
|
|
class SmsSenderForm {
|
|
constructor(type, formSelector) {
|
|
this.type = type;
|
|
this.formElem = document.querySelector(formSelector);
|
|
this.realmUrl = config.get('realmUrl');
|
|
|
|
this.selectAreaCode = document.querySelector("#areaCodeInput");
|
|
this.inputPhoneNumber = document.querySelector("#phoneNumberInput");
|
|
this.inputCode = document.querySelector("#smsCodeInput");
|
|
this.btnSend = document.querySelector("#btnSendSmsCode");
|
|
|
|
this.countdown = null;
|
|
this.resendTimeout = 120;
|
|
this.areaCodeSelect = null;
|
|
|
|
this.bindEvents();
|
|
this.initConfig();
|
|
this.initCaptcha();
|
|
}
|
|
|
|
bindEvents() {
|
|
this.btnSend.addEventListener('click', this.onBtnSendClick.bind(this));
|
|
|
|
this.inputPhoneNumber.addEventListener('input', () => {
|
|
// Hide error message when user types
|
|
const errorMsg = this.formElem.querySelector('.pf-v5-c-form__helper-text--error');
|
|
if (errorMsg) {
|
|
errorMsg.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
this.formElem.addEventListener('submit', () => {
|
|
if (this.areaCodeSelect) {
|
|
this.areaCodeSelect.enable();
|
|
}
|
|
});
|
|
}
|
|
|
|
initCaptcha() {
|
|
this.captcha = new PhoneProviderGeetestCaptcha();
|
|
}
|
|
|
|
initConfig() {
|
|
fetch(this.realmUrl + '/sms').then((res) => {
|
|
if (res.ok) {
|
|
return res.json();
|
|
} else {
|
|
throw new Error(msg.localize('cannotGetConfig'));
|
|
}
|
|
}).then((res) => {
|
|
this.setAreaCodeList(res.areaCodeList || []);
|
|
|
|
// Initialize TomSelect after data is loaded
|
|
this.areaCodeSelect = new TomSelect('#areaCodeInput', {
|
|
maxItems: 1,
|
|
valueField: 'value',
|
|
labelField: 'text',
|
|
searchField: ['text', 'value'],
|
|
create: false,
|
|
});
|
|
|
|
if (res.areaLocked) {
|
|
this.areaCodeSelect.disable();
|
|
}
|
|
|
|
const defaultAreaCode = this.selectAreaCode.getAttribute('data-value') || res.defaultAreaCode || '86';
|
|
this.areaCodeSelect.setValue(defaultAreaCode.toString());
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
this.showError(err.message);
|
|
});
|
|
}
|
|
|
|
getFilledAreaCode(areaCode) {
|
|
const maxLen = 4;
|
|
let areaCodeStr = areaCode.toString();
|
|
return '+' + areaCodeStr + ('\u2002'.repeat(maxLen - areaCodeStr.length));
|
|
}
|
|
|
|
getLocalizedName(nameList, langCode) {
|
|
if (langCode in nameList) {
|
|
return nameList[langCode];
|
|
} else {
|
|
return nameList['en'];
|
|
}
|
|
}
|
|
|
|
showError(errorMessage) {
|
|
// Find or create error message element
|
|
let errorElement = this.formElem.querySelector('.phone-error-message');
|
|
if (!errorElement) {
|
|
errorElement = document.createElement('div');
|
|
errorElement.className = 'pf-v5-c-form__helper-text pf-v5-c-form__helper-text--error phone-error-message';
|
|
const phoneGroup = this.formElem.querySelector('[name="phoneNumber"]').closest('.pf-v5-c-form__group');
|
|
if (phoneGroup) {
|
|
phoneGroup.appendChild(errorElement);
|
|
}
|
|
}
|
|
errorElement.textContent = errorMessage;
|
|
errorElement.style.display = 'block';
|
|
}
|
|
|
|
setAreaCodeList(areaCodeList) {
|
|
const langCode = msg.localize('countryNameLangCode');
|
|
|
|
// Clear existing options
|
|
this.selectAreaCode.innerHTML = '';
|
|
|
|
// Add new options
|
|
areaCodeList.forEach((info) => {
|
|
const option = document.createElement('option');
|
|
option.value = info.areaCode;
|
|
const displayName = this.getFilledAreaCode(info.areaCode) + '\u2002\u2002' + this.getLocalizedName(info.name, langCode);
|
|
option.textContent = displayName;
|
|
this.selectAreaCode.appendChild(option);
|
|
});
|
|
}
|
|
|
|
startCountdown() {
|
|
let currentTimeout = this.resendTimeout;
|
|
const resendMsg = msg.localize('resendVerificationCode');
|
|
const secondMsg = msg.localize('second');
|
|
|
|
this.countdown = setInterval(() => {
|
|
currentTimeout -= 1;
|
|
if (currentTimeout <= 0) {
|
|
this.stopCountdown();
|
|
return;
|
|
}
|
|
this.btnSend.textContent = resendMsg + ' (' + currentTimeout.toString() + secondMsg + ')';
|
|
}, 1000);
|
|
}
|
|
|
|
stopCountdown() {
|
|
if (this.countdown !== null) {
|
|
clearInterval(this.countdown);
|
|
this.countdown = null;
|
|
this.btnSend.textContent = msg.localize('resendVerificationCode');
|
|
this.btnSend.disabled = false;
|
|
}
|
|
}
|
|
|
|
checkInput() {
|
|
if (this.inputPhoneNumber.value.trim() === "") {
|
|
this.showError(msg.localize('phoneNumberIsEmpty'));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
onBtnSendClick() {
|
|
if (!this.checkInput()) return;
|
|
|
|
this.captcha.verify().then((data) => {
|
|
this.btnSend.disabled = true;
|
|
this.btnSend.textContent = msg.localize('sending');
|
|
|
|
data.areaCode = this.areaCodeSelect.getValue();
|
|
data.phoneNumber = this.inputPhoneNumber.value;
|
|
|
|
fetch(this.realmUrl + '/sms/' + this.type + '-code', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
headers: { 'Content-Type': 'application/json' },
|
|
}).then((res) => {
|
|
if (res.ok) {
|
|
return res.json();
|
|
} else {
|
|
throw new Error(msg.localize('sendVerificationError', [res.status + ' ' + res.statusText]));
|
|
}
|
|
}).then((res) => {
|
|
if (res.status == 1) {
|
|
this.startCountdown();
|
|
} else if (res.status == 0) {
|
|
throw new Error(res.errormsg ? msg.localize(res.errormsg, [res.error]) : res.error);
|
|
}
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
this.showError(err.message);
|
|
|
|
this.btnSend.disabled = false;
|
|
this.btnSend.textContent = msg.localize('sendVerificationCode');
|
|
});
|
|
}).catch((err) => {
|
|
if (err !== 'close') { // User closed captcha
|
|
console.error(err);
|
|
this.showError(typeof err === 'string' ? err : err.message);
|
|
this.btnSend.disabled = false;
|
|
this.btnSend.textContent = msg.localize('sendVerificationCode');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
// Initialize SMS sender form for login
|
|
window.SmsSenderForm = new SmsSenderForm("login", "#kc-form-login");
|
|
|
|
// Handle tab switching to set the login type
|
|
document.addEventListener('pf.tab.activate', function(event) {
|
|
const tabId = event.detail.tabId;
|
|
let loginTypeInput = document.querySelector('#loginType');
|
|
|
|
if (!loginTypeInput) {
|
|
loginTypeInput = document.createElement('input');
|
|
loginTypeInput.type = 'hidden';
|
|
loginTypeInput.name = 'loginType';
|
|
loginTypeInput.id = 'loginType';
|
|
document.querySelector('#kc-form-login').appendChild(loginTypeInput);
|
|
}
|
|
|
|
loginTypeInput.value = tabId; // 'password' or 'phone'
|
|
});
|
|
|
|
// Set initial login type to password (default active tab)
|
|
const initialLoginType = document.createElement('input');
|
|
initialLoginType.type = 'hidden';
|
|
initialLoginType.name = 'loginType';
|
|
initialLoginType.id = 'loginType';
|
|
initialLoginType.value = 'password';
|
|
document.querySelector('#kc-form-login').appendChild(initialLoginType);
|
|
}); |