diff --git a/app/Dockerfile b/app/Dockerfile index 0c5c8ac..c780015 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -42,7 +42,7 @@ FROM nginx:alpine COPY --from=development /frontend/build /usr/share/nginx/html # Optionally copy a custom Nginx config (if needed) -COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY nginx-container.conf /etc/nginx/conf.d/default.conf # Expose port 80 for Nginx (default HTTP port) EXPOSE 80 diff --git a/app/nginx-container.conf b/app/nginx-container.conf new file mode 100644 index 0000000..8bf7166 --- /dev/null +++ b/app/nginx-container.conf @@ -0,0 +1,13 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri /index.html; + } + + error_page 404 /index.html; +} diff --git a/app/nginx.conf b/app/nginx.conf deleted file mode 100644 index 6c3bbfb..0000000 --- a/app/nginx.conf +++ /dev/null @@ -1,14 +0,0 @@ -server { - listen 3000; - server_name localhost; - - root /usr/share/nginx/html; - index index.html; - - location / { - try_files $uri /index.html; - } - - # Redirect 404 errors to index.html (for React Router) - error_page 404 /index.html; -} \ No newline at end of file diff --git a/app/package-lock.json b/app/package-lock.json index 58de338..a675c68 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,11 +1,11 @@ { - "name": "dwinzo-beta", + "name": "aalai-beta", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "dwinzo-beta", + "name": "aalai-beta", "version": "0.1.0", "dependencies": { "@dnd-kit/core": "^6.3.1", diff --git a/app/package.json b/app/package.json index ba25aa0..eff8f85 100644 --- a/app/package.json +++ b/app/package.json @@ -1,5 +1,5 @@ { - "name": "dwinzo-beta", + "name": "aalai-beta", "version": "0.1.0", "private": true, "dependencies": { diff --git a/app/public/favicon.ico b/app/public/favicon.ico index ae16133..dde3da4 100644 Binary files a/app/public/favicon.ico and b/app/public/favicon.ico differ diff --git a/app/public/index.html b/app/public/index.html index 22359c2..8e84a3b 100644 --- a/app/public/index.html +++ b/app/public/index.html @@ -22,7 +22,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - Dwinzo (beta) + Aalai (beta) diff --git a/app/public/logo192.png b/app/public/logo192.png index 92738c5..01528ba 100644 Binary files a/app/public/logo192.png and b/app/public/logo192.png differ diff --git a/app/public/logo512.png b/app/public/logo512.png index 6da0496..cf446d4 100644 Binary files a/app/public/logo512.png and b/app/public/logo512.png differ diff --git a/app/src/assets/textures/floor/blue.png b/app/src/assets/textures/floor/blue.png new file mode 100644 index 0000000..343445d Binary files /dev/null and b/app/src/assets/textures/floor/blue.png differ diff --git a/app/src/assets/textures/floor/wall-2.png b/app/src/assets/textures/floor/wall-2.png new file mode 100644 index 0000000..786d3b6 Binary files /dev/null and b/app/src/assets/textures/floor/wall-2.png differ diff --git a/app/src/assets/textures/floor/white.png b/app/src/assets/textures/floor/white.png index efc1ea4..3d3418b 100644 Binary files a/app/src/assets/textures/floor/white.png and b/app/src/assets/textures/floor/white.png differ diff --git a/app/src/assets/textures/floor/white1.png b/app/src/assets/textures/floor/white1.png new file mode 100644 index 0000000..0270b48 Binary files /dev/null and b/app/src/assets/textures/floor/white1.png differ diff --git a/app/src/components/icons/Logo.tsx b/app/src/components/icons/Logo.tsx index 822e83e..bd1d82a 100644 --- a/app/src/components/icons/Logo.tsx +++ b/app/src/components/icons/Logo.tsx @@ -7,109 +7,14 @@ export function LogoIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - + - - - - - - - - - - - - - - - ); @@ -118,97 +23,45 @@ export function LogoIcon() { export function LogoIconLarge() { return ( - - - - - - - - - - - - - - - - - + + + + + + + + + + ); } diff --git a/app/src/components/templates/LoadingPage.tsx b/app/src/components/templates/LoadingPage.tsx index e6bcb8a..fe7aa36 100644 --- a/app/src/components/templates/LoadingPage.tsx +++ b/app/src/components/templates/LoadingPage.tsx @@ -80,7 +80,7 @@ const LoadingPage: React.FC = ({ progress }) => {
-
Entering A New World of Dwinzo
+
Entering A New World with your Aalai
{validatedProgress}%
diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 13fb414..cb54f87 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -1,4 +1,4 @@ -import * as THREE from "three" + import * as THREE from "three" import { useEffect } from 'react' import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi'; import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store'; diff --git a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts new file mode 100644 index 0000000..5360d44 --- /dev/null +++ b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts @@ -0,0 +1,62 @@ +import * as THREE from 'three'; +import * as Types from "../../../../types/world/worldTypes"; +import * as CONSTANTS from "../../../../types/world/worldConstants"; + +import texturePath from "../../../../assets/textures/floor/white1.png"; +import texturePathDark from "../../../../assets/textures/floor/black.png"; + +// Cache for materials +const materialCache = new Map(); + +export default function addFloorToScene( + shape: THREE.Shape, + layer: number, + floorGroup: Types.RefGroup, + userData: any, +) { + const savedTheme: string | null = localStorage.getItem('theme'); + + const textureLoader = new THREE.TextureLoader(); + + const textureScale = CONSTANTS.floorConfig.textureScale; + + const materialKey = `floorMaterial_${textureScale}`; + + let material: THREE.Material; + + if (materialCache.has(materialKey)) { + material = materialCache.get(materialKey) as THREE.Material; + } else { + const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath); + // const floorTexture = textureLoader.load(texturePath); + + floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; + floorTexture.repeat.set(textureScale, textureScale); + floorTexture.colorSpace = THREE.SRGBColorSpace; + + material = new THREE.MeshStandardMaterial({ + map: floorTexture, + side: THREE.DoubleSide, + }); + + materialCache.set(materialKey, material); + } + + const extrudeSettings = { + depth: CONSTANTS.floorConfig.height, + bevelEnabled: false, + }; + + const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const mesh = new THREE.Mesh(geometry, material); + + mesh.receiveShadow = true; + mesh.position.y = (layer) * CONSTANTS.wallConfig.height; + mesh.rotateX(Math.PI / 2); + mesh.name = `Floor_Layer_${layer}`; + + // Store UUIDs for debugging or future processing + mesh.userData.uuids = userData; + + floorGroup.current.add(mesh); +} diff --git a/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts b/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts new file mode 100644 index 0000000..1c199de --- /dev/null +++ b/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts @@ -0,0 +1,190 @@ +import * as THREE from 'three'; +import * as turf from '@turf/turf'; +import * as CONSTANTS from '../../../../types/world/worldConstants'; +import * as Types from "../../../../types/world/worldTypes"; + +// temp +import blueFloorImage from "../../../../assets/textures/floor/blue.png" + +function loadOnlyFloors( + floorGroup: Types.RefGroup, + linesByLayer: any, + layer: any, +): void { + + ////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well ////////// + + let floorsInLayer = linesByLayer[layer]; + floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName); + const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) => + pair.map((point) => ({ + position: [point[0].x, point[0].z], + uuid: point[1] + })) + ); + const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position))); + + function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) { + const floorpolygons = []; + const connectedLines = []; + const unprocessedLines = [...FloorLineFeatures]; // Copy the features + + while (unprocessedLines.length > 0) { + const currentLine = unprocessedLines.pop(); + const coordinates = currentLine.geometry.coordinates; + + // Check if the line is closed (forms a polygon) + if ( + coordinates[0][0] === coordinates[coordinates.length - 1][0] && + coordinates[0][1] === coordinates[coordinates.length - 1][1] + ) { + floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon + continue; + } + + // Check if the line connects to another line + let connected = false; + for (let i = unprocessedLines.length - 1; i >= 0; i--) { + const otherCoordinates = unprocessedLines[i].geometry.coordinates; + + // Check if lines share a start or end point + if ( + coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] && + coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1] + ) { + // Merge lines + const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)]; + unprocessedLines[i] = turf.lineString(mergedCoordinates); + connected = true; + break; + } else if ( + coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] && + coordinates[coordinates.length - 1][1] === otherCoordinates[0][1] + ) { + // Merge lines + const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)]; + unprocessedLines[i] = turf.lineString(mergedCoordinates); + connected = true; + break; + } + } + + if (!connected) { + connectedLines.push(currentLine); // Add unconnected line as-is + } + } + + return { floorpolygons, connectedLines }; + } + + const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures); + + function convertConnectedLinesToPolygons(connectedLines: any) { + return connectedLines.map((line: any) => { + const coordinates = line.geometry.coordinates; + + // If the line has more than two points, close the polygon + if (coordinates.length > 2) { + const firstPoint = coordinates[0]; + const lastPoint = coordinates[coordinates.length - 1]; + + // Check if already closed; if not, close it + if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) { + coordinates.push(firstPoint); + } + + // Convert the closed line into a polygon + return turf.polygon([coordinates]); + } + + // If not enough points for a polygon, return the line unchanged + return line; + }); + } + + const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines); + + if (convertedConnectedPolygons.length > 0) { + const validPolygons = convertedConnectedPolygons.filter( + (polygon: any) => polygon.geometry?.type === "Polygon" + ); + + if (validPolygons.length > 0) { + floorpolygons.push(...validPolygons); + } + } + + function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) { + return floorpolygons.map((polygon: any) => { + const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon) + + // Map each coordinate back to its original structure + const mappedPoints = coordinates.map((coord: [number, number]) => { + const [x, z] = coord; + + // Find the original point matching this coordinate + const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z); + + if (!originalPoint) { + throw new Error(`Original point for coordinate [${x}, ${z}] not found.`); + } + + return originalPoint; + }); + + // Create pairs of consecutive points + const pairs: typeof originalLines = []; + for (let i = 0; i < mappedPoints.length - 1; i++) { + pairs.push([mappedPoints[i], mappedPoints[i + 1]]); + } + + return pairs; + }); + } + + const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer); + + convertedFloorPolygons.forEach((floor) => { + const points: THREE.Vector3[] = []; + + floor.forEach((lineSegment) => { + const startPoint = lineSegment[0][0]; + points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z)); + }); + + const lastLine = floor[floor.length - 1]; + const endPoint = lastLine[1][0]; + points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z)); + + const shape = new THREE.Shape(); + shape.moveTo(points[0].x, points[0].z); + + points.forEach(point => shape.lineTo(point.x, point.z)); + shape.closePath(); + + const extrudeSettings = { + depth: 0.3, + bevelEnabled: false + }; + + const texture = new THREE.TextureLoader().load(blueFloorImage); + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + texture.colorSpace = THREE.SRGBColorSpace; + + const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide, map: texture }); + const mesh = new THREE.Mesh(geometry, material); + + mesh.castShadow = true; + mesh.receiveShadow = true; + + mesh.position.y = (floor[0][0][2] - 0.99) * CONSTANTS.wallConfig.height; + mesh.rotateX(Math.PI / 2); + mesh.name = `Only_Floor_Line_${floor[0][0][2]}`; + + mesh.userData = floor; + floorGroup?.current?.add(mesh); + }); +} + +export default loadOnlyFloors; diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 280167d..452b69a 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -15,7 +15,6 @@ import DecalInstance from '../../../Decal/decalInstance'; import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; - function Wall({ wall }: { readonly wall: Wall }) { const { wallStore } = useSceneContext(); const { walls, addDecal } = wallStore(); diff --git a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx index d9f8df0..8c72dcf 100644 --- a/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx +++ b/app/src/modules/builder/wallAsset/Instances/Instances/wallAssetInstance.tsx @@ -1,18 +1,25 @@ import * as THREE from 'three'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useThree } from '@react-three/fiber'; +import { Base, Geometry, Subtraction } from '@react-three/csg'; import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils'; import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import { Base, Geometry, Subtraction } from '@react-three/csg'; import useModuleStore from '../../../../../store/useModuleStore'; import { useSceneContext } from '../../../../scene/sceneContext'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; -import { useActiveTool, useToggleView } from '../../../../../store/builder/store'; +import { useActiveTool, useSocketStore, useToggleView } from '../../../../../store/builder/store'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../../version/versionContext'; +import { getUserData } from '../../../../../functions/getUserData'; import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment'; -import { useThree } from '@react-three/fiber'; + +import { upsertWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi'; +import { deleteWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi'; function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; + const { socket } = useSocketStore(); const { raycaster, pointer, camera, scene, controls, gl } = useThree(); const { wallStore, wallAssetStore } = useSceneContext(); const { walls, getWallById } = wallStore(); @@ -26,6 +33,10 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const groupRef = useRef(null); const wall = useMemo(() => getWallById(wallAsset.wallUuid), [getWallById, wallAsset.wallUuid, walls]); const draggingRef = useRef(false); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); useEffect(() => { const loader = new GLTFLoader(); @@ -131,11 +142,31 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { const wallRotation = intersect.object.rotation.clone(); - updateWallAsset(wallAsset.modelUuid, { + const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, { wallUuid: intersect.object.userData.wallUuid, position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z], rotation: [wallRotation.x, wallRotation.y, wallRotation.z], }); + + if (projectId && updatedWallAsset) { + + // API + + // upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset); + + // SOCKET + + const data = { + wallAssetData: updatedWallAsset, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:wall-asset:add', data); + + } } }; @@ -149,13 +180,34 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) { canvasElement.removeEventListener('pointerup', onPointerUp); }; - }, [gl, camera, toggleView, activeModule, selectedWallAsset]) + }, [gl, camera, toggleView, activeModule, selectedWallAsset, socket]) const handlePointerClick = useCallback((wallAsset: WallAsset) => { if (activeTool === 'delete' && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) { - removeWallAsset(wallAsset.modelUuid); + const removedWallAsset = removeWallAsset(wallAsset.modelUuid); + + if (projectId && removedWallAsset) { + + // API + + // deleteWallAssetApi(projectId, selectedVersion?.versionId || '', removedWallAsset.modelUuid, removedWallAsset.wallUuid); + + // SOCKET + + const data = { + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization, + modelUuid: removedWallAsset.modelUuid, + wallUuid: removedWallAsset.wallUuid + } + + socket.emit('v1:wall-asset:delete', data); + + } } - }, [activeTool, activeModule, deletableWallAsset]) + }, [activeTool, activeModule, deletableWallAsset, socket]) const handlePointerOver = useCallback((wallAsset: WallAsset, currentObject: THREE.Object3D) => { if (activeTool === "delete" && activeModule === 'builder') { diff --git a/app/src/modules/builder/wallAsset/wallAssetCreator.tsx b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx index aacca0e..c27646f 100644 --- a/app/src/modules/builder/wallAsset/wallAssetCreator.tsx +++ b/app/src/modules/builder/wallAsset/wallAssetCreator.tsx @@ -1,11 +1,16 @@ import { useThree } from '@react-three/fiber'; import { useEffect } from 'react' -import { useSelectedItem, useSocketStore, useToggleView } from '../../../store/builder/store'; import useModuleStore from '../../../store/useModuleStore'; +import { useSelectedItem, useSocketStore, useToggleView } from '../../../store/builder/store'; import { MathUtils, Vector3 } from 'three'; import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../version/versionContext'; +import { getUserData } from '../../../functions/getUserData'; import closestPointOnLineSegment from '../line/helpers/getClosestPointOnLineSegment'; +import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi'; + function WallAssetCreator() { const { socket } = useSocketStore(); const { pointer, camera, raycaster, scene, gl } = useThree(); @@ -14,6 +19,10 @@ function WallAssetCreator() { const { wallAssetStore } = useSceneContext(); const { addWallAsset } = wallAssetStore(); const { selectedItem, setSelectedItem } = useSelectedItem(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); useEffect(() => { const canvasElement = gl.domElement; @@ -52,6 +61,25 @@ function WallAssetCreator() { }; addWallAsset(newWallAsset); + if (projectId) { + + // API + + // upsertWallAssetApi(projectId, selectedVersion?.versionId || '', newWallAsset); + + // SOCKET + + const data = { + wallAssetData: newWallAsset, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:wall-asset:add', data); + + } } } }; diff --git a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx index f9d1290..bae9f87 100644 --- a/app/src/modules/builder/wallAsset/wallAssetGroup.tsx +++ b/app/src/modules/builder/wallAsset/wallAssetGroup.tsx @@ -7,6 +7,7 @@ import { useParams } from 'react-router-dom'; import useModuleStore from '../../../store/useModuleStore'; import WallAssetCreator from './wallAssetCreator' import WallAssetInstances from './Instances/wallAssetInstances' +import { getWallAssetsApi } from '../../../services/factoryBuilder/asset/wallAsset/getWallAssetsApi'; function WallAssetGroup() { const { togglView } = useToggleView(); @@ -26,6 +27,20 @@ function WallAssetGroup() { setDeletableWallAsset(null); }, [togglView, activeModule, activeTool]) + useEffect(() => { + if (projectId && selectedVersion) { + getWallAssetsApi(projectId, selectedVersion?.versionId || '').then((wallAssets) => { + if (wallAssets && wallAssets.length > 0) { + setWallAssets(wallAssets); + } else { + setWallAssets([]); + } + }).catch((err) => { + console.log(err); + }) + } + }, [projectId, selectedVersion?.versionId]) + return ( <> diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 3f4bfdb..db9e96a 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -1,6 +1,17 @@ -import React from 'react'; +import { useEffect } from 'react'; +import { useSocketStore } from '../../../store/builder/store'; export default function SocketResponses() { + const { socket } = useSocketStore(); + + useEffect(() => { + socket.on("v1:wall-asset:response:delete", (data: any) => { + }); + + return () => { + socket.off("v1:wall-asset:response:delete"); + } + }, [socket]) return ( <> diff --git a/app/src/pages/UserAuth.tsx b/app/src/pages/UserAuth.tsx index 4ac7078..fec9a47 100644 --- a/app/src/pages/UserAuth.tsx +++ b/app/src/pages/UserAuth.tsx @@ -129,7 +129,7 @@ const UserAuth: React.FC = () => {
-

