162 lines
5.8 KiB
TypeScript
162 lines
5.8 KiB
TypeScript
import { FiActivity, FiSun } from "react-icons/fi";
|
|
import { useCallback, useMemo } from "react";
|
|
|
|
import { $selectedLineId } from "../../../controller/recoil";
|
|
import { Avatar } from "antd";
|
|
import LineIcon from "../lineIcon";
|
|
import { LineMemberState } from "@nirvana/core/models/line.model";
|
|
import MasterLineData from "@nirvana/core/models/masterLineData.model";
|
|
import moment from "moment";
|
|
import { useGetUserDetails } from "../../../controller/index";
|
|
import { useLineDataProvider } from "../../../controller/lineDataProvider";
|
|
import { useRecoilState } from "recoil";
|
|
|
|
// todo: send a much more comprehensive master line object? or just add properties to the
|
|
// masterLineData object so that we don't have different models to maintain between client and server
|
|
|
|
export default function LineRow({
|
|
masterLineData,
|
|
}: {
|
|
masterLineData: MasterLineData;
|
|
}) {
|
|
const [selectedLineId, setSelectedLineId] = useRecoilState($selectedLineId);
|
|
const { data: userData } = useGetUserDetails();
|
|
|
|
// TODO: p2 move those socket handler functions to another hook so that they don't come from the context as this will cause each line row to re-render on changes to the context state/value
|
|
const { handleUnTuneToLine } = useLineDataProvider();
|
|
|
|
/** show user line details */
|
|
const handleSelectLine = useCallback(() => {
|
|
// if not already selected so that we are not changing this recoil atom of selected line id and causing a mess
|
|
if (selectedLineId !== masterLineData.lineDetails._id.toString()) {
|
|
setSelectedLineId((prevSelectedLineId) => {
|
|
// untune myself from the previously selected if it was a temporary one/inbox
|
|
// todo: p3: consolidate this logic as it's used in escape but different scenarios sort of so p3
|
|
if (
|
|
prevSelectedLineId &&
|
|
masterLineData.currentUserMember?.state === LineMemberState.INBOX
|
|
)
|
|
handleUnTuneToLine(prevSelectedLineId);
|
|
|
|
return masterLineData.lineDetails._id.toString();
|
|
});
|
|
}
|
|
}, [setSelectedLineId, masterLineData, selectedLineId]);
|
|
|
|
// take the source of truth list of memeberIds tuned in, and see if I'm in it
|
|
const isUserTunedIn = useMemo(
|
|
() =>
|
|
masterLineData.tunedInMemberIds?.includes(userData?.user?._id.toString()),
|
|
[masterLineData.tunedInMemberIds, userData]
|
|
);
|
|
|
|
/**
|
|
* TODO: slowly add to this and fix based on added features
|
|
* */
|
|
const renderActivityIcon = useMemo(() => {
|
|
if (isUserTunedIn) return <FiActivity className="text-black" />;
|
|
|
|
// if there is someone or me broadcasting here
|
|
if (masterLineData.currentBroadcastersUserIds?.length > 0)
|
|
return <FiSun className="text-xs text-teal-500" />;
|
|
|
|
// if there is new activity blocks for me
|
|
if (masterLineData.currentUserMember.lastVisitDate)
|
|
return (
|
|
<span className="h-2 w-2 rounded-full bg-slate-800 animate-pulse"></span>
|
|
);
|
|
|
|
return (
|
|
<span className="h-2 w-2 rounded-full bg-white animate-pulse"></span>
|
|
);
|
|
}, [masterLineData, isUserTunedIn]);
|
|
|
|
const renderRightActivity = useMemo(() => {
|
|
// TODO: get the profile pictures of the broadcasters
|
|
if (masterLineData.currentBroadcastersUserIds?.length > 0)
|
|
return (
|
|
<Avatar.Group
|
|
key={`lineRowRightActivityGroup-${masterLineData.lineDetails._id.toString()}`}
|
|
maxCount={2}
|
|
maxPopoverTrigger="click"
|
|
size="small"
|
|
maxStyle={{
|
|
color: "#f56a00",
|
|
backgroundColor: "#fde3cf",
|
|
cursor: "pointer",
|
|
borderRadius: "0",
|
|
}}
|
|
className="shadow-lg"
|
|
>
|
|
{masterLineData.otherUserObjects?.map((otherUser, index) => (
|
|
<Avatar
|
|
key={`lineListActivitySection-${otherUser._id.toString()}-${index}`}
|
|
src={otherUser.picture ?? ""}
|
|
shape="square"
|
|
size={"small"}
|
|
/>
|
|
))}
|
|
</Avatar.Group>
|
|
);
|
|
|
|
// if there is new activity/black dot, then show relative time as little bolder? or too much?
|
|
|
|
// TODO: compare last visit date to latest audio block
|
|
if (masterLineData.currentUserMember.lastVisitDate)
|
|
return (
|
|
<span className={`text-gray-400 ml-auto text-xs font-semibold`}>
|
|
{moment(masterLineData.currentUserMember.lastVisitDate).fromNow()}
|
|
</span>
|
|
);
|
|
|
|
return (
|
|
<span className={`text-gray-300 ml-auto text-xs `}>
|
|
{moment(masterLineData.currentUserMember.lastVisitDate).fromNow()}
|
|
</span>
|
|
);
|
|
}, [masterLineData]);
|
|
|
|
const profilePictures = useMemo(() => {
|
|
const pictureSources: string[] = [];
|
|
|
|
// ?don't add in my image as that's useless contextually?
|
|
// if (userData?.user?.picture) pictureSources.push(userData.user.picture);
|
|
|
|
masterLineData.otherUserObjects?.forEach((otherUser) => {
|
|
if (otherUser.picture) pictureSources.push(otherUser.picture);
|
|
});
|
|
|
|
return pictureSources;
|
|
}, [masterLineData, userData]);
|
|
|
|
return (
|
|
<div
|
|
onClick={handleSelectLine}
|
|
className={`flex flex-row items-center justify-start gap-2 p-2 px-4 h-14 hover:bg-gray-200 cursor-pointer transition-all
|
|
last:border-b-0 border-b border-b-gray-200 relative z-50 ${
|
|
selectedLineId === masterLineData.lineDetails._id.toString() &&
|
|
"bg-gray-200 scale-110 shadow-2xl translate-x-3"
|
|
}`}
|
|
>
|
|
{/* status dot */}
|
|
{renderActivityIcon}
|
|
|
|
<span className="flex flex-row gap-2 items-center justify-start text-slate-800">
|
|
{profilePictures && <LineIcon sourceImages={profilePictures} />}
|
|
|
|
<h2
|
|
className={`text-inherit text-md truncate ${
|
|
masterLineData.currentUserMember.lastVisitDate
|
|
? "font-semibold"
|
|
: ""
|
|
}`}
|
|
>
|
|
{masterLineData.lineDetails.name}
|
|
</h2>
|
|
</span>
|
|
|
|
<div className="ml-auto">{renderRightActivity}</div>
|
|
</div>
|
|
);
|
|
}
|