Enhance contact UI and email handling

Add an email template and improve contact flow: create backend/templates/email/contact_me.html and update backend/advertisement/tasks.py to use SiteConfiguration.contact_email with a fallback to brunovontor@gmail.com when sending contact form emails. Revamp frontend contact experience: ContactMeForm is now open by default, uses controlled email/message inputs, shows loading/success/error states and posts to /api/advertisement/contact-me/ via publicApi. Update ContactPage and Home to include richer contact sections (framer-motion animations, icons, social links and responsive layouts). Also add a PowerShell helper entry to .claude/settings.local.json.
This commit is contained in:
2026-06-07 23:17:10 +02:00
parent 3766b033bc
commit ad7f0fbe55
6 changed files with 385 additions and 59 deletions

View File

@@ -1,35 +1,50 @@
import React, { useState, useRef } from "react"
import styles from "./contact-me.module.css"
import { LuMousePointerClick } from "react-icons/lu";
import { publicApi } from "@/api/publicClient";
export default function ContactMeForm() {
const [opened, setOpened] = useState(false)
const [contentMoveUp, setContentMoveUp] = useState(false)
const [openingBehind, setOpeningBehind] = useState(false)
// const [success, setSuccess] = useState(false)
const [opened, setOpened] = useState(true)
const [contentMoveUp, setContentMoveUp] = useState(true)
const [openingBehind, setOpeningBehind] = useState(true)
const [email, setEmail] = useState("")
const [message, setMessage] = useState("")
const [loading, setLoading] = useState(false)
const [success, setSuccess] = useState(false)
const [error, setError] = useState("")
const openingRef = useRef<HTMLDivElement>(null)
function handleSubmit() {
// form submission logic here
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
setLoading(true)
setError("")
try {
await publicApi.post("/api/advertisement/contact-me/", { email, message, hp: "" })
setSuccess(true)
setEmail("")
setMessage("")
} catch {
setError("Nepodařilo se odeslat zprávu. Zkuste to prosím znovu.")
} finally {
setLoading(false)
}
}
const toggleOpen = () => {
if (!opened) {
setOpened(true)
setOpeningBehind(false)
setContentMoveUp(false)
// Wait for the rotate-opening animation to finish before moving content up
// The actual moveUp will be handled in onTransitionEnd
setContentMoveUp(false)
} else {
setContentMoveUp(false)
setOpeningBehind(false)
setTimeout(() => setOpened(false), 1000) // match transition duration
setTimeout(() => setOpened(false), 1000)
}
}
const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
if (opened && e.propertyName === "transform") {
setContentMoveUp(true)
setContentMoveUp(true)
setTimeout(() => setOpeningBehind(true), 10)
}
if (!opened && e.propertyName === "transform") {
@@ -38,7 +53,6 @@ export default function ContactMeForm() {
}
return (
<div className={styles["contact-me"]}>
<div
ref={openingRef}
@@ -52,7 +66,7 @@ export default function ContactMeForm() {
onClick={toggleOpen}
onTransitionEnd={handleTransitionEnd}
>
<LuMousePointerClick/>
<LuMousePointerClick />
</div>
<div
@@ -61,21 +75,50 @@ export default function ContactMeForm() {
contentMoveUp ? styles["content-moveup"] : ''
].filter(Boolean).join(' ')}
>
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
placeholder="Váš email"
required
/>
<textarea
name="message"
placeholder="Vaše zpráva"
required
/>
<input type="hidden" name="state" />
<input type="submit"/>
</form>
{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 }}>Zpráva odeslána!</p>
<p style={{ color: "color-mix(in hsl, var(--c-text), transparent 35%)", fontSize: "0.85rem", margin: 0 }}>
Ozvu se vám do 24 hodin.
</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",
}}
>
Nová zpráva
</button>
</div>
) : (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
placeholder="Váš email"
required
value={email}
onChange={e => setEmail(e.target.value)}
/>
<textarea
name="message"
placeholder="Vaše zpráva"
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 ? "Odesílám…" : "Odeslat"} disabled={loading} />
</form>
)}
</div>
<div className={styles.cover}></div>