Welcome to Dwinzo

+

Welcome to Aalai

{isSignIn ? ( <> diff --git a/app/src/services/factoryBuilder/asset/wallAsset/deleteWallAssetApi.ts b/app/src/services/factoryBuilder/asset/wallAsset/deleteWallAssetApi.ts new file mode 100644 index 0000000..3751aae --- /dev/null +++ b/app/src/services/factoryBuilder/asset/wallAsset/deleteWallAssetApi.ts @@ -0,0 +1,40 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteWallAssetApi = async ( + projectId: string, + versionId: string, + modelUuid: string, + wallUuid: string, +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/delete/wallasset`, { + method: "PATCH", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, modelUuid, wallUuid }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to delete wall asset:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to delete wall asset"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/asset/wallAsset/getWallAssetsApi.ts b/app/src/services/factoryBuilder/asset/wallAsset/getWallAssetsApi.ts new file mode 100644 index 0000000..d6b12ed --- /dev/null +++ b/app/src/services/factoryBuilder/asset/wallAsset/getWallAssetsApi.ts @@ -0,0 +1,37 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getWallAssetsApi = async ( + projectId: string, + versionId: string, +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/wallassets/${projectId}/${versionId}`, { + method: "GET", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to get wall assets:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to get wall assets"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/factoryBuilder/asset/wallAsset/upsertWallAssetApi.ts b/app/src/services/factoryBuilder/asset/wallAsset/upsertWallAssetApi.ts new file mode 100644 index 0000000..9f94183 --- /dev/null +++ b/app/src/services/factoryBuilder/asset/wallAsset/upsertWallAssetApi.ts @@ -0,0 +1,39 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const upsertWallAssetApi = async ( + projectId: string, + versionId: string, + wallAssetData: WallAsset +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/V1/wall-asset`, { + method: "POST", + headers: { + Authorization: "Bearer ", + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", + refresh_token: localStorage.getItem("refreshToken") || "", + }, + body: JSON.stringify({ projectId, versionId, wallAssetData }), + }); + + const newAccessToken = response.headers.get("x-access-token"); + if (newAccessToken) { + localStorage.setItem("token", newAccessToken); + } + + if (!response.ok) { + console.error("Failed to upsert wall asset:", response.statusText); + } + + const result = await response.json(); + return result; + } catch (error) { + echo.error("Failed to upsert wall asset"); + if (error instanceof Error) { + console.log(error.message); + } else { + console.log("An unknown error occurred"); + } + } +}; diff --git a/app/src/store/builder/useWallAssetStore.ts b/app/src/store/builder/useWallAssetStore.ts index 3d4e89d..d6081d7 100644 --- a/app/src/store/builder/useWallAssetStore.ts +++ b/app/src/store/builder/useWallAssetStore.ts @@ -5,9 +5,9 @@ interface WallAssetStore { wallAssets: WallAsset[]; setWallAssets: (assets: WallAsset[]) => void; addWallAsset: (asset: WallAsset) => void; - updateWallAsset: (uuid: string, updated: Partial) => void; + updateWallAsset: (uuid: string, updated: Partial) => WallAsset | undefined; setWallAssetPosition: (uuid: string, position: [number, number, number]) => void; - removeWallAsset: (uuid: string) => void; + removeWallAsset: (uuid: string) => WallAsset | undefined; clearWallAssets: () => void; setVisibility: (uuid: string, isVisible: boolean) => void; @@ -31,12 +31,17 @@ export const createWallAssetStore = () => { state.wallAssets.push(asset); }), - updateWallAsset: (uuid, updated) => set(state => { - const asset = state.wallAssets.find(a => a.modelUuid === uuid); - if (asset) { - Object.assign(asset, updated); - } - }), + updateWallAsset: (uuid, updated) => { + let updatedWallAsset: WallAsset | undefined; + set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + Object.assign(asset, updated); + updatedWallAsset = JSON.parse(JSON.stringify(asset)); + } + }); + return updatedWallAsset; + }, setWallAssetPosition: (uuid, position) => set(state => { const asset = state.wallAssets.find(a => a.modelUuid === uuid); @@ -45,9 +50,17 @@ export const createWallAssetStore = () => { } }), - removeWallAsset: (uuid) => set(state => { - state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid); - }), + removeWallAsset: (uuid) => { + let removedAsset: WallAsset | undefined; + set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + removedAsset = JSON.parse(JSON.stringify(asset)); + state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid); + } + }); + return removedAsset; + }, clearWallAssets: () => { set(state => { diff --git a/app/src/styles/layout/loading.scss b/app/src/styles/layout/loading.scss index 5b4fe12..5331c2f 100644 --- a/app/src/styles/layout/loading.scss +++ b/app/src/styles/layout/loading.scss @@ -7,7 +7,6 @@ background: var(--background-color-solid); &.comparisionLoading { - position: fixed; top: 0; right: 0; @@ -48,11 +47,15 @@ } .loading-hero-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; .logo { @include flex-center; width: 100%; margin-bottom: 35px; - + scale: 0.8; circle { fill: transparent; } @@ -99,4 +102,4 @@ } } } -} \ No newline at end of file +} diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 1d49585..83933b7 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -331,7 +331,7 @@ export const lineConfig: LineConfig = { export const wallConfig: WallConfig = { defaultColor: "#f2f2f2", // Default color of the walls - height: 7, // Height of the walls + height: 7.5, // Height of the walls width: 0.05, // Width of the walls }; diff --git a/compose.yaml b/compose.yaml index a747cd9..60ae66f 100644 --- a/compose.yaml +++ b/compose.yaml @@ -7,18 +7,10 @@ services: - REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:7999 - REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:4999 - REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 - container_name: dwinzo-beta-Demo + container_name: aalai-beta-Demo stdin_open: true tty: true ports: - - "8300:3000" - environment: - - WDS_SOCKET_PORT=0 - - PORT=3000 - - DOCSIFY_PORT=8201 + - "8300:80" volumes: - ./app:/app - -volumes: - frontend: - driver: local diff --git a/nginx-host.conf b/nginx-host.conf new file mode 100644 index 0000000..ee620a5 --- /dev/null +++ b/nginx-host.conf @@ -0,0 +1,13 @@ +server { + listen 80; + server_name aalai.ai www.aalai.ai; + + location / { + proxy_pass http://127.0.0.1:8300; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +}