Files
Dwinzo_Demo/app/src/components/layout/sidebarRight/properties/ThreadProperties.tsx

125 lines
5.9 KiB
TypeScript

import { useState } from "react";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import { getRelativeTime } from "../../../ui/collaboration/function/getRelativeTime";
import { KebabIcon } from "../../../icons/ExportCommonIcons";
import { getAvatarColorUsingUserID } from "../../../../modules/collaboration/functions/getAvatarColor";
import { deleteThreadApi } from "../../../../services/builder/collab/comments/deleteThreadApi";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../store/socket/useSocketStore";
import { getUserData } from "../../../../functions/getUserData";
import useThreadResponseHandler from "../../../../modules/collaboration/responseHandler/useThreadResponseHandler";
const ThreadProperties = () => {
const { threadStore, versionStore } = useSceneContext();
const { threads, setSelectedThread } = threadStore();
const { userId, organization } = getUserData();
const { selectedVersion } = versionStore();
const { projectId } = useParams();
const { threadSocket } = useSocketStore();
const [selectedChart, setSelectedChart] = useState<ThreadSchema | null>(null);
const [isKebabActive, setIsKebabActive] = useState<boolean>(false);
const { removeThreadFromScene } = useThreadResponseHandler();
const handleDeleteThread = (val: ThreadSchema) => {
if (!projectId) return;
const threadIdToDelete = val?.threadId;
if (!threadSocket?.connected) {
// API fallback
deleteThreadApi(projectId, threadIdToDelete, selectedVersion?.versionId || "").then(
(res) => {
if (res.message === "Thread deleted Successfully") {
removeThreadFromScene(res.data._id);
}
}
);
} else {
// SOCKET path
const deleteThreadPayload = {
projectId,
userId,
organization,
threadId: threadIdToDelete,
versionId: selectedVersion?.versionId || "",
};
threadSocket.emit("v1:thread:delete", deleteThreadPayload);
}
};
return (
<div className="global-properties-container">
{threads &&
threads.map((val) => {
const isMenuVisible =
selectedChart?.createdAt === val.createdAt && isKebabActive;
return (
<section key={val?.threadId} className="thread-section">
<div className="thread-card">
{/* Avatar */}
<div
className="thread-avatar"
style={{
backgroundColor: getAvatarColorUsingUserID(val.creatorId),
}}
>
{val?.creatorName?.charAt(0).toUpperCase()}
</div>
{/* Content */}
<div className="thread-content">
{/* Title + username */}
<div>
<div className="thread-title">{val.threadTitle}</div>
<div className="thread-username">{val.creatorName}</div>
</div>
{/* Last updated + kebab */}
<div className="thread-footer">
<div className="thread-time">
{getRelativeTime(val.createdAt)}
</div>
<button
className="thread-kebab-button"
onClick={() => {
// Toggle menu visibility per-thread
if (
selectedChart?.createdAt === val.createdAt &&
isKebabActive
) {
setIsKebabActive(false);
setSelectedChart(null);
} else {
setSelectedChart(val);
setIsKebabActive(true);
}
}}
>
<KebabIcon />
</button>
</div>
</div>
</div>
{/* Kebab menu shown only for selected thread */}
{isMenuVisible && (
<div className="thread-menu">
<button onClick={() => setSelectedThread(val)}>Visible</button>
<button>Show in Scene</button>
{val.creatorId === userId && (
<button onClick={() => handleDeleteThread(val)}>
Delete
</button>
)}
</div>
)}
</section>
);
})}
</div>
);
};
export default ThreadProperties;