diff options
| author | Elizabeth Hunt <me@liz.coffee> | 2026-01-01 18:32:49 -0800 |
|---|---|---|
| committer | Elizabeth Hunt <me@liz.coffee> | 2026-01-01 18:32:49 -0800 |
| commit | 9af1854a7e35785a8e86426c4fb1edd465f164a3 (patch) | |
| tree | 8a070c6a9498d952c9ef4ba045f2ebfb25f7b335 /src/routes/contact/+page.svelte | |
| parent | 0248a3899ed910f005dccaeefc1d9dcb893e8154 (diff) | |
| download | mistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.tar.gz mistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.zip | |
Massive refactor courtesy of 5 dollars of AI tokens
Diffstat (limited to 'src/routes/contact/+page.svelte')
| -rw-r--r-- | src/routes/contact/+page.svelte | 325 |
1 files changed, 325 insertions, 0 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> |
