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

(image error) Size: 237 KiB

Binary file not shown.

After

(image error) Size: 251 KiB

View File

@ -1,25 +1,78 @@
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">
<KebabIcon /> {userName ? userName.charAt(0).toUpperCase() : "Anonymous"}
</div>
<div
onClick={(e) => {
e.stopPropagation();
handleKebabIconClick();
}}
>
<KebabIcon />
</div>
</div> </div>
</div> </div>
</div> </div>
); );
}; };
export default DashboardCard; export default DashboardCard;

View File

@ -1,21 +1,137 @@
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>
); );
}; };
export default DashboardHome; export default DashboardHome;

View File

@ -4,18 +4,40 @@ 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>
); );
}; };
export default DashboardNavBar; export default DashboardNavBar;

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>
@ -52,7 +110,7 @@ const SidePannel: React.FC = () => {
<SettingsIcon /> <SettingsIcon />
Settings Settings
</div> </div>
<div className="option-list" style={{cursor: "pointer"}}> <div className="option-list" style={{ cursor: "pointer" }}>
<LogoutIcon /> <LogoutIcon />
Log out Log out
</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 emailParts = email.split("@");
if (emailParts.length < 2) {
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) {
} }
}, []);
const handleProjectRename = (newName: string) => {
setProjectName(newName);
localStorage.setItem("projectName", newName);
}; };
return ( return (

View File

@ -38,9 +38,8 @@ 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">
<SearchIcon /> <SearchIcon />

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,14 +1,36 @@
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>
); );
}; };
export default Dashboard; export default Dashboard;

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,454 +1,497 @@
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;
} }
const socket = io( const socket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
{ {
reconnection: true, reconnection: true,
auth: { email, organization }, auth: { email, organization },
} }
); );
const visualizationSocket = io( const visualizationSocket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
{ {
reconnection: true, reconnection: true,
auth: { email, organization }, auth: { email, organization },
} }
); );
set({ socket, visualizationSocket }); const dashBoardSocket = io(
}, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`,
disconnectSocket: () => { {
set((state: any) => { reconnection: true,
state.socket?.disconnect(); auth: { email, organization, userId },
state.visualizationSocket?.disconnect(); }
return { socket: null }; );
});
}, set({ socket, visualizationSocket, dashBoardSocket });
},
disconnectSocket: () => {
set((state: any) => {
state.socket?.disconnect();
state.visualizationSocket?.disconnect();
state.dashBoardSocket?.disconnect();
return { socket: null };
});
},
})); }));
export const useLoadingProgress = create<{ export const useLoadingProgress = create<{
loadingProgress: number; loadingProgress: number;
setLoadingProgress: (x: number) => void; setLoadingProgress: (x: number) => void;
}>((set) => ({ }>((set) => ({
loadingProgress: 1, loadingProgress: 1,
setLoadingProgress: (x: number) => set({ loadingProgress: x }), setLoadingProgress: (x: number) => set({ loadingProgress: x }),
})); }));
export const useOrganization = create<any>((set: any) => ({ export const useOrganization = create<any>((set: any) => ({
organization: "", organization: "",
setOrganization: (x: any) => set(() => ({ organization: x })), setOrganization: (x: any) => set(() => ({ organization: x })),
})); }));
export const useToggleView = create<any>((set: any) => ({ export const useToggleView = create<any>((set: any) => ({
toggleView: false, toggleView: false,
setToggleView: (x: any) => set(() => ({ toggleView: x })), setToggleView: (x: any) => set(() => ({ toggleView: x })),
})); }));
export const useUpdateScene = create<any>((set: any) => ({ export const useUpdateScene = create<any>((set: any) => ({
updateScene: false, updateScene: false,
setUpdateScene: (x: any) => set(() => ({ updateScene: x })), setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
})); }));
export const useWalls = create<any>((set: any) => ({ export const useWalls = create<any>((set: any) => ({
walls: [], walls: [],
setWalls: (x: any) => set(() => ({ walls: x })), setWalls: (x: any) => set(() => ({ walls: x })),
})); }));
export const useRoomsState = create<any>((set: any) => ({ export const useRoomsState = create<any>((set: any) => ({
roomsState: [], roomsState: [],
setRoomsState: (x: any) => set(() => ({ roomsState: x })), setRoomsState: (x: any) => set(() => ({ roomsState: x })),
})); }));
export const useZones = create<any>((set: any) => ({ export const useZones = create<any>((set: any) => ({
zones: [], zones: [],
setZones: (callback: any) => setZones: (callback: any) =>
set((state: any) => ({ set((state: any) => ({
zones: typeof callback === "function" ? callback(state.zones) : callback, zones: typeof callback === "function" ? callback(state.zones) : callback,
})), })),
})); }));
interface ZonePointsState { interface ZonePointsState {
zonePoints: THREE.Vector3[]; zonePoints: THREE.Vector3[];
setZonePoints: (points: THREE.Vector3[]) => void; setZonePoints: (points: THREE.Vector3[]) => void;
} }
export const useZonePoints = create<ZonePointsState>((set) => ({ export const useZonePoints = create<ZonePointsState>((set) => ({
zonePoints: [], zonePoints: [],
setZonePoints: (points) => set({ zonePoints: points }), setZonePoints: (points) => set({ zonePoints: points }),
})); }));
export const useSelectedItem = create<any>((set: any) => ({ export const useSelectedItem = create<any>((set: any) => ({
selectedItem: { name: "", id: "", type: undefined, category: '', subCatergory: '' }, selectedItem: {
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), name: "",
id: "",
type: undefined,
category: "",
subCatergory: "",
},
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
})); }));
export const useNavMesh = create<any>((set: any) => ({ export const useNavMesh = create<any>((set: any) => ({
navMesh: null, navMesh: null,
setNavMesh: (x: any) => set({ navMesh: x }), setNavMesh: (x: any) => set({ navMesh: x }),
})); }));
export const useSelectedAssets = create<any>((set: any) => ({ export const useSelectedAssets = create<any>((set: any) => ({
selectedAssets: [], selectedAssets: [],
setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
})); }));
export const useLayers = create<any>((set: any) => ({ export const useLayers = create<any>((set: any) => ({
Layers: 1, Layers: 1,
setLayers: (x: any) => set(() => ({ Layers: x })), setLayers: (x: any) => set(() => ({ Layers: x })),
})); }));
export const useCamPosition = create<any>((set: any) => ({ export const useCamPosition = create<any>((set: any) => ({
camPosition: { x: undefined, y: undefined, z: undefined }, camPosition: { x: undefined, y: undefined, z: undefined },
setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }),
})); }));
export const useMenuVisible = create<any>((set: any) => ({ export const useMenuVisible = create<any>((set: any) => ({
menuVisible: false, menuVisible: false,
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
})); }));
export const useDeleteTool = create<any>((set: any) => ({ export const useDeleteTool = create<any>((set: any) => ({
deleteTool: false, deleteTool: false,
setDeleteTool: (x: any) => set(() => ({ deleteTool: x })), setDeleteTool: (x: any) => set(() => ({ deleteTool: x })),
})); }));
export const useToolMode = create<any>((set: any) => ({ export const useToolMode = create<any>((set: any) => ({
toolMode: null, toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })), setToolMode: (x: any) => set(() => ({ toolMode: x })),
})); }));
export const useNewLines = create<any>((set: any) => ({ export const useNewLines = create<any>((set: any) => ({
newLines: [], newLines: [],
setNewLines: (x: any) => set(() => ({ newLines: x })), setNewLines: (x: any) => set(() => ({ newLines: x })),
})); }));
export const useDeletedLines = create<any>((set: any) => ({ export const useDeletedLines = create<any>((set: any) => ({
deletedLines: [], deletedLines: [],
setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
})); }));
export const useMovePoint = create<any>((set: any) => ({ export const useMovePoint = create<any>((set: any) => ({
movePoint: false, movePoint: false,
setMovePoint: (x: any) => set(() => ({ movePoint: x })), setMovePoint: (x: any) => set(() => ({ movePoint: x })),
})); }));
export const useDeletePointOrLine = create<any>((set: any) => ({ export const useDeletePointOrLine = create<any>((set: any) => ({
deletePointOrLine: false, deletePointOrLine: false,
setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
})); }));
export const useFloorItems = create<any>((set: any) => ({ export const useFloorItems = create<any>((set: any) => ({
floorItems: null, floorItems: null,
setFloorItems: (callback: any) => setFloorItems: (callback: any) =>
set((state: any) => ({ set((state: any) => ({
floorItems: floorItems:
typeof callback === "function" ? callback(state.floorItems) : callback, typeof callback === "function" ? callback(state.floorItems) : callback,
})), })),
})); }));
export const useWallItems = create<any>((set: any) => ({ export const useWallItems = create<any>((set: any) => ({
wallItems: [], wallItems: [],
setWallItems: (callback: any) => setWallItems: (callback: any) =>
set((state: any) => ({ set((state: any) => ({
wallItems: wallItems:
typeof callback === "function" ? callback(state.wallItems) : callback, typeof callback === "function" ? callback(state.wallItems) : callback,
})), })),
})); }));
export const useSelectedWallItem = create<any>((set: any) => ({ export const useSelectedWallItem = create<any>((set: any) => ({
selectedWallItem: null, selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
})); }));
export const useSelectedFloorItem = create<any>((set: any) => ({ export const useSelectedFloorItem = create<any>((set: any) => ({
selectedFloorItem: null, selectedFloorItem: null,
setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
})); }));
export const useDeletableFloorItem = create<any>((set: any) => ({ export const useDeletableFloorItem = create<any>((set: any) => ({
deletableFloorItem: null, deletableFloorItem: null,
setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
})); }));
export const useSetScale = create<any>((set: any) => ({ export const useSetScale = create<any>((set: any) => ({
scale: null, scale: null,
setScale: (x: any) => set(() => ({ scale: x })), setScale: (x: any) => set(() => ({ scale: x })),
})); }));
export const useRoofVisibility = create<any>((set: any) => ({ export const useRoofVisibility = create<any>((set: any) => ({
roofVisibility: false, roofVisibility: false,
setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
})); }));
export const useWallVisibility = create<any>((set: any) => ({ export const useWallVisibility = create<any>((set: any) => ({
wallVisibility: false, wallVisibility: false,
setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
})); }));
export const useShadows = create<any>((set: any) => ({ export const useShadows = create<any>((set: any) => ({
shadows: false, shadows: false,
setShadows: (x: any) => set(() => ({ shadows: x })), setShadows: (x: any) => set(() => ({ shadows: x })),
})); }));
export const useSunPosition = create<any>((set: any) => ({ export const useSunPosition = create<any>((set: any) => ({
sunPosition: { x: undefined, y: undefined, z: undefined }, sunPosition: { x: undefined, y: undefined, z: undefined },
setSunPosition: (newSuntPosition: any) => setSunPosition: (newSuntPosition: any) =>
set({ sunPosition: newSuntPosition }), set({ sunPosition: newSuntPosition }),
})); }));
export const useRemoveLayer = create<any>((set: any) => ({ export const useRemoveLayer = create<any>((set: any) => ({
removeLayer: false, removeLayer: false,
setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
})); }));
export const useRemovedLayer = create<any>((set: any) => ({ export const useRemovedLayer = create<any>((set: any) => ({
removedLayer: null, removedLayer: null,
setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
})); }));
export const useActiveLayer = create<any>((set: any) => ({ export const useActiveLayer = create<any>((set: any) => ({
activeLayer: 1, activeLayer: 1,
setActiveLayer: (x: any) => set({ activeLayer: x }), setActiveLayer: (x: any) => set({ activeLayer: x }),
})); }));
interface RefTextUpdateState { interface RefTextUpdateState {
refTextupdate: number; refTextupdate: number;
setRefTextUpdate: ( setRefTextUpdate: (
callback: (currentValue: number) => number | number callback: (currentValue: number) => number | number
) => void; ) => void;
} }
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({ export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
refTextupdate: -1000, refTextupdate: -1000,
setRefTextUpdate: (callback) => setRefTextUpdate: (callback) =>
set((state) => ({ set((state) => ({
refTextupdate: refTextupdate:
typeof callback === "function" typeof callback === "function"
? callback(state.refTextupdate) ? callback(state.refTextupdate)
: callback, : callback,
})), })),
})); }));
export const useResetCamera = create<any>((set: any) => ({ export const useResetCamera = create<any>((set: any) => ({
resetCamera: false, resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }), setResetCamera: (x: any) => set({ resetCamera: x }),
})); }));
export const useAddAction = create<any>((set: any) => ({ export const useAddAction = create<any>((set: any) => ({
addAction: null, addAction: null,
setAddAction: (x: any) => set({ addAction: x }), setAddAction: (x: any) => set({ addAction: x }),
})); }));
export const useActiveTool = create<any>((set: any) => ({ export const useActiveTool = create<any>((set: any) => ({
activeTool: "cursor", activeTool: "cursor",
setActiveTool: (x: any) => set({ activeTool: x }), setActiveTool: (x: any) => set({ activeTool: x }),
})); }));
export const useActiveSubTool = create<any>((set: any) => ({ export const useActiveSubTool = create<any>((set: any) => ({
activeSubTool: "cursor", activeSubTool: "cursor",
setActiveSubTool: (x: any) => set({ activeSubTool: x }), setActiveSubTool: (x: any) => set({ activeSubTool: x }),
})); }));
export const use2DUndoRedo = create<any>((set: any) => ({ export const use2DUndoRedo = create<any>((set: any) => ({
is2DUndoRedo: null, is2DUndoRedo: null,
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
})); }));
export const useElevation = create<any>((set: any) => ({ export const useElevation = create<any>((set: any) => ({
elevation: 45, elevation: 45,
setElevation: (x: any) => set({ elevation: x }), setElevation: (x: any) => set({ elevation: x }),
})); }));
export const useAzimuth = create<any>((set: any) => ({ export const useAzimuth = create<any>((set: any) => ({
azimuth: -160, azimuth: -160,
setAzimuth: (x: any) => set({ azimuth: x }), setAzimuth: (x: any) => set({ azimuth: x }),
})); }));
export const useRenderDistance = create<any>((set: any) => ({ export const useRenderDistance = create<any>((set: any) => ({
renderDistance: 40, renderDistance: 40,
setRenderDistance: (x: any) => set({ renderDistance: x }), setRenderDistance: (x: any) => set({ renderDistance: x }),
})); }));
export const useCamMode = create<any>((set: any) => ({ export const useCamMode = create<any>((set: any) => ({
camMode: "ThirdPerson", camMode: "ThirdPerson",
setCamMode: (x: any) => set({ camMode: x }), setCamMode: (x: any) => set({ camMode: x }),
})); }));
export const useUserName = create<any>((set: any) => ({ export const useUserName = create<any>((set: any) => ({
userName: "", userName: "",
setUserName: (x: any) => set({ userName: x }), setUserName: (x: any) => set({ userName: x }),
})); }));
export const useObjectPosition = create<any>((set: any) => ({ export const useObjectPosition = create<any>((set: any) => ({
objectPosition: { x: undefined, y: undefined, z: undefined }, objectPosition: { x: undefined, y: undefined, z: undefined },
setObjectPosition: (newObjectPosition: any) => setObjectPosition: (newObjectPosition: any) =>
set({ objectPosition: newObjectPosition }), set({ objectPosition: newObjectPosition }),
})); }));
export const useObjectRotation = create<any>((set: any) => ({ export const useObjectRotation = create<any>((set: any) => ({
objectRotation: { x: undefined, y: undefined, z: undefined }, objectRotation: { x: undefined, y: undefined, z: undefined },
setObjectRotation: (newObjectRotation: any) => setObjectRotation: (newObjectRotation: any) =>
set({ objectRotation: newObjectRotation }), set({ objectRotation: newObjectRotation }),
})); }));
export const useDrieTemp = create<any>((set: any) => ({ export const useDrieTemp = create<any>((set: any) => ({
drieTemp: undefined, drieTemp: undefined,
setDrieTemp: (x: any) => set({ drieTemp: x }), setDrieTemp: (x: any) => set({ drieTemp: x }),
})); }));
export const useActiveUsers = create<any>((set: any) => ({ export const useActiveUsers = create<any>((set: any) => ({
activeUsers: [], activeUsers: [],
setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
set((state: { activeUsers: any[] }) => ({ set((state: { activeUsers: any[] }) => ({
activeUsers: activeUsers:
typeof callback === "function" ? callback(state.activeUsers) : callback, typeof callback === "function" ? callback(state.activeUsers) : callback,
})), })),
})); }));
export const useDrieUIValue = create<any>((set: any) => ({ export const useDrieUIValue = create<any>((set: any) => ({
drieUIValue: { touch: null, temperature: null, humidity: null }, drieUIValue: { touch: null, temperature: null, humidity: null },
setDrieUIValue: (x: any) => setDrieUIValue: (x: any) =>
set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
setTouch: (value: any) => setTouch: (value: any) =>
set((state: any) => ({ set((state: any) => ({
drieUIValue: { ...state.drieUIValue, touch: value }, drieUIValue: { ...state.drieUIValue, touch: value },
})), })),
setTemperature: (value: any) => setTemperature: (value: any) =>
set((state: any) => ({ set((state: any) => ({
drieUIValue: { ...state.drieUIValue, temperature: value }, drieUIValue: { ...state.drieUIValue, temperature: value },
})), })),
setHumidity: (value: any) => setHumidity: (value: any) =>
set((state: any) => ({ set((state: any) => ({
drieUIValue: { ...state.drieUIValue, humidity: value }, drieUIValue: { ...state.drieUIValue, humidity: value },
})), })),
})); }));
export const useStartSimulation = create<any>((set: any) => ({ export const useStartSimulation = create<any>((set: any) => ({
startSimulation: false, startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }), setStartSimulation: (x: any) => set({ startSimulation: x }),
})); }));
export const useEyeDropMode = create<any>((set: any) => ({ export const useEyeDropMode = create<any>((set: any) => ({
eyeDropMode: false, eyeDropMode: false,
setEyeDropMode: (x: any) => set({ eyeDropMode: x }), setEyeDropMode: (x: any) => set({ eyeDropMode: x }),
})); }));
export const useEditingPoint = create<any>((set: any) => ({ export const useEditingPoint = create<any>((set: any) => ({
editingPoint: false, editingPoint: false,
setEditingPoint: (x: any) => set({ editingPoint: x }), setEditingPoint: (x: any) => set({ editingPoint: x }),
})); }));
export const usezoneTarget = create<any>((set: any) => ({ export const usezoneTarget = create<any>((set: any) => ({
zoneTarget: [], zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }), setZoneTarget: (x: any) => set({ zoneTarget: x }),
})); }));
export const usezonePosition = create<any>((set: any) => ({ export const usezonePosition = create<any>((set: any) => ({
zonePosition: [], zonePosition: [],
setZonePosition: (x: any) => set({ zonePosition: x }), setZonePosition: (x: any) => set({ zonePosition: x }),
})); }));
interface EditPositionState { interface EditPositionState {
Edit: boolean; Edit: boolean;
setEdit: (value: boolean) => void; setEdit: (value: boolean) => void;
} }
export const useEditPosition = create<EditPositionState>((set) => ({ export const useEditPosition = create<EditPositionState>((set) => ({
Edit: false, Edit: false,
setEdit: (value) => set({ Edit: value }), setEdit: (value) => set({ Edit: value }),
})); }));
export const useAsset3dWidget = create<any>((set: any) => ({ export const useAsset3dWidget = create<any>((set: any) => ({
widgetSelect: "", widgetSelect: "",
setWidgetSelect: (x: any) => set({ widgetSelect: x }), setWidgetSelect: (x: any) => set({ widgetSelect: x }),
})); }));
export const useWidgetSubOption = create<any>((set: any) => ({ export const useWidgetSubOption = create<any>((set: any) => ({
widgetSubOption: "2D", widgetSubOption: "2D",
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
})); }));
export const useLimitDistance = create<any>((set: any) => ({ 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) => ({
gridValue: { ...state.gridValue, ...value }, gridValue: { ...state.gridValue, ...value },
})), })),
setPlaneValue: (value: any) => setPlaneValue: (value: any) =>
set((state: any) => ({ set((state: any) => ({
planeValue: { ...state.planeValue, ...value }, planeValue: { ...state.planeValue, ...value },
})), })),
})); }));
export const usePlayAgv = create<any>((set, get) => ({ export const usePlayAgv = create<any>((set, get) => ({
PlayAgv: [], PlayAgv: [],
setPlayAgv: (updateFn: (prev: any[]) => any[]) => setPlayAgv: (updateFn: (prev: any[]) => any[]) =>
set({ PlayAgv: updateFn(get().PlayAgv) }), set({ PlayAgv: updateFn(get().PlayAgv) }),
})); }));
// Define the Asset type // Define the Asset type
type Asset = { type Asset = {
id: string; id: string;
name: string; name: string;
position?: [number, number, number]; // Optional: 3D position position?: [number, number, number]; // Optional: 3D position
rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation
}; };
// Zustand store type // Zustand store type
type ZoneAssetState = { type ZoneAssetState = {
zoneAssetId: Asset | null; zoneAssetId: Asset | null;
setZoneAssetId: (asset: Asset | null) => void; setZoneAssetId: (asset: Asset | null) => void;
}; };
// Zustand store // Zustand store
export const useZoneAssetId = create<ZoneAssetState>((set) => ({ export const useZoneAssetId = create<ZoneAssetState>((set) => ({
zoneAssetId: null, zoneAssetId: null,
setZoneAssetId: (asset) => set({ zoneAssetId: asset }), setZoneAssetId: (asset) => set({ zoneAssetId: asset }),
})); }));
// version visible hidden // version visible hidden
interface VersionHistoryState { interface VersionHistoryState {
viewVersionHistory: boolean; viewVersionHistory: boolean;
setVersionHistory: (value: boolean) => void; setVersionHistory: (value: boolean) => void;
} }
const useVersionHistoryStore = create<VersionHistoryState>((set) => ({ const useVersionHistoryStore = create<VersionHistoryState>((set) => ({
viewVersionHistory: false, viewVersionHistory: false,
setVersionHistory: (value) => set({ viewVersionHistory: value }), setVersionHistory: (value) => set({ viewVersionHistory: value }),
})); }));
export default useVersionHistoryStore; export default useVersionHistoryStore;
interface ShortcutStore { interface ShortcutStore {
showShortcuts: boolean; showShortcuts: boolean;
setShowShortcuts: (value: boolean) => void; setShowShortcuts: (value: boolean) => void;
toggleShortcuts: () => void; toggleShortcuts: () => void;
} }
export const useShortcutStore = create<ShortcutStore>((set) => ({ export const useShortcutStore = create<ShortcutStore>((set) => ({
showShortcuts: false, showShortcuts: false,
setShowShortcuts: (value) => set({ showShortcuts: value }), setShowShortcuts: (value) => set({ showShortcuts: value }),
toggleShortcuts: () => toggleShortcuts: () =>
set((state) => ({ showShortcuts: !state.showShortcuts })), set((state) => ({ showShortcuts: !state.showShortcuts })),
})); }));