From 66092158b293a21e516a238b2dd2f8e0008782cf Mon Sep 17 00:00:00 2001 From: Angel <angelsola2004@gmailcom> Date: Mon, 12 May 2025 20:26:04 +0200 Subject: [PATCH] api dades --- app/src/ar_scenes/FloorScene.jsx | 272 +++++++++---------------------- app/src/styles/ar.css | 10 +- 2 files changed, 83 insertions(+), 199 deletions(-) diff --git a/app/src/ar_scenes/FloorScene.jsx b/app/src/ar_scenes/FloorScene.jsx index 0a5293f..e57d7eb 100644 --- a/app/src/ar_scenes/FloorScene.jsx +++ b/app/src/ar_scenes/FloorScene.jsx @@ -1,208 +1,64 @@ -import React, { Suspense, useState, useRef, useEffect} from "react"; +import React, { useEffect, useState, useRef, Suspense } from "react"; import { Canvas, useFrame } from "@react-three/fiber"; -import { OrbitControls, useGLTF } from "@react-three/drei"; -import ModelSelector from "./ModelSelector"; -import Model from "./Model"; - +import { OrbitControls } from "@react-three/drei"; +import * as THREE from "three"; import Select from "react-select"; -// Conjuntos de modelos -const modelSets = [ - [ - { url: "/nexus/P0B.glb", label: "Base P0" }, - { url: "/nexus/P0O0.glb", label: "Oficina 0" }, - { url: "/nexus/P0O1.glb", label: "Oficina 1" }, - { url: "/nexus/P0O2.glb", label: "Oficina 2" }, - ], - [ - { url: "/nexus/P1B.glb", label: "Base P1" }, - { url: "/nexus/P1O0.glb", label: "Oficina 0" }, - { url: "/nexus/P1O1.glb", label: "Oficina 1" }, - { url: "/nexus/P1O2.glb", label: "Oficina 2" }, - { url: "/nexus/P1O3.glb", label: "Oficina 3" }, - { url: "/nexus/P1O4.glb", label: "Oficina 4" }, - { url: "/nexus/P1O5.glb", label: "Oficina 5" }, - { url: "/nexus/P1O6.glb", label: "Oficina 6" }, - { url: "/nexus/P1O7.glb", label: "Oficina 7" }, - { url: "/nexus/P1O8.glb", label: "Oficina 8" }, - { url: "/nexus/P1O9.glb", label: "Oficina 9" }, - { url: "/nexus/P1O10.glb", label: "Oficina 10" }, - ], -]; - -// Preload modelos -modelSets.flat().forEach((model) => useGLTF.preload(model.url)); - -const Model3D = ({ url, position = [0, 0, 0], scale = [5, 5, 5], visible }) => { - const gltf = useGLTF(url); - return ( - <primitive - object={gltf.scene} - position={position} - scale={scale} - visible={visible} - /> - ); -}; - -const FloorScene = () => { - const [activeSetIndex, setActiveSetIndex] = useState(0); - const [modelStates, setModelStates] = useState( - modelSets.map((set) => - set.map((model) => ({ - ...model, - position: [0, 0, 0], - scale: [5, 5, 5], - visible: true, - })) - ) - ); - - const toggleModelVisibility = (modelIndex) => { - setModelStates((prev) => - prev.map((set, i) => - i === activeSetIndex - ? set.map((model, j) => - j === modelIndex ? { ...model, visible: !model.visible } : model - ) - : set - ) - ); - }; - - const handleSetChange = (e) => { - setActiveSetIndex(Number(e.target.value)); - }; - - return ( - <> - <ModelSelector - modelSets={modelSets} - activeSetIndex={activeSetIndex} - handleSetChange={handleSetChange} - modelStates={modelStates} - toggleModelVisibility={toggleModelVisibility} - /> - - <Canvas camera={{ position: [0, 1, 8] }}> - <ambientLight /> - <directionalLight position={[5, 5, 5]} /> - <Suspense fallback={null}> - {modelStates[activeSetIndex].map((model, index) => ( - <Model - key={`${model.url}-${index}`} - url={model.url} - position={model.position} - scale={model.scale} - visible={model.visible} - /> - ))} - </Suspense> - <OrbitControls enableZoom={false} enablePan={false} /> - </Canvas> - </> - ); -}; +import Model from "./Model"; - -const Floor = ({ activeOffice, setActiveOffice }) => { +const Floor = ({ floorData, activeOffice, setActiveOffice }) => { const groupRef = useRef(); - useFrame(() => { if (groupRef.current) { groupRef.current.rotation.y += 0.003; } }); - return ( - <group ref={groupRef}> - <Model - path="/baseMT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={1} - /> - - <Model - path="/oficina1MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 1 ? 0.9 : 0.2} - onClick={() => setActiveOffice(1)} - /> - - <Model - path="/oficina2MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 2 ? 0.9 : 0.2} - onClick={() => setActiveOffice(2)} - /> - - <Model - path="/oficina3MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 3 ? 0.9 : 0.2} - onClick={() => setActiveOffice(3)} - /> - - <Model - path="/oficina4MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 4 ? 0.9 : 0.2} - onClick={() => setActiveOffice(4)} - /> - - <Model - path="/oficina5MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 5 ? 0.9 : 0.2} - onClick={() => setActiveOffice(5)} - /> + if (!floorData) return null; - <Model - path="/oficina6MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 6? 0.9 : 0.2} - onClick={() => setActiveOffice(6)} - /> + const [base, ...offices] = floorData.urlModelos; + const scale = Array(3).fill(Number(floorData.scale) || 1); - <Model - path="/oficina7MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 7 ? 0.9 : 0.2} - onClick={() => setActiveOffice(7)} - /> - - <Model - path="/oficina8MT.glb" - scale={[1, 1, 1]} - position={[0, 0, 0]} - opacity={activeOffice === 8? 0.9 : 0.2} - onClick={() => setActiveOffice(8)} - /> + return ( + <group ref={groupRef}> + <Model path={base} scale={scale} position={[0, 0, 0]} opacity={1} /> + + {offices.map((path, index) => { + const officeIndex = index + 1; + return ( + <Model + key={path} + path={path} + scale={scale} + position={[0, 0, 0]} + opacity={activeOffice === officeIndex ? 0.9 : 0.2} + onClick={() => setActiveOffice(officeIndex)} + /> + ); + })} </group> ); }; const App = () => { + const [floors, setFloors] = useState([]); + const [activeFloorIndex, setActiveFloorIndex] = useState(0); const [activeOffice, setActiveOffice] = useState(null); - const options = [ - { value: null, label: "Eliga su oficina" }, - { value: 1, label: "Oficina 1" }, - { value: 2, label: "Oficina 2" }, - { value: 3, label: "Oficina 3" }, - { value: 4, label: "Oficina 4" }, - { value: 5, label: "Oficina 5" }, - { value: 6, label: "Oficina 6" }, - { value: 7, label: "Oficina 7" }, - { value: 8, label: "Oficina 8" }, - ]; + useEffect(() => { + fetch("https://serverm3d.onrender.com/floors/building/1") + .then((res) => res.json()) + .then((data) => setFloors(data)) + .catch((err) => console.error("Error fetching floors:", err)); + }, []); + + const options = [{ value: null, label: "Eliga su oficina" }]; + const currentFloor = floors[activeFloorIndex]; + if (currentFloor) { + const officeOptions = currentFloor.urlModelos + .slice(1) + .map((_, i) => ({ value: i + 1, label: `Oficina ${i + 1}` })); + options.push(...officeOptions); + } const selectedOption = options.find((opt) => opt.value === activeOffice); @@ -214,7 +70,7 @@ const App = () => { bottom: 30, left: "50%", transform: "translateX(-50%)", - width: "260px", + width: "260px", zIndex: 1000, display: "flex", flexDirection: "column", @@ -230,7 +86,7 @@ const App = () => { placeholder="Seleccionar oficina" menuPlacement="top" menuPortalTarget={document.body} - styles={{ + styles={{ control: (base, state) => ({ ...base, backgroundColor: "#2b2b2b", @@ -288,14 +144,14 @@ const App = () => { fontWeight: isSelected ? "bold" : 400, transition: "background 0.2s ease, color 0.2s ease", }), - }} + }} /> {activeOffice !== null && ( <button onClick={() => setActiveOffice(null)} style={{ - width: "100%", + width: "100%", padding: "10px 0", fontSize: "15px", borderRadius: "10px", @@ -303,22 +159,50 @@ const App = () => { color: "white", border: "none", cursor: "pointer", - transition: "background 0.3s ease", fontWeight: "bold", }} - onMouseOver={(e) => (e.currentTarget.style.backgroundColor = "#cc0000")} - onMouseOut={(e) => (e.currentTarget.style.backgroundColor = "red")} > Ocultar oficina </button> )} + + {floors.length > 1 && ( + <div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}> + {floors.map((floor, index) => ( + <button + key={floor.id} + onClick={() => { + setActiveFloorIndex(index); + setActiveOffice(null); // reset + }} + style={{ + padding: "6px 12px", + backgroundColor: index === activeFloorIndex ? "red" : "#2b2b2b", + color: "white", + border: "1px solid #444", + borderRadius: "8px", + cursor: "pointer", + fontWeight: "bold", + }} + > + {floor.nombre} + </button> + ))} + </div> + )} </div> <Canvas camera={{ position: [0, 30, 30], fov: 50 }}> <ambientLight intensity={0.5} /> <directionalLight position={[10, 10, 5]} castShadow /> <OrbitControls target={[0, 0, 0]} /> - <Floor activeOffice={activeOffice} setActiveOffice={setActiveOffice} /> + <Suspense fallback={null}> + <Floor + floorData={currentFloor} + activeOffice={activeOffice} + setActiveOffice={setActiveOffice} + /> + </Suspense> </Canvas> </div> ); diff --git a/app/src/styles/ar.css b/app/src/styles/ar.css index a8937bd..c9548bc 100644 --- a/app/src/styles/ar.css +++ b/app/src/styles/ar.css @@ -127,7 +127,7 @@ .popup-form input:focus, .popup-form textarea:focus { outline: none; - border-color: #4f46e5; + border-color: "red"; box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.2); } @@ -156,12 +156,12 @@ } .form-actions button[type="submit"] { - background-color: #4f46e5; + background-color: #e12c2c; color: white; } .form-actions button[type="submit"]:hover { - background-color: #4338ca; + background-color: #38ca42; } .form-actions button[type="button"] { @@ -178,7 +178,7 @@ padding: 0.8rem 2rem; font-size: 1.1rem; font-weight: 600; - background-color: #4f46e5; + background-color: #e12c2c; color: white; border: none; border-radius: 10px; @@ -188,6 +188,6 @@ } .form-button:hover { - background-color: #4338ca; + background-color: #38ca42; transform: scale(1.02); } -- GitLab