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:
653
bron/endpoint.js
Normal file
653
bron/endpoint.js
Normal file
@@ -0,0 +1,653 @@
|
||||
import { Canvas, useThree } from "@react-three/fiber";
|
||||
import axios from "axios";
|
||||
// import { EffectComposer } from "@react-three/postprocessing";
|
||||
import DoorHole from "./logic/DoorHole";
|
||||
import { Suspense, useState, useEffect } from "react";
|
||||
import Preloader from "./logic/preloader";
|
||||
import Door from "./logic/UI/door";
|
||||
import Design from "./logic/UI/design";
|
||||
import Information from "./logic/UI/information";
|
||||
import * as THREE from "three";
|
||||
import { MyContext } from "./logic/data/contextapi";
|
||||
import Extra from "./logic/UI/extra";
|
||||
import Samenstling from "./logic/UI/samenstling";
|
||||
import Arrow from "./logic/UI/arrow";
|
||||
import { DirectionalLightHelper, CameraHelper } from "three";
|
||||
import React, { useRef } from "react";
|
||||
export default function Endpoint() {
|
||||
const [json, setJson] = useState({ Data: [] });
|
||||
|
||||
const [step, setStep] = useState("door");
|
||||
const [type, settype] = useState("Taatsdeur");
|
||||
const [door, setdoor] = useState("3panel");
|
||||
const [frameSize, setFrameSize] = useState(0.125);
|
||||
const [glassType, setGlassType] = useState(0x111111);
|
||||
const [frameType, setFrameType] = useState(
|
||||
"./images/doortypes/RAL 9005 fijn structuur.png"
|
||||
);
|
||||
const [width, setWidth] = useState(90); // State for width
|
||||
const [height, setHeight] = useState(250); // State for height
|
||||
const [holeWidth, setHoleWidth] = useState(90);
|
||||
const [doorConfig, setDoorConfig] = useState("enkele");
|
||||
const [sidePannel, setSidePannel] = useState("geen");
|
||||
const [sidePannelConfig, setSidePannelConfig] = useState("eigen maat");
|
||||
const [sidePannelSize, setSidePannelSize] = useState(width);
|
||||
const [stalenType, setStalenType] = useState("tussen");
|
||||
const [stalenPart, setStalenPart] = useState(1);
|
||||
const [handle, setHandle] = useState(1);
|
||||
const [maxWidth, setMaxWidth] = useState(105);
|
||||
const [prwType, setPrwType] = useState("Enkele");
|
||||
const [prwImage, setPrwImage] = useState(
|
||||
"./images/doortypes/enkele deur.png"
|
||||
);
|
||||
const [extraOptions, setExtraOptions] = useState([
|
||||
"Meetservice",
|
||||
"Montage service",
|
||||
]);
|
||||
const [count, setCount] = useState(1);
|
||||
|
||||
const [coverSheetSteel, setCoverSheetSteel] = useState(false);
|
||||
const [coverLearn, setCoverLearn] = useState(false);
|
||||
const [coverWoodliness, setCoverWoodliness] = useState(false);
|
||||
const [coverMirrors, setCoverMirrors] = useState(false);
|
||||
const [coverCylinderLockKey, setCoverCylinderLockKey] = useState(false);
|
||||
const [coverDontKnow, setCoverDontKnow] = useState(false);
|
||||
|
||||
const [handleSheetSteel, setHandleSheetSteel] = useState(false);
|
||||
const [handleLearn, setHandleLearn] = useState(false);
|
||||
const [handleWoodliness, setHandleWoodliness] = useState(false);
|
||||
const [handleMirrors, setHandleMirrors] = useState(false);
|
||||
const [handleCylinderLockKey, setHandleCylinderLockKey] = useState(false);
|
||||
|
||||
const [standardBlack, setStandardBlack] = useState(false);
|
||||
const [alternativeRALColour, setAlternativeRALColour] = useState(false);
|
||||
const [metallicCoating, setMetallicCoating] = useState(false);
|
||||
|
||||
const [bright, setBright] = useState(false);
|
||||
const [canaleOrCrepi, setCanaleOrCrepi] = useState(false);
|
||||
|
||||
const [fireResistant, setFireResistant] = useState(false);
|
||||
const [outdoorPlacement, setOutdoorPlacement] = useState(false);
|
||||
|
||||
const [maxHeight, setMaxHeight] = useState(0);
|
||||
const [contentHeight, setContentHeight] = useState("calc(100vh - 320px)");
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const [inprogress, setInprogress] = useState(false);
|
||||
|
||||
const [bubbles, setBubbles] = useState();
|
||||
|
||||
const [attachDesign, setAttachDesign] = useState(null);
|
||||
|
||||
const [colorPickerOpened, setColorPickerOpened] = useState(false);
|
||||
|
||||
const [customFrameType, setCustomFrameType] = useState({name: "", color: ""});
|
||||
|
||||
const [compositionImage, setCompositionImage] = useState("https://config.livingsteel.nl/images/doortypes/3%20panel.png");
|
||||
|
||||
const [glContext, setGlContext] = useState(null);
|
||||
const [sceneContext, setSceneContext] = useState(null); // Store the Scene context
|
||||
const [cameraContext, setCameraContext] = useState(null); // Store the Camera context
|
||||
|
||||
// Calculate the maximum height based on the available screen height
|
||||
useEffect(() => {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||||
|
||||
const isAndroid = /android/i.test(userAgent);
|
||||
const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
|
||||
const calculateMaxHeight = () => {
|
||||
let availableHeight;
|
||||
if (window.innerWidth > 800) {
|
||||
const screenHeight = window.innerHeight;
|
||||
// Adjust maxHeight to leave space for other elements like headers or footers
|
||||
availableHeight = screenHeight - 100; // Adjust this value as needed
|
||||
} else {
|
||||
setContentHeight(
|
||||
`calc(100vh - 25vh - ${isAndroid ? "270px" : "310px"})`
|
||||
);
|
||||
const screenHeight = window.innerHeight * 0.65;
|
||||
// Adjust maxHeight to leave space for other elements like headers or footers 30
|
||||
availableHeight = screenHeight + 210; // Adjust this value as needed
|
||||
}
|
||||
setMaxHeight(availableHeight);
|
||||
};
|
||||
|
||||
fetchBubbles();
|
||||
|
||||
calculateMaxHeight(); // Call once initially
|
||||
window.addEventListener("resize", calculateMaxHeight); // Recalculate on window resize
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", calculateMaxHeight); // Cleanup
|
||||
};
|
||||
}, []);
|
||||
|
||||
const fetchBubbles = async () => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
"https://api.config-fencing.com/api/get-bubbles"
|
||||
);
|
||||
setBubbles(response.data.bubbles);
|
||||
} catch (error) {
|
||||
console.error("Error fetching bubbles:", error);
|
||||
}
|
||||
};
|
||||
// Create a ref for the SpotLight
|
||||
const spotLightRef = useRef();
|
||||
return (
|
||||
<>
|
||||
<MyContext.Provider
|
||||
value={{
|
||||
json,
|
||||
setJson,
|
||||
setStep,
|
||||
sidePannel,
|
||||
setSidePannel,
|
||||
type,
|
||||
settype,
|
||||
door,
|
||||
setdoor,
|
||||
width,
|
||||
setWidth,
|
||||
height,
|
||||
setHeight,
|
||||
holeWidth,
|
||||
setHoleWidth,
|
||||
doorConfig,
|
||||
setDoorConfig,
|
||||
prwType,
|
||||
setPrwType,
|
||||
prwImage,
|
||||
setPrwImage,
|
||||
count,
|
||||
setCount,
|
||||
frameSize,
|
||||
setFrameSize,
|
||||
glassType,
|
||||
setGlassType,
|
||||
frameType,
|
||||
setFrameType,
|
||||
sidePannelConfig,
|
||||
setSidePannelConfig,
|
||||
sidePannelSize,
|
||||
setSidePannelSize,
|
||||
stalenType,
|
||||
setStalenType,
|
||||
stalenPart,
|
||||
setStalenPart,
|
||||
handle,
|
||||
setHandle,
|
||||
maxWidth,
|
||||
setMaxWidth,
|
||||
coverSheetSteel,
|
||||
setCoverSheetSteel,
|
||||
coverLearn,
|
||||
setCoverLearn,
|
||||
coverWoodliness,
|
||||
setCoverWoodliness,
|
||||
coverMirrors,
|
||||
setCoverMirrors,
|
||||
coverCylinderLockKey,
|
||||
setCoverCylinderLockKey,
|
||||
coverDontKnow,
|
||||
setCoverDontKnow,
|
||||
handleSheetSteel,
|
||||
setHandleSheetSteel,
|
||||
handleLearn,
|
||||
setHandleLearn,
|
||||
handleWoodliness,
|
||||
setHandleWoodliness,
|
||||
handleMirrors,
|
||||
setHandleMirrors,
|
||||
handleCylinderLockKey,
|
||||
setHandleCylinderLockKey,
|
||||
standardBlack,
|
||||
setStandardBlack,
|
||||
alternativeRALColour,
|
||||
setAlternativeRALColour,
|
||||
metallicCoating,
|
||||
setMetallicCoating,
|
||||
bright,
|
||||
setBright,
|
||||
canaleOrCrepi,
|
||||
setCanaleOrCrepi,
|
||||
fireResistant,
|
||||
setFireResistant,
|
||||
outdoorPlacement,
|
||||
setOutdoorPlacement,
|
||||
setExtraOptions,
|
||||
extraOptions,
|
||||
open,
|
||||
setOpen,
|
||||
inprogress,
|
||||
setInprogress,
|
||||
bubbles,
|
||||
setBubbles,
|
||||
attachDesign,
|
||||
setAttachDesign,
|
||||
colorPickerOpened,
|
||||
setColorPickerOpened,
|
||||
customFrameType,
|
||||
setCustomFrameType,
|
||||
compositionImage,
|
||||
setCompositionImage,
|
||||
glContext,
|
||||
sceneContext,
|
||||
cameraContext,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: "100vw", height: "100svh", overflow: "hidden" }}>
|
||||
<div className="body-can-2" style={{}}>
|
||||
<div className="body-can-2-1" style={{}}>
|
||||
<div className="body-can-2-1-1" style={{}}>
|
||||
<Suspense fallback={<Preloader />}>
|
||||
<Canvas
|
||||
frameloop="demand"
|
||||
gl={{
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
toneMapping: THREE.SRGBColorSpace,
|
||||
}}
|
||||
camera={{ fov: 53 }}
|
||||
onCreated={({ gl, scene, camera }) => {
|
||||
setGlContext(gl);
|
||||
setSceneContext(scene);
|
||||
setCameraContext(camera);
|
||||
}}
|
||||
// shadows // Enable shadows
|
||||
>
|
||||
{/* Ambient light for basic illumination */}
|
||||
|
||||
<DoorHole />
|
||||
</Canvas>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="body-can-2-1-2" style={{ overflowY: "hidden" }}>
|
||||
<div
|
||||
className="quot"
|
||||
style={{
|
||||
backgroundColor: "#bdc79d",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
{/* <span
|
||||
style={{
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
marginLeft: "30px",
|
||||
}}
|
||||
>
|
||||
Prijs incl. BTW
|
||||
</span> */}
|
||||
{/* <div
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
borderRadius: "20px",
|
||||
width: "auto",
|
||||
padding: "5px",
|
||||
margin: "0 0 0 10px",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="body-txt"
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
setStep("door");
|
||||
}}
|
||||
>
|
||||
€ 2200,00
|
||||
</span>
|
||||
</div> */}
|
||||
</div>
|
||||
<div
|
||||
className={`step-content ${
|
||||
step === "door" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{
|
||||
maxHeight: `${maxHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
marginTop: "auto",
|
||||
}}
|
||||
onClick={() => {
|
||||
setStep("door");
|
||||
}}
|
||||
>
|
||||
<button
|
||||
className={`body-btn ${
|
||||
step === "door" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{}}
|
||||
>
|
||||
1
|
||||
</button>
|
||||
<span
|
||||
className={`body-txt ${
|
||||
step === "door" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{ opacity: step === "door" ? 1 : 0.4 }}
|
||||
onClick={() => {
|
||||
setStep("door");
|
||||
}}
|
||||
>
|
||||
DEURMAAT & TYPE
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "20px",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
checked={step === "door"}
|
||||
readOnly
|
||||
onChange={() => setStep("door")}
|
||||
className={`radio ${
|
||||
step === "door" ? "expand" : "collapsed"
|
||||
}`}
|
||||
/>
|
||||
{/* <Arrow direction={step === 'door' ? 'down' : 'up'} /> */}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
overflowY: "auto",
|
||||
padding: step == "door" ? "10px" : 0,
|
||||
height: step == "door" ? contentHeight : 0,
|
||||
opacity: step == "door" ? 1 : 0,
|
||||
transition:
|
||||
"height 0.3s ease-in-out, opacity 0.5s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Door />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`step-content ${
|
||||
step === "samenstling" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{
|
||||
maxHeight: `${maxHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => {
|
||||
setStep("samenstling");
|
||||
}}
|
||||
>
|
||||
<button
|
||||
className={`body-btn ${
|
||||
step === "samenstling" ? "expand" : "collapsed"
|
||||
}`}
|
||||
>
|
||||
2
|
||||
</button>
|
||||
<span
|
||||
className={`body-txt ${
|
||||
step === "samenstling" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{ opacity: step === "samenstling" ? 1 : 0.4 }}
|
||||
onClick={() => {
|
||||
setStep("samenstling");
|
||||
}}
|
||||
>
|
||||
Samenstelling
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "20px",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
checked={step === "samenstling"}
|
||||
readOnly
|
||||
onChange={() => setStep("samenstling")}
|
||||
className={`radio ${
|
||||
step === "samenstling" ? "expand" : "collapsed"
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
overflowY: "auto",
|
||||
padding: step == "samenstling" ? "10px" : 0,
|
||||
height: step == "samenstling" ? contentHeight : 0,
|
||||
opacity: step == "samenstling" ? 1 : 0,
|
||||
transition:
|
||||
"height 0.3s ease-in-out, opacity 0.5s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Samenstling />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`step-content ${
|
||||
step === "design" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{
|
||||
maxHeight: `${maxHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => {
|
||||
setStep("design");
|
||||
}}
|
||||
>
|
||||
<button
|
||||
className={`body-btn ${
|
||||
step === "design" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{}}
|
||||
>
|
||||
3
|
||||
</button>
|
||||
<span
|
||||
className={`body-txt ${
|
||||
step === "design" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{ opacity: step === "design" ? 1 : 0.4 }}
|
||||
onClick={() => {
|
||||
setStep("design");
|
||||
}}
|
||||
>
|
||||
Design, Kleur & GLAS
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "20px",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
checked={step === "design"}
|
||||
readOnly
|
||||
onChange={() => setStep("design")}
|
||||
className={`radio ${
|
||||
step === "design" ? "expand" : "collapsed"
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
overflowY: "auto",
|
||||
padding: step == "design" ? "10px" : 0,
|
||||
height: step == "design" ? contentHeight : 0,
|
||||
opacity: step == "design" ? 1 : 0,
|
||||
transition:
|
||||
"height 0.3s ease-in-out, opacity 0.5s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Design />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`step-content ${
|
||||
step === "extra" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{
|
||||
maxHeight: `${maxHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => {
|
||||
setStep("extra");
|
||||
}}
|
||||
>
|
||||
<button
|
||||
className={`body-btn ${
|
||||
step === "extra" ? "expand" : "collapsed"
|
||||
}`}
|
||||
>
|
||||
4
|
||||
</button>
|
||||
<span
|
||||
className={`body-txt ${
|
||||
step === "extra" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{ opacity: step === "extra" ? 1 : 0.4 }}
|
||||
onClick={() => {
|
||||
setStep("extra");
|
||||
}}
|
||||
>
|
||||
Extra Opties
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "20px",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
checked={step === "extra"}
|
||||
readOnly
|
||||
onChange={() => setStep("extra")}
|
||||
className={`radio ${
|
||||
step === "extra" ? "expand" : "collapsed"
|
||||
}`}
|
||||
/>
|
||||
{/* <Arrow direction={step === 'extra' ? 'down' : 'up'} /> */}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
overflowY: "auto",
|
||||
padding: step == "extra" ? "10px" : 0,
|
||||
height: step == "extra" ? contentHeight : 0,
|
||||
opacity: step == "extra" ? 1 : 0,
|
||||
transition:
|
||||
"height 0.3s ease-in-out, opacity 0.5s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Extra />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`pd step-content ${
|
||||
step === "information" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{
|
||||
maxHeight: `${maxHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => {
|
||||
setStep("information");
|
||||
}}
|
||||
>
|
||||
<button
|
||||
className={`body-btn ${
|
||||
step === "information" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{}}
|
||||
>
|
||||
5
|
||||
</button>
|
||||
<span
|
||||
className={`body-txt ${
|
||||
step === "information" ? "expand" : "collapsed"
|
||||
}`}
|
||||
style={{ opacity: step === "information" ? 1 : 0.4 }}
|
||||
onClick={() => {
|
||||
setStep("information");
|
||||
}}
|
||||
>
|
||||
Order informatie
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
right: "20px",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
checked={step === "information"}
|
||||
readOnly
|
||||
onChange={() => setStep("information")}
|
||||
className={`radio ${
|
||||
step === "information" ? "expand" : "collapsed"
|
||||
}`}
|
||||
/>
|
||||
{/* <Arrow
|
||||
direction={step === 'information' ? 'down' : 'up'}
|
||||
/> */}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
overflowY: "auto",
|
||||
padding: step == "information" ? "10px" : 0,
|
||||
height: step == "information" ? contentHeight : 0,
|
||||
opacity: step == "information" ? 1 : 0,
|
||||
transition:
|
||||
"height 0.3s ease-in-out, opacity 0.5s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Information />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MyContext.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user