added subscriptions

This commit is contained in:
2023-01-24 16:30:49 +10:00
parent 4c83399d4a
commit 0b1fee1cdc
15 changed files with 690 additions and 73 deletions

View File

@@ -92,33 +92,33 @@
/* Padding */
@each $index, $size in $spacer {
.p-#{$index} {
padding: #{$size};
padding: #{$size} !important;
}
.pt-#{$index} {
padding-top: #{$size};
padding-top: #{$size} !important;
}
.pb-#{$index} {
padding-bottom: #{$size};
padding-bottom: #{$size} !important;
}
.pl-#{$index} {
padding-left: #{$size};
padding-left: #{$size} !important;
}
.pr-#{$index} {
padding-right: #{$size};
padding-right: #{$size} !important;
}
.px-#{$index} {
padding-left: #{$size};
padding-right: #{$size};
padding-left: #{$size} !important;
padding-right: #{$size} !important;
}
.py-#{$index} {
padding-top: #{$size};
padding-bottom: #{$size};
padding-top: #{$size} !important;
padding-bottom: #{$size} !important;
}
}

View File

@@ -65,6 +65,14 @@ export const routes = [
},
component: () => import("@/views/Rules.vue"),
},
{
path: "/unsubscribe",
name: "unsubscribe",
meta: {
title: "Unsubscribe",
},
component: () => import("@/views/Unsubscribe.vue"),
},
{
path: "/terms",
name: "terms",

View File

@@ -110,25 +110,67 @@
Join our mailing list to receive tips, tricks and be notified of
upcoming workshops.
</p>
<div class="form-row">
<SMInput ref="email" type="email" placeholder="Email address" />
<SMButton label="Subscribe" @click="handleSubscribe" />
</div>
<SMDialog :loading="formLoading" class="p-0">
<form @submit.prevent="handleSubscribe">
<div class="form-row">
<SMMessage
v-if="formMessage.message"
:type="formMessage.type"
:message="formMessage.message"
:icon="formMessage.icon" />
<SMInput
v-model="subscribeFormData.email.value"
placeholder="Email address"
:error="subscribeFormData.email.error"
@blur="fieldValidate(subscribeFormData.email)" />
<SMCaptchaNotice />
<SMButton type="submit" label="Subscribe" />
</div>
</form>
</SMDialog>
</SMContainer>
</SMContainer>
</template>
<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";
import { reactive, ref } from "vue";
import { buildUrlQuery, excerpt } from "../helpers/common";
import {
useValidation,
isValidated,
fieldValidate,
restParseErrors,
} from "../helpers/validation";
import SMInput from "../components/SMInput.vue";
import SMButton from "../components/SMButton.vue";
import SMCarousel from "../components/SMCarousel.vue";
import SMCarouselSlide from "../components/SMCarouselSlide.vue";
import SMMessage from "../components/SMMessage.vue";
import SMCaptchaNotice from "../components/SMCaptchaNotice.vue";
import SMDialog from "../components/SMDialog.vue";
import { useReCaptcha } from "vue-recaptcha-v3";
const slides = ref([]);
const email = ref(null);
const { executeRecaptcha, recaptchaLoaded } = useReCaptcha();
const subscribeFormData = reactive({
email: {
value: "",
error: "",
rules: {
required: true,
required_message: "An email address is needed.",
email: true,
email_message: "That does not appear to be an email address.",
},
},
});
const formMessage = reactive({
message: "",
type: "error",
icon: "",
});
const formLoading = ref(false);
const handleLoad = async () => {
slides.value = [];
@@ -179,10 +221,34 @@ const handleLoad = async () => {
}
};
const handleSubscribe = () => {
console.log("form");
const handleSubscribe = async () => {
formLoading.value = true;
formMessage.icon = "";
formMessage.type = "error";
formMessage.message = "";
try {
if (isValidated(subscribeFormData)) {
await recaptchaLoaded();
const captcha = await executeRecaptcha("submit");
await axios.post("subscriptions", {
email: subscribeFormData.email.value,
captcha_token: captcha,
});
subscribeFormData.email.value = "";
formMessage.type = "success";
formMessage.message = "Your email address has been subscribed.";
}
} catch (err) {
restParseErrors(subscribeFormData, [formMessage, "message"], err);
}
formLoading.value = false;
};
useValidation(subscribeFormData);
handleLoad();
</script>

View File

@@ -0,0 +1,118 @@
<template>
<SMContainer>
<SMRow>
<SMDialog narrow :loading="formLoading">
<template v-if="!formDone">
<h1>Unsubscribe</h1>
<p>
If you would like to unsubscribe from our mailing list,
you have come to the right page!
</p>
<SMMessage
v-if="formMessage.message"
:type="formMessage.type"
:message="formMessage.message"
:icon="formMessage.icon" />
<form @submit.prevent="submit">
<SMInput
v-model="formData.email.value"
name="email"
label="Email"
required
:error="formData.email.error"
@blur="fieldValidate(formData.email)" />
<SMCaptchaNotice />
<SMFormFooter>
<template #right>
<SMButton type="submit" label="Unsubscribe" />
</template>
</SMFormFooter>
</form>
</template>
<template v-else>
<h1>Unsubscribed</h1>
<p class="text-center">
You have now been unsubscribed from our newsletter.
</p>
<SMRow class="pb-2">
<SMColumn class="justify-content-center">
<SMButton :to="{ name: 'home' }" label="Home" />
</SMColumn>
</SMRow>
</template>
</SMDialog>
</SMRow>
</SMContainer>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import SMInput from "../components/SMInput.vue";
import SMButton from "../components/SMButton.vue";
import SMFormFooter from "../components/SMFormFooter.vue";
import SMDialog from "../components/SMDialog.vue";
import SMMessage from "../components/SMMessage.vue";
import axios from "axios";
import { useRoute } from "vue-router";
import {
useValidation,
isValidated,
fieldValidate,
restParseErrors,
} from "../helpers/validation";
import SMCaptchaNotice from "../components/SMCaptchaNotice.vue";
import { useReCaptcha } from "vue-recaptcha-v3";
const { executeRecaptcha, recaptchaLoaded } = useReCaptcha();
const formLoading = ref(false);
const formDone = ref(false);
const formMessage = reactive({
message: "",
type: "error",
icon: "",
});
const formData = reactive({
email: {
value: "",
error: "",
rules: {
required: true,
required_message: "An email address is required.",
email: true,
email_message: "That does not look like an email address.",
},
},
});
useValidation(formData);
const submit = async () => {
formLoading.value = true;
formMessage.type = "error";
formMessage.icon = "fa-solid fa-circle-exclamation";
formMessage.message = "";
try {
if (isValidated(formData)) {
await recaptchaLoaded();
const captcha = await executeRecaptcha("submit");
await axios.delete("subscriptions", {
email: formData.email.value,
captcha_token: captcha,
});
formDone.value = true;
}
} catch (err) {
restParseErrors(formData, [formMessage, "message"], err);
}
formLoading.value = false;
};
if (useRoute().query.email !== undefined) {
formData.email.value = useRoute().query.email;
submit();
}
</script>

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>STEMMechanics - Subscription</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800&display=swap');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-size: 1.1rem;
font-family: Nunito, Arial, Helvetica, sans-serif !important;
color: #000000;
padding: 2rem;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
div.main {
margin: 0 auto;
background-color: #ffffff;
overflow: hidden;
}
div.footer {
margin: 2rem auto;
max-width: 48rem;
font-size: 70%;
text-align: center;
}
a.brand {
display: block;
margin-bottom: 2rem;
padding: 0 2rem;
}
a.brand:hover {
text-decoration: none;
}
h2 {
margin-bottom: 2rem;
}
p {
margin-bottom: 1rem;
}
a.brand img {
width: 100%;
max-width: 100%;
object-fit: contain;
}
.code {
display: block;
font-size: 200%;
text-align: center;
margin-top: 2rem;
margin-bottom: 2rem;
letter-spacing: 0.5rem;
}
.feedback {
font-size: 90%;
text-align: center;
}
.border {
border-top: 1px solid #ddd;
margin-bottom: 2rem;
}
a, a:visited, a:hover {
color: #2563EB;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="main">
<a href="https://www.stemmechanics.com.au/" class="brand">
<img alt="STEMMechanics Logo" src="{{ $message->embed(public_path('img').'/logo.png') }}">
</a>
<h2>Howdy there,</h2>
<p>At your request, you are now subscribed to our newsletter giving you tips, tricks and letting you know when new workshops are scheduled.</p>
<p>If this wasn't you, you can unsubscribe by visiting <a href="https://www.stemmechanics.com.au/unsubscribe?email={{ $email }}">stemmechanics.com.au/unsubscribe</a></p>
<div class="border"></div>
<p class="feedback">Need help or got feedback? <a href="https://www.stemmechanics.com.au/contact">Contact us</a> or touch base at <a href="https://twitter.com/stemmechanics">@stemmechanics</a>.</p>
</div>
<div class="footer">Sent by STEMMechanics &middot; <a href="https://www.stemmechanics.com.au/">Visit our Website</a> &middot; <a href="https://twitter.com/stemmechanics">@stemmechanics</a><br>PO Box 36, Edmonton, QLD 4869, Australia</div>
</body>
</html>

View File

@@ -0,0 +1,14 @@
Howdy there,
At your request, you are now subscribed to our newsletter giving you tips, tricks and letting you know when new workshops are scheduled.
If this wasn't you, you can unsubscribe by visiting the following URL in your browser:
https://www.stemmechanics.com.au/unsubscribe
Need help or got feedback? Contact us at https://www.stemmechanics.com.au/contact or touch base on twitter at @stemmechanics
--
Sent by STEMMechanics
https://www.stemmechanics.com.au/
PO Box 36, Edmonton, QLD 4869, Australia

View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>STEMMechanics - Subscription</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800&display=swap');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-size: 1.1rem;
font-family: Nunito, Arial, Helvetica, sans-serif !important;
color: #000000;
padding: 2rem;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
div.main {
margin: 0 auto;
background-color: #ffffff;
overflow: hidden;
}
div.footer {
margin: 2rem auto;
max-width: 48rem;
font-size: 70%;
text-align: center;
}
a.brand {
display: block;
margin-bottom: 2rem;
padding: 0 2rem;
}
a.brand:hover {
text-decoration: none;
}
h2 {
margin-bottom: 2rem;
}
p {
margin-bottom: 1rem;
}
a.brand img {
width: 100%;
max-width: 100%;
object-fit: contain;
}
.code {
display: block;
font-size: 200%;
text-align: center;
margin-top: 2rem;
margin-bottom: 2rem;
letter-spacing: 0.5rem;
}
.feedback {
font-size: 90%;
text-align: center;
}
.border {
border-top: 1px solid #ddd;
margin-bottom: 2rem;
}
a, a:visited, a:hover {
color: #2563EB;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="main">
<a href="https://www.stemmechanics.com.au/" class="brand">
<img alt="STEMMechanics Logo" src="{{ $message->embed(public_path('img').'/logo.png') }}">
</a>
<h2>Howdy there,</h2>
<p>At your request, you are now unsubscribed from our newsletter.</p>
<div class="border"></div>
<p class="feedback">Need help or got feedback? <a href="https://www.stemmechanics.com.au/contact">Contact us</a> or touch base at <a href="https://twitter.com/stemmechanics">@stemmechanics</a>.</p>
</div>
<div class="footer">Sent by STEMMechanics &middot; <a href="https://www.stemmechanics.com.au/">Visit our Website</a> &middot; <a href="https://twitter.com/stemmechanics">@stemmechanics</a><br>PO Box 36, Edmonton, QLD 4869, Australia</div>
</body>
</html>

View File

@@ -0,0 +1,10 @@
Howdy there,
At your request, you have been unsubscribed from our newsletter.
Need help or got feedback? Contact us at https://www.stemmechanics.com.au/contact or touch base on twitter at @stemmechanics
--
Sent by STEMMechanics
https://www.stemmechanics.com.au/
PO Box 36, Edmonton, QLD 4869, Australia