adding a webform
This commit is contained in:
@@ -0,0 +1 @@
|
||||
NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY=YOUR_WEB3FORMS_ACCESS_KEY
|
||||
@@ -32,5 +32,8 @@ node_modules/
|
||||
.next/
|
||||
out/
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
# ---> Local environment config
|
||||
.env.local
|
||||
|
||||
# ---> Local backups
|
||||
|
||||
@@ -82,6 +82,20 @@ Clone the Gitea repo:
|
||||
git clone http://10.10.10.11:3000/kismet.hasanaj/novarix.uk.git /var/www/novarix.uk
|
||||
```
|
||||
|
||||
If you want the built-in contact form to send mail through Web3Forms, create a
|
||||
local environment file before building:
|
||||
|
||||
```bash
|
||||
cd /var/www/novarix.uk
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
Then edit `.env.local` and set:
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY=your_web3forms_access_key
|
||||
```
|
||||
|
||||
Install the website dependencies and build the static site:
|
||||
|
||||
```bash
|
||||
|
||||
+146
-24
@@ -30,6 +30,8 @@ import { openCookieBanner } from "@/components/CookieBanner";
|
||||
|
||||
// Type for the mouse-pointer position used to move the background glow.
|
||||
type PointerState = { x: number; y: number };
|
||||
const WEB3FORMS_ENDPOINT = "https://api.web3forms.com/submit";
|
||||
|
||||
export default function HomePage() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// STATE
|
||||
@@ -39,6 +41,11 @@ export default function HomePage() {
|
||||
// ---------------------------------------------------------------------------
|
||||
const [pointer, setPointer] = useState<PointerState>({ x: 50, y: 22 });
|
||||
const [copiedEmail, setCopiedEmail] = useState(false);
|
||||
const [formStatus, setFormStatus] = useState<
|
||||
"idle" | "submitting" | "success" | "error"
|
||||
>("idle");
|
||||
const [formMessage, setFormMessage] = useState("");
|
||||
const web3FormsKey = process.env.NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// BACKGROUND POSITION
|
||||
@@ -65,6 +72,63 @@ export default function HomePage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleContactSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!web3FormsKey) {
|
||||
setFormStatus("error");
|
||||
setFormMessage(
|
||||
"Contact form is not configured yet. Please use the copy email button for now."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const form = event.currentTarget;
|
||||
const formData = new FormData(form);
|
||||
formData.append("access_key", web3FormsKey);
|
||||
formData.append("subject", "Novarix website enquiry");
|
||||
formData.append("from_name", "Novarix website");
|
||||
formData.append("replyto", String(formData.get("email") ?? ""));
|
||||
|
||||
const payload = Object.fromEntries(formData);
|
||||
|
||||
setFormStatus("submitting");
|
||||
setFormMessage("Sending message...");
|
||||
|
||||
try {
|
||||
const response = await fetch(WEB3FORMS_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
const result = (await response.json()) as {
|
||||
success?: boolean;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
if (response.ok && result.success) {
|
||||
form.reset();
|
||||
setFormStatus("success");
|
||||
setFormMessage("Message sent. We will get back to you within one working day.");
|
||||
return;
|
||||
}
|
||||
|
||||
setFormStatus("error");
|
||||
setFormMessage(
|
||||
result.message || "The message could not be sent. Please try again."
|
||||
);
|
||||
} catch {
|
||||
setFormStatus("error");
|
||||
setFormMessage(
|
||||
"The message could not be sent right now. Please try again or copy the email address instead."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main
|
||||
id="top"
|
||||
@@ -366,31 +430,89 @@ export default function HomePage() {
|
||||
{site.contact.description}
|
||||
</p>
|
||||
|
||||
{/* Email button + small response-time note */}
|
||||
<div className="mt-8 flex flex-wrap items-center gap-3">
|
||||
<a
|
||||
href={`mailto:${site.contact.email}`}
|
||||
className="group inline-flex h-12 items-center gap-2 rounded-xl bg-[var(--button-bg)] px-5 text-sm font-semibold text-[var(--button-fg)] shadow-sm transition-all hover:-translate-y-0.5 hover:bg-[var(--button-hover)] hover:shadow-md"
|
||||
>
|
||||
{site.contact.email}
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="transition-transform group-hover:translate-x-0.5"
|
||||
>
|
||||
→
|
||||
<form className="mt-8 space-y-4" onSubmit={handleContactSubmit}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="botcheck"
|
||||
className="hidden"
|
||||
tabIndex={-1}
|
||||
autoComplete="off"
|
||||
/>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-medium text-[var(--text)]">
|
||||
Name
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
required
|
||||
className="h-12 w-full rounded-xl border border-[var(--border-strong)] bg-[var(--surface-strong)] px-4 text-sm text-[var(--text)] outline-none transition-colors placeholder:text-[var(--text-soft)] focus:border-[var(--accent)]"
|
||||
placeholder="Your name"
|
||||
/>
|
||||
</label>
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-medium text-[var(--text)]">
|
||||
Email
|
||||
</span>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
required
|
||||
className="h-12 w-full rounded-xl border border-[var(--border-strong)] bg-[var(--surface-strong)] px-4 text-sm text-[var(--text)] outline-none transition-colors placeholder:text-[var(--text-soft)] focus:border-[var(--accent)]"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-medium text-[var(--text)]">
|
||||
Message
|
||||
</span>
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
onClick={copyContactEmail}
|
||||
className="inline-flex h-12 items-center rounded-xl border border-[var(--border-strong)] bg-[var(--surface)] px-5 text-sm font-semibold text-[var(--text)] backdrop-blur transition-all hover:-translate-y-0.5 hover:border-[var(--accent)] hover:text-[var(--accent)]"
|
||||
>
|
||||
{copiedEmail ? "Copied" : "Copy email"}
|
||||
</button>
|
||||
<span className="text-sm text-[var(--text-soft)]">
|
||||
{site.contact.note}
|
||||
</span>
|
||||
</div>
|
||||
<textarea
|
||||
name="message"
|
||||
required
|
||||
rows={6}
|
||||
className="w-full rounded-xl border border-[var(--border-strong)] bg-[var(--surface-strong)] px-4 py-3 text-sm text-[var(--text)] outline-none transition-colors placeholder:text-[var(--text-soft)] focus:border-[var(--accent)]"
|
||||
placeholder="Tell us a little about what you need."
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={formStatus === "submitting"}
|
||||
className="inline-flex h-12 items-center rounded-xl bg-[var(--button-bg)] px-5 text-sm font-semibold text-[var(--button-fg)] shadow-sm transition-all hover:-translate-y-0.5 hover:bg-[var(--button-hover)] hover:shadow-md disabled:translate-y-0 disabled:opacity-60 disabled:shadow-none"
|
||||
>
|
||||
{formStatus === "submitting" ? "Sending..." : "Send message"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={copyContactEmail}
|
||||
className="inline-flex h-12 items-center rounded-xl border border-[var(--border-strong)] bg-[var(--surface)] px-5 text-sm font-semibold text-[var(--text)] backdrop-blur transition-all hover:-translate-y-0.5 hover:border-[var(--accent)] hover:text-[var(--accent)]"
|
||||
>
|
||||
{copiedEmail ? "Copied" : "Copy email"}
|
||||
</button>
|
||||
<span className="text-sm text-[var(--text-soft)]">
|
||||
{site.contact.note}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{formMessage && (
|
||||
<p
|
||||
className={`text-sm ${
|
||||
formStatus === "error"
|
||||
? "text-red-500"
|
||||
: formStatus === "success"
|
||||
? "text-emerald-500"
|
||||
: "text-[var(--text-soft)]"
|
||||
}`}
|
||||
>
|
||||
{formMessage}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user