508 lines
15 KiB
React
508 lines
15 KiB
React
import React, { useState, useEffect, lazy, Suspense } from "react";
|
||
import {
|
||
Box,
|
||
TextField,
|
||
Typography,
|
||
Button,
|
||
Grid,
|
||
Checkbox,
|
||
FormControlLabel,
|
||
Snackbar,
|
||
Alert,
|
||
CircularProgress,
|
||
Card,
|
||
CardContent,
|
||
Modal,
|
||
Fade,
|
||
Backdrop,
|
||
} from "@mui/material";
|
||
import SEO from "../SEO";
|
||
import api from "../../api";
|
||
import Faq from "../Faq";
|
||
const FAQ = lazy(() => import('../Faq'));
|
||
|
||
const Contact = () => {
|
||
const [metaTitle, setMetaTitle] = useState("Contactez-nous");
|
||
const [metaDescription, setMetaDescription] = useState(
|
||
"Contactez notre équipe pour plus d'informations."
|
||
);
|
||
const [formData, setFormData] = useState({
|
||
name: "",
|
||
email: "",
|
||
subject: "",
|
||
message: "",
|
||
consent: false,
|
||
});
|
||
const [errors, setErrors] = useState({});
|
||
const [loading, setLoading] = useState(false);
|
||
const [successMessage, setSuccessMessage] = useState(false);
|
||
const [openLightbox, setOpenLightbox] = useState(false);
|
||
|
||
const [showFAQ, setShowFAQ] = useState(false); // État pour afficher/masquer la FAQ
|
||
|
||
|
||
const handleToggleFAQ = () => {
|
||
setShowFAQ((prev) => !prev);
|
||
};
|
||
|
||
useEffect(() => {
|
||
const fetchSEOData = async () => {
|
||
try {
|
||
const response = await api.get(
|
||
"wp/v2/pages/116?_fields=acf,rank_math_title,rank_math_description"
|
||
);
|
||
const { rank_math_title, rank_math_description } = response.data;
|
||
setMetaTitle(rank_math_title || "Contactez-nous");
|
||
setMetaDescription(rank_math_description || "Contactez notre équipe.");
|
||
} catch (error) {
|
||
console.error(
|
||
"Erreur lors de la récupération des données SEO :",
|
||
error
|
||
);
|
||
}
|
||
};
|
||
|
||
fetchSEOData();
|
||
}, []);
|
||
|
||
const validate = () => {
|
||
const newErrors = {};
|
||
if (!formData.name) newErrors.name = "Le nom est requis.";
|
||
if (!formData.email || !/\S+@\S+\.\S+/.test(formData.email))
|
||
newErrors.email = "Une adresse e-mail valide est requise.";
|
||
if (!formData.subject) newErrors.subject = "Le sujet est requis.";
|
||
if (!formData.message) newErrors.message = "Le message est requis.";
|
||
if (!formData.consent)
|
||
newErrors.consent =
|
||
"Vous devez accepter la politique de confidentialité.";
|
||
return newErrors;
|
||
};
|
||
|
||
const handleChange = (e) => {
|
||
const { name, value, type, checked } = e.target;
|
||
setFormData({
|
||
...formData,
|
||
[name]: type === "checkbox" ? checked : value,
|
||
});
|
||
};
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
const validationErrors = validate();
|
||
setErrors(validationErrors);
|
||
|
||
if (Object.keys(validationErrors).length === 0) {
|
||
setLoading(true);
|
||
|
||
try {
|
||
const response = await fetch(
|
||
"https://votre-site.com/wp-json/custom/v1/contact",
|
||
{
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
body: JSON.stringify(formData),
|
||
}
|
||
);
|
||
|
||
if (response.ok) {
|
||
setSuccessMessage(true);
|
||
setFormData({
|
||
name: "",
|
||
email: "",
|
||
subject: "",
|
||
message: "",
|
||
consent: false,
|
||
});
|
||
} else {
|
||
const errorData = await response.json();
|
||
throw new Error(errorData.message || "Une erreur est survenue.");
|
||
}
|
||
} catch (error) {
|
||
alert(error.message);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
};
|
||
|
||
const handleOpenLightbox = () => {
|
||
setOpenLightbox(true);
|
||
};
|
||
|
||
const handleCloseLightbox = () => {
|
||
setOpenLightbox(false);
|
||
};
|
||
|
||
return (
|
||
<Box>
|
||
{/* SEO */}
|
||
<SEO title={metaTitle} description={metaDescription} />
|
||
|
||
{/* Section Attention */}
|
||
<Box
|
||
sx={{
|
||
backgroundImage: `url('https://via.placeholder.com/1920x800')`,
|
||
backgroundSize: "cover",
|
||
backgroundPosition: "center",
|
||
minHeight: "50vh",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
textAlign: "center",
|
||
color: "white",
|
||
padding: "20px",
|
||
}}
|
||
>
|
||
<Box>
|
||
<Typography
|
||
variant="h1"
|
||
sx={{
|
||
color: "#000",
|
||
fontWeight: "bold",
|
||
fontSize: { xs: "2rem", md: "3rem", lg: "4rem" },
|
||
mb: 2,
|
||
}}
|
||
>
|
||
Contactez-nous
|
||
</Typography>
|
||
<Typography
|
||
variant="body2"
|
||
sx={{
|
||
color: "#000",
|
||
fontSize: { xs: "1rem", md: "1rem" },
|
||
maxWidth: "600px",
|
||
mx: "auto",
|
||
}}
|
||
>
|
||
Notre bureau d’étude technique est, par essence, spécialisé.
|
||
Vous pouvez donc faire appel à nous pour un diagnostic ponctuel portant sur tel ou tel équipement ou ouvrage du bâtiment
|
||
(structures, chaufferie, ascenseur).<br></br> <br></br>
|
||
Une question ? Une demande particulière ? Remplissez le formulaire
|
||
ci-dessous ou consultez nos coordonnées.
|
||
</Typography>
|
||
</Box>
|
||
</Box>
|
||
|
||
{/* Section Coordonnées et Horaires */}
|
||
<Box sx={{ padding: "40px 20px", backgroundColor: "#f9f9f9" }}>
|
||
<Grid container spacing={4}>
|
||
|
||
{/* Coordonnées */}
|
||
<Grid item xs={12} md={6}>
|
||
<Card
|
||
sx={{
|
||
boxShadow: 2,
|
||
borderRadius: 2,
|
||
padding: "20px",
|
||
display: "flex",
|
||
justifyContent: "space-between",
|
||
alignItems: "center",
|
||
height: "80%",
|
||
}}
|
||
>
|
||
<Box>
|
||
<Typography
|
||
variant="h2"
|
||
sx={{
|
||
fontSize: { xs: "2rem", md: "2rem", lg: "3rem" },
|
||
fontWeight: "bold",
|
||
color: "#0e467f",
|
||
mb: 2,
|
||
}}
|
||
>
|
||
Nos coordonnées
|
||
</Typography>
|
||
|
||
<Typography variant="body1">
|
||
<strong>Adresse :</strong>67 Bd Winston Churchill, Le Mans,
|
||
France
|
||
</Typography>
|
||
<Typography variant="body1">
|
||
<strong>Téléphone :</strong> 02.43.85.09.01
|
||
</Typography>
|
||
<Typography variant="body1">
|
||
<strong>Email :</strong> contact@be-in3.com
|
||
</Typography>
|
||
</Box>
|
||
|
||
<Box
|
||
onClick={handleOpenLightbox}
|
||
sx={{
|
||
position: "relative",
|
||
cursor: "pointer",
|
||
width: "120px",
|
||
height: "120px",
|
||
borderRadius: "8px",
|
||
overflow: "hidden",
|
||
boxShadow: 3,
|
||
"&:hover": {
|
||
transform: "scale(1.10)",
|
||
boxShadow: 4,
|
||
transition: "transform 0.3s, box-shadow 0.3s",
|
||
},
|
||
"&:hover::before": {
|
||
content: '"Cliquez pour agrandir"',
|
||
position: "absolute",
|
||
top: "50%",
|
||
left: "50%",
|
||
transform: "translate(-50%, -50%)",
|
||
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
||
color: "white",
|
||
padding: "5px 10px",
|
||
borderRadius: "4px",
|
||
fontSize: "12px",
|
||
},
|
||
}}
|
||
>
|
||
<img
|
||
src="https://picsum.photos/id/442/300.webp"
|
||
alt="Carte"
|
||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||
/>
|
||
</Box>
|
||
</Card>
|
||
</Grid>
|
||
|
||
{/* Horaires */}
|
||
<Grid item xs={12} md={6}>
|
||
<Card
|
||
sx={{
|
||
boxShadow: 2,
|
||
borderRadius: 2,
|
||
padding: "20px",
|
||
backgroundColor: "#fff",
|
||
height: "80%",
|
||
}}
|
||
>
|
||
<CardContent>
|
||
<Typography
|
||
variant="h2"
|
||
sx={{
|
||
fontSize: { xs: "2rem", md: "2rem", lg: "3rem" },
|
||
fontWeight: "bold",
|
||
color: "#0e467f",
|
||
mb: 2,
|
||
textAlign: "left",
|
||
}}
|
||
>
|
||
Horaires d'ouverture
|
||
</Typography>
|
||
|
||
<Typography variant="body1">
|
||
<strong>Lundi - Mardi :</strong> 9h00 - 16h00
|
||
</Typography>
|
||
<Typography variant="body1">
|
||
<strong>Mercredi :</strong> 09h00 - 12h00
|
||
</Typography>
|
||
<Typography variant="body1">
|
||
<strong>Jeudi - Vendredi :</strong> 09h00 - 17h00
|
||
</Typography>
|
||
<Typography variant="body1">
|
||
<strong>Samedi - Dimanche :</strong> Fermé
|
||
</Typography>
|
||
</CardContent>
|
||
</Card>
|
||
</Grid>
|
||
</Grid>
|
||
</Box>
|
||
|
||
{/* Lightbox */}
|
||
<Modal
|
||
open={openLightbox}
|
||
onClose={handleCloseLightbox}
|
||
closeAfterTransition
|
||
BackdropComponent={Backdrop}
|
||
BackdropProps={{ timeout: 500 }}
|
||
>
|
||
<Fade in={openLightbox}>
|
||
<Box
|
||
sx={{
|
||
position: "absolute",
|
||
top: "50%",
|
||
left: "50%",
|
||
transform: "translate(-50%, -50%)",
|
||
width: "90%",
|
||
maxWidth: "800px",
|
||
backgroundColor: "white",
|
||
boxShadow: 24,
|
||
borderRadius: 2,
|
||
overflow: "hidden",
|
||
}}
|
||
>
|
||
<iframe
|
||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2670.1862696285393!2d0.22040227623964043!3d47.990787261369235!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47e28ec5f984044d%3A0xa3a21789f4a4eaa6!2sIN3%20Int%C3%A9grale%20Ing%C3%A9nierie%20Internationale%20Bureau%20D'%C3%A9tudes%20Ing%C3%A9nieries%20Ma%C3%AEtrise%20d'oeuvre!5e0!3m2!1sfr!2sfr!4v1736328111099!5m2!1sfr!2sfr%22%20width=%22600%22%20height=%22450%22%20style=%22border:0;%22%20allowfullscreen=%22%22%20loading=%22lazy%22%20referrerpolicy=%22no-referrer-when-downgrade%22"
|
||
width="100%"
|
||
height="400"
|
||
title="Carte interactive"
|
||
style={{ border: 0 }}
|
||
allowFullScreen=""
|
||
loading="lazy"
|
||
/>
|
||
</Box>
|
||
</Fade>
|
||
</Modal>
|
||
|
||
{/* Section Action */}
|
||
<Box
|
||
sx={{
|
||
backgroundColor: "#0e467f",
|
||
color: "white",
|
||
textAlign: "center",
|
||
padding: "40px 20px",
|
||
}}
|
||
>
|
||
<Typography
|
||
variant="h2"
|
||
sx={{
|
||
fontSize: { xs: "2rem", md: "2rem", lg: "3rem" }, // Responsive
|
||
fontWeight: "bold",
|
||
mb: 2,
|
||
fontSize: { xs: "1.5rem", md: "2rem" },
|
||
}}
|
||
>
|
||
Besoin d'une assistance immédiate ?
|
||
</Typography>
|
||
<Button
|
||
onClick={handleToggleFAQ}
|
||
variant="contained"
|
||
sx={{
|
||
textTransform: "none",
|
||
fontWeight: "bold",
|
||
backgroundColor: "#00bcd4",
|
||
"&:hover": { backgroundColor: "#0288d1" },
|
||
}}
|
||
>
|
||
{showFAQ ? "Masquer la FAQ" : "Afficher la FAQ"}
|
||
</Button>
|
||
</Box>
|
||
|
||
{/* Section FAQ */}
|
||
<Suspense fallback={<div>Chargement...</div>}>
|
||
<Faq showFAQ={showFAQ} />
|
||
</Suspense>
|
||
{/* Formulaire de contact */}
|
||
<Box
|
||
sx={{
|
||
maxWidth: "800px",
|
||
margin: "auto",
|
||
padding: "40px",
|
||
boxShadow: 3,
|
||
borderRadius: 2,
|
||
backgroundColor: "#fff",
|
||
mt: 4,
|
||
}}
|
||
>
|
||
<Typography
|
||
variant="h2"
|
||
sx={{
|
||
mb: 4,
|
||
textAlign: "center",
|
||
fontWeight: "bold",
|
||
color: "#0e467f",
|
||
}}
|
||
>
|
||
Formulaire de contact
|
||
</Typography>
|
||
<form onSubmit={handleSubmit} noValidate>
|
||
<TextField
|
||
label="Nom"
|
||
name="name"
|
||
value={formData.name}
|
||
onChange={handleChange}
|
||
error={Boolean(errors.name)}
|
||
helperText={errors.name}
|
||
fullWidth
|
||
margin="normal"
|
||
variant="outlined"
|
||
/>
|
||
<TextField
|
||
label="E-mail"
|
||
name="email"
|
||
value={formData.email}
|
||
onChange={handleChange}
|
||
error={Boolean(errors.email)}
|
||
helperText={errors.email}
|
||
fullWidth
|
||
margin="normal"
|
||
variant="outlined"
|
||
/>
|
||
<TextField
|
||
label="Sujet"
|
||
name="subject"
|
||
value={formData.subject}
|
||
onChange={handleChange}
|
||
error={Boolean(errors.subject)}
|
||
helperText={errors.subject}
|
||
fullWidth
|
||
margin="normal"
|
||
variant="outlined"
|
||
/>
|
||
<TextField
|
||
label="Message"
|
||
name="message"
|
||
value={formData.message}
|
||
onChange={handleChange}
|
||
error={Boolean(errors.message)}
|
||
helperText={errors.message}
|
||
fullWidth
|
||
margin="normal"
|
||
variant="outlined"
|
||
multiline
|
||
rows={4}
|
||
/>
|
||
<FormControlLabel
|
||
control={
|
||
<Checkbox
|
||
name="consent"
|
||
checked={formData.consent}
|
||
onChange={handleChange}
|
||
/>
|
||
}
|
||
label="J'accepte la politique de confidentialité."
|
||
sx={{ mt: 2, color: errors.consent ? "red" : "inherit" }}
|
||
/>
|
||
{errors.consent && (
|
||
<Typography variant="caption" color="error">
|
||
{errors.consent}
|
||
</Typography>
|
||
)}
|
||
<Box sx={{ textAlign: "center", mt: 3 }}>
|
||
<Button
|
||
type="submit"
|
||
variant="contained"
|
||
color="primary"
|
||
size="large"
|
||
disabled={loading}
|
||
sx={{
|
||
textTransform: "none",
|
||
fontWeight: "bold",
|
||
px: 5,
|
||
}}
|
||
>
|
||
{loading ? (
|
||
<CircularProgress size={24} sx={{ color: "#fff" }} />
|
||
) : (
|
||
"Envoyer"
|
||
)}
|
||
</Button>
|
||
</Box>
|
||
</form>
|
||
|
||
<Snackbar
|
||
open={successMessage}
|
||
autoHideDuration={6000}
|
||
onClose={() => setSuccessMessage(false)}
|
||
>
|
||
<Alert onClose={() => setSuccessMessage(false)} severity="success">
|
||
Message envoyé avec succès !
|
||
</Alert>
|
||
</Snackbar>
|
||
</Box>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
export default Contact;
|