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/
|
.next/
|
||||||
out/
|
out/
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
|
|
||||||
|
# ---> Local environment config
|
||||||
|
.env.local
|
||||||
|
|
||||||
# ---> Local backups
|
# ---> 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
|
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:
|
Install the website dependencies and build the static site:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+135
-13
@@ -30,6 +30,8 @@ import { openCookieBanner } from "@/components/CookieBanner";
|
|||||||
|
|
||||||
// Type for the mouse-pointer position used to move the background glow.
|
// Type for the mouse-pointer position used to move the background glow.
|
||||||
type PointerState = { x: number; y: number };
|
type PointerState = { x: number; y: number };
|
||||||
|
const WEB3FORMS_ENDPOINT = "https://api.web3forms.com/submit";
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// STATE
|
// STATE
|
||||||
@@ -39,6 +41,11 @@ export default function HomePage() {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
const [pointer, setPointer] = useState<PointerState>({ x: 50, y: 22 });
|
const [pointer, setPointer] = useState<PointerState>({ x: 50, y: 22 });
|
||||||
const [copiedEmail, setCopiedEmail] = useState(false);
|
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
|
// 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 (
|
return (
|
||||||
<main
|
<main
|
||||||
id="top"
|
id="top"
|
||||||
@@ -366,20 +430,63 @@ export default function HomePage() {
|
|||||||
{site.contact.description}
|
{site.contact.description}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Email button + small response-time note */}
|
<form className="mt-8 space-y-4" onSubmit={handleContactSubmit}>
|
||||||
<div className="mt-8 flex flex-wrap items-center gap-3">
|
<input
|
||||||
<a
|
type="checkbox"
|
||||||
href={`mailto:${site.contact.email}`}
|
name="botcheck"
|
||||||
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"
|
className="hidden"
|
||||||
>
|
tabIndex={-1}
|
||||||
{site.contact.email}
|
autoComplete="off"
|
||||||
<span
|
/>
|
||||||
aria-hidden="true"
|
|
||||||
className="transition-transform group-hover:translate-x-0.5"
|
<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>
|
</span>
|
||||||
</a>
|
<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>
|
||||||
|
<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
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={copyContactEmail}
|
onClick={copyContactEmail}
|
||||||
@@ -391,6 +498,21 @@ export default function HomePage() {
|
|||||||
{site.contact.note}
|
{site.contact.note}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user