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

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);
});