aboutsummaryrefslogtreecommitdiff
path: root/src/routes/contact
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2026-01-01 18:32:49 -0800
committerElizabeth Hunt <me@liz.coffee>2026-01-01 18:32:49 -0800
commit9af1854a7e35785a8e86426c4fb1edd465f164a3 (patch)
tree8a070c6a9498d952c9ef4ba045f2ebfb25f7b335 /src/routes/contact
parent0248a3899ed910f005dccaeefc1d9dcb893e8154 (diff)
downloadmistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.tar.gz
mistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.zip
Massive refactor courtesy of 5 dollars of AI tokens
Diffstat (limited to 'src/routes/contact')
-rw-r--r--src/routes/contact/+page.svelte325
-rw-r--r--src/routes/contact/index.svelte158
-rw-r--r--src/routes/contact/submit/+server.js (renamed from src/routes/contact/submit.js)31
3 files changed, 338 insertions, 176 deletions
diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte
new file mode 100644
index 0000000..c66d9df
--- /dev/null
+++ b/src/routes/contact/+page.svelte
@@ -0,0 +1,325 @@
+<script>
+ import { browser } from '$app/environment';
+ import HCaptcha from 'svelte-hcaptcha';
+
+ const mapsUrl = 'https://maps.app.goo.gl/s1AFqfKvUKgXDCrq5';
+
+ let submission = {
+ name: '',
+ email: '',
+ message: '',
+ phone: '',
+ captchaToken: ''
+ };
+
+ let captcha;
+ let noticeType = 'info';
+ let noticeMessage = '';
+
+ function setNotice(type, message) {
+ noticeType = type;
+ noticeMessage = message;
+ }
+
+ function handleSubmit(e) {
+ e.preventDefault();
+
+ if (!browser) return;
+ if (!submission.captchaToken) {
+ setNotice('error', 'Please complete the captcha first.');
+ return;
+ }
+
+ setNotice('info', 'Sending...');
+ fetch('/contact/submit', {
+ method: 'POST',
+ body: JSON.stringify(submission)
+ })
+ .then((x) => x.json())
+ .then((x) => {
+ if (x.success) {
+ setNotice('success', 'Success! Reloading...');
+ setTimeout(() => window.location.reload(), 1000);
+ } else {
+ setNotice('error', x.error ?? 'Something went wrong. Please try again.');
+ }
+ })
+ .catch((err) => {
+ console.log(err);
+ setNotice('error', 'Network error. Please try again.');
+ });
+ }
+
+ function onCaptchaError() {
+ setNotice('error', 'Failed to verify captcha, try again.');
+ captcha?.reset();
+ submission.captchaToken = '';
+ }
+
+ function onCaptchaSuccess({ detail: { token } }) {
+ submission.captchaToken = token;
+ }
+</script>
+
+<div class="contact">
+ <header class="contact__header">
+ <h1>Contact</h1>
+ </header>
+
+ {#if noticeMessage}
+ <div
+ class={'notice notice--' + noticeType}
+ role={noticeType === 'error' ? 'alert' : 'status'}
+ aria-live={noticeType === 'error' ? 'assertive' : 'polite'}
+ >
+ {noticeMessage}
+ </div>
+ {/if}
+
+ <div class="contact__grid">
+ <div class="contact__sidebar">
+ <section class="card" aria-label="Contact details">
+ <h2>Details</h2>
+
+ <div class="contact__methods">
+ <a class="contact__method" href={mapsUrl} target="_blank" rel="noopener noreferrer">
+ <span class="contact__icon" aria-hidden="true"><i class="bi bi-pin-map"></i></span>
+ <span class="contact__methodBody">
+ <span class="contact__methodTitle">Office</span>
+ <span class="contact__methodText">
+ 534 Trejo Street, Suite 200F<br />Rexburg, ID 83440
+ </span>
+ </span>
+ </a>
+
+ <a class="contact__method" href="tel:12084994517">
+ <span class="contact__icon" aria-hidden="true"><i class="bi bi-telephone"></i></span>
+ <span class="contact__methodBody">
+ <span class="contact__methodTitle">Phone</span>
+ <span class="contact__methodText">(208) 499 - 4517</span>
+ </span>
+ </a>
+
+ <a class="contact__method" href="mailto:contact@mistymountainstherapy.com">
+ <span class="contact__icon" aria-hidden="true"><i class="bi bi-envelope"></i></span>
+ <span class="contact__methodBody">
+ <span class="contact__methodTitle">Email</span>
+ <span class="contact__methodText">contact@mistymountainstherapy.com</span>
+ </span>
+ </a>
+ </div>
+ </section>
+
+ <section class="card card--warn" aria-label="Crisis resources">
+ <h2>In a crisis?</h2>
+ <p style="margin: 0">
+ We do not have a crisis line. If you or someone you know is in danger please call 911, visit your
+ nearest emergency room, call the National Suicide Prevention Lifeline at
+ <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741.
+ </p>
+ </section>
+ </div>
+
+ <section class="card" aria-label="Send a message">
+ <h2>Send a message</h2>
+ <form class="contact__form" on:submit|preventDefault={handleSubmit}>
+ <div class="contact__fields">
+ <label class="field">
+ <span class="field__label">Email *</span>
+ <input
+ type="email"
+ class="form-control"
+ bind:value={submission.email}
+ placeholder="johnnyappleseed@example.com"
+ required
+ />
+ </label>
+
+ <label class="field">
+ <span class="field__label">Name *</span>
+ <input
+ type="text"
+ class="form-control"
+ bind:value={submission.name}
+ placeholder="Johnny Appleseed"
+ required
+ />
+ </label>
+
+ <label class="field">
+ <span class="field__label">Phone</span>
+ <input
+ type="text"
+ class="form-control"
+ bind:value={submission.phone}
+ placeholder="(208) 123-4567"
+ />
+ </label>
+
+ <label class="field">
+ <span class="field__label">Message *</span>
+ <textarea
+ class="form-control"
+ bind:value={submission.message}
+ rows="6"
+ placeholder="Hello! I would like to schedule a free 15-minute consultation..."
+ required
+ ></textarea>
+ </label>
+ </div>
+
+ <div class="contact__captcha">
+ <HCaptcha
+ sitekey={import.meta.env.VITE_HCAPTCHA_KEY}
+ bind:this={captcha}
+ on:success={onCaptchaSuccess}
+ on:error={onCaptchaError}
+ />
+ </div>
+
+ <div class="contact__actions">
+ <button type="submit" class="button button--primary" disabled={!submission.captchaToken}>
+ Submit
+ </button>
+ <p class="text-muted" style="margin: 0">
+ Please watch spam for replies.
+ </p>
+ </div>
+ </form>
+ </section>
+ </div>
+</div>
+
+<style>
+ .contact {
+ display: grid;
+ gap: var(--space-5);
+ }
+
+ .contact__header {
+ display: grid;
+ gap: var(--space-2);
+ }
+
+ .contact__lede {
+ margin: 0;
+ color: var(--color-muted);
+ }
+
+ .contact__grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-5);
+ align-items: start;
+ }
+
+ @media (min-width: 900px) {
+ .contact__grid {
+ grid-template-columns: 1fr minmax(0, 320px);
+ }
+
+ .contact__sidebar {
+ order: 2;
+ }
+ }
+
+ .contact__sidebar {
+ display: grid;
+ gap: var(--space-5);
+ min-width: 0;
+ }
+
+ .contact__methods {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-3);
+ }
+
+ .contact__method {
+ display: grid;
+ grid-template-columns: 2.25rem 1fr;
+ gap: var(--space-3);
+ align-items: start;
+ padding: var(--space-3);
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--color-border);
+ text-decoration: none;
+ background: rgba(255, 255, 255, 0.55);
+ }
+
+ .contact__method:hover {
+ border-color: var(--color-accent);
+ }
+
+ .contact__icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.25rem;
+ height: 2.25rem;
+ border-radius: 999px;
+ background: color-mix(in srgb, var(--color-accent) 10%, transparent);
+ color: var(--color-accent-strong);
+ }
+
+ .contact__icon i {
+ font-size: 1.1rem;
+ }
+
+ .contact__methodBody {
+ display: grid;
+ gap: 0.15rem;
+ }
+
+ .contact__methodTitle {
+ font-weight: 700;
+ }
+
+ .contact__methodText {
+ color: var(--color-muted);
+ line-height: 1.35;
+ word-break: break-word;
+ }
+
+ .contact__form {
+ display: grid;
+ gap: var(--space-4);
+ }
+
+ .contact__fields {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-3);
+ }
+
+ @media (min-width: 700px) {
+ .contact__fields {
+ grid-template-columns: 1fr;
+ }
+
+ .field--full {
+ grid-column: 1 / -1;
+ }
+ }
+
+ .field {
+ display: grid;
+ gap: var(--space-2);
+ }
+
+ .field__label {
+ font-weight: 650;
+ }
+
+ .contact__captcha {
+ display: grid;
+ justify-content: start;
+ }
+
+ .contact__actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-3);
+ align-items: center;
+ }
+</style>
diff --git a/src/routes/contact/index.svelte b/src/routes/contact/index.svelte
deleted file mode 100644
index 5bd68f1..0000000
--- a/src/routes/contact/index.svelte
+++ /dev/null
@@ -1,158 +0,0 @@
-<script context="module">
- import { browser } from '$app/env';
- import { toast } from '@zerodevx/svelte-toast'
- import HCaptcha from 'svelte-hcaptcha';
-
- let submission = {
- name: '',
- email: '',
- message: '',
- phone: '',
- captchaToken: '',
- };
-
- let captcha;
-
- function handleSubmit (e) {
- e.preventDefault();
-
- if (browser) {
- const sendToast = toast.push('Sending...', {
- duration: 300,
- initial: 0,
- next: 0.2,
- dismissable: false
- });
- fetch('/contact/submit', {
- method: "POST",
- body: JSON.stringify(submission)
- })
- .then((x) => x.json())
- .then((x) => {
- toast.set(sendToast, { next: 1 });
-
- if (x.success) {
- toast.push('Success! Reloading...', {
- theme: {
- '--toastBackground': '#48BB78',
- '--toastBarBackground': '#2F855A'
- },
- duration: 1000,
- onpop: () => { window.location.reload(); },
- });
- } else if (x.error) {
- toast.push(x.error, {
- theme: {
- '--toastBackground': '#F56565',
- '--toastBarBackground': '#C53030'
- }
- });
- }
- })
- .catch((err) => console.log(err));
- }
- }
-
- function onCaptchaError () {
- toast.push('Failed to verify captcha, try again.', {
- theme: {
- '--toastBackground': '#F56565',
- '--toastBarBackground': '#C53030'
- }
- });
- captcha.reset();
- }
-
- function onCaptchaSuccess ({ detail: { token } }) {
- submission.captchaToken = token;
- }
-</script>
-
-<main>
- <h1 class="text-center">Get in touch.</h1>
- <div class="d-flex justify-content-center flex-row row">
- <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2">
- <h1><i class="bi bi-map-fill"></i></h1>
- <p style="hyphens: auto;">
- <a href="https://maps.app.goo.gl/s1AFqfKvUKgXDCrq5">534 Trejo Street
- <br>
- Suite 200F
- <br>
- Rexburg, ID
- <br>
- 83440
- </a>
- </p>
- </div>
- <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2">
- <div><h1><i class="bi bi-phone-fill"></i></h1></div>
- <p style="hyphens: auto;">
- Scheduling and Other
- <br>
- <a href="tel:12084994517">(208) 499 - 4517</a>
- </p>
- </div>
- <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2" style="word-break: break-all;">
- <h1><i class="bi bi-envelope-fill"></i></h1>
- <div>
- <p style="hyphens: auto;">
- Billing
- <br>
- <a href="mailto:billing@mistymountainstherapy.com">billing@mistymountainstherapy.com</a>
- </p>
- <p style="hyphens: auto;">
- Inquiries
- <br>
- <a href="mailto:contact@mistymountainsthreapy.com">contact@mistymountainstherapy.com</a>
- </p>
- <div><em>note: please watch spam for replies</em></div>
- </div>
- </div>
- </div>
- <br>
- <hr>
- <form class="bg-light border shadow p-4" on:submit|preventDefault={handleSubmit}>
- <h2>Or send us a message.</h2>
- <div class="row mb-2">
- <div class="form-group col-md-6">
- <label for="email">Email *</label>
- <input id="email" type="email" class="form-control" bind:value={submission.email} placeholder="johnnyappleseed@example.com" required>
- </div>
- <div class="form-group col-md-6">
- <label for="name">Name *</label>
- <input id="name" type="text" class="form-control" bind:value={submission.name} placeholder="Johnny Appleseed" required>
- </div>
- </div>
- <div class="form-group">
- <label for="phone">Phone</label>
- <input id="phone" type="text" class="form-control" bind:value={submission.phone} placeholder="(208) 123-4567">
- </div>
- <div class="form-group">
- <label for="message">Message *</label>
- <textarea id="message" class="form-control" bind:value={submission.message} rows="3" placeholder="Hello! I would like to schedule a free 15-minute consultation..." required></textarea>
- </div>
- <div class="pt-2">
- <HCaptcha
- sitekey={import.meta.env.VITE_HCAPTCHA_KEY}
- bind:this={captcha}
- on:success={onCaptchaSuccess}
- on:error={onCaptchaError}
- />
- </div>
- <button type="submit" class="btn btn-primary">Submit</button>
- <div class="my-2"><em>note: please watch spam for any replies</em></div>
- </form>
- <br>
-
- <div class="bg-light border shadow p-4">
- <div class="d-flex justify-content-center">
- <div class="col-md-8 mt-2">
- <div>
- We do not have a crisis line. If you or someone you know is in danger please call 911, visit
- your nearest emergency room, call the National Suicide Prevention Lifeline for free crisis
- counseling at <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741.
- </div>
- </div>
- </div>
- </div>
-</main>
diff --git a/src/routes/contact/submit.js b/src/routes/contact/submit/+server.js
index 0befd0e..eed95fe 100644
--- a/src/routes/contact/submit.js
+++ b/src/routes/contact/submit/+server.js
@@ -39,7 +39,7 @@ class MistyMountainsMailer {
}
}
-export async function post({ request }) {
+export async function POST({ request }) {
const body = await request.json();
const { HCAPTCHA_SECRET, FORM_TO_EMAIL } = process.env;
const mailer = new MistyMountainsMailer(
@@ -61,12 +61,10 @@ export async function post({ request }) {
.catch(() => false);
if (!captchaVerified) {
- return {
- statusCode: 400,
- body: {
- error: 'Captcha verification failed'
- }
- };
+ return new Response(JSON.stringify({ error: 'Captcha verification failed' }), {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' }
+ });
}
const text = `<p>New MMT Message</h1>
@@ -86,17 +84,14 @@ export async function post({ request }) {
});
if (!messageSent) {
- return {
- statusCode: 500,
- body: {
- error: 'Message could not be sent'
- }
- };
+ return new Response(JSON.stringify({ error: 'Message could not be sent' }), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
}
- return {
- body: {
- success: true
- }
- };
+ return new Response(JSON.stringify({ success: true }), {
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
}