UNPKG

nested-comments-react

Version:
227 lines (206 loc) 6.54 kB
import React from "react"; import { useState, useEffect } from "react"; import ReplyBox from "../ReplyBox/ReplyBox"; import "./NestedComments.css"; import { v4 as uuid } from "uuid"; import ReplyIcon from "../Svg/ReplyIcon"; export function NestedComments({ data = [], commentAdded = () => {}, userName, paginationSize = 2, userId, }) { const PARENT_ROOT = "*"; let [treeData, setTreeData] = useState({ children: [], id: PARENT_ROOT }); let childSet = new Set(); let [mapColors, setMapColors] = useState({}); const getRandomColor = (userId) => { let mapColorsCopy = { ...mapColors }; if (userId !== undefined && mapColorsCopy.userId !== undefined) return mapColors.userId; var color = "#"; for (var i = 0; i < 6; i++) { color += Math.floor(Math.random() * 10); } if (userId !== undefined) setMapColors({ ...mapColors, userId: color }); return color; }; const createTree = (src, mapRelations) => { if (!mapRelations.has(src.childId)) { let obj = { id: src.childId, name: src.name, comment: src.comment, color: src.color !== undefined ? src.color : getRandomColor(src.userId), children: [], }; return obj; } else { let children = []; let obj = { id: src.childId, name: src.name, comment: src.comment, color: src.color !== undefined ? src.color : getRandomColor(src.userId), children, }; mapRelations.get(src.childId).forEach((ele) => { children.push(createTree(ele, mapRelations)); }); return obj; } }; const createMap = (data) => { let mapRelations = new Map(); data.forEach((ele) => { childSet.add(ele.childId); if (mapRelations.has(ele.parentId)) { mapRelations.set(ele.parentId, [ ...mapRelations.get(ele.parentId), ele, ]); } else { mapRelations.set(ele.parentId, [ele]); } }); return mapRelations; }; const getRootId = () => { let res = new Set(); data.forEach((ele) => { if (!childSet.has(ele.parentId)) { res.add(ele.parentId); } }); return [...res]; }; useEffect(() => { let mapRelations = createMap(data); let res = []; let rootIds = getRootId(); if (rootIds.length > 0) { for (let rootId of rootIds) { mapRelations.get(rootId).forEach((ele, index) => { res.push(createTree(mapRelations.get(rootId)[index], mapRelations)); }); } } let nestedData = { children: [...res], id: PARENT_ROOT }; setTreeData(nestedData); }, []); let Recurse = ({ root, commentAdded }) => { let [showComments, setShowComments] = useState(false); let [showTextBox, setShowTextBox] = useState(false); let [treeKey, setTreeKey] = useState(""); let [currLimit, setCurrLimit] = useState(paginationSize); const cancel = () => { setShowTextBox(false); }; const onReply = (reply) => { const unique_id = uuid(); const small_id = unique_id.slice(0, 8); root.children.unshift({ id: small_id, name: userName, comment: reply, color: getRandomColor(userId), children: [], }); setShowComments(true); setShowTextBox(false); setTreeKey(small_id); commentAdded({ parentId: root.id == "*" ? uuid().slice(0, 8) : root.id, childId: small_id, comment: reply, name: userName, userId: userId, }); }; return ( <div> {root.id === PARENT_ROOT && ( <ReplyBox onReply={(reply) => onReply(reply)} isRoot={true} /> )} <div className={root.id !== PARENT_ROOT ? "recursive-align" : ""}> {root.id !== PARENT_ROOT && ( <div style={{ display: "flex" }}> <div className="circle" style={{ backgroundColor: root.color }} title={root.name} > <p className="circle-inner"> {root && root.name && root.name.substring(0, 2)} </p> </div>{" "} <div className="nested-comment">{root && root.comment}</div> </div> )} {root.id !== PARENT_ROOT && ( <div className="recursive-reply-button-div"> <div className="reply-img-div"> <ReplyIcon className="reply-icon" /> </div> <div> <p onClick={() => setShowTextBox(!showTextBox)} className="recursive-reply-button" > Reply </p> </div> </div> )} {showTextBox && ( <div className="recursive-reply-box-align"> <ReplyBox onReply={(reply) => onReply(reply)} cancel={() => cancel()} ></ReplyBox> </div> )} {((showComments && root) || root.id === PARENT_ROOT) && root.children.slice(0, currLimit).map((ele) => { return ( <span key={ele.id}> <div> <Recurse root={ele} commentAdded={commentAdded} /> </div> </span> ); })} {!showComments && root.id !== PARENT_ROOT && root.children && root.children.length != 0 && ( <p className="recursive-view-replies-button" onClick={() => setShowComments(true)} > view replies </p> )} {(showComments || root.id === PARENT_ROOT) && root.children.length != PARENT_ROOT && currLimit < root.children.length && ( <p className="show-more-button" onClick={() => { setCurrLimit(currLimit + paginationSize); }} > show more </p> )} </div> </div> ); }; return ( <div> <Recurse root={treeData} commentAdded={commentAdded} /> </div> ); }