1. Integerated DashBoard, #97
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import React, { useState, useRef } from "react";
|
||||
import { KebabIcon } from "../../icons/ExportCommonIcons";
|
||||
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";
|
||||
import OuterClick from "../../../utils/outerClick";
|
||||
|
||||
interface DashBoardCardProps {
|
||||
projectName: string;
|
||||
|
@ -21,57 +22,112 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
|||
projectId,
|
||||
handleRestoreProject,
|
||||
}) => {
|
||||
let navigate = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
const { setProjectName } = useProjectName();
|
||||
const { userId, organization, userName } = getUserData();
|
||||
const [isKebabOpen, setIsKebabOpen] = useState(false);
|
||||
|
||||
const handleKebabIconClick = async () => {
|
||||
try {
|
||||
if (handleRestoreProject) {
|
||||
await handleRestoreProject(projectId);
|
||||
} else if (handleDeleteProject) {
|
||||
await handleDeleteProject(projectId);
|
||||
}
|
||||
} catch { }
|
||||
};
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const navigateToProject = async () => {
|
||||
try {
|
||||
const viewedProject = await viewProject(organization, projectId, userId);
|
||||
console.log("Saved viewwdProject:", viewedProject);
|
||||
console.log("Viewed project:", viewedProject);
|
||||
} catch (error) {
|
||||
console.error("Error deleting project:", error);
|
||||
console.error("Error opening project:", error);
|
||||
}
|
||||
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
};
|
||||
|
||||
const handleOptionClick = async (option: string) => {
|
||||
switch (option) {
|
||||
case "delete":
|
||||
if (handleDeleteProject) {
|
||||
await handleDeleteProject(projectId);
|
||||
}
|
||||
break;
|
||||
case "restore":
|
||||
if (handleRestoreProject) {
|
||||
await handleRestoreProject(projectId);
|
||||
}
|
||||
break;
|
||||
case "openInNewTab":
|
||||
window.open(`/${projectId}`, "_blank");
|
||||
break;
|
||||
case "rename":
|
||||
// Add rename logic here
|
||||
break;
|
||||
case "duplicate":
|
||||
// Add duplication logic here
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setIsKebabOpen(false);
|
||||
};
|
||||
|
||||
OuterClick({
|
||||
contextClassName: ["kebab-wrapper", "kebab-options-wrapper"],
|
||||
setMenuVisible: () => setIsKebabOpen(false),
|
||||
});
|
||||
return (
|
||||
<div className="dashboard-card-container" onClick={navigateToProject} title={projectName}>
|
||||
<div className="preview-container">
|
||||
{thumbnail ? <img src={thumbnail} alt="" /> : <img src={img} alt="" />}
|
||||
</div>
|
||||
<div className="project-details-container">
|
||||
<div className="project-details">
|
||||
<div className="project-name">{projectName}</div>
|
||||
<div className="project-data">24-12-2025</div>
|
||||
<button
|
||||
className="dashboard-card-container"
|
||||
onClick={navigateToProject}
|
||||
title={projectName}
|
||||
>
|
||||
<div className="dashboard-card-wrapper">
|
||||
<div className="preview-container">
|
||||
{thumbnail ? (
|
||||
<img src={thumbnail} alt="" />
|
||||
) : (
|
||||
<img src={img} alt="" />
|
||||
)}
|
||||
</div>
|
||||
<div className="users-list-container">
|
||||
<div className="user-profile">
|
||||
{userName ? userName.charAt(0).toUpperCase() : "Anonymous"}
|
||||
<div className="project-details-container">
|
||||
<div className="project-details">
|
||||
<div className="project-name">{projectName}</div>
|
||||
<div className="project-data">24-12-2025</div>
|
||||
</div>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleKebabIconClick();
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
<div className="users-list-container" ref={kebabRef}>
|
||||
<div className="user-profile">
|
||||
{userName ? userName.charAt(0).toUpperCase() : "A"}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="kebab-wrapper"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation(); // Prevents click from bubbling up
|
||||
console.log("Kebab menu clicked");
|
||||
setIsKebabOpen((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isKebabOpen && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{["rename", "delete", "duplicate", "open in new tab"].map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
console.log(option);
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,11 @@ const DashboardHome: React.FC = () => {
|
|||
setIsSearchActive(false);
|
||||
return;
|
||||
}
|
||||
const filterRecentProcess = await searchProject(organization, userId, inputValue);
|
||||
const filterRecentProcess = await searchProject(
|
||||
organization,
|
||||
userId,
|
||||
inputValue
|
||||
);
|
||||
setIsSearchActive(true);
|
||||
setRecentProjects(filterRecentProcess.message ? {} : filterRecentProcess);
|
||||
};
|
||||
|
@ -127,7 +131,7 @@ const DashboardHome: React.FC = () => {
|
|||
<MarketPlaceBanner />
|
||||
|
||||
<div className="container">
|
||||
<h2 className="section-header">Recent Projects</h2>
|
||||
<h2 className="section-header">Recents</h2>
|
||||
<div className="cards-container">{renderProjects()}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -135,3 +139,5 @@ const DashboardHome: React.FC = () => {
|
|||
};
|
||||
|
||||
export default DashboardHome;
|
||||
|
||||
|
||||
|
|
|
@ -1,155 +1,154 @@
|
|||
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';
|
||||
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;
|
||||
_id: string;
|
||||
projectName: string;
|
||||
thumbnail: string;
|
||||
createdBy: string;
|
||||
projectUuid?: string;
|
||||
}
|
||||
|
||||
interface WorkspaceProjects {
|
||||
[key: string]: Project[];
|
||||
[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 [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);
|
||||
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;
|
||||
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>
|
||||
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" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header-wrapper" style={{ display: "flex", gap: "7px" }}>
|
||||
<button
|
||||
className={`header ${activeFolder === "myProjects" && "active"}`}
|
||||
onClick={() => setActiveFolder("myProjects")}
|
||||
>
|
||||
My Projects
|
||||
</button>
|
||||
<button
|
||||
className={`header ${activeFolder === "shared" && "active"}`}
|
||||
onClick={() => setActiveFolder("shared")}
|
||||
>
|
||||
Shared with me
|
||||
</button>
|
||||
</div>
|
||||
<div className="cards-container">{renderProjects()}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardProjects;
|
|
@ -1,122 +1,120 @@
|
|||
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';
|
||||
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;
|
||||
_id: string;
|
||||
projectName: string;
|
||||
thumbnail: string;
|
||||
createdBy: string;
|
||||
projectUuid?: string;
|
||||
}
|
||||
|
||||
interface DiscardedProjects {
|
||||
[key: string]: Project[];
|
||||
[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 [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);
|
||||
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;
|
||||
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>
|
||||
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" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header" style={{ display: "flex", gap: "7px" }}></div>
|
||||
<div className="cards-container">{renderTrashProjects()}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardTrash;
|
|
@ -49,7 +49,7 @@ const DashboardTutorial = () => {
|
|||
page="tutorial"
|
||||
/>
|
||||
|
||||
<div className="container">
|
||||
<div className="container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header" style={{ display: 'flex', gap: '7px' }}></div>
|
||||
<div className="cards-container">
|
||||
{renderTrashProjects()}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import SidePannel from '../components/layout/Dashboard/SidePannel';
|
||||
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';
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import SidePannel from "../components/layout/Dashboard/SidePannel";
|
||||
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,
|
||||
} from "../store/builder/store";
|
||||
import { getUserData } from "../components/layout/Dashboard/functions/getUserData";
|
||||
import DashboardTutorial from "../components/layout/Dashboard/DashboardTutorial";
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState<string>('Home');
|
||||
const [activeTab, setActiveTab] = useState<string>("Home");
|
||||
const { setUserName } = useUserName();
|
||||
const { setOrganization } = useOrganization();
|
||||
const { userId, organization, email, userName } = getUserData();
|
||||
|
@ -21,14 +24,14 @@ const Dashboard: React.FC = () => {
|
|||
setUserName(userName);
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
}, []);
|
||||
return (
|
||||
<div className="dashboard-main">
|
||||
<SidePannel setActiveTab={setActiveTab} activeTab={activeTab} />
|
||||
{activeTab == 'Home' && <DashboardHome />}
|
||||
{activeTab == 'Projects' && <DashboardProjects />}
|
||||
{activeTab == 'Trash' && <DashboardTrash />}
|
||||
{activeTab == 'Tutorials' && <DashboardTutorial />}
|
||||
{activeTab == "Home" && <DashboardHome />}
|
||||
{activeTab == "Projects" && <DashboardProjects />}
|
||||
{activeTab == "Trash" && <DashboardTrash />}
|
||||
{activeTab == "Tutorials" && <DashboardTutorial />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,19 +5,28 @@
|
|||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
padding: 27px 17px;
|
||||
|
||||
.side-pannel-container {
|
||||
padding: 32px;
|
||||
min-width: 240px;
|
||||
height: 100vh;
|
||||
min-width: 280px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
border-right: 1px solid var(--border-color);
|
||||
// border-right: 1px solid var(--border-color);
|
||||
background: var(--background-color);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 30px;
|
||||
box-shadow: var(--box-shadow-medium);
|
||||
|
||||
.side-pannel-header {
|
||||
@include flex-space-between;
|
||||
|
||||
.user-container {
|
||||
@include flex-center;
|
||||
gap: 6px;
|
||||
|
||||
.user-profile {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
|
@ -28,10 +37,12 @@
|
|||
color: var(--primary-color);
|
||||
border-radius: #{$border-radius-circle};
|
||||
}
|
||||
|
||||
.user-name {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
.notifications-container {
|
||||
@include flex-center;
|
||||
height: 24px;
|
||||
|
@ -39,82 +50,117 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.new-project-button {
|
||||
padding: 12px 16px;
|
||||
cursor: not-allowed;
|
||||
color: var(--accent-color);
|
||||
color: var(--text-color);
|
||||
background: var(--background-color-secondary);
|
||||
border-radius: #{$border-radius-large};
|
||||
border-radius: #{$border-radius-xxx};
|
||||
}
|
||||
|
||||
.side-bar-content-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
|
||||
.side-bar-options-container {
|
||||
.option-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
padding: 8px 10px;
|
||||
margin: 4px 0;
|
||||
border-radius: #{$border-radius-medium};
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--background-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
color: var(--accent-color);
|
||||
color: var(--text-button-color);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: var(--highlight-accent-color);
|
||||
background: var(--background-color-button);
|
||||
|
||||
&:hover {
|
||||
background: var(--highlight-accent-color);
|
||||
background: var(--background-color-button);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-home-container {
|
||||
width: 100%;
|
||||
padding-left: 18px;
|
||||
|
||||
.dashboard-navbar-container {
|
||||
margin-top: 28px;
|
||||
padding: 8px 34px 8px 12px;
|
||||
margin-bottom: 22px;
|
||||
@include flex-center;
|
||||
|
||||
.title {
|
||||
text-transform: capitalize;
|
||||
font-size: var(--font-size-large);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.market-place-button {
|
||||
@include flex-center;
|
||||
gap: 6px;
|
||||
padding: 8px 14px;
|
||||
background: var(--accent-gradient-color);
|
||||
background: var(--background-color-button);
|
||||
white-space: nowrap;
|
||||
border-radius: #{$border-radius-large};
|
||||
color: var(--primary-color);
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
|
||||
color: var(--text-button-color);
|
||||
}
|
||||
|
||||
.search-wrapper {
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 22px 0;
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
.header {
|
||||
height: calc(100% - 357px);
|
||||
|
||||
|
||||
.header-wrapper {
|
||||
font-size: var(--font-size-large);
|
||||
|
||||
.header {
|
||||
color: var(--input-text-color);
|
||||
padding: 6px 8px;
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
|
||||
&.active {
|
||||
|
||||
background: var(--background-color-button);
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cards-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
padding-top: 18px;
|
||||
gap: 18px;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.dashboard-card-container {
|
||||
|
@ -123,11 +169,23 @@
|
|||
min-width: 260px;
|
||||
position: relative;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: #{$border-radius-large};
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
|
||||
.dashboard-card-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
@ -135,27 +193,38 @@
|
|||
vertical-align: top;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
}
|
||||
}
|
||||
|
||||
.project-details-container {
|
||||
@include flex-space-between;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 8px 16px;
|
||||
background: var(--primary-color);
|
||||
border-radius: #{$border-radius-large};
|
||||
padding: 13px 16px;
|
||||
background: var(--background-color);
|
||||
// backdrop-filter: blur(18px);
|
||||
|
||||
border-radius: #{$border-radius-xlarge};
|
||||
transform: translateY(100%);
|
||||
transition: transform 0.25s linear;
|
||||
|
||||
.project-details {
|
||||
.project-name {
|
||||
margin-bottom: 2px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.project-data {
|
||||
color: var(--accent-color);
|
||||
color: var(--input-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.users-list-container {
|
||||
@include flex-center;
|
||||
gap: 6px;
|
||||
position: relative; // Needed for absolute positioning of kebab-options-wrapper
|
||||
|
||||
.user-profile {
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
|
@ -165,8 +234,65 @@
|
|||
color: var(--primary-color);
|
||||
border-radius: #{$border-radius-circle};
|
||||
}
|
||||
|
||||
.kebab {
|
||||
padding: 10px;
|
||||
@include flex-center;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.kebab-options-wrapper {
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
right: 40px;
|
||||
background: var(--background-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
z-index: 100;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: translate(100%, 100%);
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
|
||||
.option {
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
text-transform: capitalize;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--background-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
|
||||
|
||||
overflow: visible;
|
||||
|
||||
.kebab-options-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.project-details-container {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.market-place-banner-container {
|
||||
|
@ -174,13 +300,14 @@
|
|||
height: 230px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 0 24px;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: #{$border-radius-xxx};
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
position: absolute;
|
||||
left: 52px;
|
||||
|
@ -191,6 +318,7 @@
|
|||
color: #ffffff;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.context {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
|
@ -201,11 +329,13 @@
|
|||
color: #ffffff;
|
||||
font-family: #{$font-roboto};
|
||||
}
|
||||
|
||||
.arrow-context {
|
||||
position: absolute;
|
||||
bottom: 27px;
|
||||
right: 300px;
|
||||
}
|
||||
|
||||
.explore-button {
|
||||
position: absolute;
|
||||
top: 95px;
|
||||
|
|
Loading…
Reference in New Issue