updated dashboard duplication
This commit is contained in:
@@ -2,289 +2,314 @@ import React, { useState, useRef, useEffect, act } from "react";
|
||||
import img from "../../assets/image/image.png";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useLoadingProgress, useProjectName, useSocketStore } from "../../store/builder/store";
|
||||
import {
|
||||
useLoadingProgress,
|
||||
useProjectName,
|
||||
useSocketStore,
|
||||
} from "../../store/builder/store";
|
||||
import { viewProject } from "../../services/dashboard/viewProject";
|
||||
import OuterClick from "../../utils/outerClick";
|
||||
import { KebabIcon } from "../icons/ExportCommonIcons";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { updateProject } from "../../services/dashboard/updateProject";
|
||||
|
||||
interface DashBoardCardProps {
|
||||
projectName: string;
|
||||
thumbnail: any;
|
||||
projectId: string;
|
||||
createdAt?: string;
|
||||
isViewed?: string;
|
||||
createdBy?: { _id: string, userName: string };
|
||||
handleDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleTrashDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleRestoreProject?: (projectId: string) => Promise<void>;
|
||||
handleDuplicateWorkspaceProject?: (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string,
|
||||
userId?: string
|
||||
) => Promise<void>;
|
||||
handleDuplicateRecentProject?: (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string
|
||||
) => Promise<void>;
|
||||
active?: string;
|
||||
setIsSearchActive?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setRecentDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setProjectDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setActiveFolder?: React.Dispatch<React.SetStateAction<string>>;
|
||||
projectName: string;
|
||||
thumbnail: any;
|
||||
projectId: string;
|
||||
createdAt?: string;
|
||||
isViewed?: string;
|
||||
createdBy?: { _id: string; userName: string };
|
||||
handleDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleTrashDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleRestoreProject?: (projectId: string) => Promise<void>;
|
||||
handleDuplicateWorkspaceProject?: (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string,
|
||||
userId?: string
|
||||
) => Promise<void>;
|
||||
handleDuplicateRecentProject?: (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string
|
||||
) => Promise<void>;
|
||||
active?: string;
|
||||
setIsSearchActive?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setRecentDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setProjectDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setActiveFolder?: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
type RelativeTimeFormatUnit = any;
|
||||
|
||||
const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
projectName,
|
||||
thumbnail,
|
||||
projectId,
|
||||
active,
|
||||
handleDeleteProject,
|
||||
handleRestoreProject,
|
||||
handleTrashDeleteProject,
|
||||
handleDuplicateWorkspaceProject,
|
||||
handleDuplicateRecentProject,
|
||||
createdAt,
|
||||
createdBy,
|
||||
setRecentDuplicateData,
|
||||
setProjectDuplicateData,
|
||||
setActiveFolder
|
||||
projectName,
|
||||
thumbnail,
|
||||
projectId,
|
||||
active,
|
||||
handleDeleteProject,
|
||||
handleRestoreProject,
|
||||
handleTrashDeleteProject,
|
||||
handleDuplicateWorkspaceProject,
|
||||
handleDuplicateRecentProject,
|
||||
createdAt,
|
||||
createdBy,
|
||||
setRecentDuplicateData,
|
||||
setProjectDuplicateData,
|
||||
setActiveFolder,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { setProjectName } = useProjectName();
|
||||
const { userId, organization, userName } = getUserData();
|
||||
const [isKebabOpen, setIsKebabOpen] = useState(false);
|
||||
const [renameValue, setRenameValue] = useState(projectName);
|
||||
const [isRenaming, setIsRenaming] = useState(false);
|
||||
const { projectSocket } = useSocketStore();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
const navigate = useNavigate();
|
||||
const { setProjectName } = useProjectName();
|
||||
const { userId, organization, userName } = getUserData();
|
||||
const [isKebabOpen, setIsKebabOpen] = useState(false);
|
||||
const [renameValue, setRenameValue] = useState(projectName);
|
||||
const [isRenaming, setIsRenaming] = useState(false);
|
||||
const { projectSocket } = useSocketStore();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const navigateToProject = async (e: any) => {
|
||||
console.log('active: ', active);
|
||||
if (active && active == "trash") return;
|
||||
try {
|
||||
const viewProjects = await viewProject(organization, projectId, userId)
|
||||
console.log('viewProjects: ', viewProjects);
|
||||
console.log('projectName: ', projectName);
|
||||
setLoadingProgress(1)
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
} catch {
|
||||
const navigateToProject = async (e: any) => {
|
||||
if (active && active == "trash") return;
|
||||
try {
|
||||
const viewProjects = await viewProject(organization, projectId, userId);
|
||||
|
||||
setLoadingProgress(1);
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
} catch {}
|
||||
};
|
||||
|
||||
const handleOptionClick = async (option: string) => {
|
||||
switch (option) {
|
||||
case "delete":
|
||||
if (handleDeleteProject) {
|
||||
handleDeleteProject(projectId);
|
||||
} else if (handleTrashDeleteProject) {
|
||||
handleTrashDeleteProject(projectId);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOptionClick = async (option: string) => {
|
||||
switch (option) {
|
||||
case "delete":
|
||||
if (handleDeleteProject) {
|
||||
handleDeleteProject(projectId);
|
||||
} else if (handleTrashDeleteProject) {
|
||||
handleTrashDeleteProject(projectId);
|
||||
}
|
||||
break;
|
||||
case "restore":
|
||||
if (handleRestoreProject) {
|
||||
await handleRestoreProject(projectId);
|
||||
}
|
||||
break;
|
||||
case "open in new tab":
|
||||
try {
|
||||
if (active === "shared" && createdBy) {
|
||||
console.log("ihreq");
|
||||
const newTab = await viewProject(organization, projectId, createdBy?._id);
|
||||
console.log('newTab: ', newTab);
|
||||
} else {
|
||||
const newTab = await viewProject(organization, projectId, userId);
|
||||
console.log('newTab: ', newTab);
|
||||
setProjectName(projectName);
|
||||
setIsKebabOpen(false);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
window.open(`/${projectId}`, "_blank");
|
||||
break;
|
||||
case "rename":
|
||||
setIsRenaming(true);
|
||||
break;
|
||||
case "duplicate":
|
||||
if (handleDuplicateWorkspaceProject) {
|
||||
setProjectDuplicateData &&
|
||||
setProjectDuplicateData({
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
});
|
||||
await handleDuplicateWorkspaceProject(projectId, projectName, thumbnail, userId);
|
||||
if (active === "shared" && setActiveFolder) {
|
||||
setActiveFolder("myProjects")
|
||||
}
|
||||
} else if (handleDuplicateRecentProject) {
|
||||
setRecentDuplicateData &&
|
||||
setRecentDuplicateData({
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
userId
|
||||
});
|
||||
await handleDuplicateRecentProject(projectId, projectName, thumbnail);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case "restore":
|
||||
if (handleRestoreProject) {
|
||||
await handleRestoreProject(projectId);
|
||||
}
|
||||
setIsKebabOpen(false);
|
||||
};
|
||||
|
||||
OuterClick({
|
||||
contextClassName: ["kebab-wrapper", "kebab-options-wrapper"],
|
||||
setMenuVisible: () => setIsKebabOpen(false),
|
||||
});
|
||||
|
||||
const handleProjectName = async (projectName: string) => {
|
||||
setRenameValue(projectName);
|
||||
if (!projectId) return;
|
||||
break;
|
||||
case "open in new tab":
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
if (!projects || !projects.Projects) return;
|
||||
let projectUuid = projects.Projects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
if (active === "shared" && createdBy) {
|
||||
const newTab = await viewProject(
|
||||
organization,
|
||||
projectId,
|
||||
createdBy?._id
|
||||
);
|
||||
const updateProjects = {
|
||||
projectId: projectUuid,
|
||||
organization,
|
||||
userId,
|
||||
projectName,
|
||||
thumbnail: undefined,
|
||||
};
|
||||
} else {
|
||||
const newTab = await viewProject(organization, projectId, userId);
|
||||
|
||||
if (projectSocket) {
|
||||
projectSocket.emit("v1:project:update", updateProjects);
|
||||
}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
function getRelativeTime(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
const intervals: Record<RelativeTimeFormatUnit, number> = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1,
|
||||
};
|
||||
|
||||
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
|
||||
for (const key in intervals) {
|
||||
const unit = key as RelativeTimeFormatUnit;
|
||||
const diff = Math.floor(diffInSeconds / intervals[unit]);
|
||||
if (diff >= 1) {
|
||||
return rtf.format(-diff, unit);
|
||||
}
|
||||
setProjectName(projectName);
|
||||
setIsKebabOpen(false);
|
||||
}
|
||||
} catch (error) {}
|
||||
window.open(`/${projectId}`, "_blank");
|
||||
break;
|
||||
case "rename":
|
||||
setIsRenaming(true);
|
||||
break;
|
||||
case "duplicate":
|
||||
if (handleDuplicateWorkspaceProject) {
|
||||
setProjectDuplicateData &&
|
||||
setProjectDuplicateData({
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
});
|
||||
await handleDuplicateWorkspaceProject(
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
userId
|
||||
);
|
||||
if (active === "shared" && setActiveFolder) {
|
||||
setActiveFolder("myProjects");
|
||||
}
|
||||
} else if (handleDuplicateRecentProject) {
|
||||
setRecentDuplicateData &&
|
||||
setRecentDuplicateData({
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
userId,
|
||||
});
|
||||
await handleDuplicateRecentProject(projectId, projectName, thumbnail);
|
||||
}
|
||||
return "just now";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setIsKebabOpen(false);
|
||||
};
|
||||
|
||||
const kebabOptionsMap: Record<string, string[]> = {
|
||||
default: ["rename", "delete", "duplicate", "open in new tab"],
|
||||
trash: ["restore", "delete"],
|
||||
shared: ["duplicate", "open in new tab"],
|
||||
OuterClick({
|
||||
contextClassName: ["kebab-wrapper", "kebab-options-wrapper"],
|
||||
setMenuVisible: () => setIsKebabOpen(false),
|
||||
});
|
||||
|
||||
const handleProjectName = async (projectName: string) => {
|
||||
setRenameValue(projectName);
|
||||
if (!projectId) return;
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
if (!projects || !projects.Projects) return;
|
||||
let projectUuid = projects.Projects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
);
|
||||
const updateProjects = {
|
||||
projectId: projectUuid?._id,
|
||||
organization,
|
||||
userId,
|
||||
projectName,
|
||||
thumbnail: undefined,
|
||||
};
|
||||
// const updatedProjectName = await updateProject(
|
||||
// projectUuid._id,
|
||||
// userId,
|
||||
// organization,
|
||||
// undefined,
|
||||
// projectName
|
||||
// );
|
||||
if (projectSocket) {
|
||||
projectSocket.emit("v1:project:update", updateProjects);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
function getRelativeTime(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
const intervals: Record<RelativeTimeFormatUnit, number> = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1,
|
||||
};
|
||||
|
||||
const getOptions = () => {
|
||||
if (active === "trash") return kebabOptionsMap.trash;
|
||||
if (active === "shared") return kebabOptionsMap.shared;
|
||||
if (createdBy && createdBy?._id !== userId) return kebabOptionsMap.shared;
|
||||
return kebabOptionsMap.default;
|
||||
};
|
||||
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
|
||||
return (
|
||||
<button
|
||||
className="dashboard-card-container"
|
||||
onClick={navigateToProject}
|
||||
title={projectName}
|
||||
onMouseLeave={() => setIsKebabOpen(false)}
|
||||
for (const key in intervals) {
|
||||
const unit = key as RelativeTimeFormatUnit;
|
||||
const diff = Math.floor(diffInSeconds / intervals[unit]);
|
||||
if (diff >= 1) {
|
||||
return rtf.format(-diff, unit);
|
||||
}
|
||||
}
|
||||
return "just now";
|
||||
}
|
||||
|
||||
const kebabOptionsMap: Record<string, string[]> = {
|
||||
default: ["rename", "delete", "duplicate", "open in new tab"],
|
||||
trash: ["restore", "delete"],
|
||||
shared: ["duplicate", "open in new tab"],
|
||||
};
|
||||
|
||||
const getOptions = () => {
|
||||
if (active === "trash") return kebabOptionsMap.trash;
|
||||
if (active === "shared") return kebabOptionsMap.shared;
|
||||
if (createdBy && createdBy?._id !== userId) return kebabOptionsMap.shared;
|
||||
return kebabOptionsMap.default;
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className="dashboard-card-container"
|
||||
onClick={navigateToProject}
|
||||
title={projectName}
|
||||
onMouseLeave={() => setIsKebabOpen(false)}
|
||||
>
|
||||
<div className="dashboard-card-wrapper">
|
||||
<div className="preview-container">
|
||||
{thumbnail ? (
|
||||
<img src={thumbnail} alt="" />
|
||||
) : (
|
||||
<img src={img} alt="" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="project-details-container"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<div className="dashboard-card-wrapper">
|
||||
<div className="preview-container">
|
||||
{thumbnail ? <img src={thumbnail} alt="" /> : <img src={img} alt="" />}
|
||||
</div>
|
||||
<div className="project-details-container" onClick={(e) => { e.stopPropagation() }}>
|
||||
<div className="project-details">
|
||||
{isRenaming ? (
|
||||
<input
|
||||
value={renameValue}
|
||||
onChange={(e) => {
|
||||
e.stopPropagation();
|
||||
handleProjectName(e.target.value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setIsRenaming(false);
|
||||
setProjectName(renameValue);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setProjectName(renameValue);
|
||||
setIsRenaming(false);
|
||||
}
|
||||
}}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<span>{renameValue}</span>
|
||||
)}
|
||||
{createdAt && (
|
||||
<div className="project-data">
|
||||
{active && active == "trash" ? `Trashed by you` : `Edited `}{" "}
|
||||
{getRelativeTime(createdAt)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="users-list-container" ref={kebabRef}>
|
||||
<div className="user-profile">
|
||||
{(!createdBy) ? userName ? userName?.charAt(0).toUpperCase() : "A" : createdBy?.userName?.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<button
|
||||
className="kebab-wrapper"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsKebabOpen((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isKebabOpen && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{getOptions().map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="project-details">
|
||||
{isRenaming ? (
|
||||
<input
|
||||
value={renameValue}
|
||||
onChange={(e) => {
|
||||
e.stopPropagation();
|
||||
handleProjectName(e.target.value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setIsRenaming(false);
|
||||
setProjectName(renameValue);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setProjectName(renameValue);
|
||||
setIsRenaming(false);
|
||||
}
|
||||
}}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<span>{renameValue}</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
{createdAt && (
|
||||
<div className="project-data">
|
||||
{active && active == "trash" ? `Trashed by you` : `Edited `}{" "}
|
||||
{getRelativeTime(createdAt)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="users-list-container" ref={kebabRef}>
|
||||
<div className="user-profile">
|
||||
{!createdBy
|
||||
? userName
|
||||
? userName?.charAt(0).toUpperCase()
|
||||
: "A"
|
||||
: createdBy?.userName?.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<button
|
||||
className="kebab-wrapper"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsKebabOpen((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isKebabOpen && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{getOptions().map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardCard;
|
||||
export default DashboardCard;
|
||||
|
||||
Reference in New Issue
Block a user