Skip to content

Commit 55034c6

Browse files
authoredFeb 26, 2023
Merge pull request #20 from whythawk/add-contact-page
Added new contact page
2 parents 837b302 + 406104a commit 55034c6

File tree

6 files changed

+162
-1
lines changed

6 files changed

+162
-1
lines changed
 

‎{{cookiecutter.project_slug}}/backend/app/app/api/api_v1/api.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
login,
55
users,
66
proxy,
7+
services,
78
)
89

910
api_router = APIRouter()
1011
api_router.include_router(login.router, prefix="/login", tags=["login"])
1112
api_router.include_router(users.router, prefix="/users", tags=["users"])
1213
api_router.include_router(proxy.router, prefix="/proxy", tags=["proxy"])
14+
api_router.include_router(services.router, prefix="/service", tags=["service"])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from typing import Any
2+
3+
from fastapi import APIRouter
4+
5+
from app import schemas
6+
from app.utilities import send_web_contact_email
7+
from app.schemas import EmailContent
8+
9+
router = APIRouter()
10+
11+
12+
@router.post("/contact", response_model=schemas.Msg, status_code=201)
13+
def send_email(*, data: EmailContent) -> Any:
14+
"""
15+
Standard app contact us.
16+
"""
17+
send_web_contact_email(data=data)
18+
return {"msg": "Web contact email sent"}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { apiCore } from "./core"
22
import { apiAuth } from "./auth"
3+
import { apiService } from "./services"
34

4-
export { apiCore, apiAuth }
5+
export { apiCore, apiAuth, apiService }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ISendEmail, IMsg } from "@/interfaces"
2+
import { apiCore } from "./core"
3+
4+
export const apiService = {
5+
// USER CONTACT MESSAGE
6+
async postEmailContact(data: ISendEmail) {
7+
return await useFetch<IMsg>(`${apiCore.url()}/service/contact`,
8+
{
9+
method: "POST",
10+
body: data,
11+
}
12+
)
13+
},
14+
}

