add turnstile

This commit is contained in:
Rivaland Tawouafo 2024-02-04 08:01:14 +01:00
parent bd9b4ee2b5
commit 11ab30d0f5
7 changed files with 784 additions and 91 deletions

View file

@ -36,23 +36,24 @@ const localePath = useLocalePath()
<div class="flex flex-col gap-3 justify-between items-start w-fit sm:w-1/2 md:w-fit">
<h1 class="text-2xl text-c-blue">{{ t('footer.links.title') }}</h1>
<ul class="text-white text-sm">
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
t('footer.links.success') }}</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
t('footer.links.articles') }}</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
t('footer.links.services') }}</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
<NuxtLink :to="localePath('/portfolio')"> {{
t('footer.links.success') }}</NuxtLink>
</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
<NuxtLink :to="localePath('/blog')">
{{
t('footer.links.articles') }}
</NuxtLink>
</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
<NuxtLink :to="localePath('/services')">
{{
t('footer.links.services') }}
</NuxtLink>
</li>
</ul>
</div>
<!-- <div class="flex flex-col gap-3 justify-between items-start w-fit sm:w-1/2 md:w-fit">
<h1 class="text-2xl text-c-blue">{{ t('footer.socials.title') }}</h1>
<ul class="text-white text-sm">
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
t('footer.socials.linkedin') }}</li>
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
t('footer.socials.twitter') }}</li>
</ul>
</div> -->
</div>
</div>
<hr class="bg-white h-[1px] my-12 w-full">

View file

