diff --git a/package-lock.json b/package-lock.json index f5f58e4..d376dcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@react-three/drei": "^10.0.2", "@react-three/fiber": "^9.0.4", "@types/three": "^0.173.0", + "axios": "^1.7.9", "deventds2": "^0.1.10", "leaflet": "^1.9.4", "lucide-react": "^0.475.0", @@ -5973,6 +5974,32 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -15565,6 +15592,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/psl": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", diff --git a/package.json b/package.json index eb5de88..bb403f9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@react-three/drei": "^10.0.2", "@react-three/fiber": "^9.0.4", "@types/three": "^0.173.0", + "axios": "^1.7.9", "deventds2": "^0.1.10", "leaflet": "^1.9.4", "lucide-react": "^0.475.0", diff --git a/src/api/axios.ts b/src/api/axios.ts new file mode 100644 index 0000000..3b9dc65 --- /dev/null +++ b/src/api/axios.ts @@ -0,0 +1,10 @@ +import axios from "axios"; +import { getCookie } from "../utils/cookie"; + +const instanceFleet = axios.create({ + baseURL: `https://api.fleet.cartesiancs.com/api/`, + timeout: 7000, + headers: { "x-access-token": getCookie("token") }, +}); + +export default instanceFleet; diff --git a/src/state/exportStore.ts b/src/state/exportStore.ts index c11d1cd..693dd61 100644 --- a/src/state/exportStore.ts +++ b/src/state/exportStore.ts @@ -2,11 +2,18 @@ import { create } from "zustand"; type ActionStore = { action: boolean; + fleetSpaceId: string; + exportType: "glb" | "fleet"; setAction: (action: boolean) => void; + setFleet: (fleetSpaceId: string, exportType: "glb" | "fleet") => void; }; export const useActionStore = create((set) => ({ action: false, + fleetSpaceId: "", + exportType: "glb", setAction: (action) => set(() => ({ action: action })), + setFleet: (fleetSpaceId, exportType) => + set(() => ({ fleetSpaceId: fleetSpaceId, exportType: exportType })), })); diff --git a/src/three/Space.tsx b/src/three/Space.tsx index f6854b4..2c42c8a 100644 --- a/src/three/Space.tsx +++ b/src/three/Space.tsx @@ -6,6 +6,7 @@ import * as THREE from "three"; import { useActionStore } from "@/state/exportStore"; import { GLTFExporter } from "three/examples/jsm/Addons.js"; import Car from "./Car"; +import instanceFleet from "@/api/axios"; function Building({ shape, @@ -130,13 +131,38 @@ function Roads({ area }: { area: any }) { export function Export() { const { scene } = useThree(); const action = useActionStore((state) => state.action); + const fleetSpaceId = useActionStore((state) => state.fleetSpaceId); + + const exportType = useActionStore((state) => state.exportType); + const setAction = useActionStore((state) => state.setAction); + useEffect(() => { if (action === true) { setAction(false); exportGLB(); } }, [action, setAction, scene]); + + const uploadFleet = async (blob) => { + const formData = new FormData(); + + formData.append("object", blob, "box3d.glb"); + formData.append("title", "New Object"); + formData.append("description", ""); + formData.append("spaceId", fleetSpaceId); + + const requestUploadFile = await instanceFleet.post( + "space/file/mesh", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + }, + } + ); + }; + const exportGLB = () => { const sceneClone = scene.clone(true); sceneClone.traverse((child) => { @@ -151,13 +177,20 @@ export function Export() { (result) => { if (result instanceof ArrayBuffer) { const blob = new Blob([result], { type: "model/gltf-binary" }); - const link = document.createElement("a"); - link.style.display = "none"; - document.body.appendChild(link); - link.href = URL.createObjectURL(blob); - link.download = "scene.glb"; - link.click(); - document.body.removeChild(link); + + if (exportType == "glb") { + const link = document.createElement("a"); + link.style.display = "none"; + document.body.appendChild(link); + link.href = URL.createObjectURL(blob); + link.download = "scene.glb"; + link.click(); + document.body.removeChild(link); + } + + if (exportType == "fleet") { + uploadFleet(blob); + } } else { console.error("GLB export failed: unexpected result", result); } diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 9d6f083..9a0d80d 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -19,6 +19,7 @@ import { Modal } from "@/components/modal/Modal"; import { TopNav } from "@/components/nav/TopNav"; import { getCookie } from "@/utils/cookie"; import { Row } from "@/components/flex/Row"; +import instanceFleet from "@/api/axios"; const IconSize = css({ width: "14px", @@ -33,9 +34,12 @@ function App() { const [isWarnModal, setIsWarnModal] = useState(false); const [isExportModal, setIsExportModal] = useState(false); const [isFleetLogin, setIsFleetLogin] = useState(false); + const [isFleetModal, setIsFleetModal] = useState(false); + const [spaceList, setSpaceList] = useState([]); const setCenter = useAreaStore((state) => state.setCenter); const setAction = useActionStore((state) => state.setAction); + const setFleet = useActionStore((state) => state.setFleet); const checkIsBig = () => { const a = areaData[0].lat - areaData[1].lat; @@ -58,6 +62,31 @@ function App() { setAction(true); }; + const getFleetSpaces = async () => { + const getSpace: any = await instanceFleet.get("space"); + + setSpaceList([ + ...getSpace.data.spaces.map((item) => { + return { + ...item, + key: item.id, + }; + }), + ]); + }; + + const putGlbOnFleetSpace = (spaceId) => { + setFleet(spaceId, "fleet"); + setTimeout(() => { + exportFleet(); + }, 100); + }; + + const loadFleetSpace = () => { + getFleetSpaces(); + setIsFleetModal(true); + }; + const checkFleetLogin = () => { try { const isCookie = getCookie("token"); @@ -174,7 +203,9 @@ function App() { {isFleetLogin ? ( - + ) : ( + ))} + + + );