1/* eslint-disable import/no-cycle */ 2import { getConfigValue } from '../configs.js'; 3import { openModal, closeModal, createModalFromContent } from '../utils.js'; 4import { 5 setupOtpValidation, 6 sendOtp, 7 verifyOtp, 8 sendEmailOtp, 9 showErrorMessage, 10} from '../forms.js'; 11import { verifyOtpLinkAura } from '../aura/api.js'; 12import { welcomeModal } from '../login/login-utils.js'; 13import { getCustomer } from './api.js'; 14import { dataLayerAuraAutoEnrollmentOtpResend, dataLayerOpenPopup } from '../analytics/google-data-layer.js'; 15 16export default async function openOtpVerificationModal( 17 inputElement, 18 countryIso, 19 resendCounter, 20 placeholders, 21) { 22 const customerExistsData = JSON.parse(sessionStorage.getItem('customerExistsData') || '{}'); 23 const auraAutoEnrollment = (await getConfigValue('aura-autoenrollment') === 'true'); 24 const OTP_VERIFICATION = 'otp-verification-dialog'; 25 const modalOtp = document.createElement('div'); 26 modalOtp.classList.add('otp-verification-container'); 27 28 const otpContainerTitle = placeholders.sentOtpModalTitle || 'Verify'; 29 const otpContainerInnerTitleText = document.createElement('p'); 30 otpContainerInnerTitleText.textContent = placeholders.sentOtpModalText || 'Please enter the OTP sent to'; 31 32 let timerInterval; 33 function startResendOtpTimer() { 34 const timerElement = document.querySelector('.resend-code-text'); 35 let timeRemaining = 59; // Start at 59 seconds 36 // Clear any existing interval to avoid multiple timers 37 if (timerInterval) { 38 clearInterval(timerInterval); 39 } 40 timerInterval = setInterval(() => { 41 if (timeRemaining > 0) { 42 timeRemaining -= 1; 43 const seconds = timeRemaining < 10 ? `0${timeRemaining}` : timeRemaining; 44 timerElement.textContent = `${placeholders.resendInText || 'Resend in'} 00:${seconds}s`; 45 } else { 46 clearInterval(timerInterval); 47 timerElement.textContent = `${placeholders.resendotp || 'Resend OTP'}`; 48 timerElement.classList.add('resend-code'); 49 } 50 }, 1000); // Update every 1 second 51 document.querySelector('.resend-code-text')?.addEventListener('click', async (event) => { 52 event.preventDefault(); 53 if (event.target.classList.contains('resend-code')) { 54 dataLayerAuraAutoEnrollmentOtpResend(); 55 } 56 if (countryIso) { 57 sendOtp(inputElement, countryIso, resendCounter, placeholders); 58 } else { 59 sendEmailOtp(inputElement, resendCounter, placeholders); 60 } 61 }); 62 } 63 64 if (countryIso) { 65 const otpContainerInnercountryIso = document.createElement('span'); 66 otpContainerInnercountryIso.textContent = `+${countryIso}${inputElement.value}`; 67 otpContainerInnerTitleText.append(otpContainerInnercountryIso); 68 } else { 69 otpContainerInnerTitleText.textContent = placeholders.accountFoundSendotpText 70 || 'Aura account found! Please verify the OTP sent to your mobile number to link.'; 71 } 72 73 modalOtp.appendChild(otpContainerInnerTitleText); 74 75 const otpFieldsContainer = document.createElement('div'); 76 otpFieldsContainer.classList.add('otp-fields-container'); 77 78 for (let i = 0; i < 6; i += 1) { 79 const otpInputContainer = document.createElement('div'); 80 otpInputContainer.classList.add('otp-input-container'); 81 const otpInput = document.createElement('input'); 82 otpInput.type = 'text'; 83 otpInput.classList.add('otp-input'); 84 otpInput.autocomplete = 'off'; 85 otpInput.inputMode = 'numeric'; 86 otpInput.maxLength = 1; 87 otpInput.pattern = '\\d{1}'; 88 89 const line = document.createElement('div'); 90 line.classList.add('line'); 91 92 otpInputContainer.appendChild(otpInput); 93 otpInputContainer.appendChild(line); 94 otpFieldsContainer.appendChild(otpInputContainer); 95 96 otpInput.addEventListener('input', () => { 97 if (this.value.trim() !== '') { 98 this.nextElementSibling.style.display = 'none'; 99 } else { 100 this.nextElementSibling.style.display = 'block'; 101 } 102 }); 103 } 104 modalOtp.appendChild(otpFieldsContainer); 105 106 const otpMessageContainer = document.createElement('p'); 107 otpMessageContainer.textContent = placeholders.invalidOtpMessage || 'Please enter a valid OTP'; 108 otpMessageContainer.classList.add('otp-message-container'); 109 modalOtp.appendChild(otpMessageContainer); 110 111 const otpVerifyButton = document.createElement('button'); 112 otpVerifyButton.textContent = placeholders.otpVerifyButtonText || 'Verify'; 113 otpVerifyButton.classList.add('otp-verify-button'); 114 otpVerifyButton.disabled = true; 115 modalOtp.appendChild(otpVerifyButton); 116 117 const resendCodeText = document.createElement('p');
118 resendCodeText.classList.add('resend-code-text'); 119 resendCodeText.textContent = placeholders.resendCodeText || 'Not received the code?'; 120 const resendCode = document.createElement('a'); 121 resendCode.href = ''; 122 resendCode.textContent = placeholders.resendCode || 'Resend Code'; 123 resendCode.classList.add('resend-code'); 124 resendCodeText.appendChild(resendCode); 125 modalOtp.appendChild(resendCodeText); 126 127 await createModalFromContent( 128 OTP_VERIFICATION, 129 otpContainerTitle, 130 modalOtp.outerHTML, 131 [OTP_VERIFICATION], 132 ); 133 openModal(OTP_VERIFICATION); 134 if (auraAutoEnrollment) { 135 if (resendCounter === 1) { 136 dataLayerOpenPopup('verify otp'); 137 } 138 startResendOtpTimer(); 139 } 140 141 const otpInputs = document.querySelectorAll('.otp-input'); 142 otpInputs.forEach((input) => { 143 input.addEventListener('input', (event) => { 144 event.target.value = event.target.value.replace(/\D/g, ''); 145 }); 146 }); 147 148 const otpLine = document.querySelectorAll('.line'); 149 const otpVerifyButtonField = document.querySelector('.otp-verify-button'); 150 151 setupOtpValidation(otpInputs, otpVerifyButtonField, otpLine); 152 153 otpVerifyButtonField.addEventListener('click', async (event) => { 154 event.preventDefault(); 155 const otp = Array.from(otpInputs).map((i) => i.value).join(''); 156 const apcID = customerExistsData?.apcIDNumber || ''; 157 if (!!(customerExistsData?.token) || !!(localStorage.getItem('loginType'))) { 158 let auraLinkingStatus; 159 const auraLinkingDetails = JSON.parse(sessionStorage.getItem('_aura_linking_details_social_signin') || '{}'); 160 if (auraLinkingDetails) { 161 const { type, value } = auraLinkingDetails; 162 auraLinkingStatus = await verifyOtpLinkAura(otp, '', type, value, true); 163 } else { 164 auraLinkingStatus = await verifyOtpLinkAura(otp, apcID); 165 } 166 if (auraLinkingStatus) { 167 closeModal('otp-verification-dialog'); 168 welcomeModal(placeholders); 169 } else { 170 document.querySelector('.otp-verification-container')?.classList.add('otp-error'); 171 } 172 } else { 173 const verifyOtpResponse = await verifyOtp(countryIso, inputElement, otp, placeholders); 174 // v1 on success returns true, in v2 on success returns information. 175 const verifyOtpStatus = verifyOtpResponse === true 176 || (verifyOtpResponse?.error === null && verifyOtpResponse?.message === null); 177 if (verifyOtpStatus && auraAutoEnrollment) { 178 const phoneNumber = document.querySelector('.mobile-number-field input'); 179 const countryDropdown = document.querySelector('#country-dropdown'); 180 const fullNameInput = document.querySelector('#fullname'); 181 const changeNumberBtn = document.querySelector('.change-number-element'); 182 changeNumberBtn?.classList.add('hidden'); 183 countryDropdown.disabled = true; 184 phoneNumber.readOnly = true; 185 document.querySelector('.verifyMobileNumber')?.classList.add('hide'); 186 let searchUser = customerExistsData; 187 let loginType = 'Email'; 188 const setLoginType = (searchUserFlag) => { 189 if (!customerExistsData?.auraLinked) {
190 loginType = searchUserFlag ? 'Email-Aura_signin' : 'Email-Aura_create'; 191 } 192 sessionStorage.setItem('loginType', loginType); 193 }; 194 195 if (!(searchUser?.apc_identifier_number) || window.location.href.includes('/register')) { 196 searchUser = verifyOtpResponse; 197 if (searchUser.apc_identifier_number) { 198 sessionStorage.setItem('apcIdentifierNumber', searchUser.apc_identifier_number); 199 } 200 if (!!(fullNameInput) && !!(searchUser?.first_name)) { 201 fullNameInput.value = `${searchUser?.first_name} ${searchUser?.last_name}`; 202 } 203 } else { 204 sessionStorage.setItem('apcIdentifierNumber', searchUser); 205 } 206 const verifiedText = document.createElement('div'); 207 verifiedText.innerHTML = ` <p class='verified-text'> 208 <img src="/icons/aura-logo-color.svg"> 209 <span>${((!!searchUser?.apc_identifier_number) || (!!customerExistsData?.apcIDNumber)) ? (placeholders?.auraAccountVerifiedText || 'An Aura account was found and verified') : (placeholders?.numberVerifiedAccountCreated || 'Aura account has been created and linked to your account.')}</span> 210 </p>`; 211 document.querySelector('.mobile-number-field')?.insertAdjacentElement('afterend', verifiedText); 212 sessionStorage.removeItem('customerExistsData'); 213 setLoginType(!searchUser?.message); 214 } 215 } 216 }); 217 218 document.querySelector('.resend-code').addEventListener('click', async (event) => { 219 event.preventDefault(); 220 await sendOtp(inputElement, countryIso, resendCounter, placeholders); 221 }); 222} 223 224// handle user phone number verification. 225export async function phoneNumberVerification(placeholders) { 226 const cntryCode = document.querySelector('#country-dropdown')?.value; 227 const countryCode = cntryCode.replace('+', ''); 228 const mobileNo = document.querySelector('#mobile'); 229 const inputFieldWrapper = document.querySelector( 230 '.input-field-wrapper:has(.input-wrapper.mobile-number-field)', 231 ); 232 const customerExistsData = JSON.parse(sessionStorage.getItem('customerExistsData')); 233 const mobile = mobileNo.value; 234 if (mobile === '') { 235 const errorMessage = placeholders.noMobileMessage || 'Please enter Mobile Number'; 236 showErrorMessage(inputFieldWrapper, errorMessage); 237 return; 238 } 239 240 if (mobile.length !== mobileNo.minLength) { 241 const errorMessage = placeholders.validMobileMessage || 'Please enter Valid Mobile Number'; 242 showErrorMessage(inputFieldWrapper, errorMessage); 243 return; 244 } 245 246 if (!(customerExistsData?.maskedMobileNo)) { 247 try { 248 const resendCounter = 0; 249 await sendOtp(mobileNo, countryCode, resendCounter, placeholders); 250 } catch (error) { 251 console.error('Error in handleOtpRequest:', error); 252 } 253 } else if (customerExistsData?.token) { 254 const resendCounter = 0; 255 const customer = await getCustomer(); 256 if (customer?.email) { 257 await sendEmailOtp(customer.email, resendCounter, placeholders); 258 } 259 } else { 260 const userEmail = document.querySelector('.email-add') 261 || document.querySelector('.email-info-container p'); 262 if (userEmail.textContent) { 263 const resendCounter = 0; 264 await sendEmailOtp(userEmail.textContent, resendCounter, placeholders); 265 } 266 } 267}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.