Tom Butcher 8ef109b8e7 Update environment variables, refactor context usage, and enhance UI components
- Changed API and Keycloak URLs in `.env` and `.env.development`.
- Updated `vite.config.js` to reflect new allowed hosts.
- Refactored components to use `useContent` context instead of individual contexts for blogs, companies, and projects.
- Improved error handling in `App` component with `AppError`.
- Added FPS monitoring to `ParticlesBackground` component for developer mode.
- Removed unused contexts and adjusted related imports.
- Enhanced styling for various components and added new styles for FPS monitor.
- Cleaned up SVG files by removing unnecessary attributes.
2025-11-15 19:32:09 +00:00

149 lines
3.9 KiB
JavaScript

import { useState, useRef } from "react";
import axios from "axios";
import CheckIcon from "../../icons/CheckIcon";
import Turnstile from "./Turnstile";
import { useNavigate } from "react-router-dom";
import { useContent } from "../../contexts/ContentContext";
import LoadingIcon from "../../icons/LoadingIcon.jsx";
import { useEffect } from "react";
const apiUrl = import.meta.env.VITE_API_URL;
const turnstileKey = import.meta.env.VITE_TURNSTILE_KEY;
const ContactForm = () => {
const navigate = useNavigate();
const { settings } = useContent();
const turnstileRef = useRef(null); // Ref for Turnstile
const [formData, setFormData] = useState({
name: "",
email: "",
message: "",
});
const [token, setToken] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [loadTurnstile, setLoadTurnstile] = useState(false);
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
useEffect(() => {
if (turnstileKey && turnstileKey != "") {
setTimeout(() => {
setLoadTurnstile(true);
}, 500);
}
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
if (!token) {
alert("Please complete the CAPTCHA");
return;
}
try {
setLoading(true);
// Send formData + token to your backend using axios
const response = await axios.post(`${apiUrl}/contact`, {
...formData,
token,
});
console.log(settings);
navigate(`/${settings.redirects.contactFormComplete}`);
console.log("Form submitted:", response.data);
} catch (error) {
console.error("Error submitting form:", error);
const errorData = error.response.data;
setError(errorData);
if (errorData.code.startsWith("captcha-")) {
turnstileRef.current.reset();
}
} finally {
setLoading(false);
}
};
return (
<div className="tb-contact-form-wrapper">
<form onSubmit={handleSubmit} className="tb-form">
<div className="tb-form-input-wrapper">
<input
id="name"
type="text"
name="name"
value={formData.name}
onChange={handleChange}
required
className="tb-form-input"
placeholder="Your Name"
disabled={loading}
autoComplete="name"
/>
</div>
<div className="tb-form-input-wrapper">
<input
id="email"
type="email"
name="email"
value={formData.email}
onChange={handleChange}
required
className="tb-form-input"
placeholder="Email"
disabled={loading}
autoComplete="email"
/>
</div>
<div className="tb-form-input-wrapper">
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
required
rows="5"
className="tb-form-input"
placeholder="Write your message here..."
disabled={loading}
autoComplete="message"
></textarea>
</div>
{/* Cloudflare Turnstile */}
{loadTurnstile == true && (
<Turnstile
siteKey={turnstileKey}
theme="light"
ref={turnstileRef}
onVerify={(token) => setToken(token)}
/>
)}
<div className="tb-form-actions">
<button
type="submit"
className={"tb-button"}
style={{ marginTop: 0 }}
disabled={loading}
>
{loading ? <LoadingIcon /> : <CheckIcon />}
Send Message
</button>
{error && <p className="tb-form-error">{error.message}</p>}
</div>
</form>
</div>
);
};
export default ContactForm;