feat: Latest production version with interior scene and glass
Includes room interior with floor, walls, glass you can see through, and all uncommitted production changes that were running live. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
416
bron/RequestForm.js
Normal file
416
bron/RequestForm.js
Normal file
@@ -0,0 +1,416 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import TechInformation from "./TechInformation";
|
||||
|
||||
const RequestForm = ({ techInformation, attachDesign, glContext, sceneContext, cameraContext }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
aanhef: "Dhr",
|
||||
voornaam: "",
|
||||
tussenvoegsel: "",
|
||||
achternaam: "",
|
||||
straatnaam: "",
|
||||
huisnummer: "",
|
||||
postcode: "",
|
||||
woonplaats: "",
|
||||
land: "Nederland",
|
||||
emailadres: "",
|
||||
telefoonnummer: "",
|
||||
comment: "",
|
||||
file: null,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setFormData({...formData, file: attachDesign});
|
||||
}, [attachDesign])
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isClearSubmitting, setIsClearSubmitting] = useState(false);
|
||||
const [formErrors, setFormErrors] = useState({});
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value, files } = e.target;
|
||||
if (name === "file") {
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]: files[0],
|
||||
});
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]: value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
const errors = {};
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if (["comment", "tussenvoegsel", "file"].includes(key)) return;
|
||||
if (!formData[key]) {
|
||||
errors[key] = "Dit veld is verplicht";
|
||||
}
|
||||
});
|
||||
return errors;
|
||||
};
|
||||
|
||||
const dataURLToBlob = (dataURL) => {
|
||||
const byteString = atob(dataURL.split(',')[1]);
|
||||
const mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
|
||||
const arrayBuffer = new ArrayBuffer(byteString.length);
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
uint8Array[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
|
||||
return new Blob([arrayBuffer], { type: mimeString });
|
||||
};
|
||||
|
||||
const handleSubmit = async (isReset = false) => {
|
||||
const errors = validate();
|
||||
if (Object.keys(errors).length === 0) {
|
||||
setIsSubmitting(true);
|
||||
setIsClearSubmitting(isReset);
|
||||
try {
|
||||
glContext.render(sceneContext, cameraContext);
|
||||
const image = glContext.domElement.toDataURL('image/png');
|
||||
const imageBlob = dataURLToBlob(image);
|
||||
|
||||
const formDataToSubmit = new FormData();
|
||||
Object.keys(formData).forEach((key) => {
|
||||
formDataToSubmit.append(key, formData[key]);
|
||||
});
|
||||
|
||||
formDataToSubmit.append('constructImage', imageBlob, 'constructImage.png');
|
||||
|
||||
formDataToSubmit.append(
|
||||
"techInformation",
|
||||
JSON.stringify(techInformation)
|
||||
);
|
||||
|
||||
formDataToSubmit.append(
|
||||
"platform", "clooz"
|
||||
);
|
||||
|
||||
const response = await axios.post(
|
||||
"https://api-lumbronch.agreatidea.studio/api/request-a-quote",
|
||||
formDataToSubmit,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
navigate("/request-confirmation");
|
||||
|
||||
if (isReset) {
|
||||
setFormData({
|
||||
aanhef: "Dhr",
|
||||
voornaam: "",
|
||||
tussenvoegsel: "",
|
||||
achternaam: "",
|
||||
straatnaam: "",
|
||||
huisnummer: "",
|
||||
postcode: "",
|
||||
woonplaats: "",
|
||||
land: "Nederland",
|
||||
emailadres: "",
|
||||
telefoonnummer: "",
|
||||
comment: "",
|
||||
file: null,
|
||||
});
|
||||
}
|
||||
// Handle successful form submission
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
// Handle error in form submission
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
} else {
|
||||
setFormErrors(errors);
|
||||
}
|
||||
};
|
||||
|
||||
const formStyle = {
|
||||
maxWidth: "400px",
|
||||
margin: "0 auto",
|
||||
backgroundColor: "#2D3748",
|
||||
padding: "20px",
|
||||
borderRadius: "8px",
|
||||
};
|
||||
|
||||
const inputStyle = {
|
||||
width: "100%",
|
||||
padding: "10px",
|
||||
marginBottom: "10px",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "#fff",
|
||||
color: "#333",
|
||||
border: "none",
|
||||
boxSizing: "border-box",
|
||||
};
|
||||
|
||||
const fileInputStyle = {
|
||||
display: "none",
|
||||
};
|
||||
|
||||
const labelStyle = {
|
||||
color: "#fff",
|
||||
fontSize: "14px",
|
||||
fontWeight: "bold",
|
||||
display: "block",
|
||||
};
|
||||
|
||||
const errorStyle = {
|
||||
color: "red",
|
||||
fontSize: "12px",
|
||||
margin: 0,
|
||||
};
|
||||
|
||||
const buttonStyle = {
|
||||
backgroundColor: "#48BB78",
|
||||
color: "#FFF",
|
||||
fontSize: "16px",
|
||||
padding: "10px 20px",
|
||||
borderRadius: "100px",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
};
|
||||
|
||||
const linkButtonStyle = {
|
||||
fontSize: "14px",
|
||||
color: "#FFF",
|
||||
cursor: "pointer",
|
||||
display: "block",
|
||||
};
|
||||
|
||||
const fileUploadLabelStyle = {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
cursor: "pointer",
|
||||
backgroundColor: "#48BB78",
|
||||
padding: "8px 15px",
|
||||
borderRadius: "50px",
|
||||
color: "#FFF",
|
||||
fontSize: "14px",
|
||||
textAlign: "center",
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TechInformation techInformation={techInformation} />
|
||||
<div style={formStyle}>
|
||||
<h2 style={{ color: "#FFF", marginBottom: "20px", fontSize: "16px" }}>
|
||||
Vul uw gegevens in
|
||||
</h2>
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<select
|
||||
name="aanhef"
|
||||
value={formData.aanhef}
|
||||
onChange={handleChange}
|
||||
style={{
|
||||
...inputStyle,
|
||||
border: formErrors.aanhef ? "1px solid red" : "none",
|
||||
}}
|
||||
required
|
||||
>
|
||||
<option value="Dhr">Dhr.</option>
|
||||
<option value="Mevr">Mevr.</option>
|
||||
</select>
|
||||
{formErrors.aanhef && <p style={errorStyle}>{formErrors.aanhef}</p>}
|
||||
</div>
|
||||
{[
|
||||
"voornaam",
|
||||
"tussenvoegsel",
|
||||
"achternaam",
|
||||
"straatnaam",
|
||||
"huisnummer",
|
||||
"postcode",
|
||||
"woonplaats",
|
||||
"emailadres",
|
||||
"telefoonnummer",
|
||||
].map((field) => (
|
||||
<div
|
||||
key={field}
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
name={field}
|
||||
value={formData[field]}
|
||||
onChange={handleChange}
|
||||
placeholder={field.charAt(0).toUpperCase() + field.slice(1)}
|
||||
style={{
|
||||
...inputStyle,
|
||||
border: formErrors[field] ? "1px solid red" : "none",
|
||||
}}
|
||||
required
|
||||
/>
|
||||
{formErrors[field] && <p style={errorStyle}>{formErrors[field]}</p>}
|
||||
</div>
|
||||
))}
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<select
|
||||
name="land"
|
||||
value={formData.land}
|
||||
onChange={handleChange}
|
||||
style={{
|
||||
...inputStyle,
|
||||
border: formErrors.land ? "1px solid red" : "none",
|
||||
}}
|
||||
required
|
||||
>
|
||||
<option value="Nederland">Nederland</option>
|
||||
<option value="Spanje">Spanje</option>
|
||||
<option value="Duitsland">Duitsland</option>
|
||||
<option value="België">België</option>
|
||||
{/* Add more options as needed */}
|
||||
</select>
|
||||
{formErrors.land && <p style={errorStyle}>{formErrors.land}</p>}
|
||||
</div>
|
||||
<div key="comment" style={{ marginBottom: "10px", display: "flex" }}>
|
||||
<textarea
|
||||
rows={3}
|
||||
name="comment"
|
||||
value={formData.comment}
|
||||
onChange={handleChange}
|
||||
placeholder="Opmerkingen"
|
||||
style={{
|
||||
...inputStyle,
|
||||
border: formErrors.comment ? "1px solid red" : "none",
|
||||
}}
|
||||
/>
|
||||
{formErrors.comment && <p style={errorStyle}>{formErrors.comment}</p>}
|
||||
</div>
|
||||
<div style={{ color: "red", marginBottom: "20px" }}>
|
||||
* Vul alle velden correct in.
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<label htmlFor="file" style={labelStyle}>
|
||||
Afbeelding bijvoegen:
|
||||
</label>
|
||||
<label
|
||||
htmlFor="file"
|
||||
style={{
|
||||
...fileUploadLabelStyle,
|
||||
backgroundColor: formData.file ? "#48BB78" : "red",
|
||||
}}
|
||||
>
|
||||
<img src="/images/upload.png" width={20} />
|
||||
Kies bestand
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
name="file"
|
||||
id="file"
|
||||
onChange={handleChange}
|
||||
style={{
|
||||
...fileInputStyle,
|
||||
border: formErrors.file ? "1px solid red" : "none",
|
||||
}}
|
||||
/>
|
||||
{formErrors.file && <p style={errorStyle}>{formErrors.file}</p>}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "end",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSubmit(false)}
|
||||
style={{ ...buttonStyle, marginTop: "10px", minHeight: "44px", minWidth: "187px" }}
|
||||
disabled={isSubmitting}
|
||||
className={`relative ${
|
||||
isSubmitting ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
>
|
||||
{isSubmitting && !isClearSubmitting ? (
|
||||
<div className="absolute inset-0 flex justify-center items-center">
|
||||
<svg
|
||||
className="animate-spin h-5 w-5 text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
) : (
|
||||
"Offerte aanvragen"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSubmit(true)}
|
||||
style={{ ...buttonStyle, marginTop: "20px", width: "100%", minHeight: "44px" }}
|
||||
disabled={isSubmitting}
|
||||
className={`relative ${
|
||||
isSubmitting ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
>
|
||||
{isSubmitting && isClearSubmitting ? (
|
||||
<div className="absolute inset-0 flex justify-center items-center">
|
||||
<svg
|
||||
className="animate-spin h-5 w-5 text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
) : (
|
||||
"Versturen en nog een offerte aanvragen"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RequestForm;
|
||||
Reference in New Issue
Block a user