turnstile is working - keep SSL turned of on dev

This commit is contained in:
David Bruno Vontor
2026-06-11 11:35:36 +02:00
parent 192143bfb6
commit 5ca62497b1
12 changed files with 245 additions and 79 deletions

View File

@@ -3,6 +3,7 @@ import styles from "./contact-me.module.css"
import { LuMousePointerClick } from "react-icons/lu";
import { publicApi } from "@/api/publicClient";
import { useTranslation } from "react-i18next";
import { useTurnstile } from "@/hooks/useTurnstile";
export default function ContactMeForm() {
const { t } = useTranslation("home");
@@ -12,21 +13,33 @@ export default function ContactMeForm() {
const [email, setEmail] = useState("")
const [message, setMessage] = useState("")
const [loading, setLoading] = useState(false)
const [envelopeFading, setEnvelopeFading] = useState(false)
const [success, setSuccess] = useState(false)
const [error, setError] = useState("")
const openingRef = useRef<HTMLDivElement>(null)
const { containerRef, token: turnstileToken, enabled: turnstileEnabled, reset: resetTurnstile } = useTurnstile()
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
if (!turnstileToken) return
setLoading(true)
setError("")
try {
await publicApi.post("/api/advertisement/contact-me/", { email, message, hp: "" })
setSuccess(true)
await publicApi.post("/api/advertisement/contact-me/", { email, message, hp: "", turnstile_token: turnstileToken ?? "" })
setEmail("")
setMessage("")
// Step 1: slide form into envelope (content drops down behind cover, 1s transition)
setContentMoveUp(false)
setOpeningBehind(false)
// Step 2: close flap after form has slid in
setTimeout(() => setOpened(false), 1100)
// Step 3: fade out envelope after flap finishes closing
setTimeout(() => setEnvelopeFading(true), 2300)
// Step 4: show success panel
setTimeout(() => setSuccess(true), 2700)
} catch {
setError(t("contact.sendError"))
resetTurnstile()
} finally {
setLoading(false)
}
@@ -54,73 +67,74 @@ export default function ContactMeForm() {
}
}
function handleNewMessage() {
setSuccess(false)
setEnvelopeFading(false)
setOpened(true)
setContentMoveUp(true)
setOpeningBehind(true)
}
if (success) {
return (
<div className={styles["success-panel"]}>
<div style={{ fontSize: "2.5rem" }}></div>
<p style={{ color: "var(--c-other)", fontWeight: 700, margin: 0 }}>{t("contact.messageSent")}</p>
<p style={{ color: "color-mix(in hsl, var(--c-text), transparent 35%)", fontSize: "0.85rem", margin: 0 }}>
{t("contact.replyIn24h")}
</p>
<button
onClick={handleNewMessage}
style={{
marginTop: "0.5rem", background: "none", border: "1px solid var(--c-lines)",
color: "var(--c-text)", padding: "0.4em 1.2em", borderRadius: "0.5em",
cursor: "pointer", fontSize: "0.82rem",
}}
>
{t("contact.newMessage")}
</button>
</div>
)
}
return (
<div className={styles["contact-me"]}>
<div className={[styles["contact-me"], envelopeFading ? styles["envelope-fadeout"] : ""].filter(Boolean).join(" ")}>
<div
ref={openingRef}
className={
[
styles.opening,
opened ? styles["rotate-opening"] : "",
openingBehind ? styles["opening-behind"] : ""
].filter(Boolean).join(" ")
}
className={[
styles.opening,
opened ? styles["rotate-opening"] : "",
openingBehind ? styles["opening-behind"] : ""
].filter(Boolean).join(" ")}
onClick={toggleOpen}
onTransitionEnd={handleTransitionEnd}
>
<LuMousePointerClick />
</div>
<div
className={[
styles.content,
contentMoveUp ? styles["content-moveup"] : ''
].filter(Boolean).join(' ')}
>
{success ? (
<div style={{
display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
height: "100%", gap: "0.75rem", padding: "1.5rem", textAlign: "center",
}}>
<div style={{ fontSize: "2.5rem" }}></div>
<p style={{ color: "var(--c-other)", fontWeight: 700, margin: 0 }}>{t("contact.messageSent")}</p>
<p style={{ color: "color-mix(in hsl, var(--c-text), transparent 35%)", fontSize: "0.85rem", margin: 0 }}>
{t("contact.replyIn24h")}
</p>
<button
onClick={() => setSuccess(false)}
style={{
marginTop: "0.5rem", background: "none", border: "1px solid var(--c-lines)",
color: "var(--c-text)", padding: "0.4em 1.2em", borderRadius: "0.5em",
cursor: "pointer", fontSize: "0.82rem",
}}
>
{t("contact.newMessage")}
</button>
</div>
) : (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
placeholder={t("contact.emailPlaceholder")}
required
value={email}
onChange={e => setEmail(e.target.value)}
/>
<textarea
name="message"
placeholder={t("contact.messagePlaceholder")}
required
value={message}
onChange={e => setMessage(e.target.value)}
/>
{error && (
<p style={{ color: "#ff6b6b", fontSize: "0.8rem", margin: "0", textAlign: "center" }}>{error}</p>
)}
<input type="submit" value={loading ? t("contact.sendingButton") : t("contact.sendButton")} disabled={loading} />
</form>
)}
<div className={[styles.content, contentMoveUp ? styles["content-moveup"] : ""].filter(Boolean).join(" ")}>
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
placeholder={t("contact.emailPlaceholder")}
required
value={email}
onChange={e => setEmail(e.target.value)}
/>
<textarea
name="message"
placeholder={t("contact.messagePlaceholder")}
required
value={message}
onChange={e => setMessage(e.target.value)}
/>
{error && (
<p style={{ color: "#ff6b6b", fontSize: "0.8rem", margin: "0", textAlign: "center" }}>{error}</p>
)}
{turnstileEnabled && <div style={{ display: "flex", justifyContent: "center" }}><div ref={containerRef} /></div>}
<input type="submit" value={loading ? t("contact.sendingButton") : t("contact.sendButton")} disabled={loading || !turnstileToken} />
</form>
</div>
<div className={styles.cover}></div>

View File

@@ -126,6 +126,35 @@
background: linear-gradient(135deg, var(--c-boxes), var(--c-background-light));
}
@keyframes envelopeFadeOut {
from { opacity: 1; transform: scale(1) translateY(0); }
to { opacity: 0; transform: scale(0.88) translateY(-12px); }
}
.envelope-fadeout {
animation: envelopeFadeOut 0.4s ease forwards;
pointer-events: none;
}
@keyframes successFadeIn {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
.success-panel {
margin: 15em auto 3em;
width: 30em;
max-width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 2rem;
text-align: center;
animation: successFadeIn 0.5s ease forwards;
}
@keyframes shake {
0% { transform: translateX(0); }
25% { transform: translateX(-2px) rotate(-8deg); }
@@ -147,7 +176,8 @@
@media only screen and (max-width: 990px){
.contact-me {
.contact-me,
.success-panel {
width: min(30em, 100%);
margin: 11rem auto 1.5rem;
}