160 lines
5.1 KiB
Text
160 lines
5.1 KiB
Text
---
|
|
import { POST, generateInitialState } from "@pages/endpoints/contact";
|
|
import * as ContactFormTypes from "../types/ContactForm";
|
|
|
|
async function handlePost(): Promise<ContactFormTypes.State> {
|
|
try {
|
|
let response =
|
|
await (await POST(Astro))?.json();
|
|
|
|
if (!response) {
|
|
return generateInitialState("Invalid response.");
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
let message = "An unexpected error occurred.";
|
|
if (error instanceof Error) {
|
|
message = "An unexpected error occurred: " + error.message;
|
|
}
|
|
|
|
return generateInitialState(message);
|
|
}
|
|
}
|
|
|
|
// CANNOT USE SESSION INSIDE AN ASTRO COMPONENT! MUST REVALIDATE FORM FIELDS OR CONVERT TO REGULAR PAGE (preferable as there will never be more than one contact form)
|
|
|
|
const state = (Astro.request.method === "POST")? await handlePost() : generateInitialState();
|
|
|
|
---
|
|
<script>
|
|
// @ts-nocheck
|
|
import CapWidget from "@cap.js/widget";
|
|
import "iconify-icon";
|
|
</script>
|
|
<script>
|
|
const widget = document.querySelector('cap-widget');
|
|
const shadowRoot = widget?.shadowRoot;
|
|
const credits = shadowRoot?.querySelector('[part="attribution"]');
|
|
|
|
if (credits) {
|
|
const clone = credits.cloneNode(true);
|
|
const poweredByTextBefore = document.createTextNode("(by ");
|
|
const poweredByTextAfter = document.createTextNode(")");
|
|
document.querySelector('#captcha-credits')?.appendChild(poweredByTextBefore);
|
|
document.querySelector('#captcha-credits')?.appendChild(clone);
|
|
document.querySelector('#captcha-credits')?.appendChild(poweredByTextAfter);
|
|
widget?.style.setProperty('--cap-credits-display', 'none');
|
|
}
|
|
</script>
|
|
<style>
|
|
cap-widget {
|
|
--cap-background: var(--bg-color);
|
|
--cap-border-color: rgba(255,255,255,0);
|
|
--cap-border-radius: 0;
|
|
--cap-widget-height: initial;
|
|
--cap-widget-width: 100%;
|
|
--cap-widget-padding: 0 0 11px 0;
|
|
--cap-gap: 3ch;
|
|
--cap-color: var(--text-color);
|
|
--cap-checkbox-size: 32px;
|
|
--cap-checkbox-border: 2px solid var(--border-color);
|
|
--cap-checkbox-border-radius: 4px;
|
|
--cap-checkbox-background: var(--input-bg);
|
|
--cap-checkbox-margin: 4px;
|
|
--cap-font: "Courier New", Courier, monospace;
|
|
--cap-spinner-color: var(--text-color);
|
|
--cap-spinner-background-color: var(--input-bg);
|
|
--cap-spinner-thickness: 2px;
|
|
--cap-credits-display: inline;
|
|
margin: 0;
|
|
display: block;
|
|
}
|
|
cap-widget::part(attribution) {
|
|
display: var(--cap-credits-display);
|
|
}
|
|
form {
|
|
display: grid;
|
|
gap: 1rem;
|
|
width: 100%;
|
|
margin: 0 auto;
|
|
grid-template-areas:
|
|
"header header header header "
|
|
"name name phone phone"
|
|
"msg msg msg msg"
|
|
"captcha captcha verify verify"
|
|
"otp otp submit submit";
|
|
}
|
|
form fieldset {
|
|
display: contents;
|
|
}
|
|
#captcha-credits {
|
|
font-size: x-small;
|
|
}
|
|
div {
|
|
grid-area: header;
|
|
}
|
|
label[for="name"] {
|
|
grid-area: name;
|
|
}
|
|
label[for="phone"] {
|
|
grid-area: phone;
|
|
}
|
|
label[for="msg"] {
|
|
grid-area: msg;
|
|
}
|
|
label[for="captcha"] {
|
|
grid-area: captcha;
|
|
margin-bottom: 0;
|
|
}
|
|
button {
|
|
height: 39px;
|
|
margin: 29px 0 10px 0;
|
|
padding: 8px 12px;
|
|
}
|
|
button#send_otp {
|
|
grid-area: verify;
|
|
}
|
|
button#send_msg {
|
|
grid-area: submit;
|
|
}
|
|
</style>
|
|
|
|
<h2>Contact <iconify-icon icon="streamline-sharp-color:chat-bubble-typing-oval"></iconify-icon></h2>
|
|
{state.state !== "complete" && <form method="post" x-data="{}">
|
|
<div>
|
|
<p>Use the below form to shoot me a quick text!</p>
|
|
{state.error && <p>{state.error}</p>}
|
|
</div>
|
|
<fieldset id="send_otp" disabled={state.state !== "initial"}>
|
|
<label for="name">
|
|
Name
|
|
<input type="text" id="name" name="name" value="Bad Blocks" />
|
|
{"name" in state.fields && state.fields.name.hasError && <p>{state.fields.name.error}</p>}
|
|
</label>
|
|
<label for="phone">
|
|
Phone
|
|
<input type="text" id="phone" name="phone" value="206-745-2154" />
|
|
{"phone" in state.fields && state.fields.phone.hasError && <p>{state.fields.phone.error}</p>}
|
|
</label>
|
|
<label for="msg">
|
|
Msg
|
|
<textarea id="msg" name="msg">I think badblocks rocks! A quick brown fox jumped over the lazy dog!</textarea>
|
|
{"msg" in state.fields && state.fields.msg.hasError && <p>{state.fields.msg.error}</p>}
|
|
</label>
|
|
</fieldset>
|
|
<button id="send_otp" name="action" value="send_otp" type="submit" disabled={state.state !== "initial"}>Verify Your Number!</button>
|
|
<fieldset id="send_msg" disabled={state.state !== "otp_sent"}>
|
|
<label for="otp">
|
|
Code
|
|
<input type="text" id="otp" name="otp" placeholder="123456" />
|
|
{"otp" in state.fields && state.fields.otp.hasError && <p>{state.fields.otp.error}</p>}
|
|
</label>
|
|
</fieldset>
|
|
<button id="send_msg" name="action" value="send_msg" type="submit" disabled={state.state !== "otp_sent"}>Text Me!</button>
|
|
<label for="captcha">
|
|
Captcha <span id="captcha-credits"></span>
|
|
<cap-widget id="captcha" data-cap-api-endpoint="/cap/"></cap-widget>
|
|
{"captcha" in state.fields && state.fields.captcha.hasError && <p>{state.fields.captcha.error}</p>}
|
|
</label>
|
|
</form> || <p>Your message has been sent successfully!</p>}
|