getting a basic queue but need to add whole timeline nicely
This commit is contained in:
@@ -2,16 +2,20 @@ import { useEffect, useState } from "react";
|
|||||||
import { configure, GlobalHotKeys, KeyMap } from "react-hotkeys";
|
import { configure, GlobalHotKeys, KeyMap } from "react-hotkeys";
|
||||||
import { useRecoilState, useRecoilValue } from "recoil";
|
import { useRecoilState, useRecoilValue } from "recoil";
|
||||||
import {
|
import {
|
||||||
|
allRelevantConversationsAtom,
|
||||||
|
audioQueueAtom,
|
||||||
hasMicPermissionsAtom,
|
hasMicPermissionsAtom,
|
||||||
isRecordingAtom,
|
isRecordingAtom,
|
||||||
priorityConvosSelector,
|
priorityConvosSelector,
|
||||||
selectedPriorityConvoAtom,
|
selectedConvoAtom,
|
||||||
} from "../../recoil/main";
|
} from "../../recoil/main";
|
||||||
import MicRecorder from "mic-recorder-to-mp3";
|
import MicRecorder from "mic-recorder-to-mp3";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { conversationService } from "@nirvana/common/services";
|
import { conversationService } from "@nirvana/common/services";
|
||||||
import { useAuth } from "../../contexts/authContext";
|
import { useAuth } from "../../contexts/authContext";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { AudioClip } from "@nirvana/common/models/conversation";
|
||||||
|
|
||||||
// New instance
|
// New instance
|
||||||
const recorder = new MicRecorder({
|
const recorder = new MicRecorder({
|
||||||
@@ -22,72 +26,48 @@ const MAX_SHORTCUT_MAPPINGS_PRIORITY = 8;
|
|||||||
|
|
||||||
export default function AudioHandler() {
|
export default function AudioHandler() {
|
||||||
const { currUser } = useAuth();
|
const { currUser } = useAuth();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { convoId } = router.query;
|
||||||
|
|
||||||
const priorityConvos = useRecoilValue(priorityConvosSelector);
|
const priorityConvos = useRecoilValue(priorityConvosSelector);
|
||||||
|
const mapAllConvos = useRecoilValue(allRelevantConversationsAtom);
|
||||||
|
|
||||||
const [mapShortcutsToConvoId, setmapShortcutsToConvoId] = useState<
|
const [mapShortcutsToConvoId, setmapShortcutsToConvoId] = useState<
|
||||||
Map<string, string>
|
Map<string, string>
|
||||||
>(new Map<string, string>());
|
>(new Map<string, string>());
|
||||||
|
|
||||||
const [selectedConvoId, setSelectedConversationId] = useRecoilState(
|
const [selectedConvoId, setSelectedConversationId] =
|
||||||
selectedPriorityConvoAtom
|
useRecoilState(selectedConvoAtom);
|
||||||
);
|
|
||||||
|
const [audioQueue, setAudioQueue] = useRecoilState(audioQueueAtom);
|
||||||
|
|
||||||
|
function onEndedPlaying(e) {
|
||||||
|
toast.success("finished playing");
|
||||||
|
|
||||||
|
// remove from queue and the queue manager will handle the rest
|
||||||
|
setAudioQueue((prevQueue) => {
|
||||||
|
const newQueue: AudioClip[] = [...prevQueue];
|
||||||
|
newQueue.shift();
|
||||||
|
return newQueue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (audioQueue.length > 0) {
|
||||||
|
const audio = new Audio(audioQueue[0].audioDataUrl);
|
||||||
|
audio.onended = onEndedPlaying;
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
}, [audioQueue]);
|
||||||
|
|
||||||
const [hasMicPermissions, sethasMicPermissions] = useRecoilState(
|
const [hasMicPermissions, sethasMicPermissions] = useRecoilState(
|
||||||
hasMicPermissionsAtom
|
hasMicPermissionsAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
// set keyboard shortcuts for 1->8, but only if this component is shown, and not in stuff like
|
|
||||||
// convo view
|
|
||||||
useEffect(() => {
|
|
||||||
// reset entire map of shortcuts now with new list of priority convos
|
|
||||||
|
|
||||||
const newMap = new Map<string, string>();
|
|
||||||
|
|
||||||
priorityConvos.map((convo, i) => {
|
|
||||||
if (i < MAX_SHORTCUT_MAPPINGS_PRIORITY) {
|
|
||||||
const shortcut = (i + 1).toString();
|
|
||||||
newMap.set(shortcut, convo.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setmapShortcutsToConvoId(newMap);
|
|
||||||
}, [priorityConvos]);
|
|
||||||
|
|
||||||
const selectingPriorityConvoHandler = (event) => {
|
|
||||||
const key = event.key;
|
|
||||||
|
|
||||||
// select the convo based on the right convo
|
|
||||||
|
|
||||||
if (!mapShortcutsToConvoId.has(key)) {
|
|
||||||
toast.error("Not a valid conversation selected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedConvoId = mapShortcutsToConvoId.get(key);
|
|
||||||
|
|
||||||
if (selectedConvoId) {
|
|
||||||
setSelectedConversationId(selectedConvoId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// set keyboard shortcuts for 1->8, but only if this component is shown, and not in stuff like
|
|
||||||
// convo view
|
|
||||||
useEffect(() => {
|
|
||||||
// reset entire map of shortcuts now with new list of priority convos
|
|
||||||
|
|
||||||
const newMap = new Map<string, string>();
|
|
||||||
|
|
||||||
priorityConvos.map((convo, i) => {
|
|
||||||
if (i < MAX_SHORTCUT_MAPPINGS_PRIORITY) {
|
|
||||||
const shortcut = (i + 1).toString();
|
|
||||||
newMap.set(shortcut, convo.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setmapShortcutsToConvoId(newMap);
|
|
||||||
}, [priorityConvos]);
|
|
||||||
|
|
||||||
// checking for permissions for recording
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
|
// checking for permissions for recording
|
||||||
// won't work in https!!!
|
// won't work in https!!!
|
||||||
navigator.mediaDevices
|
navigator.mediaDevices
|
||||||
.getUserMedia({ audio: true })
|
.getUserMedia({ audio: true })
|
||||||
@@ -111,6 +91,22 @@ export default function AudioHandler() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// set keyboard shortcuts for 1->8, but only if this component is shown, and not in stuff like
|
||||||
|
// convo view
|
||||||
|
useEffect(() => {
|
||||||
|
// reset entire map of shortcuts now with new list of priority convos
|
||||||
|
|
||||||
|
const newMap = new Map<string, string>();
|
||||||
|
|
||||||
|
priorityConvos.map((convo, i) => {
|
||||||
|
if (i < MAX_SHORTCUT_MAPPINGS_PRIORITY) {
|
||||||
|
const shortcut = (i + 1).toString();
|
||||||
|
newMap.set(shortcut, convo.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setmapShortcutsToConvoId(newMap);
|
||||||
|
}, [priorityConvos]);
|
||||||
|
|
||||||
configure({
|
configure({
|
||||||
ignoreTags: ["input", "select", "textarea"],
|
ignoreTags: ["input", "select", "textarea"],
|
||||||
});
|
});
|
||||||
@@ -205,9 +201,7 @@ export default function AudioHandler() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currConvo = priorityConvos.find(
|
const currConvo = mapAllConvos.get(selectedConvoId);
|
||||||
(convo) => convo.id == selectedConvoId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!currConvo?.cachedAudioClip) {
|
if (!currConvo?.cachedAudioClip) {
|
||||||
toast.error("nothing to play");
|
toast.error("nothing to play");
|
||||||
@@ -218,6 +212,29 @@ export default function AudioHandler() {
|
|||||||
audio.play();
|
audio.play();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectingPriorityConvoHandler = (event) => {
|
||||||
|
const key = event.key;
|
||||||
|
|
||||||
|
// STOP if we are in a convo detail page, as we want to talk in this channel, if so
|
||||||
|
if (convoId) {
|
||||||
|
toast.error("Cannot select a priority convo from here!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the convo based on the shortcut
|
||||||
|
|
||||||
|
if (!mapShortcutsToConvoId.has(key)) {
|
||||||
|
toast.error("Not a valid conversation selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedConvoId = mapShortcutsToConvoId.get(key);
|
||||||
|
|
||||||
|
if (selectedConvoId) {
|
||||||
|
setSelectedConversationId(selectedConvoId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const keyMap: KeyMap = {
|
const keyMap: KeyMap = {
|
||||||
SELECT_PRIORITY_CONVO: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
SELECT_PRIORITY_CONVO: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
||||||
START_RECORDING: {
|
START_RECORDING: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Avatar, Tooltip } from "antd";
|
|||||||
import { useRecoilState, useRecoilValue } from "recoil";
|
import { useRecoilState, useRecoilValue } from "recoil";
|
||||||
import {
|
import {
|
||||||
checkIncomingMessageSelector,
|
checkIncomingMessageSelector,
|
||||||
selectedPriorityConvoAtom,
|
selectedConvoAtom,
|
||||||
} from "../../recoil/main";
|
} from "../../recoil/main";
|
||||||
import Conversation from "../../../common/models/conversation";
|
import Conversation from "../../../common/models/conversation";
|
||||||
import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup";
|
import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup";
|
||||||
@@ -23,9 +23,7 @@ export default function PriorityConvoRow(props: {
|
|||||||
itemIndex: number;
|
itemIndex: number;
|
||||||
}) {
|
}) {
|
||||||
// figure out if this is a selectedConvo
|
// figure out if this is a selectedConvo
|
||||||
const [selectedConvo, setSelectedConvo] = useRecoilState(
|
const [selectedConvo, setSelectedConvo] = useRecoilState(selectedConvoAtom);
|
||||||
selectedPriorityConvoAtom
|
|
||||||
);
|
|
||||||
|
|
||||||
const isSelected = selectedConvo == props.conversation.id ? true : false;
|
const isSelected = selectedConvo == props.conversation.id ? true : false;
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ import { yesterday } from "@nirvana/common/helpers/dateTime";
|
|||||||
import { AudioClip } from "@nirvana/common/models/conversation";
|
import { AudioClip } from "@nirvana/common/models/conversation";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilState, useRecoilValue } from "recoil";
|
||||||
import {
|
import {
|
||||||
allRelevantContactsAtom,
|
allRelevantContactsAtom,
|
||||||
allUsersConversationsAtom,
|
allUsersConversationsAtom,
|
||||||
|
audioQueueAtom,
|
||||||
|
audioQueueCurrentClipSelector,
|
||||||
|
selectedConvoAtom,
|
||||||
} from "../../recoil/main";
|
} from "../../recoil/main";
|
||||||
import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup";
|
import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -21,6 +24,9 @@ export default function TimelineAudioClip(props: {
|
|||||||
const audioClipUser = relContactsMap.get(props.audioClip.senderUserId);
|
const audioClipUser = relContactsMap.get(props.audioClip.senderUserId);
|
||||||
const userConvoAssoc = userConvosMap.get(props.convoId);
|
const userConvoAssoc = userConvosMap.get(props.convoId);
|
||||||
|
|
||||||
|
const audioQueueCurrentClip = useRecoilValue(audioQueueCurrentClipSelector);
|
||||||
|
const [audioQueue, setAudioQueue] = useRecoilState(audioQueueAtom);
|
||||||
|
|
||||||
const [audioDuration, setAudioDuration] = useState<number>();
|
const [audioDuration, setAudioDuration] = useState<number>();
|
||||||
|
|
||||||
const loadedMetadata = (data) => {
|
const loadedMetadata = (data) => {
|
||||||
@@ -33,11 +39,21 @@ export default function TimelineAudioClip(props: {
|
|||||||
// audio.onloadedmetadata = loadedMetadata;
|
// audio.onloadedmetadata = loadedMetadata;
|
||||||
|
|
||||||
const playAudioClip = () => {
|
const playAudioClip = () => {
|
||||||
toast(`${audioClipUser?.firstName} speaking...`);
|
setAudioQueue((prevQueue) => {
|
||||||
|
return [...prevQueue, props.audioClip];
|
||||||
audio.play();
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let customClasses = "bg-slate-100 border";
|
||||||
|
if (audioQueueCurrentClip?.id == props.audioClip.id) {
|
||||||
|
customClasses = "animate-pulse bg-orange-200";
|
||||||
|
} else if (
|
||||||
|
props.audioClip.createdDate <
|
||||||
|
(userConvoAssoc?.lastInteractionDate || yesterday)
|
||||||
|
) {
|
||||||
|
customClasses = "bg-sky-100";
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
onClick={playAudioClip}
|
onClick={playAudioClip}
|
||||||
@@ -47,12 +63,8 @@ export default function TimelineAudioClip(props: {
|
|||||||
${
|
${
|
||||||
props.index % 2 == 1 &&
|
props.index % 2 == 1 &&
|
||||||
"translate-y-[4.75rem] border-t-4 border-t-teal-600"
|
"translate-y-[4.75rem] border-t-4 border-t-teal-600"
|
||||||
} ${props.index % 2 == 0 && "border-b-4 border-b-teal-600"} ${
|
} ${props.index % 2 == 0 && "border-b-4 border-b-teal-600"}
|
||||||
props.audioClip.createdDate <
|
${customClasses}`}
|
||||||
(userConvoAssoc?.lastInteractionDate || yesterday)
|
|
||||||
? "bg-slate-100 border"
|
|
||||||
: "bg-sky-100 "
|
|
||||||
}`}
|
|
||||||
style={{
|
style={{
|
||||||
minWidth: "max-content",
|
minWidth: "max-content",
|
||||||
width: `100px`,
|
width: `100px`,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { QueryRoutes } from "@nirvana/common/helpers/routes";
|
import { QueryRoutes } from "@nirvana/common/helpers/routes";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { GlobalHotKeys, KeyMap, configure } from "react-hotkeys";
|
import { GlobalHotKeys, KeyMap, configure } from "react-hotkeys";
|
||||||
import { selectedPriorityConvoAtom } from "../../recoil/main";
|
import { selectedConvoAtom } from "../../recoil/main";
|
||||||
import { useSetRecoilState } from "recoil";
|
import { useSetRecoilState } from "recoil";
|
||||||
|
|
||||||
export default function KeyboardShortcutHandler() {
|
export default function KeyboardShortcutHandler() {
|
||||||
@@ -11,7 +11,7 @@ export default function KeyboardShortcutHandler() {
|
|||||||
ignoreTags: [],
|
ignoreTags: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const setSelectedPriorityConvo = useSetRecoilState(selectedPriorityConvoAtom);
|
const setSelectedPriorityConvo = useSetRecoilState(selectedConvoAtom);
|
||||||
|
|
||||||
const handleEscape = () => {
|
const handleEscape = () => {
|
||||||
console.log("woah");
|
console.log("woah");
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ import {
|
|||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import LinkIcon from "../Drawer/LinkIcon";
|
import LinkIcon from "../Drawer/LinkIcon";
|
||||||
import UserAvatar, { UserAvatarSizes } from "../UserDetails/UserAvatar";
|
import UserAvatar, { UserAvatarSizes } from "../UserDetails/UserAvatar";
|
||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||||
import {
|
import {
|
||||||
allRelevantConversationsAtom,
|
allRelevantConversationsAtom,
|
||||||
|
selectedConvoAtom,
|
||||||
userConvoAssociationSelector,
|
userConvoAssociationSelector,
|
||||||
} from "../../recoil/main";
|
} from "../../recoil/main";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@@ -73,62 +74,6 @@ const testDrawerItems: {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const testAudioClips: {
|
|
||||||
senderName: string;
|
|
||||||
relativeSentTime: string;
|
|
||||||
duration: number;
|
|
||||||
alreadyPlayed: boolean;
|
|
||||||
isGap?: boolean;
|
|
||||||
isLink?: boolean;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
senderName: "John",
|
|
||||||
relativeSentTime: "yesterday",
|
|
||||||
duration: 150,
|
|
||||||
alreadyPlayed: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
senderName: "Moha",
|
|
||||||
relativeSentTime: "5 minutes ago",
|
|
||||||
duration: 600,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
isGap: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
senderName: "Alex",
|
|
||||||
relativeSentTime: "7 hours ago",
|
|
||||||
duration: 10,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
senderName: "Ben",
|
|
||||||
relativeSentTime: "2 hours ago",
|
|
||||||
duration: 300,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
senderName: "Alex",
|
|
||||||
relativeSentTime: "30 minutes ago",
|
|
||||||
duration: 200,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
senderName: "Moha",
|
|
||||||
relativeSentTime: "8 minutes ago",
|
|
||||||
duration: 600,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
isLink: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
senderName: "Moha",
|
|
||||||
relativeSentTime: "5 minutes ago",
|
|
||||||
duration: 600,
|
|
||||||
alreadyPlayed: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const AUDIO_CLIP_FETCH_LIMIT = 50;
|
const AUDIO_CLIP_FETCH_LIMIT = 50;
|
||||||
|
|
||||||
export default function ViewConvo(props: { conversationId: string }) {
|
export default function ViewConvo(props: { conversationId: string }) {
|
||||||
@@ -158,7 +103,10 @@ export default function ViewConvo(props: { conversationId: string }) {
|
|||||||
|
|
||||||
const [audioClips, setAudioClips] = useState<AudioClip[]>([] as AudioClip[]);
|
const [audioClips, setAudioClips] = useState<AudioClip[]>([] as AudioClip[]);
|
||||||
|
|
||||||
|
const setSelectedConvoId = useSetRecoilState(selectedConvoAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// should have this convo, otherwise unauthorized
|
||||||
if (!convo || !convo.activeMembers.includes(currUser!.uid)) {
|
if (!convo || !convo.activeMembers.includes(currUser!.uid)) {
|
||||||
toast.error("Not authorized for this conversation");
|
toast.error("Not authorized for this conversation");
|
||||||
|
|
||||||
@@ -170,6 +118,9 @@ export default function ViewConvo(props: { conversationId: string }) {
|
|||||||
return;
|
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
|
// 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
|
// 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
|
// any new message is seamlessly added to the timeline
|
||||||
@@ -235,22 +186,21 @@ export default function ViewConvo(props: { conversationId: string }) {
|
|||||||
{convo?.name}
|
{convo?.name}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ConversationMemberStateIcon
|
|
||||||
convoUserAssocState={userConvoAssoc?.state}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className="p-2 rounded-full hover:cursor-pointer hover:bg-slate-200 group-hover:visible invisible">
|
<span className="p-2 rounded-full hover:cursor-pointer hover:bg-slate-200 group-hover:visible invisible">
|
||||||
<FaEdit className="ml-auto text-md text-slate-400" />
|
<FaEdit className="ml-auto text-md text-slate-400" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className="flex flex-row items-center space-x-2 hover:cursor-pointer group">
|
<span className="flex flex-row items-center space-x-2 hover:cursor-pointer group">
|
||||||
<MasterAvatarGroupWithUserFetch
|
{convo?.activeMembers && (
|
||||||
listOfUserIds={convo?.activeMembers}
|
<MasterAvatarGroupWithUserFetch
|
||||||
showCurrUser={true}
|
listOfUserIds={convo.activeMembers}
|
||||||
maxUserCount={10}
|
showCurrUser={true}
|
||||||
size={UserAvatarSizes.small}
|
maxUserCount={10}
|
||||||
/>
|
size={UserAvatarSizes.small}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<span className="text-xs text-slate-300 hover:decoration-slate-400 group-hover:underline ">
|
<span className="text-xs text-slate-300 hover:decoration-slate-400 group-hover:underline ">
|
||||||
{convo?.activeMembers.length} members
|
{convo?.activeMembers.length} members
|
||||||
</span>
|
</span>
|
||||||
@@ -258,6 +208,12 @@ export default function ViewConvo(props: { conversationId: string }) {
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className="flex flex-row items-center space-x-3">
|
<span className="flex flex-row items-center space-x-3">
|
||||||
|
{userConvoAssoc?.state && (
|
||||||
|
<ConversationMemberStateIcon
|
||||||
|
convoUserAssocState={userConvoAssoc.state}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{userConvoAssoc?.state != ConversationMemberState.default && (
|
{userConvoAssoc?.state != ConversationMemberState.default && (
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ export default function MasterAvatarGroup(props: {
|
|||||||
export function MasterAvatarGroupWithUserFetch(props: {
|
export function MasterAvatarGroupWithUserFetch(props: {
|
||||||
listOfUserIds: string[];
|
listOfUserIds: string[];
|
||||||
showCurrUser?: boolean;
|
showCurrUser?: boolean;
|
||||||
|
maxUserCount?: number;
|
||||||
|
size?: UserAvatarSizes;
|
||||||
}) {
|
}) {
|
||||||
const relContactsMap = useRecoilValue(allRelevantContactsAtom);
|
const relContactsMap = useRecoilValue(allRelevantContactsAtom);
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ export enum RecoilActions {
|
|||||||
|
|
||||||
IS_RECORDING_ATOM = "IS_RECORDING_ATOM",
|
IS_RECORDING_ATOM = "IS_RECORDING_ATOM",
|
||||||
HAS_MIC_PERMISSIONS = "HAS_MIC_PERMISSIONS",
|
HAS_MIC_PERMISSIONS = "HAS_MIC_PERMISSIONS",
|
||||||
|
|
||||||
|
AUDIO_QUEUE_ATOM = "AUDIO_QUEUE_ATOM",
|
||||||
|
AUDIO_QUEUE_CURRENT_ITEM_SELECTOR = "AUDIO_QUEUE_CURRENT_ITEM_SELECTOR",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nirvanaUserDataAtom = atom<NirvanaUser | null>({
|
export const nirvanaUserDataAtom = atom<NirvanaUser | null>({
|
||||||
@@ -410,7 +413,7 @@ export const isRecordingAtom = atom<boolean>({
|
|||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const selectedPriorityConvoAtom = atom<string | null>({
|
export const selectedConvoAtom = atom<string | null>({
|
||||||
// convoId
|
// convoId
|
||||||
key: RecoilActions.SELECTED_CONVERSATION_ATOM,
|
key: RecoilActions.SELECTED_CONVERSATION_ATOM,
|
||||||
default: null,
|
default: null,
|
||||||
@@ -420,3 +423,21 @@ export const hasMicPermissionsAtom = atom<boolean>({
|
|||||||
key: RecoilActions.HAS_MIC_PERMISSIONS,
|
key: RecoilActions.HAS_MIC_PERMISSIONS,
|
||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const audioQueueAtom = atom<AudioClip[]>({
|
||||||
|
key: RecoilActions.AUDIO_QUEUE_ATOM,
|
||||||
|
default: [] as AudioClip[],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const audioQueueCurrentClipSelector = selector<AudioClip | null>({
|
||||||
|
key: RecoilActions.AUDIO_QUEUE_CURRENT_ITEM_SELECTOR,
|
||||||
|
get: ({ get }) => {
|
||||||
|
const currentQueue = get(audioQueueAtom);
|
||||||
|
|
||||||
|
if (currentQueue[0]) {
|
||||||
|
return currentQueue[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user