shortcuts for sidebar for priority convos
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
import { Avatar } from "antd";
|
||||||
|
import { useRecoilValue } from "recoil";
|
||||||
|
import { selectedPriorityConvoAtom } from "../../recoil/main";
|
||||||
|
import Conversation from "../../../common/models/conversation";
|
||||||
|
import { MasterAvatarGroupWithUserFetch } from "../UserDetails/MasterAvatarGroup";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
export default function PriorityConvoRow(props: {
|
||||||
|
conversation: Conversation;
|
||||||
|
itemIndex: number;
|
||||||
|
}) {
|
||||||
|
// figure out if this is a selectedConvo
|
||||||
|
const selectedConvo = useRecoilValue(selectedPriorityConvoAtom);
|
||||||
|
|
||||||
|
const isSelected = selectedConvo == props.conversation.id ? true : false;
|
||||||
|
|
||||||
|
// who was the last sender based on the lastInteractionDate etc.
|
||||||
|
const myTurn = false;
|
||||||
|
|
||||||
|
// todo: implement method in conversation
|
||||||
|
// const isOneonOne =
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={`group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer ${
|
||||||
|
isSelected && "bg-slate-50 shadow-lg"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<MasterAvatarGroupWithUserFetch
|
||||||
|
listOfUserIds={props.conversation.activeMembers}
|
||||||
|
showCurrUser={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className="flex flex-col items-start ml-2">
|
||||||
|
<span className="flex flex-row items-center space-x-2">
|
||||||
|
<span className="text-slate-400">{props.conversation.name}</span>
|
||||||
|
<span
|
||||||
|
className="ml-auto shadow-lg flex flex-row items-center h-[1.5rem] w-[1.5rem]
|
||||||
|
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer text-xs"
|
||||||
|
>
|
||||||
|
{props.itemIndex}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="text-slate-300 text-xs">
|
||||||
|
{moment(props.conversation.lastActivityDate.toDate()).fromNow()}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
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 { useSetRecoilState } from "recoil";
|
||||||
|
|
||||||
configure({
|
configure({
|
||||||
ignoreTags: [],
|
ignoreTags: [],
|
||||||
@@ -9,9 +11,13 @@ configure({
|
|||||||
export default function KeyboardShortcutHandler() {
|
export default function KeyboardShortcutHandler() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const setSelectedPriorityConvo = useSetRecoilState(selectedPriorityConvoAtom);
|
||||||
|
|
||||||
const handleEscape = () => {
|
const handleEscape = () => {
|
||||||
console.log("woah");
|
console.log("woah");
|
||||||
router.push({ query: { page: QueryRoutes.convos } });
|
router.push({ query: { page: QueryRoutes.convos } });
|
||||||
|
|
||||||
|
setSelectedPriorityConvo(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const keyMap: KeyMap = {
|
const keyMap: KeyMap = {
|
||||||
|
|||||||
@@ -1,20 +1,111 @@
|
|||||||
|
import { Avatar, Tooltip, Badge } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FaRocket } from "react-icons/fa";
|
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||||
|
import {
|
||||||
|
FaCircle,
|
||||||
|
FaMicrophone,
|
||||||
|
FaPlay,
|
||||||
|
FaRocket,
|
||||||
|
FaUser,
|
||||||
|
} from "react-icons/fa";
|
||||||
|
import {
|
||||||
|
priorityConvosSelector,
|
||||||
|
selectedPriorityConvoAtom,
|
||||||
|
} from "../../recoil/main";
|
||||||
|
import PriorityConvoRow from "../Conversations/PriorityConvoRow";
|
||||||
|
import { GlobalHotKeys, HotKeys } from "react-hotkeys";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
const MAX_SHORTCUT_MAPPINGS_PRIORITY = 8;
|
||||||
|
|
||||||
export default function Priority() {
|
export default function Priority() {
|
||||||
return (
|
const priorityConvos = useRecoilValue(priorityConvosSelector);
|
||||||
<div className="mx-auto my-auto flex flex-col">
|
const [mapShortcutsToConvoId, setmapShortcutsToConvoId] = useState<
|
||||||
<img
|
Map<string, string>
|
||||||
src="/illustrations/undraw_absorbed_in_xahs.svg"
|
>(new Map<string, string>());
|
||||||
className="h-[15rem] mx-auto my-auto"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span></span>
|
const setSelectedConversationId = useSetRecoilState(
|
||||||
<span className="text-slate-400 text-center mt-5">
|
selectedPriorityConvoAtom
|
||||||
One place for your most important
|
);
|
||||||
<br></br>people and items <FaRocket className="inline" />.<br></br>
|
|
||||||
<span className="text-red-600">Keep this clean at all costs.</span>
|
// set keyboard shortcuts for 1->8, but only if this component is shown, and not in stuff like
|
||||||
</span>
|
// convo view
|
||||||
</div>
|
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;
|
||||||
|
console.log(mapShortcutsToConvoId);
|
||||||
|
console.log(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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyMap = {
|
||||||
|
SELECT_PRIORITY_CONVO: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
SELECT_PRIORITY_CONVO: selectingPriorityConvoHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{priorityConvos?.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<GlobalHotKeys
|
||||||
|
keyMap={keyMap}
|
||||||
|
handlers={handlers}
|
||||||
|
allowChanges={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{priorityConvos.map((convo, i) => (
|
||||||
|
<PriorityConvoRow
|
||||||
|
key={convo.id}
|
||||||
|
conversation={convo}
|
||||||
|
itemIndex={i + 1}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="mx-auto my-auto flex flex-col">
|
||||||
|
<img
|
||||||
|
src="/illustrations/undraw_absorbed_in_xahs.svg"
|
||||||
|
className="h-[15rem] mx-auto my-auto"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span></span>
|
||||||
|
<span className="text-slate-400 text-center mt-5">
|
||||||
|
One place for your
|
||||||
|
<br></br> important conversations <FaRocket className="inline" />.
|
||||||
|
<br></br>
|
||||||
|
<span className="text-red-600">Keep this clean at all costs.</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
FaCircle,
|
FaCircle,
|
||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { HiSpeakerphone } from "react-icons/hi";
|
import { HiSpeakerphone } from "react-icons/hi";
|
||||||
|
import Priority from "./Priority";
|
||||||
|
|
||||||
function Sidebar() {
|
function Sidebar() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -167,169 +168,7 @@ function Sidebar() {
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
{/* list of pinned convos */}
|
{/* list of pinned convos */}
|
||||||
<span className="flex flex-row items-center bg-slate-50 rounded-lg shadow-lg p-2 w-full">
|
<Priority />
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="text-slate-500 font-semibold">Josh</span>
|
|
||||||
|
|
||||||
<span className="text-slate-300 text-xs">engineer</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<Tooltip title={"Press and hold R to send a voice clip."}>
|
|
||||||
<span
|
|
||||||
className="ml-auto shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-orange-700 bg-slate-100 text-lg font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
<FaMicrophone />
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
<span
|
|
||||||
className="ml-2 shadow-lg flex flex-row items-center h-10 w-10 justify-center
|
|
||||||
rounded-lg text-teal-600 bg-slate-100 text-lg font-bold"
|
|
||||||
>
|
|
||||||
<FaPlay />
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer">
|
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Avatar src="https://yt3.ggpht.com/ytc/AKedOLQDVVudyMlzgNrCzOfNkUKn0KGGwfHQ-PjU02p6PQ=s48-c-k-c0x00ffffff-no-rj" />
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="text-slate-400">Mark</span>
|
|
||||||
|
|
||||||
<span className="text-slate-300 text-xs">architect</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="ml-auto shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer">
|
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Badge dot color={"green"}>
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/200/100" />
|
|
||||||
</Badge>
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="flex flex-row space-x-2 items-center">
|
|
||||||
<span className="text-slate-500 font-semibold">Sydney</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="text-slate-300 text-xs">designer</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<FaCircle className="ml-auto text-orange-500 mr-2 animate-pulse text-[0.7em]" />
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="ml-2 shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer">
|
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Badge dot color={"green"}>
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/202/600" />
|
|
||||||
</Badge>
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="text-slate-400">Jessica</span>
|
|
||||||
|
|
||||||
<span className="text-slate-300 text-xs">recruiter</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="ml-auto shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
4
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer">
|
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/200/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
<Avatar shape="circle" src="https://picsum.photos/240/300" />
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="text-slate-400">General</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="ml-auto shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
5
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="group flex flex-row items-center rounded-lg p-2 w-full hover:cursor-pointer">
|
|
||||||
<Avatar.Group
|
|
||||||
maxCount={2}
|
|
||||||
size="large"
|
|
||||||
maxStyle={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
|
|
||||||
>
|
|
||||||
<Avatar src="https://joeschmoe.io/api/v1/random" />
|
|
||||||
<Avatar style={{ backgroundColor: "#f56a00" }}>K</Avatar>
|
|
||||||
<Avatar style={{ backgroundColor: "#87d068" }} icon={<FaUser />} />
|
|
||||||
<Avatar style={{ backgroundColor: "#1890ff" }} icon={<FaUser />} />
|
|
||||||
<Avatar style={{ backgroundColor: "#1890ff" }} icon={<FaUser />} />
|
|
||||||
<Avatar style={{ backgroundColor: "#1890ff" }} icon={<FaUser />} />
|
|
||||||
</Avatar.Group>
|
|
||||||
|
|
||||||
<span className="flex flex-col items-start ml-2">
|
|
||||||
<span className="text-slate-400">Engineering</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
className="ml-auto shadow-lg flex flex-row items-center h-10 w-10
|
|
||||||
justify-center rounded-lg text-slate-400 font-bold hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
5
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { allRelevantContactsAtom } from "../../recoil/main";
|
|||||||
import { userService } from "@nirvana/common/services";
|
import { userService } from "@nirvana/common/services";
|
||||||
import { Avatar } from "antd";
|
import { Avatar } from "antd";
|
||||||
|
|
||||||
const AVATAR_SHAPE = "square";
|
const AVATAR_SHAPE = "circle";
|
||||||
|
|
||||||
export default function MasterAvatarGroup(props: {
|
export default function MasterAvatarGroup(props: {
|
||||||
listOfUsers: User[];
|
listOfUsers: User[];
|
||||||
@@ -69,12 +69,10 @@ export default function MasterAvatarGroup(props: {
|
|||||||
maxCount={2}
|
maxCount={2}
|
||||||
size="default"
|
size="default"
|
||||||
maxStyle={{
|
maxStyle={{
|
||||||
color: "rgb(203 213 225)",
|
color: "rgb(148 163 184)",
|
||||||
fontSize: "10px",
|
fontSize: "10px",
|
||||||
backgroundColor: "rgb(248 250 252)",
|
backgroundColor: "rgb(248 250 252)",
|
||||||
borderRadius: 0,
|
|
||||||
}}
|
}}
|
||||||
className="bg-slate-50 text-slate-300"
|
|
||||||
>
|
>
|
||||||
{finalistUsers.map((oUser) => (
|
{finalistUsers.map((oUser) => (
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ export enum RecoilActions {
|
|||||||
RELEVANT_CONTACTS_SELECTOR_CACHE = "RELEVANT_CONTACTS_SELECTOR_CACHE",
|
RELEVANT_CONTACTS_SELECTOR_CACHE = "RELEVANT_CONTACTS_SELECTOR_CACHE",
|
||||||
|
|
||||||
USER_DATA = "USER_DATA",
|
USER_DATA = "USER_DATA",
|
||||||
|
|
||||||
|
SELECTED_CONVERSATION_ATOM = "SELECTED_CONVERSATION_ATOM",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nirvanaUserDataAtom = atom<NirvanaUser | null>({
|
export const nirvanaUserDataAtom = atom<NirvanaUser | null>({
|
||||||
@@ -152,6 +154,8 @@ export const priorityConvosSelector = selector<Conversation[]>({
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// todo: sort by createdDate, not lastActivityDate
|
||||||
|
|
||||||
return priorityConvos;
|
return priorityConvos;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -305,3 +309,15 @@ export const allRelevantContactsAtom = atom<Map<string, NirvanaUser>>({
|
|||||||
|
|
||||||
// todo: useful selector where a component can pass in a list of users
|
// todo: useful selector where a component can pass in a list of users
|
||||||
// and return their full information...either get from cache if there or fetch from database if not and update cache
|
// and return their full information...either get from cache if there or fetch from database if not and update cache
|
||||||
|
|
||||||
|
// RECORDING, SHORTCUTS, PLAYING, MIC, HEADPHONES, etc.
|
||||||
|
export const isRecording = atom<boolean>({
|
||||||
|
key: "haha",
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const selectedPriorityConvoAtom = atom<string | null>({
|
||||||
|
// convoId
|
||||||
|
key: RecoilActions.SELECTED_CONVERSATION_ATOM,
|
||||||
|
default: null,
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user