@ -1,59 +1,97 @@
<script setup lang="ts">
const { t } = useI18n({ useScope: 'global' })
import { useReCaptcha } from 'vue-recaptcha-v3';
// import { useReCaptcha } from 'vue-recaptcha-v3';
import { useForm } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/yup';
import * as yup from 'yup';
const { t, locale } = useI18n({ useScope: 'global' })
const localePath = useLocalePath()
const newMessage = reactive({
name: '',
email: '',
phone: '',
message: '',
})
const recaptchaInstance = useReCaptcha();
const recaptcha = async () => {
// optional you can await for the reCaptcha load
await recaptchaInstance?.recaptchaLoaded();
const schema = toTypedSchema(
yup.object({
name: yup.string().trim().min(3).required(),
email: yup.string().required().email(),
phone: yup.string().required(),
message: yup.string().required(),
}),
);
// get the token, a custom action could be added as argument to the method
const token = await recaptchaInstance?.executeRecaptcha('yourActionHere');
const { errors, values, defineField, handleSubmit } = useForm({
validationSchema: schema,
});
return token;
};
const [name, nameAttrs] = defineField('name');
const [email, emailAttrs] = defineField('email');
const [phone, phoneAttrs] = defineField('phone');
const [message, messageAttrs] = defineField('message');
async function submit(){
const token = await recaptcha();
const mail = useMail()
const toggle = ref(false)
const token = ref("")
const turnstile = ref()
function reset() {
turnstile.value?.reset()
}
const onSubmit = handleSubmit(async (values) => {
// const token = await recaptcha('login')
// .then(() => {
// })
toggle.value = !toggle.value
mail.send({
from: values.email,
subject: 'Incredible',
text: values.message,
})
});
</script>
<template>
<form action="" class="w-full lg:w-1/3 flex flex-col">
<form @submit.prevent="onSubmit" class="w-full lg:w-1/3 flex flex-col">
<div class="footer__form__field flex flex-col mb-3">
<label for="name">{{ t('footer.form.name') }}</label>
<input v-model="newMessage.name" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
name="name" type="text" :placeholder="t('footer.form.name_placeholder')">
<p class="text-red-500 ml-3 mt-1"></p>
<input id="name" v-model="name" v-bind="nameAttrs"
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="name" type="text"
:placeholder="t('footer.form.name_placeholder')" autocomplete="username">
<p class="text-red-500 ml-3 mt-1 transition-all">
{{ errors.name }}
</p>
</div>
<div class="footer__form__field flex flex-col mb-3">
<label for="email">{{ t('footer.form.email') }}</label>
<input v-model="newMessage.email" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
name="email" type="email" :placeholder="`${t('footer.form.email_placeholder')} myname@example.com`">
<p class="text-red-500 ml-3 mt-1"></p>
<input id="email" v-model="email" v-bind="emailAttrs"
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="email" type="email"
:placeholder="`${t('footer.form.email_placeholder')} myname@example.com`" autocomplete="email">
<p class="text-red-500 ml-3 mt-1 transition-all">
{{ errors.email }}
</p>
</div>
<div class="footer__form__field flex flex-col mb-3">
<label for="phone">{{ t('footer.form.phone') }}</label>
<input v-model="newMessage.phone" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
name="phone" type="tel" :placeholder="t('footer.form.phone_placeholder')">
<p class="text-red-500 ml-3 mt-1"></p>
<input id="phone" v-model="phone" v-bind="phoneAttrs"
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="phone" type="tel"
:placeholder="t('footer.form.phone_placeholder')" autocomplete="tel">
<p class="text-red-500 ml-3 mt-1 transition-all">
{{ errors.phone }}
</p>
</div>
<div class="footer__form__field flex flex-col mb-3">
<label for="name">{{ t('footer.form.message') }}</label>
<textarea v-model="newMessage.message" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
rows="3" name="message"></textarea>
<p class="text-red-500 ml-3 mt-1"></p>
<label for="message">{{ t('footer.form.message') }}</label>
<textarea id="message" v-model="message" v-bind="messageAttrs"
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" rows="3" name="message"></textarea>
<p class="text-red-500 ml-3 mt-1 transition-all">
{{ errors.message }}
</p>
</div>
<NuxtTurnstile v-if="toggle" ref="turnstile" v-model="token" :key="locale" :options="{ action: 'vue' }" />
<button class="btn__contact bg-c-blue text-c-darkblue px-7 py-2 uppercase text-xl rounded-full mt-3">
<button type="submit" class="btn__contact bg-c-blue text-c-darkblue px-7 py-2 uppercase text-xl rounded-full mt-3">
{{ t('footer.form.btn_form') }}
</button>
</form>

View file

@ -8,7 +8,17 @@ export default defineNuxtConfig({
"@dargmuesli/nuxt-cookie-control",
'@nuxt/content',
'@nuxthq/studio',
'@vueuse/motion/nuxt'
'@vueuse/motion/nuxt',
['nuxt-mail', {
message: {
to: 'foo@bar.de',
},
smtp: {
host: "smtp.example.com",
port: 587,
},
}],
'@nuxtjs/turnstile'
],
app: {
pageTransition: { name: 'page', mode: 'out-in' }
@ -41,6 +51,7 @@ export default defineNuxtConfig({
cookieKey: "i18n_redirected",
redirectOn: "root",
alwaysRedirect: true,
cookieCrossOrigin: true
},
},
cookieControl: {
@ -53,5 +64,5 @@ export default defineNuxtConfig({
},
content: {
}
},
});

696
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@
"devDependencies": {
"@dargmuesli/nuxt-cookie-control": "^7.2.4",
"@nuxthq/studio": "^1.0.10",
"@nuxtjs/turnstile": "^0.6.3",
"autoprefixer": "^10.4.17",
"nuxt": "^3.8.2",
"nuxt-aos": "^1.2.2",
@ -25,7 +26,9 @@
"dependencies": {
"@nuxt/content": "^2.11.0",
"@nuxtjs/i18n": "^8.0.0",
"@vee-validate/yup": "^4.12.5",
"@vueuse/motion": "^2.0.0",
"vue-recaptcha-v3": "^2.0.1"
"nuxt-mail": "^4.0.2",
"vee-validate": "^4.12.5"
}
}

View file

@ -1,5 +1,8 @@
const cookieControl = useCookieControl()
if (cookieControl.cookiesEnabledIds.value.includes('google-analytics')) {
initGoogleAnalytics() // placeholder for your custom initialization
}
export default defineNuxtPlugin((nuxtApp) => {
const cookieControl = useCookieControl()
if (cookieControl.cookiesEnabledIds.value?.includes('google-analytics')) {
initGoogleAnalytics() // placeholder for your custom initialization
}
})

View file

@ -1,13 +0,0 @@
import { VueReCaptcha } from 'vue-recaptcha-v3';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueReCaptcha, {
siteKey: '6Le062UpAAAAAEsjplkXWsQIiDzO_sVICajoqPk2',
loaderOptions: {
autoHideBadge: false,
explicitRenderParameters: {
badge: 'bottomright',
},
},
});
});