fixed components
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import React, { useState } from "react"
|
||||
import styles from "./contact-me.module.css"
|
||||
|
||||
interface ContactFormResponse {
|
||||
success: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export default function ContactMeForm() {
|
||||
const [opened, setOpened] = useState(false)
|
||||
const [formData, setFormData] = useState({ message: "", email: "" })
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [success, setSuccess] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
const toggleOpen = () => {
|
||||
setOpened((prev) => !prev)
|
||||
}
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
const { name, value } = e.target
|
||||
setFormData((prev) => ({ ...prev, [name]: value }))
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const response = await fetch("/submit-contactme/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": getCSRFToken(),
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
})
|
||||
|
||||
const data: ContactFormResponse = await response.json()
|
||||
|
||||
if (data.success) {
|
||||
setSuccess(true)
|
||||
setFormData({ message: "", email: "" })
|
||||
} else {
|
||||
setError("Zpráva nebyla odeslaná.")
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Chyba připojení nebo serveru.")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Utility to read CSRF token from cookies (Django)
|
||||
const getCSRFToken = (): string => {
|
||||
const match = document.cookie.match(/csrftoken=([^;]+)/)
|
||||
return match ? match[1] : ""
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles["contact-me"]}>
|
||||
<div
|
||||
className={
|
||||
opened
|
||||
? `${styles.opening} ${styles["rotate-opening"] || ""}`
|
||||
: styles.opening
|
||||
}
|
||||
onClick={toggleOpen}
|
||||
>
|
||||
<i className="fa-solid fa-arrow-pointer" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
opened
|
||||
? `${styles.content} ${styles["content-moveup"] || ""}`
|
||||
: styles.content
|
||||
}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Váš email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<textarea
|
||||
name="message"
|
||||
placeholder="Vaše zpráva"
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<input type="submit" value={loading ? "Odesílám..." : "Odeslat"} />
|
||||
</form>
|
||||
|
||||
{success && (
|
||||
<div className={styles.successFormAlert}>
|
||||
<span>Zpráva odeslaná!</span>
|
||||
<button onClick={() => setSuccess(false)}>×</button>
|
||||
</div>
|
||||
)}
|
||||
{error && <div className={styles.errorFormAlert}>{error}</div>}
|
||||
</div>
|
||||
|
||||
<div className={styles.cover}></div>
|
||||
<div className={styles.triangle}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user