import { LinkType } from "@nirvana/common/models/conversation"; import { UserStatus } from "@nirvana/common/models/user"; import { Tooltip } from "antd"; import { duration } from "moment"; import { LegacyRef, useEffect, useRef, useState, MutableRefObject, } from "react"; import toast from "react-hot-toast"; import { FaCheck, FaEdit, FaExternalLinkAlt, FaGithub, FaImages, FaMicrophone, FaPlay, FaRegClock, FaRocket, FaStream, } from "react-icons/fa"; import LinkIcon from "../Drawer/LinkIcon"; import UserAvatar, { UserAvatarSizes } from "../UserDetails/UserAvatar"; import { useRecoilValue, useSetRecoilState } from "recoil"; import { allRelevantConversationsAtom, audioQueueCurrentClipSelector, isRecordingAtom, selectedConvoAtom, userConvoAssociationSelector, } from "../../recoil/main"; import { useRouter } from "next/router"; import Conversation, { AudioClip, ConversationMemberState, } from "@nirvana/common/models/conversation"; import { useAuth } from "../../contexts/authContext"; import { QueryRoutes, Routes } from "@nirvana/common/helpers/routes"; import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup"; import { conversationService } from "@nirvana/common/services"; import ConversationMemberStateIcon from "../Conversations/ConversationMemberStateIcon"; import { collection, limit, onSnapshot, orderBy, query, where, } from "firebase/firestore"; import { firestoreDb as db } from "../../services/firebaseService"; import Collections from "@nirvana/common/services/collections"; import TimelineAudioClip from "../Conversations/TimelineAudioClip"; import Modal from "antd/lib/modal/Modal"; import { configure } from "react-hotkeys"; const testDrawerItems: { linkType: LinkType; linkName: string; relativeSentTime: string; }[] = [ { linkType: LinkType.googleMeet, linkName: "Gmeet - Meeting Link", relativeSentTime: "5 seconds ago", }, { linkType: LinkType.atlassian, linkName: "Jira Ticket - Ecommerce Plugin", relativeSentTime: "20 minutes ago", }, { linkType: LinkType.github, linkName: "React library for hotkeys", relativeSentTime: "2 hours ago", }, { linkType: LinkType.googleDrive, linkName: "Engineering - Team Drive Folder", relativeSentTime: "last week", }, ]; const AUDIO_CLIP_FETCH_LIMIT = 50; enum ConvoModal { na = "na", editTldr = "editTldr", adminEdit = "adminEdit", } export default function ViewConvo(props: { conversationId: string }) { const { currUser } = useAuth(); const allConvosMap = useRecoilValue(allRelevantConversationsAtom); const endOfTimeline = useRef(null); const [currentConvoModal, setCurrConvoModal] = useState( ConvoModal.na ); const router = useRouter(); // auth if do not have this conversation in react cache, then we are not authorized // if somehow it's still cached but we were removed, // then authenticate by checking if we are in the array of users for the conversation const convo: Conversation | undefined = allConvosMap.get( props.conversationId ); const userConvoAssoc = useRecoilValue( userConvoAssociationSelector(props.conversationId) ); const [audioClips, setAudioClips] = useState([] as AudioClip[]); const setSelectedConvoId = useSetRecoilState(selectedConvoAtom); useEffect(() => { endOfTimeline.current?.scrollIntoView({ behavior: "smooth" }); }, [audioClips]); useEffect(() => { // should have this convo, otherwise unauthorized if (!convo || !convo.activeMembers.includes(currUser!.uid)) { toast.error("Not authorized for this conversation"); router.push({ pathname: Routes.home, query: { page: QueryRoutes.convos }, }); return; } // set the selected convo as this one as we are now on this page setSelectedConvoId(props.conversationId); // subscribe to the data for the conversation such that we can render the timeline // get all audioClips for this conversation realtime listener so that when I speak it's also put on the timeline // any new message is seamlessly added to the timeline const audioClipsQuery = query( collection( db, Collections.conversations, props.conversationId, Collections.conversationAudioClips ), orderBy("createdDate", "desc"), limit(AUDIO_CLIP_FETCH_LIMIT) ); const unsubscribe = onSnapshot(audioClipsQuery, (querySnapshot) => { const audioClips: AudioClip[] = [] as AudioClip[]; querySnapshot.forEach((doc) => { const audClip = doc.data() as AudioClip; audClip.id = doc.id; // appending all messages in sort order audioClips.push(audClip); }); setAudioClips(audioClips.reverse()); console.log(audioClips); }); return unsubscribe; }, []); const handleOrganizeConversation = async ( toState: ConversationMemberState ) => { try { // use service to make change in database which will change local data await conversationService.updateUserConvoRelationship( currUser!.uid, props.conversationId, toState ); toast.success("Moved conversation to " + toState); } catch (error) { console.error(error); toast.error("Problem in moving conversation"); } }; const handleCloseModal = () => { setCurrConvoModal(ConvoModal.na); }; // to allow not having commands while editing the input configure({ ignoreTags: ["input", "select", "textarea"], }); const handleEditTldr = () => { console.log("updating tldr with modal"); }; const [editTldrMode, setEditTldrMode] = useState(false); const [newTldr, setNewTldr] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const saveNewTldr = async (e) => { if (!newTldr) { toast.error("can't have a blank tldr!"); return; } setIsSubmitting(true); try { await conversationService.updateTldr( props.conversationId, newTldr, currUser!.uid ); toast.success("Updated TLDR;"); setEditTldrMode(false); } catch (error) { toast.error("problem in updating tldr"); console.error(error); } setIsSubmitting(false); }; const handleAdminEdit = () => { toast("Coming soon!"); }; const isRecording = useRecoilValue(isRecordingAtom); const audioQueueCurrentItem = useRecoilValue(audioQueueCurrentClipSelector); return ( <> {/*

Some contents...

Some contents...

Some contents...

*/}
{/* convo name and action buttons on top */}
{/* header */} {convo?.name} {convo?.activeMembers && ( )} {convo?.activeMembers.length} members {userConvoAssoc?.state && ( )} {userConvoAssoc?.state != ConversationMemberState.default && ( )} {userConvoAssoc?.state != ConversationMemberState.later && ( )} {userConvoAssoc?.state != ConversationMemberState.priority && ( )} {userConvoAssoc?.state != ConversationMemberState.done && ( )} {!editTldrMode ? ( <> setEditTldrMode(true)} className="flex flex-row group items-center" > tldr; {convo?.tldr} ) : (