‎{{cookiecutter.project_slug}}/frontend/components/layouts/default/Footer.vue

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const footerNavigation = {
2525
{ name: "About", to: "/about" },
2626
{ name: "Authentication", to: "/authentication" },
2727
{ name: "Blog", to: "/blog" },
28+
{ name: "Contact", to: "/contact" },
2829
],
2930
social: [
3031
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<template>
2+
<div class="relative isolate bg-white">
3+
<div class="mx-auto grid max-w-7xl grid-cols-1 lg:grid-cols-2">
4+
<div class="relative px-6 pt-24 pb-20 sm:pt-32 lg:static lg:py-48 lg:px-8">
5+
<div class="mx-auto max-w-xl lg:mx-0 lg:max-w-lg">
6+
<div
7+
class="absolute inset-y-0 left-0 -z-10 w-full overflow-hidden bg-gray-100 ring-1 ring-gray-900/10 lg:w-1/2">
8+
<svg
9+
class="absolute inset-0 h-full w-full stroke-gray-200 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)]"
10+
aria-hidden="true">
11+
<defs>
12+
<pattern id="83fd4e5a-9d52-42fc-97b6-718e5d7ee527" width="200" height="200" x="100%" y="-1"
13+
patternUnits="userSpaceOnUse">
14+
<path d="M130 200V.5M.5 .5H200" fill="none" />
15+
</pattern>
16+
</defs>
17+
<rect width="100%" height="100%" stroke-width="0" fill="white" />
18+
<svg x="100%" y="-1" class="overflow-visible fill-gray-50">
19+
<path d="M-470.5 0h201v201h-201Z" stroke-width="0" />
20+
</svg>
21+
<rect width="100%" height="100%" stroke-width="0" fill="url(#83fd4e5a-9d52-42fc-97b6-718e5d7ee527)" />
22+
</svg>
23+
</div>
24+
<h2 class="text-3xl font-bold tracking-tight text-gray-900">Get in touch</h2>
25+
<p class="mt-6 text-lg leading-8 text-gray-600">
26+
We would love to hear from you.
27+
</p>
28+
<dl class="mt-10 space-y-4 text-base leading-7 text-gray-600">
29+
<div class="flex gap-x-4">
30+
<dt class="flex-none">
31+
<span class="sr-only">Telephone</span>
32+
<BuildingOffice2Icon class="h-7 w-6 text-gray-400" aria-hidden="true" />
33+
</dt>
34+
<dd>545 Mavis Island<br />Chicago, IL 99191</dd>
35+
</div>
36+
<div class="flex gap-x-4">
37+
<dt class="flex-none">
38+
<span class="sr-only">Telephone</span>
39+
<PhoneIcon class="h-7 w-6 text-gray-400" aria-hidden="true" />
40+
</dt>
41+
<dd><a class="hover:text-gray-900" href="tel:+1 (555) 234-5678">+1 (555) 234-5678</a></dd>
42+
</div>
43+
<div class="flex gap-x-4">
44+
<dt class="flex-none">
45+
<span class="sr-only">Telephone</span>
46+
<EnvelopeIcon class="h-7 w-6 text-gray-400" aria-hidden="true" />
47+
</dt>
48+
<dd><a class="hover:text-gray-900" href="mailto:hello@example.com">hello@example.com</a></dd>
49+
</div>
50+
</dl>
51+
<p class="mt-6 text-sm leading-8 text-gray-600">
52+
We care about your data. Read our <NuxtLink to="/privacy" class="font-semibold hover:text-indigo-600">privacy
53+
policy</NuxtLink>.
54+
</p>
55+
</div>
56+
</div>
57+
<Form @submit="submit" :validation-schema="schema" class="px-6 pb-24 pt-20 sm:pb-32 lg:py-48 lg:px-8">
58+
<div class="mx-auto max-w-xl lg:mr-0 lg:max-w-lg">
59+
<div class="space-y-6">
60+
<div>
61+
<label for="email-address" class="block text-sm font-medium text-gray-700">Email address</label>
62+
<div class="mt-2.5 group relative inline-block w-full">
63+
<Field id="email-address" name="email" type="email" autocomplete="email" placeholder="Enter your email"
64+
class="block w-full rounded-md border-0 py-2 px-3.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" />
65+
<ErrorMessage name="email"
66+
class="absolute left-5 top-5 translate-y-full w-48 px-2 py-1 bg-gray-700 rounded-lg text-center text-white text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700" />
67+
</div>
68+
</div>
69+
<div>
70+
<label for="contact-message" class="block text-sm font-medium text-gray-700">Message</label>
71+
<div class="mt-2.5 group relative inline-block w-full">
72+
<Field id="contact-message" name="message" as="textarea" rows="4" placeholder="Enter your message"
73+
class="block w-full rounded-md border-0 py-2 px-3.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" />
74+
<ErrorMessage name="message"
75+
class="absolute left-5 top-5 translate-y-full w-48 px-2 py-1 bg-gray-700 rounded-lg text-center text-white text-sm after:content-[''] after:absolute after:left-1/2 after:bottom-[100%] after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:border-b-gray-700" />
76+
</div>
77+
</div>
78+
</div>
79+
<div class="mt-8 flex justify-end">
80+
<button type="submit"
81+
class="rounded-md bg-indigo-600 px-3.5 py-2.5 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Send
82+
message</button>
83+
</div>
84+
</div>
85+
</Form>
86+
</div>
87+
</div>
88+
</template>
89+
90+
<script setup lang="ts">
91+
import { BuildingOffice2Icon, EnvelopeIcon, PhoneIcon } from "@heroicons/vue/24/outline"
92+
import { ISendEmail } from "@/interfaces"
93+
import { useToastStore, useAuthStore } from "@/stores"
94+
import { apiService } from "@/api"
95+
96+
const toasts = useToastStore()
97+
const auth = useAuthStore()
98+
99+
const schema = {
100+
email: { email: true, required: true },
101+
message: { required: true },
102+
}
103+
104+
async function submit(values: any) {
105+
const data: ISendEmail = {
106+
email: values.email,
107+
subject: `Website contact from: ${values.email} `,
108+
content: values.message,
109+
}
110+
try {
111+
await apiService.postEmailContact(data)
112+
toasts.addNotice({
113+
title: "Message sent",
114+
content: "Thanks so much for contacting us.",
115+
})
116+
navigateTo("/")
117+
} catch (error) {
118+
toasts.addNotice({
119+
title: "Contact error",
120+
content: "Something went wrong with your email. Please check your details, or internet connection, and try again.",
121+
icon: "error"
122+
})
123+
}
124+
}
125+
</script>

0 commit comments

Comments
 (0)
Please sign in to comment.