diff --git a/_includes/newsletter.liquid b/_includes/newsletter.liquid
new file mode 100644
index 000000000000..ebceefcbc10f
--- /dev/null
+++ b/_includes/newsletter.liquid
@@ -0,0 +1,68 @@
+
+
+
diff --git a/_includes/related_posts.liquid b/_includes/related_posts.liquid
index 37aeef5f6852..2d02344ad8d7 100644
--- a/_includes/related_posts.liquid
+++ b/_includes/related_posts.liquid
@@ -18,5 +18,5 @@
{% endfor %}
{% if site.newsletter.enabled and site.footer_fixed %}
{{ site.data[site.active_lang].strings.newsletter.subscribe_to_receive }}
- {% include scripts/newsletter.liquid left=true %}
+ {% include newsletter.liquid left=true %}
{% endif %}
diff --git a/_includes/scripts.liquid b/_includes/scripts.liquid
index e1a2a8a842e2..7bbd07166933 100644
--- a/_includes/scripts.liquid
+++ b/_includes/scripts.liquid
@@ -310,3 +310,7 @@
{% endif %}
+
+{% if site.newsletter.enabled %}
+
+{% endif %}
diff --git a/_layouts/about.liquid b/_layouts/about.liquid
index ba5d7df6d0ed..9bae797d3aca 100644
--- a/_layouts/about.liquid
+++ b/_layouts/about.liquid
@@ -73,7 +73,7 @@ layout: default
{% endif %}
{% if site.newsletter.enabled and site.footer_fixed %}
- {% include scripts/newsletter.liquid center=true %}
+ {% include newsletter.liquid center=true %}
{% endif %}
diff --git a/assets/js/newsletter.js b/assets/js/newsletter.js
new file mode 100644
index 000000000000..679e42bda90e
--- /dev/null
+++ b/assets/js/newsletter.js
@@ -0,0 +1,105 @@
+function submitHandler(event) {
+ event.preventDefault();
+ var container = event.target.parentNode;
+ var form = container.querySelector(".newsletter-form");
+ var formInput = container.querySelector(".newsletter-form-input");
+ var success = container.querySelector(".newsletter-success");
+ var errorContainer = container.querySelector(".newsletter-error");
+ var errorMessage = container.querySelector(".newsletter-error-message");
+ var backButton = container.querySelector(".newsletter-back-button");
+ var submitButton = container.querySelector(".newsletter-form-button");
+ var loadingButton = container.querySelector(".newsletter-loading-button");
+
+ const rateLimit = () => {
+ errorContainer.style.display = "flex";
+ errorMessage.innerText = "Too many signups, please try again in a little while";
+ submitButton.style.display = "none";
+ formInput.style.display = "none";
+ backButton.style.display = "block";
+ };
+
+ // Compare current time with time of previous sign up
+ var time = new Date();
+ var timestamp = time.valueOf();
+ var previousTimestamp = localStorage.getItem("loops-form-timestamp");
+
+ // If last sign up was less than a minute ago
+ // display error
+ if (previousTimestamp && Number(previousTimestamp) + 60000 > timestamp) {
+ rateLimit();
+ return;
+ }
+ localStorage.setItem("loops-form-timestamp", timestamp);
+
+ submitButton.style.display = "none";
+ loadingButton.style.display = "flex";
+
+ var formBody = "userGroup=&email=" + encodeURIComponent(formInput.value);
+ fetch(event.target.action, {
+ method: "POST",
+ body: formBody,
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ })
+ .then((res) => [res.ok, res.json(), res])
+ .then(([ok, dataPromise, res]) => {
+ if (ok) {
+ // If response successful
+ // display success
+ success.style.display = "flex";
+ form.reset();
+ } else {
+ // If response unsuccessful
+ // display error message or response status
+ dataPromise.then((data) => {
+ errorContainer.style.display = "flex";
+ errorMessage.innerText = data.message ? data.message : res.statusText;
+ });
+ }
+ })
+ .catch((error) => {
+ // check for cloudflare error
+ if (error.message === "Failed to fetch") {
+ rateLimit();
+ return;
+ }
+ // If error caught
+ // display error message if available
+ errorContainer.style.display = "flex";
+ if (error.message) errorMessage.innerText = error.message;
+ localStorage.setItem("loops-form-timestamp", "");
+ })
+ .finally(() => {
+ formInput.style.display = "none";
+ loadingButton.style.display = "none";
+ backButton.style.display = "block";
+ });
+}
+function resetFormHandler(event) {
+ var container = event.target.parentNode;
+ var formInput = container.querySelector(".newsletter-form-input");
+ var success = container.querySelector(".newsletter-success");
+ var errorContainer = container.querySelector(".newsletter-error");
+ var errorMessage = container.querySelector(".newsletter-error-message");
+ var backButton = container.querySelector(".newsletter-back-button");
+ var submitButton = container.querySelector(".newsletter-form-button");
+
+ success.style.display = "none";
+ errorContainer.style.display = "none";
+ errorMessage.innerText = "Oops! Something went wrong, please try again";
+ backButton.style.display = "none";
+ formInput.style.display = "flex";
+ submitButton.style.display = "flex";
+}
+
+var formContainers = document.getElementsByClassName("newsletter-form-container");
+
+for (var i = 0; i < formContainers.length; i++) {
+ var formContainer = formContainers[i];
+ var handlersAdded = formContainer.classList.contains("newsletter-handlers-added");
+ if (handlersAdded) continue;
+ formContainer.querySelector(".newsletter-form").addEventListener("submit", submitHandler);
+ formContainer.querySelector(".newsletter-back-button").addEventListener("click", resetFormHandler);
+ formContainer.classList.add("newsletter-handlers-added");
+}