PageSourceSearch

https://www.americaneagle.ae/blocks/aura-join/aura-join.js

js americaneagle.ae collected 2026-10-02 13:25:48 UTC 18,125 bytes, 396 lines download raw bytes

1import { decorateIcons } from '../../scripts/aem.js';
2import {
3  getMaxLengthByCountryCode,
4  getCountryIso,
5  getConfigValue,
6  CACHE_KEYS,
7} from '../../scripts/configs.js';
8import { openModal, closeModal, createModalFromContent } from '../../scripts/utils.js';
9import {
10  loadFragment, fetchPlaceholdersForLocale, isLoggedInUser,
11} from '../../scripts/scripts.js';
12import {
13  PHONE_PATTERN,
14  FULLNAME_PATTERN,
15  EMAIL_PATTERN,
16  showErrorMessage,
17  validateForm,
18} from '../../scripts/forms.js';
19
20import {
21  loginMobile, checkUserExists, userRegister, verifyOtpApiCall, getAuraCustomerData,
22} from '../../scripts/aura/api.js';
23import {
24  nextStage,
25  prevStage,
26  resetOtp,
27  phonenumberValidation,
28  submitOnEnter,
29  auraModalRedirection,
30  debouncedFormValidation,
31  addFormValidation,
32  phonenumberBlurValidation,
33} from '../../scripts/aura-utils/aura-utils.js';
34
35import { dataLayerAuraBlock } from '../../scripts/analytics/google-data-layer.js';
36
37const placeholders = await fetchPlaceholdersForLocale();
38let auraProfileExistsByPhone = false;
39let auraProfileExistsByEmail = false;
40let isSubmitting = false;
41// const requiredFullData = (await getConfigValue('required-full-customerdata')) === 'true';
42
43export default async function decorate(block) {
44  const containerClasses = ['aura-title', 'aura-mobile-number', 'aura-otp', 'aura-user-details'];
45
46  Array.from(block.children).forEach((child, index) => {
47    child.classList.add(containerClasses[index]);
48  });
49
50  let loginFlowText = placeholders.auraLoginButton || 'Login';
51
52  const countrycode = await getConfigValue('country-code');
53  const countryPrefix = `+${await getCountryIso(countrycode)}`;
54  const maxLength = await getMaxLengthByCountryCode(countrycode);
55
56  if (isLoggedInUser()) {
57    loginFlowText = placeholders.linkYourAura || 'Link your Aura';
58  }
59
60  const otpLength = 6;
61
62  const mobileForm = document.createElement('div');
63  mobileForm.innerHTML = ` <form class="aura-contact-form" novalidate="">
64      <div>
65      <div class="input-field-wrapper">
66          <div class="input-wrapper">
67          <label for="login-mobile">${countryPrefix}</label>
68          <input type="tel" id="login-mobile" name="login-mobile" aria-label="${placeholders.mobileNumberInputText || 'Mobile Number'}" placeholder="${placeholders.mobileNumberInputText || 'Mobile Number'}" required maxlength="${maxLength}" minlength="${maxLength}" autocomplete="off">
69          </div>
70        </div>
71        <div class="aura-buttons">
72        <button class="secondary-btn" type="submit" data-dismiss="modal"><span>${placeholders.sendOtp || 'Send OTP'}</span></button>
73        <p>${placeholders.alreadyHaveAccount || 'Already have account?'} <a>${loginFlowText}</a></p>
74        </div>
75      </div>
76      </form>`;
77
78  mobileForm.classList.add('aura-contact-container');
79  block.querySelector('.aura-mobile-number').append(mobileForm);
80
81  const otpForm = document.createElement('div');
82  otpForm.innerHTML = `<form class="aura-otp-form">
83        <div class="input-field-wrapper">
84          <div class="input-wrapper">
85             <input type="number" id="otp-input" name="otp-input"
86             placeholder="${placeholders.otpPlaceholder || 'One time pin'}" required maxlength="${placeholders.otpLength || otpLength}" oninput="this.value = this.value.slice(0, ${placeholders.otpLength || otpLength});" onkeydown="return event.key !== 'e' && event.key !== 'E';" autocomplete="off">
87          </div>
88        </div>
89        <div class="otp-success-message">
90        </div>
91        <div class="aura-buttons">
92        <button class="secondary-btn" type="submit"><span>${placeholders.verifyOtp || 'Verify'}</span></button>
93        </div>
94        </form>`;
95
96  const auraOtpContainer = block.querySelector('.aura-otp');
97  otpForm.classList.add('aura-otp-container');
98  auraOtpContainer.append(otpForm);
99
100  const otpInfoDiv = document.createElement('div');
101  otpInfoDiv.classList.add('otp-info-text');
102  otpInfoDiv.innerHTML = `<div>
103                  <p>${placeholders.otpInfoText || "Didn't receive your one time pin?"} <a>${placeholders.resendOtp || 'Resend'}</a></p>
104                  </div>`;
105
106  auraOtpContainer.appendChild(otpInfoDiv);
107
108  const termsAndConditionText = block.querySelector('.aura-user-
108details > div');
109  const userDetailsForm = document.createElement('div');
110  userDetailsForm.innerHTML = `<form class="user-details-form" novalidate="">
111      <div>
112          <div class="input-field-wrapper">
113              <div class="input-wrapper mobile-disabled">
114                  <label for="mobile-number">${countryPrefix}</label>
115                  <input type="number" id="mobile-number" name="mobile-number" aria-label="${placeholders.mobileNumberInputText || 'Mobile Number'}" placeholder="" pattern="${PHONE_PATTERN}" required autocomplete="off" disabled>
116              </div>
117          </div>
118          <div class="input-field-wrapper">
119              <div class="input-wrapper">
120                  <input type="text" id="fullname" class="fullname" name="fullname" pattern="${FULLNAME_PATTERN}" placeholder="${placeholders.fullName || 'Full Name'}" aria-label="${placeholders.fullName || 'Full Name'}" required autocomplete="off" />
121              </div>
122          </div>
123          <div class="input-field-wrapper">
124              <div class="input-wrapper">
125                  <input type="email" id="email-address" name="email-address" aria-label="${placeholders.email || 'Email'}" placeholder="${placeholders.emailAddress || 'Email Address'}" pattern="${EMAIL_PATTERN}" required autocomplete="off" >
126              </div>
127          </div>
128      </div>
129      <div class="aura-buttons">
130      <div class="aura-terms-condition">
131      </div>
132        <button class="secondary-btn" type="submit"><span>${placeholders.auraCompleteRegistration || 'Complete Registration'}</span></button>
133      </div>
134      </form>`;
135
136  if (termsAndConditionText) {
137    userDetailsForm.querySelector('.aura-terms-condition')?.append(termsAndConditionText);
138  }
139
140  const congratulationsFragment = await loadFragment(`/${document.documentElement.lang}/fragments/aura/congratulations-aura`);
141  block.children[block.children.length - 1].replaceWith(congratulationsFragment.querySelector('.block'));
142  block.querySelector('.aura-user-details')?.append(userDetailsForm);
143  block.querySelector('.aura-mobile-number').classList.add('show');
144}
145
146export async function createJoinAura(reDecorate, eventAction) {
147  const MODAL_DELAY_MILLIS = 300;
148  loadFragment(`/${document.documentElement.lang}/fragments/aura/join-aura`).then(async (fragment) => {
149    dataLayerAuraBlock(eventAction, 'initiated');
150    const titleDiv = fragment.querySelector('.aura-title');
151    const modalContent = fragment.querySelector('.aura-join');
152    modalContent.firstElementChild.remove();
153    await closeModal('join-aura-dialog');
154    // Add generic overlay to eliminate flickr effect in background.
155    document.querySelector('.generic-overlay-background')?.classList.add('show');
156    if (!document.getElementById('join-aura-dialog')) {
157      await createModalFromContent('join-aura-dialog', titleDiv.textContent, modalContent.outerHTML, ['aura-modal', 'join-aura', 'aura'], 'arrow-left-black', false, 'icon-aura-close');
158
159      const joinAura = document.querySelector('#join-aura-dialog');
160
161      const arrowIcon = joinAura.querySelector('.join-aura .icon-title-left');
162      arrowIcon.classList.add('icon-hide');
163
164      const mobileForm = joinAura.querySelector('.aura-contact-form');
165      const otpForm = joinAura.querySelector('.aura-otp-form');
166      const userDetailsForm = joinAura.querySelector('.user-details-form');
167      const congratsStage = joinAura.querySelector('.aura-congratulations');
168      const congratsForm = congratsStage.querySelector('.aura-congratulations .aura-buttons');
169      const linkAura = mobileForm.querySelector('a');
170      const auraSocialLink = congratsStage.querySelector('.aura-social');
171      auraSocialLink.addEventListener('click', (event) => {
172        const link = event.target.closest('a');
173        if (link) {
174          if (link.href?.includes('apple')) {
175            dataLayerAuraBlock('click appstore');
176          } else {
177            dataLayerAuraBlock('click playstore');
178          }
179        }
180      });
181
182      const otpContainer = joinAura.querySelector('.aura-otp');
183      const defaultOtpInfoText = otpContainer.querySelector('div').textContent;
184      const defaultOtpResendText = otpContainer.querySelector('.aura-otp .otp-info-text p').innerHTML;
185
186      const successMessageDiv = otpContainer.querySelector('.otp-success-message');
187      successMessageDiv.innerHTML = `<p>${placeholders.resendOtpSendSuccessfully || 'Resend OTP Send Successfully'}</p>`;
188      successMessageDiv.classList.add('hide-message');
189
190      const countrycode = await getConfigValue('country-code');
191      const countryPrefix = `${await getCountryIso(countrycode)}`;
192      const disableInlineValidation = await getConfigValue('disable-inline-validation');
193
194      const forms = [userDetailsForm, otpForm, mobileForm];
195      // TODO - Use Block-Config(Developer authorable) instead of config(Author authorable).
196      if (disableInlineValidation === 'true') {
197        forms.slice(0, 2).forEach((element) => {
198          debouncedFormValidation(element);
199          decorateIcons(element);
200        });
201
202        await phonenumberBlurValidation(mobileForm);
203        decorateIcons(mobileForm);
204      } else {
205        forms.forEach((element) => {
206          addFormValidation(element);
207          decorateIcons(element);
208        });
209        await phonenumberValidation(mobileForm);
210      }
211
212      mobileForm.addEventListener('submit', async (event) => {
213        event.stopPropagation();
214        event.preventDefault();
215
216        if (isSubmitting) {
217          return;
218        }
219
220        isSubmitting = true;
221
222        try {
223          const mobile = mobileForm.querySelector('#login-mobile').value;
224          if (mobile === '') {
225            isSubmitting = false;
226            const inputFieldWrapper = mobileForm.querySelector('.input-field-wrapper');
227            const errorMessage = placeholders.noMobileMessage || `Please enter +${countryPrefix} Mobile Number`;
228            showErrorMessage(inputFieldWrapper, errorMessage);
229            return;
230          }
231
232          // Check if user exists with the provided mobile number and country prefix.
233          const mobileWithPrefix = `${countryPrefix}${mobile}`;
234          auraProfileExistsByPhone = await checkUserExists(mobileWithPrefix, 'mobile');
235          if (!auraProfileExistsByPhone) {
236            const status = await loginMobile(mobile, countryPrefix);
237            if (status === true) {
238              dataLayerAuraBlock(eventAction, 'mobile');
239              userDetailsForm.querySelector('#mobile-number').value = mobile;
240              resetOtp(otpContainer, defaultOtpResendText, mobileForm);
241              otpContainer.querySelector('.aura-otp > div').innerHTML = `${defaultOtpInfoText} <span class="mob-number">+${countryPrefix}${mobile}</span>`;
242              nextStage(joinAura);
243              arrowIcon.classList.remove('icon-hide');
244              joinAura.querySelector('.otp-info-text .disabled')?.classList.remove('disabled');
245              otpContainer.querySelector('.error-message-container').classList.add('hide');
246              otpContainer.querySelector('.error-message-container .error-message').textContent = '';
247            } else {
248              const inputFieldWrapper = mobileForm.querySelector('.input-field-wrapper');
249              const errorMessage = status.parameters.length > 0 ? status?.parameters[0] : 'Maximum number of attempts reached. Please try after sometime.';
250              showErrorMessage(inputFieldWrapper, errorMessage);
251            }
252          } else {
253            const inputFieldWrapper = mobileForm.querySelector('.input-field-wrapper');
254            const errorMessage = placeholders.mobileRegisteredErrorMessage || 'This phone number is already registered. Please sign-in or use a different phone number';
255            showErrorMessage(inputFieldWrapper, errorMessage);
256          }
257        } catch (error) {
258          console.error(error);
259        } finally {
260          isSubmitting = false;
261        }
262      });
263
264      otpForm.addEventListener('submit', async (event) => {
265        event.preventDefault();
266
267        if (isSubmitting) {
268          return;
269        }
270
271        isSubmitting = true;
272
273        try {
274          const mobile = mobileForm.querySelector('#login-mobile').value;
275          const otp = otpForm.querySelector('#otp-input').value;
276
277          if (otp === '') {
278            isSubmitting = false;
279            const inputFieldWrapper = otpForm.querySelector('.input-field-wrapper');
280            const errorMessage = placeholders.noOtpMessage || 'Please enter One time pin';
281            showErrorMessage(inputFieldWrapper, errorMessage);
282            return;
283          }
284
285          const status = await verifyOtpApiCall(mobile, countryPrefix, otp);
286
287          if (status === true) {
288            dataLayerAuraBlock(eventAction, 'verify otp');
289            nextStage(joinAura);
290            arrowIcon.classList.add('icon-hide');
291          } else {
292            const inputFieldWrapper = otpForm.querySelector('.input-field-wrapper');
293            const errorMessage = placeholders.incorrectOtpErrorMessage || 'Incorrect OTP';
294            showErrorMessage(inputFieldWrapper, errorMessage);
295          }
296        } catch (error) {
297          console.error(error);
298        } finally {
299          isSubmitting = false;
300        }
301      });
302
303      userDetailsForm.addEventListener('submit', async (event) => {
304        event.preventDefault();
305        if (!validateForm(userDetailsForm) || isSubmitting) {
306          return;
307        }
308        isSubmitting = true;
309
310        try {
311          const email = userDetailsForm.querySelector('#email-address').value;
312          const mobileNumber = mobileForm.querySelector('#login-mobile').value;
313
314          auraProfileExistsByEmail = await checkUserExists(email, 'email');
315          const mobile = `+${countryPrefix}${mobileNumber}`;
316          const fullname = userDetailsForm.querySelector('#fullname').value;
317
318          dataLayerAuraBlock(eventAction, 'name'); // Call dataLayerAuraBlock for successful name entry.
319          dataLayerAuraBlock(eventAction, 'email'); // Call dataLayerAuraBlock for successful email.
320
321          const nameParts = fullname.trim().split(' ');
322          const firstname = nameParts.slice(0, -1).join(' ');
323          const lastname = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';
324          const isVerified = 'Y';
325          if (!auraProfileExistsByPhone && !auraProfileExistsByEmail) {
326            const status = await userRegister(firstname, lastname, email, mobile, isVerified, true);
327            const response = await getAuraCustomerData();
328
329            if (['2', 2].includes(response?.apc_link)) {
330              congratsStage.querySelector('.aura-quick-enrolled').remove();
331              congratsStage.querySelector('.aura-social').remove();
332            } else {
333              congratsStage.querySelector('.aura-full-enrolled')?.remove();
334            }
335            if (status?.apc_identifier_number !== null || status === true) {
336              const congratulationsTitle = joinAura.querySelector('.congratulations-title');
337              joinAura.querySelector('.modal-header > h4').textContent = congratulationsTitle.querySelector('*').textContent;
338              joinAura.querySelector('.congratulations-title').remove();
339              const refreshAuraEvent = new CustomEvent('EVENT_AURA_JOINED', {
340                detail: { message: 'Aura was Joined!' },
341              });
342              window.dispatchEvent(refreshAuraEvent);
343              window.dispatchEvent(new CustomEvent('storage', { detail: CACHE_KEYS.AURA_INFO }));
344              // Call dataLayerAuraBlock for success page.
345              dataLayerAuraBlock(eventAction, 'success');
346              nextStage(joinAura);
347            } else {
348              const inputFieldWrapper = userDetailsForm.querySelector('.input-field-wrapper:last-child');
349              const auraRegisterError = sessionStorage.getItem('_aura_register_error');
350              const errorMessage = auraRegisterError || placeholders.incorrectEmailAddress || 'Please Enter Valid Email ID';
351              showErrorMessage(inputFieldWrapper, errorMessage);
352              // Call dataLayerAuraBlock for fail page
353              dataLayerAuraBlock(eventAction, 'fail');
354            }
355          } else {
356            const inputFieldWrapper = userDetailsForm.querySelector('.input-field-wrapper:last-child');
357            const errorMessage = placeholders.emailRegisteredErrorMessage || 'This email is already registered. Please sign-in or use a different email';
358            showErrorMessage(inputFieldWrapper, errorMessage);
359            // Call dataLayerAuraBlock for fail page
360            dataLayerAuraBlock(eventAction, 'fail');
361          }
362        } catch (error) {
363          console.error(error);
364        } finally {
365          isSubmitting = false;
366        }
367      });
368
369      auraModalRedirection(congratsForm, 'join-aura-dialog', 'join-aura-redirect', reDecorate);
370
371      arrowIcon.addEventListener('click', async (event) => {
372        event.preventDefault();
373        prevStage(joinAura);
374        arrowIcon.classList.add('icon-hide');
375      });
376
377      linkAura.addEventListener('click', async (event) => {
378        // eslint-disable-next-line import/no-cycle
379        const { createLinkAura } = await import('../link-your-aura/link-your-aura.js');
380        event.preventDefault();
381        closeModal('join-aura-dialog', true, false);
382        setTimeout(() => {
383          createLinkAura(reDecorate, `SignIn_${event.target.textContent.trim()}`, false);
384        }, MODAL_DELAY_MILLIS); // Adjust the delay (in milliseconds) as needed
385      });
386
387      submitOnEnter(forms);
388    }
389
390    // close aura card but not remove it
391    closeModal('aura-menu-dialog', false, false);
392    setTimeout(() => {
393      openModal('join-aura-dialog');
394    }, MODAL_DELAY_MILLIS); // Adjust the delay (in milliseconds) as needed
395  });
396}

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.