From 3866e8ade0b5d3944ae3e33748824a8511ad4a3c Mon Sep 17 00:00:00 2001 From: nomi-nonsz Date: Thu, 1 Jan 2026 09:25:02 +0700 Subject: [PATCH] Add contact form --- src/app/api/test/route.ts | 7 ++ src/app/globals.css | 2 +- src/components/form/contact-form.tsx | 96 ++++++++++++++++++++++++++++ src/components/form/form.tsx | 49 ++++++++++++++ src/components/landing-image.tsx | 6 +- src/components/texts/home.mdx | 12 ++-- src/lib/utils.ts | 2 +- 7 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 src/app/api/test/route.ts create mode 100644 src/components/form/contact-form.tsx create mode 100644 src/components/form/form.tsx diff --git a/src/app/api/test/route.ts b/src/app/api/test/route.ts new file mode 100644 index 0000000..965cf77 --- /dev/null +++ b/src/app/api/test/route.ts @@ -0,0 +1,7 @@ +import { NextResponse } from "next/server"; + +export function GET (req: Request) { + console.log(req.headers.get("x-forwarded-for") ?? 'damn'); + + return NextResponse.json({ status: "ok" }); +} \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index a5c8985..3f4af8d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -22,7 +22,7 @@ animation-timing-function: linear(0.2, 0.8, 1); } 50% { - transform: translate(0px, -180px) scale(1.18, 0.9); + transform: translate(0px, -120px) scale(1.18, 0.9); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); } } diff --git a/src/components/form/contact-form.tsx b/src/components/form/contact-form.tsx new file mode 100644 index 0000000..0197a1a --- /dev/null +++ b/src/components/form/contact-form.tsx @@ -0,0 +1,96 @@ +'use client' + +import { ChangeEvent, useRef, useState } from "react"; +import { CheckboxInput, Input, Submit } from "./form"; +import { FloatingLabel } from "../floating-label"; + +export default function ContactForm() { + const [anon, setAnon] = useState(false); + const formRef = useRef(null); + const [status, setStatus] = useState<'success' | 'loading' | 'failed' | 'idle'>('idle'); + const [errorMsg, setErrorMsg] = useState(""); + + const statusMsg = { + success: 'Sended!', + loading: 'Sending...', + failed: 'Failed :(', + idle: 'Send!' + } + + const send = async (e: React.FormEvent) => { + e.preventDefault(); + setStatus('idle'); + setErrorMsg(''); + + if (status == 'loading' || !formRef.current) return; + + const formData = new FormData(formRef.current); + + const data = { + anon, + name: formData.get('name')?.toString(), + email: formData.get('email')?.toString(), + message: formData.get('message')!.toString() + } + + if ((data.name && data.email) && (data.name.length < 1 || data.email.length < 1) && !data.anon) { + setErrorMsg("Name and email are required. If you prefer not to provide them, check the box to send anonymously."); + return; + } + + if (data.message.length < 1) { + setErrorMsg("What do you want to tell me???"); + return; + } + + setStatus('loading'); + //process + + await new Promise(res => setTimeout(res, 2000)); + setStatus('success'); + } + + return ( +
+ + + + {!anon && <> + + + } +