added dashboard with add delete and recently view the projects

This commit is contained in:
Poovizhi99 2025-05-19 14:50:33 +05:30
parent eebc91831d
commit 0ecb85a211
33 changed files with 1467 additions and 288 deletions

View File

@ -2,10 +2,13 @@
PORT=8200 PORT=8200
# Base URL for the server socket API, used for real-time communication (e.g., WebSockets). # Base URL for the server socket API, used for real-time communication (e.g., WebSockets).
REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 REACT_APP_SERVER_SOCKET_API_BASE_URL=192.168.0.110:8000
# REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000
# Base URL for the server REST API, used for HTTP requests to the backend server. # Base URL for the server REST API, used for HTTP requests to the backend server.
REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.110:5000
# REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.102:5000
# REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
# Base URL for the server marketplace, used for market place model blob. # Base URL for the server marketplace, used for market place model blob.
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import Project from "./pages/Project"; import Project from "./pages/Project";
@ -7,13 +7,24 @@ import "./styles/main.scss";
import { LoggerProvider } from "./components/ui/log/LoggerContext"; import { LoggerProvider } from "./components/ui/log/LoggerContext";
const App: React.FC = () => { const App: React.FC = () => {
useEffect(() => {
const handlePopState = () => {
window.location.reload();
};
window.addEventListener("popstate", handlePopState);
return () => {
window.removeEventListener("popstate", handlePopState);
};
}, []);
return ( return (
<LoggerProvider> <LoggerProvider>
<Router> <Router>
<Routes> <Routes>
<Route path="/" element={<UserAuth />} /> <Route path="/" element={<UserAuth />} />
<Route path="/dashboard" element={<Dashboard />} /> <Route path="/dashboard" element={<Dashboard />} />
<Route path="/project" element={<Project />} /> <Route path="/:projectId" element={<Project />} />
</Routes> </Routes>
</Router> </Router>
</LoggerProvider> </LoggerProvider>

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

View File

@ -1,24 +1,77 @@
import React from "react"; import React from "react";
import { KebabIcon } from "../../icons/ExportCommonIcons"; import { KebabIcon } from "../../icons/ExportCommonIcons";
import img from "../../../assets/image/image.png" import img from "../../../assets/image/image.png";
import { useNavigate } from "react-router-dom";
import { useProjectName } from "../../../store/builder/store";
import { viewProject } from "../../../services/dashboard/viewProject";
import { getUserData } from "./functions/getUserData";
interface DashBoardCardProps {
projectName: string;
thumbnail: any;
projectId: string;
handleDeleteProject?: (projectId: string) => Promise<void>;
handleRestoreProject?: (projectId: string) => Promise<void>;
}
const DashboardCard: React.FC<DashBoardCardProps> = ({
projectName,
handleDeleteProject,
thumbnail,
projectId,
handleRestoreProject,
}) => {
let navigate = useNavigate();
const { setProjectName } = useProjectName();
const { userId, organization, userName } = getUserData();
const handleKebabIconClick = async () => {
try {
if (handleRestoreProject) {
await handleRestoreProject(projectId);
} else if (handleDeleteProject) {
await handleDeleteProject(projectId);
}
} catch { }
};
const navigateToProject = async () => {
try {
const viewedProject = await viewProject(organization, projectId, userId);
console.log("Saved viewwdProject:", viewedProject);
} catch (error) {
console.error("Error deleting project:", error);
}
setProjectName(projectName);
navigate(`/${projectId}`);
};
const DashboardCard:React.FC = () => {
return ( return (
<div className="dashboard-card-container"> <div className="dashboard-card-container" onClick={navigateToProject} title={projectName}>
<div className="preview-container"> <div className="preview-container">
<img src={img} alt="" /> {thumbnail ? <img src={thumbnail} alt="" /> : <img src={img} alt="" />}
</div> </div>
<div className="project-details-container"> <div className="project-details-container">
<div className="project-details"> <div className="project-details">
<div className="project-name">Untitled</div> <div className="project-name">{projectName}</div>
<div className="project-data">24-12-2025</div> <div className="project-data">24-12-2025</div>
</div> </div>
<div className="users-list-container"> <div className="users-list-container">
<div className="user-profile">V</div> <div className="user-profile">
{userName ? userName.charAt(0).toUpperCase() : "Anonymous"}
</div>
<div
onClick={(e) => {
e.stopPropagation();
handleKebabIconClick();
}}
>
<KebabIcon /> <KebabIcon />
</div> </div>
</div> </div>
</div> </div>
</div>
); );
}; };

View File

@ -1,18 +1,134 @@
import React from "react"; import React, { useEffect, useState } from "react";
import DashboardCard from "./DashboardCard"; import DashboardCard from "./DashboardCard";
import DashboardNavBar from "./DashboardNavBar"; import DashboardNavBar from "./DashboardNavBar";
import MarketPlaceBanner from "./MarketPlaceBanner"; import MarketPlaceBanner from "./MarketPlaceBanner";
import { recentlyViewed } from "../../../services/dashboard/recentlyViewed";
import { getUserData } from "./functions/getUserData";
import { searchProject } from "../../../services/dashboard/searchProjects";
import { deleteProject } from "../../../services/dashboard/deleteProject";
import { useSocketStore } from "../../../store/builder/store";
interface Project {
_id: string;
projectName: string;
thumbnail: string;
createdBy: string;
projectUuid?: string;
}
interface RecentProjectsData {
[key: string]: Project[];
}
const DashboardHome: React.FC = () => { const DashboardHome: React.FC = () => {
const [recentProjects, setRecentProjects] = useState<RecentProjectsData>({});
const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
const { userId, organization } = getUserData();
const { dashBoardSocket } = useSocketStore();
const fetchRecentProjects = async () => {
try {
const projects = await recentlyViewed(organization, userId);
if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) {
setRecentProjects(projects);
}
} catch (error) {
console.error("Error fetching recent projects:", error);
}
};
const handleRecentProjectSearch = async (inputValue: string) => {
if (!inputValue.trim()) {
setIsSearchActive(false);
return;
}
const filterRecentProcess = await searchProject(organization, userId, inputValue);
setIsSearchActive(true);
setRecentProjects(filterRecentProcess.message ? {} : filterRecentProcess);
};
const handleDeleteProject = async (projectId: any) => {
try {
//API for delete project
// const deletedProject = await deleteProject(
// projectId,
// userId,
// Organization
// );
//socket for delete Project
const deleteProject = {
projectId,
organization,
userId,
};
if (dashBoardSocket) {
const handleResponse = (data: any) => {
console.log("Project add response:", data);
dashBoardSocket.off("v1-project:response:delete", handleResponse);
};
dashBoardSocket.on("v1-project:response:delete", handleResponse);
dashBoardSocket.emit("v1:project:delete", deleteProject);
}
setRecentProjects((prevDiscardedProjects: RecentProjectsData) => {
if (!Array.isArray(prevDiscardedProjects?.RecentlyViewed)) {
return prevDiscardedProjects;
}
const updatedProjectDatas = prevDiscardedProjects.RecentlyViewed.filter(
(project) => project._id !== projectId
);
return {
...prevDiscardedProjects,
RecentlyViewed: updatedProjectDatas,
};
});
setIsSearchActive(false);
} catch (error) {
console.error("Error deleting project:", error);
}
};
const renderProjects = () => {
const projectList = recentProjects[Object.keys(recentProjects)[0]];
if (!projectList?.length) {
return <div className="empty-state">No recent projects found</div>;
}
return projectList.map((project) => (
<DashboardCard
key={project._id}
projectName={project.projectName}
thumbnail={project.thumbnail}
projectId={project._id}
handleDeleteProject={handleDeleteProject}
/>
));
};
useEffect(() => {
if (!isSearchActive) {
fetchRecentProjects();
}
}, [isSearchActive]);
return ( return (
<div className="dashboard-home-container"> <div className="dashboard-home-container">
<DashboardNavBar page={"home"} /> <DashboardNavBar
page="home"
handleRecentProjectSearch={handleRecentProjectSearch}
/>
<MarketPlaceBanner /> <MarketPlaceBanner />
<div className="container"> <div className="container">
<div className="header">Recents</div> <h2 className="section-header">Recent Projects</h2>
<div className="cards-container"> <div className="cards-container">{renderProjects()}</div>
<DashboardCard />
</div>
</div> </div>
</div> </div>
); );

View File

@ -4,16 +4,38 @@ import Search from "../../ui/inputs/Search";
interface DashboardNavBarProps { interface DashboardNavBarProps {
page: React.ReactNode; page: React.ReactNode;
handleProjectsSearch?: (inputValue: string) => Promise<void>;
handleTrashSearch?: (inputValue: string) => Promise<void>;
handleRecentProjectSearch?: (inputValue: string) => Promise<void>;
} }
const DashboardNavBar: React.FC<DashboardNavBarProps> = ({ page }) => { const DashboardNavBar: React.FC<DashboardNavBarProps> = ({
page,
handleProjectsSearch,
handleTrashSearch,
handleRecentProjectSearch,
}) => {
const handleSearch = async (inputValue: string) => {
try {
if (handleProjectsSearch) {
await handleProjectsSearch(inputValue);
} else if (handleTrashSearch) {
await handleTrashSearch(inputValue);
} else if (handleRecentProjectSearch) {
await handleRecentProjectSearch(inputValue);
}
} catch (error) {
console.error("Search failed:", error);
}
};
return ( return (
<div className="dashboard-navbar-container"> <div className="dashboard-navbar-container">
<div className="title">{page}</div> <div className="title">{page}</div>
<div className="market-place-button"> <div className="market-place-button">
<CartIcon isActive /> Market Place <CartIcon isActive /> Market Place
</div> </div>
<Search onChange={() => {}} /> <Search onChange={handleSearch} />
</div> </div>
); );
}; };

View File

@ -0,0 +1,155 @@
import React, { useEffect, useState } from 'react';
import DashboardNavBar from './DashboardNavBar';
import DashboardCard from './DashboardCard';
import { getAllProjects } from '../../../services/dashboard/getAllProjects';
import { getUserData } from './functions/getUserData';
import { searchProject } from '../../../services/dashboard/searchProjects';
import { deleteProject } from '../../../services/dashboard/deleteProject';
import { useSocketStore } from '../../../store/builder/store';
interface Project {
_id: string;
projectName: string;
thumbnail: string;
createdBy: string;
projectUuid?: string;
}
interface WorkspaceProjects {
[key: string]: Project[];
}
const DashboardProjects: React.FC = () => {
const [workspaceProjects, setWorkspaceProjects] = useState<WorkspaceProjects>({});
const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
const [activeFolder, setActiveFolder] = useState<string>("myProjects");
const { dashBoardSocket } = useSocketStore();
const { userId, organization } = getUserData();
const fetchAllProjects = async () => {
try {
const projects = await getAllProjects(userId, organization);
if (JSON.stringify(projects) !== JSON.stringify(workspaceProjects)) {
setWorkspaceProjects(projects);
}
} catch (error) {
console.error("Error fetching projects:", error);
}
};
const handleProjectsSearch = async (
inputValue: string
) => {
if (!inputValue.trim()) {
setIsSearchActive(false);
return;
}
if (!setWorkspaceProjects || !setIsSearchActive) return;
const searchedProject = await searchProject(organization, userId, inputValue);
setIsSearchActive(true);
setWorkspaceProjects(searchedProject.message ? {} : searchedProject);
};
const handleDeleteProject = async (projectId: any) => {
try {
const Organization = organization
// const deletedProject = await deleteProject(
// projectId,
// userId,
// Organization
// );
const deleteProject = {
projectId,
organization: organization,
userId
}
if (dashBoardSocket) {
const handleResponse = (data: any) => {
console.log('Project add response:', data);
dashBoardSocket.off("v1-project:response:delete", handleResponse); // Clean up
};
dashBoardSocket.on("v1-project:response:delete", handleResponse);
dashBoardSocket.emit("v1:project:delete", deleteProject);
} else {
console.error("Socket is not connected.");
}
setWorkspaceProjects((prevDiscardedProjects: WorkspaceProjects) => {
if (!Array.isArray(prevDiscardedProjects?.Projects)) {
return prevDiscardedProjects;
}
const updatedProjectDatas = prevDiscardedProjects.Projects.filter(
(project) => project._id !== projectId
);
return {
...prevDiscardedProjects,
Projects: updatedProjectDatas
};
});
setIsSearchActive(false)
} catch (error) {
console.error('Error deleting project:', error);
}
};
const renderProjects = () => {
if (activeFolder !== "myProjects") return null;
const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]];
if (!projectList?.length) {
return <div className="empty-state">No projects found</div>;
}
return projectList.map((project) => (
<DashboardCard
key={project._id}
projectName={project.projectName}
thumbnail={project.thumbnail}
projectId={project._id}
handleDeleteProject={handleDeleteProject}
/>
));
};
useEffect(() => {
if (!isSearchActive) {
fetchAllProjects();
}
}, [isSearchActive]);
return (
<div className="dashboard-home-container">
<DashboardNavBar
page="projects"
handleProjectsSearch={handleProjectsSearch}
/>
<div className="container">
<div className="header" style={{ display: "flex", gap: "7px" }}>
<div
style={{ color: activeFolder === "myProjects" ? "#c4abf1" : "black" }}
onClick={() => setActiveFolder("myProjects")}
>
My Projects
</div>
<div
style={{ color: activeFolder === "shared" ? "#c4abf1" : "black" }}
onClick={() => setActiveFolder("shared")}
>
Shared with me
</div>
</div>
<div className="cards-container">
{renderProjects()}
</div>
</div>
</div>
);
};
export default DashboardProjects;

View File

@ -0,0 +1,122 @@
import React, { useEffect, useState } from 'react';
import { getTrash } from '../../../services/dashboard/getTrash';
import DashboardCard from './DashboardCard';
import DashboardNavBar from './DashboardNavBar';
import { getUserData } from './functions/getUserData';
import { trashSearchProject } from '../../../services/dashboard/trashSearchProject';
import { restoreTrash } from '../../../services/dashboard/restoreTrash';
interface Project {
_id: string;
projectName: string;
thumbnail: string;
createdBy: string;
projectUuid?: string;
}
interface DiscardedProjects {
[key: string]: Project[];
}
const DashboardTrash: React.FC = () => {
const [discardedProjects, setDiscardedProjects] = useState<DiscardedProjects>({});
console.log('discardedProjects: ', discardedProjects);
const [isSearchActive, setIsSearchActive] = useState(false);
const { userId, organization } = getUserData();
const fetchTrashProjects = async () => {
try {
const projects = await getTrash(organization);
console.log('organization: ', organization);
console.log('trashedprojects: ', projects);
if (JSON.stringify(projects) !== JSON.stringify(discardedProjects)) {
setDiscardedProjects(projects);
}
} catch (error) {
console.error('Error fetching trash projects:', error);
}
};
const handleTrashSearch = async (
inputValue: string
) => {
if (!inputValue.trim()) {
setIsSearchActive(false);
return;
}
if (!setDiscardedProjects || !setIsSearchActive) return;
const filterTrashedProcess = await trashSearchProject(organization, userId, inputValue);
setIsSearchActive(true);
setDiscardedProjects(filterTrashedProcess.message ? {} : filterTrashedProcess);
};
const handleRestoreProject = async (projectId: any) => {
try {
const Organization = organization;
const restoreProject = await restoreTrash(
Organization,
projectId
);
setDiscardedProjects((prevDiscardedProjects: DiscardedProjects) => {
// Check if TrashDatas exists and is an array
if (!Array.isArray(prevDiscardedProjects?.TrashDatas)) {
console.error('TrashDatas is not an array', prevDiscardedProjects);
return prevDiscardedProjects;
}
const updatedTrashDatas = prevDiscardedProjects.TrashDatas.filter(
(project) => project._id !== projectId
);
return {
...prevDiscardedProjects,
TrashDatas: updatedTrashDatas
};
});
setIsSearchActive(false)
} catch (error) {
console.error('Error deleting project:', error);
}
};
const renderTrashProjects = () => {
const projectList = discardedProjects[Object.keys(discardedProjects)[0]];
if (!projectList?.length) {
return <div className="empty-state">No deleted projects found</div>;
}
return projectList.map((project) => (
<DashboardCard
key={project._id}
projectName={project.projectName}
thumbnail={project.thumbnail}
projectId={project._id}
handleRestoreProject={handleRestoreProject}
/>
));
};
useEffect(() => {
console.log('isSearchActive:trash ', isSearchActive);
if (!isSearchActive) {
fetchTrashProjects();
}
}, [isSearchActive]);
return (
<div className="dashboard-home-container">
<DashboardNavBar
page="trash"
handleTrashSearch={handleTrashSearch}
/>
<div className="container">
<div className="header" style={{ display: 'flex', gap: '7px' }}></div>
<div className="cards-container">
{renderTrashProjects()}
</div>
</div>
</div>
);
};
export default DashboardTrash;

View File

@ -0,0 +1,62 @@
import React, { useEffect, useState } from 'react';
import { projectTutorial } from '../../../services/dashboard/projectTutorial';
import DashboardNavBar from './DashboardNavBar';
import DashboardCard from './DashboardCard';
interface Project {
_id: string;
projectName: string;
thumbnail: string;
createdBy: string;
projectUuid?: string;
}
interface DiscardedProjects {
[key: string]: Project[];
}
const DashboardTutorial = () => {
const [tutorialProject, setTutorialProject] = useState<DiscardedProjects>({})
const handleIcon = async () => {
try {
let tutorial = await projectTutorial()
setTutorialProject(tutorial)
} catch {
}
}
useEffect(() => {
handleIcon()
}, [])
const renderTrashProjects = () => {
const projectList = tutorialProject[Object.keys(tutorialProject)[0]];
if (!projectList?.length) {
return <div className="empty-state">No deleted projects found</div>;
}
return projectList.map((tutorials: any) => (
<DashboardCard
key={tutorials._id}
projectName={tutorials.projectName}
thumbnail={tutorials.thumbnail}
projectId={tutorials._id}
/>
));
};
return (
<div className="dashboard-home-container">
<DashboardNavBar
page="tutorial"
/>
<div className="container">
<div className="header" style={{ display: 'flex', gap: '7px' }}></div>
<div className="cards-container">
{renderTrashProjects()}
</div>
</div>
</div>
);
}
export default DashboardTutorial;

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect, useState } from "react";
import { import {
DocumentationIcon, DocumentationIcon,
HelpIcon, HelpIcon,
@ -9,40 +9,98 @@ import {
TutorialsIcon, TutorialsIcon,
} from "../../icons/DashboardIcon"; } from "../../icons/DashboardIcon";
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons"; import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
import { useNavigate } from "react-router-dom";
import img from "../../../assets/image/image.png"
import darkThemeImage from "../../../assets/image/darkThemeProject.png"
import lightThemeImage from "../../../assets/image/lightThemeProject.png"
import { createProject } from "../../../services/dashboard/createProject";
import { getUserData } from "./functions/getUserData";
import { useSocketStore } from "../../../store/builder/store";
interface SidePannelProps {
setActiveTab: React.Dispatch<React.SetStateAction<string>>;
activeTab: string
}
const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
const { userName, userId, organization } = getUserData();
const navigate = useNavigate();
const { dashBoardSocket } = useSocketStore();
const savedTheme = localStorage.getItem("theme") ?? "light";
function generateProjectId() {
const randomBytes = new Uint8Array(12);
crypto.getRandomValues(randomBytes);
return Array.from(randomBytes, (byte) =>
byte.toString(16).padStart(2, "0")).join("");
}
const handleCreateNewProject = async () => {
try {
const projectId = generateProjectId();
navigate(`/${projectId}`);
//API for creating new Project
// const project = await createProject(
// projectId,
// userId,
// img,
// organization
// );
// console.log('Created project: ', project);
const addProject = {
userId,
thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage,
organization: organization,
projectUuid: projectId,
};
if (dashBoardSocket) {
// console.log('addProject: ', addProject);
const handleResponse = (data: any) => {
console.log('Project add response:', data);
dashBoardSocket.off("v1-project:response:add", handleResponse); // Clean up
};
dashBoardSocket.on("v1-project:response:add", handleResponse);
dashBoardSocket.emit("v1:project:add", addProject);
} else {
console.error("Socket is not connected.");
}
} catch (error) {
console.error("Error creating project:", error);
}
};
const SidePannel: React.FC = () => {
const userName = localStorage.getItem("userName") ?? "Anonymous";
return ( return (
<div className="side-pannel-container"> <div className="side-pannel-container">
<div className="side-pannel-header"> <div className="side-pannel-header">
<div className="user-container"> <div className="user-container">
<div className="user-profile">{userName[0]}</div> <div className="user-profile">{userName?.charAt(0).toUpperCase()}</div>
<div className="user-name">{userName}</div> <div className="user-name">{userName ? userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase() : "Anonymous"}</div>
</div> </div>
<div className="notifications-container"> <div className="notifications-container">
<NotificationIcon /> <NotificationIcon />
</div> </div>
</div> </div>
<div className="new-project-button">+ New project</div> <div className="new-project-button" style={{ cursor: "pointer" }} onClick={handleCreateNewProject}>+ New project</div>
<div className="side-bar-content-container"> <div className="side-bar-content-container">
<div className="side-bar-options-container"> <div className="side-bar-options-container">
<div className="option-list active"> <div className={activeTab === "Home" ? "option-list active" : "option-list"} onClick={() => setActiveTab("Home")}>
<HomeIcon /> <HomeIcon />
Home Home
</div> </div>
<div className="option-list" title="coming soon"> <div className={activeTab === "Projects" ? "option-list active" : "option-list"} title="Projects" onClick={() => setActiveTab("Projects")}>
<ProjectsIcon /> <ProjectsIcon />
Projects Projects
</div> </div>
<div className="option-list" title="coming soon"> <div className={activeTab === "Trash" ? "option-list active" : "option-list"} title="Trash" onClick={() => setActiveTab("Trash")}>
<TrashIcon /> <TrashIcon />
Trash Trash
</div> </div>
<div className="option-list" title="coming soon"> <div className={activeTab === "Tutorials" ? "option-list active" : "option-list"} title="coming soon" onClick={() => setActiveTab("Tutorials")}>
<TutorialsIcon /> <TutorialsIcon />
Tutorials Tutorials
</div> </div>
<div className="option-list" title="coming soon"> <div className={activeTab === "Documentation" ? "option-list active" : "option-list"} title="coming soon" onClick={() => setActiveTab("Documentation")}>
<DocumentationIcon /> <DocumentationIcon />
Documentation Documentation
</div> </div>

View File

@ -0,0 +1,31 @@
interface UserData {
email: string;
userId: string;
userName?: string; // Optional
organization: string;
}
export const getUserData = (): UserData => {
const email = localStorage.getItem("email");
const userId = localStorage.getItem("userId");
const userName = localStorage.getItem("userName");
if (!email || !userId) {
throw new Error("User data not found in localStorage");
}
const [_, emailDomain] = email.split("@");
if (!emailDomain) {
throw new Error("Invalid email format");
}
const [organization] = emailDomain.split(".");
return {
email: email,
userId: userId,
userName: userName ?? undefined,
organization,
};
};

View File

@ -1,6 +1,9 @@
import React from "react"; import React, { useEffect } from "react";
import RenderOverlay from "./Overlay"; import RenderOverlay from "./Overlay";
import { LogoIconLarge } from "../icons/Logo"; import { LogoIconLarge } from "../icons/Logo";
import { useProjectName } from "../../store/builder/store";
import { useParams } from "react-router-dom";
import { getAllProjects } from "../../services/dashboard/getAllProjects";
interface LoadingPageProps { interface LoadingPageProps {
progress: number; // Expect progress as a percentage (0-100) progress: number; // Expect progress as a percentage (0-100)
@ -8,12 +11,46 @@ interface LoadingPageProps {
const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => { const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
const validatedProgress = Math.min(100, Math.max(0, progress)); const validatedProgress = Math.min(100, Math.max(0, progress));
const { projectName, setProjectName } = useProjectName();
const { projectId } = useParams();
const generateThumbnail = async () => {
const email = localStorage.getItem("email");
const userId = localStorage.getItem("userId");
try {
if (!email || !userId) {
console.error("User data not found in localStorage");
return;
}
const emailParts = email.split("@");
if (emailParts.length < 2) {
console.error("Invalid email format");
return;
}
const domainParts = emailParts[1].split(".");
const Organization = domainParts[0];
const projects = await getAllProjects(
userId, Organization
);
const filterProject = projects?.Projects.find((val: any) => val.projectUuid === projectId || val._id
=== projectId)
setProjectName(filterProject.projectName)
}
catch {
}
}
useEffect(() => {
generateThumbnail();
}, []);
return ( return (
<RenderOverlay> <RenderOverlay>
<div className="loading-wrapper"> <div className="loading-wrapper">
<div className="loading-container"> <div className="loading-container">
<div className="project-name">Untitled</div> <div className="project-name">{projectName}</div>
<div className="loading-hero-container"> <div className="loading-hero-container">
<div className="logo"> <div className="logo">
<LogoIconLarge /> <LogoIconLarge />

View File

@ -3,10 +3,17 @@ import RenameInput from "./inputs/RenameInput";
import { ArrowIcon } from "../icons/ExportCommonIcons"; import { ArrowIcon } from "../icons/ExportCommonIcons";
import MenuBar from "./menu/menu"; import MenuBar from "./menu/menu";
import { ProjectIcon } from "../icons/HeaderIcons"; import { ProjectIcon } from "../icons/HeaderIcons";
import { useProjectName, useSocketStore } from "../../store/builder/store";
import { useParams } from "react-router-dom";
import { updateProject } from "../../services/dashboard/updateProject";
import { getAllProjects } from "../../services/dashboard/getAllProjects";
const FileMenu: React.FC = () => { const FileMenu: React.FC = () => {
const [openMenu, setOpenMenu] = useState(false); const [openMenu, setOpenMenu] = useState(false);
const { projectName, setProjectName } = useProjectName();
const { dashBoardSocket } = useSocketStore();
const containerRef = useRef<HTMLButtonElement>(null); const containerRef = useRef<HTMLButtonElement>(null);
const { projectId } = useParams();
let clickTimeout: NodeJS.Timeout | null = null; let clickTimeout: NodeJS.Timeout | null = null;
const handleClick = () => { const handleClick = () => {
@ -31,20 +38,65 @@ const FileMenu: React.FC = () => {
return () => document.removeEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside);
}, []); }, []);
// project
const [projectName, setProjectName] = useState("Demo Project");
// Load project name from localStorage on mount const handleProjectRename = async (projectName: string) => {
useEffect(() => { setProjectName(projectName);
const savedName = localStorage.getItem("projectName"); if (!projectId) return
if (savedName) { // localStorage.setItem("projectName", newName);
setProjectName(savedName); try {
const email = localStorage.getItem("email");
const userId = localStorage.getItem("userId");
if (!email || !userId) {
return;
} }
}, []);
const handleProjectRename = (newName: string) => { const emailParts = email.split("@");
setProjectName(newName); if (emailParts.length < 2) {
localStorage.setItem("projectName", newName);
return;
}
const domainParts = emailParts[1].split(".");
const Organization = domainParts[0];
const projects = await getAllProjects(
userId, Organization
);
console.log('projects: ', projects);
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id
=== projectId)
const updateProject = {
projectId: projectUuid,
organization: Organization,
userId,
projectName,
thumbnail: undefined
}
if (dashBoardSocket) {
const handleResponse = (data: any) => {
console.log('Project update response:', data);
dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
};
dashBoardSocket.on("v1-project:response:update", handleResponse);
dashBoardSocket.emit("v1:project:update", updateProject);
}
//API for projects rename
// const updatedProjectName = await updateProject(
// projectId,
// userId,
// Organization,
// undefined,
// projectName
// );
//
} catch (error) {
}
}; };
return ( return (

View File

@ -38,8 +38,7 @@ const Search: React.FC<SearchProps> = ({
return ( return (
<div className="search-wrapper"> <div className="search-wrapper">
<div <div
className={`search-container ${ className={`search-container ${isFocused || inputValue ? "active" : ""
isFocused || inputValue ? "active" : ""
}`} }`}
> >
<div className="icon-container"> <div className="icon-container">

View File

@ -7,6 +7,7 @@ import Visualization from "../visualization/visualization";
import Setup from "./setup/setup"; import Setup from "./setup/setup";
import Simulation from "../simulation/simulation"; import Simulation from "../simulation/simulation";
import Collaboration from "../collaboration/collaboration"; import Collaboration from "../collaboration/collaboration";
import { useSocketStore } from "../../store/builder/store";
export default function Scene() { export default function Scene() {
const map = useMemo( const map = useMemo(
@ -19,11 +20,13 @@ export default function Scene() {
[] []
); );
return ( return (
<KeyboardControls map={map}> <KeyboardControls map={map}>
<Canvas <Canvas
id="canvas-container"
eventPrefix="client" eventPrefix="client"
gl={{ powerPreference: "high-performance", antialias: true }} gl={{ powerPreference: "high-performance", antialias: true, alpha: true, preserveDrawingBuffer: true, }}
onContextMenu={(e) => { onContextMenu={(e) => {
e.preventDefault(); e.preventDefault();
}} }}

View File

@ -1,12 +1,34 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import SidePannel from '../components/layout/Dashboard/SidePannel'; import SidePannel from '../components/layout/Dashboard/SidePannel';
import DashboardHome from '../components/layout/Dashboard/DashboardHome'; import DashboardHome from '../components/layout/Dashboard/DashboardHome';
import DashboardProjects from '../components/layout/Dashboard/DashboardProjects';
import DashboardTrash from '../components/layout/Dashboard/DashboardTrash';
import { useOrganization, useSocketStore, useUserName, useZones } from '../store/builder/store';
import { getUserData } from '../components/layout/Dashboard/functions/getUserData';
import DashboardTutorial from '../components/layout/Dashboard/DashboardTutorial';
const Dashboard: React.FC = () => { const Dashboard: React.FC = () => {
const [activeTab, setActiveTab] = useState<string>('Home');
const { setUserName } = useUserName();
const { setOrganization } = useOrganization();
const { userId, organization, email, userName } = getUserData();
useEffect(() => {
if (email) {
useSocketStore.getState().initializeSocket(email, organization, userId);
if (organization && userName) {
setOrganization(organization);
setUserName(userName);
}
}
}, [])
return ( return (
<div className="dashboard-main"> <div className="dashboard-main">
<SidePannel /> <SidePannel setActiveTab={setActiveTab} activeTab={activeTab} />
<DashboardHome /> {activeTab == 'Home' && <DashboardHome />}
{activeTab == 'Projects' && <DashboardProjects />}
{activeTab == 'Trash' && <DashboardTrash />}
{activeTab == 'Tutorials' && <DashboardTutorial />}
</div> </div>
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react"; import React, { useEffect, useState } from "react";
import ModuleToggle from "../components/ui/ModuleToggle"; import ModuleToggle from "../components/ui/ModuleToggle";
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft"; import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
import SideBarRight from "../components/layout/sidebarRight/SideBarRight"; import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
@ -14,8 +14,10 @@ import {
useZones, useZones,
useLoadingProgress, useLoadingProgress,
useWidgetSubOption, useWidgetSubOption,
useProjectName,
useStartSimulation,
} from "../store/builder/store"; } from "../store/builder/store";
import { useNavigate } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { usePlayButtonStore } from "../store/usePlayButtonStore"; import { usePlayButtonStore } from "../store/usePlayButtonStore";
import MarketPlace from "../modules/market/MarketPlace"; import MarketPlace from "../modules/market/MarketPlace";
import LoadingPage from "../components/templates/LoadingPage"; import LoadingPage from "../components/templates/LoadingPage";
@ -32,19 +34,59 @@ import RenderOverlay from "../components/templates/Overlay";
import LogList from "../components/ui/log/LogList"; import LogList from "../components/ui/log/LogList";
import Footer from "../components/footer/Footer"; import Footer from "../components/footer/Footer";
import SelectFloorPlan from "../components/temporary/SelectFloorPlan"; import SelectFloorPlan from "../components/temporary/SelectFloorPlan";
import { getAllProjects } from "../services/dashboard/getAllProjects";
import { viewProject } from "../services/dashboard/viewProject";
const Project: React.FC = () => { const Project: React.FC = () => {
let navigate = useNavigate(); let navigate = useNavigate();
const echo = useLogger(); const echo = useLogger();
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { loadingProgress } = useLoadingProgress(); const { loadingProgress, setLoadingProgress } = useLoadingProgress();
const { setUserName } = useUserName(); const { setUserName } = useUserName();
const { setOrganization } = useOrganization(); const { setOrganization } = useOrganization();
const { setFloorItems } = useFloorItems(); const { setFloorItems } = useFloorItems();
const { setWallItems } = useWallItems(); const { setWallItems } = useWallItems();
const { setZones } = useZones(); const { setZones } = useZones();
const { projectId } = useParams();
const { setProjectName } = useProjectName();
const generateThumbnail = async () => {
const email = localStorage.getItem("email");
const userId = localStorage.getItem("userId");
try {
if (!email || !userId) {
console.error("User data not found in localStorage");
return;
}
const emailParts = email.split("@");
if (emailParts.length < 2) {
console.error("Invalid email format");
return;
}
const domainParts = emailParts[1].split(".");
const Organization = domainParts[0];
const projects = await getAllProjects(
userId, Organization
);
const filterProject = projects?.Projects.find((val: any) => val.projectUuid === projectId || val._id
=== projectId)
const viewedProject = await viewProject(
Organization,
filterProject._id,
userId,
);
setProjectName(filterProject.projectName)
}
catch {
}
}
useEffect(() => {
generateThumbnail();
}, []);
useEffect(() => { useEffect(() => {
setFloorItems([]); setFloorItems([]);
setWallItems([]); setWallItems([]);
@ -53,7 +95,7 @@ const Project: React.FC = () => {
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
if (email) { if (email) {
const Organization = email.split("@")[1].split(".")[0]; const Organization = email.split("@")[1].split(".")[0];
useSocketStore.getState().initializeSocket(email, Organization); // useSocketStore.getState().initializeSocket(email, Organization);
const name = localStorage.getItem("userName"); const name = localStorage.getItem("userName");
if (Organization && name) { if (Organization && name) {
setOrganization(Organization); setOrganization(Organization);
@ -82,6 +124,7 @@ const Project: React.FC = () => {
const { selectedZone } = useSelectedZoneStore(); const { selectedZone } = useSelectedZoneStore();
const { setFloatingWidget } = useFloatingWidget(); const { setFloatingWidget } = useFloatingWidget();
return ( return (
<div className="project-main"> <div className="project-main">
{!selectedUser && ( {!selectedUser && (

View File

@ -26,19 +26,23 @@ const UserAuth: React.FC = () => {
e.preventDefault(); e.preventDefault();
const organization = email.split("@")[1].split(".")[0]; const organization = email.split("@")[1].split(".")[0];
console.log('email, password, organization: ', email, password, organization);
try { try {
const res = await signInApi(email, password, organization); const res = await signInApi(email, password, organization);
if (res.message === "login successfull") { if (res.message === "login successfull") {
setError(""); setError("");
setOrganization(organization); setOrganization(organization);
setUserName(res.name); setUserName(res.name);
console.log(' res.userId: ', res.userId);
localStorage.setItem("userId", res.userId); localStorage.setItem("userId", res.userId);
localStorage.setItem("email", res.email); localStorage.setItem("email", res.email);
localStorage.setItem("userName", res.name); localStorage.setItem("userName", res.name);
if (res.isShare) { if (res.isShare) {
setLoadingProgress(1); setLoadingProgress(1);
navigate("/Project"); // navigate("/Project");
navigate("/Dashboard");
} }
} else if (res.message === "User Not Found!!! Kindly signup...") { } else if (res.message === "User Not Found!!! Kindly signup...") {
setError("Account not found"); setError("Account not found");

View File

@ -0,0 +1,38 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
// let url_Backend_dwinzo = `http://192.168.0.110:5000`;
export const createProject = async (
projectUuid: string,
userId: string,
thumbnail: string,
organization: string
) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/upsertProject`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
projectUuid,
userId,
thumbnail,
organization,
}),
});
if (!response.ok) {
throw new Error("Failed to add project");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,35 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const deleteProject = async (
projectId: string,
userId: string,
organization: string
) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1//Project/archive/${projectId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ userId, organization }),
}
);
if (!response.ok) {
throw new Error("Failed to clearPanel in the zone");
}
const result = await response.json();
return result;
} catch (error) {
echo.error("Failed to clean pannel");
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,24 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getAllProjects = async (userId: string, organization: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/Projects/${userId}/${organization}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch assets");
}
return await response.json();
} catch (error: any) {
echo.error("Failed to get asset image");
throw new Error(error.message);
}
};

View File

@ -0,0 +1,28 @@
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// const url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const getTrash = async (organization: string) => {
console.log("Organization:", organization);
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/Trash/Lists?organization=${organization}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch trash data");
}
const data = await response.json();
return data;
} catch (error: any) {
console.error("Failed to fetch trash data:", error);
throw new Error(error.message || "Unknown error");
}
};

View File

@ -0,0 +1,27 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const projectTutorial = async () => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/tutorials`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
console.log("response: ", response);
if (!response.ok) {
throw new Error("Failed to add project");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,24 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const recentlyViewed = async (organization: string, userId: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/RecentlyViewed/${userId}/${organization}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch project");
}
return await response.json();
} catch (error: any) {
console.error("Failed to get project");
throw new Error(error.message);
}
};

View File

@ -0,0 +1,26 @@
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// const url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const restoreTrash = async (organization: string, projectId: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/restore?organization=${organization}&projectId=${projectId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch trash data");
}
const data = await response.json();
return data;
} catch (error: any) {
console.error("Failed to fetch trash data:", error);
throw new Error(error.message || "Unknown error");
}
};

View File

@ -0,0 +1,35 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const searchProject = async (
organization: string,
userId: string,
searchName: string
) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/searchProjects?organization=${organization}&userId=${userId}&searchName=${searchName}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to Search project");
}
console.log("response: ", response);
const result = await response.json();
console.log("result: ", result);
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,32 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const trashSearchProject = async (
organization: string,
userId: string,
searchName: string
) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/searchTrashProjects?organization=${organization}&userId=${userId}&searchName=${searchName}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to add project");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,45 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const updateProject = async (
projectId: string,
userId: string,
organization: string,
thumbnail?: string,
projectName?: string
) => {
const body: any = {
projectId,
userId,
organization,
};
if (projectName) body.projectName = projectName;
if (thumbnail) body.thumbnail = thumbnail;
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/Project/modify`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
if (!response.ok) {
throw new Error("Failed to clearPanel in the zone");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,28 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const viewProject = async (
organization: string,
projectId: string,
userId: string
) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v1/Project/view?organization=${organization}&projectId=${projectId}&userId=${userId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch");
}
return await response.json();
} catch (error: any) {
console.error("Failed to get asset image:", error);
throw new Error(error.message);
}
};

View File

@ -20,6 +20,7 @@ export const signUpApi = async (
} }
const result = await response.json(); const result = await response.json();
console.log("result: ", result);
return result; return result;
} catch (error) { } catch (error) {
echo.error("Failed to sign-up"); echo.error("Failed to sign-up");

View File

@ -1,11 +1,11 @@
import * as THREE from "three"; import * as THREE from "three";
import { create } from "zustand"; import { create } from "zustand";
import { io } from "socket.io-client"; import { io } from "socket.io-client";
import * as CONSTANTS from '../../types/world/worldConstants'; import * as CONSTANTS from "../../types/world/worldConstants";
export const useSocketStore = create<any>((set: any, get: any) => ({ export const useSocketStore = create<any>((set: any, get: any) => ({
socket: null, socket: null,
initializeSocket: (email: string, organization: string) => { initializeSocket: (email: string, organization: string, userId?: string) => {
const existingSocket = get().socket; const existingSocket = get().socket;
if (existingSocket) { if (existingSocket) {
return; return;
@ -27,12 +27,21 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
} }
); );
set({ socket, visualizationSocket }); const dashBoardSocket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`,
{
reconnection: true,
auth: { email, organization, userId },
}
);
set({ socket, visualizationSocket, dashBoardSocket });
}, },
disconnectSocket: () => { disconnectSocket: () => {
set((state: any) => { set((state: any) => {
state.socket?.disconnect(); state.socket?.disconnect();
state.visualizationSocket?.disconnect(); state.visualizationSocket?.disconnect();
state.dashBoardSocket?.disconnect();
return { socket: null }; return { socket: null };
}); });
}, },
@ -90,7 +99,13 @@ export const useZonePoints = create<ZonePointsState>((set) => ({
})); }));
export const useSelectedItem = create<any>((set: any) => ({ export const useSelectedItem = create<any>((set: any) => ({
selectedItem: { name: "", id: "", type: undefined, category: '', subCatergory: '' }, selectedItem: {
name: "",
id: "",
type: undefined,
category: "",
subCatergory: "",
},
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
})); }));
@ -385,10 +400,38 @@ export const useLimitDistance = create<any>((set: any) => ({
limitDistance: true, limitDistance: true,
setLimitDistance: (x: any) => set({ limitDistance: x }), setLimitDistance: (x: any) => set({ limitDistance: x }),
})); }));
export const useProjectName = create<any>((set: any) => ({
projectName: "Creating Your Project",
setProjectName: (x: any) => set({ projectName: x }),
}));
// // export const useProjectCount = create<any>((set: any) => ({
// // projectCount: 1, // Initial state for projectCount
// // // Function to update projectCount
// // setProjectCount: (x: number) =>
// // set((state: any) => ({
// // projectCount: state.projectCount + x,
// // })),
// // }));
// export const useProjectCount = create<any>((set: any) => ({
// projectCount: Number(localStorage.getItem("projectCount")) || 1, // Load from localStorage or default to 1
// setProjectCount: (x: number) =>
// set((state: any) => {
// const newCount = state.projectCount + x;
// localStorage.setItem("projectCount", newCount.toString()); // Sync with localStorage
// return { projectCount: newCount };
// }),
// }));
export const useTileDistance = create<any>((set: any) => ({ export const useTileDistance = create<any>((set: any) => ({
gridValue: { size: CONSTANTS.gridConfig.size, divisions: CONSTANTS.gridConfig.divisions }, gridValue: {
planeValue: { height: CONSTANTS.planeConfig.height, width: CONSTANTS.planeConfig.width }, size: CONSTANTS.gridConfig.size,
divisions: CONSTANTS.gridConfig.divisions,
},
planeValue: {
height: CONSTANTS.planeConfig.height,
width: CONSTANTS.planeConfig.width,
},
setGridValue: (value: any) => setGridValue: (value: any) =>
set((state: any) => ({ set((state: any) => ({