PageSourceSearch

https://globaladvertisingnews.com/js/controllers/newsletterSignup.js?v9e91e12689728780f01d6dd9a70eb5c9bae56d64

js globaladvertisingnews.com collected 2026-09-26 09:19:03 UTC 4,053 bytes, 150 lines download raw bytes

1import { Controller } from '../stimulus.js'
2import { postJson, EMAIL_REGEX } from '../utils/fetchUtils.js'
3const ERROR_GENERIC = 'An error occurred. Please try again later.';
4const ERROR_RESEND = 'Could not resend the activation email. Please try again later.';
5
6export default class extends Controller {
7  static targets = [
8    'emailInput', 'errorMessage', 'fullnameInput', 'timestampInput',
9    'formSection', 'checkEmailSection', 'welcomeBackSection',
10    'confirmedEmail', 'welcomeEmail', 'submitButton', 'retryMessage'
11  ];
12
13  #pendingEmail = null;
14  #retryCooldownTimer = null;
15  #countdownSpan = null;
16  #tryAgainLink = null;
17  #isRetrying = false;
18
19  disconnect() {
20    this.#clearCooldown();
21  }
22
23  async submit(event) {
24    event.preventDefault();
25
26    const email = this.emailInputTarget.value.trim();
27    this.#clearMessages();
28
29    if (!EMAIL_REGEX.test(email)) {
30      this.errorMessageTarget.innerText = 'Please enter a valid email address';
31      return;
32    }
33
34    await this.#submitEmail(email);
35  }
36
37  async tryAgain(event) {
38    event.preventDefault();
39    if (this.#retryCooldownTimer || this.#isRetrying) return;
40
41    const link = event.currentTarget;
42    this.#isRetrying = true;
43    this.#clearMessages();
44
45    const email = this.#pendingEmail;
46    if (!email) { this.#isRetrying = false; return; }
47
48    let message = ERROR_RESEND;
49    try {
50      const response = await this.#requestSignup(email);
51      if (response.ok || response.status === 409) message = 'Activation email re-sent!';
52    } catch { }
53    this.retryMessageTarget.innerText = message;
54    this.#isRetrying = false;
55
56    this.#startRetryCooldown(link);
57  }
58
59  #startRetryCooldown(link, seconds = 60) {
60    this.#tryAgainLink = link;
61    let remaining = seconds;
62
63    this.#countdownSpan = document.createElement('span');
64    const countdown = this.#countdownSpan;
65    link.insertAdjacentElement('afterend', countdown);
66    link.classList.add('pointer-events-none', 'opacity-50');
67
68    const update = () => { countdown.innerText = ` in ${remaining}s`; };
69    update();
70
71    this.#retryCooldownTimer = setInterval(() => {
72      remaining -= 1;
73      update();
74
75      if (remaining <= 0) this.#clearCooldown();
76    }, 1000);
77  }
78
79  #clearCooldown() {
80    if (this.#retryCooldownTimer) {
81      clearInterval(this.#retryCooldownTimer);
82      this.#retryCooldownTimer = null;
83    }
84    this.#countdownSpan?.remove();
85    this.#countdownSpan = null;
86    if (this.#tryAgainLink) {
87      this.#tryAgainLink.classList.remove('pointer-events-none', 'opacity-50');
88      this.#tryAgainLink = null;
89    }
90  }
91
92  async #submitEmail(email) {
93    this.#setSubmitting(true);
94
95    try {
96      const response = await this.#requestSignup(email);
97
98      if (response.ok) {
99        this.#showCheckEmail(email);
100        return;
101      }
102
103      if (response.status === 409) {
104        this.#showWelcomeBack(email);
105        return;
106      }
107
108      this.errorMessageTarget.innerText = response.status === 422
109        ? 'Please enter a valid email address'
110        : ERROR_GENERIC;
111    } catch {
112      this.errorMessageTarget.innerText = ERROR_GENERIC;
113    } finally {
114      this.#setSubmitting(false);
115    }
116  }
117
118  #requestSignup(email) {
119    return postJson('/alerts', {
120      email,
121      fullname: this.fullnameInputTarget.value,
122      timestamp: this.timestampInputTarget.value,
123    });
124  }
125
126  #setSubmitting(isSubmitting) {
127    this.submitButtonTarget.disabled = isSubmitting;
128  }
129
130  #clearMessages() {
131    this.errorMessageTarget.innerText = '';
132    this.retryMessageTarget.innerText = '';
133  }
134
135  #showSection(section) {
136    [this.formSectionTarget, this.checkEmailSectionTarget, this.welcomeBackSectionTarget]
137      .forEach(s => s.classList.toggle('hidden', s !== section));
138  }
139
140  #showCheckEmail(email) {
141    this.#pendingEmail = email;
142    this.confirmedEmailTarget.innerText = email;
143    this.#showSection(this.checkEmailSectionTarget);
144  }
145
146  #showWelcomeBack(email) {
147    this.welcomeEmailTarget.innerText = email;
148    this.#showSection(this.welcomeBackSectionTarget);
149  }
150}

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.