nice hotkey selection of a channel

This commit is contained in:
talksik
2022-05-18 06:43:21 -05:00
parent bf79e78b50
commit 8125d2223a
2 changed files with 62 additions and 45 deletions
@@ -1,20 +1,22 @@
import MasterLineData from '@nirvana/core/models/masterLineData.model'; import MasterLineData from '@nirvana/core/models/masterLineData.model';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useCallback } from 'react';
import { Avatar, Skeleton, Tooltip } from 'antd'; import { Avatar, Tooltip } from 'antd';
import { FaPlus, FaSearch } from 'react-icons/fa'; import { FiActivity, FiSun, FiX } from 'react-icons/fi';
import { FiActivity, FiPlus, FiSearch, FiSun, FiX } from 'react-icons/fi';
import useRealTimeRooms from '../../../../providers/RealTimeRoomProvider';
import useRooms from '../../../../providers/RoomsProvider';
import useAuth from '../../../../providers/AuthProvider'; import useAuth from '../../../../providers/AuthProvider';
import LineIcon from '../../../../components/lineIcon'; import LineIcon from '../../../../components/lineIcon';
import moment from 'moment'; import moment from 'moment';
import { useKeyPressEvent } from 'react-use';
import toast from 'react-hot-toast';
import { LineMemberState } from '@nirvana/core/models/line.model';
export default React.memo(function LineRow({ export default React.memo(function LineRow({
index,
line, line,
handleSelectLine, handleSelectLine,
isSelected, isSelected,
}: { }: {
index: number; // the order of this one in the list (for this view to know the shortcut to register)
line: MasterLineData; line: MasterLineData;
handleSelectLine: (newLineId: string) => void; handleSelectLine: (newLineId: string) => void;
isSelected: boolean; isSelected: boolean;
@@ -26,6 +28,23 @@ export default React.memo(function LineRow({
[line.tunedInMemberIds, user], [line.tunedInMemberIds, user],
); );
const isUserToggleTuned = useMemo(
() => line?.currentUserMember?.state === LineMemberState.TUNED,
[line],
);
const handleActivateLine = useCallback(() => {
toast('selected channel');
handleSelectLine(line.lineDetails._id.toString());
}, [handleSelectLine, line.lineDetails, index]);
const hotkeyActivateLine = useCallback(() => {
if (isUserToggleTuned) handleActivateLine();
}, [isUserToggleTuned, handleActivateLine]);
useKeyPressEvent((index + 1).toString(), hotkeyActivateLine);
const renderRightActivity = useMemo(() => { const renderRightActivity = useMemo(() => {
if (isSelected) { if (isSelected) {
return ( return (
@@ -105,24 +124,29 @@ export default React.memo(function LineRow({
return ( return (
<div <div
onClick={() => handleSelectLine(line.lineDetails._id.toString())} onClick={handleActivateLine}
role={'presentation'} role={'presentation'}
className={`flex flex-row items-center justify-start gap-2 px-4 py-4 hover:bg-gray-200 className={`flex flex-row items-center justify-start gap-2 px-4 py-4 hover:bg-gray-200
cursor-pointer transition-all relative z-50 rounded ${ cursor-pointer transition-all relative z-50 rounded ${
isSelected && 'bg-gray-200 scale-110 shadow-2xl translate-x-3' isSelected && 'bg-gray-200 scale-110 shadow-2xl translate-x-3'
}`} }`}
> >
{/* status dot */} {/* channel picture */}
{profilePictures && <LineIcon grayscale={!isUserTunedIn} sourceImages={profilePictures} />} {profilePictures && <LineIcon grayscale={!isUserTunedIn} sourceImages={profilePictures} />}
{/* channel name */}
<h2 <h2
className={`text-inherit text-md max-w-[220px] truncate text-slate-800 ${ className={`text-inherit text-md max-w-[180px] truncate text-slate-800 ${
line.currentUserMember.lastVisitDate ? 'font-semibold' : '' line.currentUserMember.lastVisitDate ? 'font-semibold' : ''
}`} }`}
> >
{line.lineDetails.name || line.otherUserObjects[0].givenName} {line.lineDetails.name || line.otherUserObjects[0].givenName}
</h2> </h2>
{isUserToggleTuned && (
<span className="ml-2 text-gray-300 text-xs p-1 px-2 bg-gray-100">{`${index + 1}`}</span>
)}
<div className="ml-auto flex-shrink-0">{renderRightActivity}</div> <div className="ml-auto flex-shrink-0">{renderRightActivity}</div>
</div> </div>
); );
@@ -1,14 +1,9 @@
import { LineMemberState } from '@nirvana/core/models/line.model'; import { LineMemberState } from '@nirvana/core/models/line.model';
import MasterLineData from '@nirvana/core/models/masterLineData.model'; import { Skeleton, Tooltip } from 'antd';
import { Avatar, Skeleton, Tooltip } from 'antd'; import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useMemo, useEffect, useState } from 'react'; import { FiActivity, FiPlus, FiSearch } from 'react-icons/fi';
import { FaPlus, FaSearch } from 'react-icons/fa';
import { FiActivity, FiPlus, FiSearch, FiSun, FiX } from 'react-icons/fi';
import useRealTimeRooms from '../../../../providers/RealTimeRoomProvider'; import useRealTimeRooms from '../../../../providers/RealTimeRoomProvider';
import useRooms from '../../../../providers/RoomsProvider'; import useRooms from '../../../../providers/RoomsProvider';
import useAuth from '../../../../providers/AuthProvider';
import LineIcon from '../../../../components/lineIcon';
import moment from 'moment';
import NavBar from '../navbar/Navbar'; import NavBar from '../navbar/Navbar';
import NoTextLogo from '@nirvana/components/logo/NoTextLogo'; import NoTextLogo from '@nirvana/components/logo/NoTextLogo';
import LineRow from '../line/LineRow'; import LineRow from '../line/LineRow';
@@ -20,18 +15,31 @@ export default function SidePanel() {
const { roomsMap, handleSelectLine, selectedLineId, handleShowNewChannelForm } = const { roomsMap, handleSelectLine, selectedLineId, handleShowNewChannelForm } =
useRealTimeRooms(); useRealTimeRooms();
const [toggleTunedLines, allLines] = useMemo(() => { // todo: sort
const masterLines: MasterLineData[] = Object.values(roomsMap); const allChannels = useMemo(() => {
const channels = Object.values(roomsMap);
const tunedLines: MasterLineData[] = []; channels.sort((channelA, channelB) => {
const restLines: MasterLineData[] = []; if (
channelA.currentUserMember.state === LineMemberState.TUNED &&
channelB.currentUserMember.state === LineMemberState.INBOX
)
return -1;
masterLines.forEach((masterLine) => { if (
if (masterLine.currentUserMember.state === LineMemberState.TUNED) tunedLines.push(masterLine); channelB.currentUserMember.state === LineMemberState.TUNED &&
else restLines.push(masterLine); channelA.currentUserMember.state === LineMemberState.INBOX
)
return 1;
if (channelA.lineDetails.createdDate > channelB.lineDetails.createdDate) return 1;
// sort also by activity
return -1;
}); });
return [tunedLines, restLines]; return channels;
}, [roomsMap]); }, [roomsMap]);
const [searchQuery, setSearchQuery] = useState<string>(''); const [searchQuery, setSearchQuery] = useState<string>('');
@@ -66,10 +74,8 @@ export default function SidePanel() {
</Tooltip> </Tooltip>
</div> </div>
{/* tuned in lines block */} {/* tuned in header + general controls */}
<div className="flex flex-col shadow-xl bg-gray-100"> <div className="flex flex-col shadow-xl bg-gray-100">
{/* tuned in header + general controls */}
<Tooltip placement="right" title={'These are your active rooms...'}> <Tooltip placement="right" title={'These are your active rooms...'}>
<div className="flex flex-row items-center py-3 px-4 pb-0"> <div className="flex flex-row items-center py-3 px-4 pb-0">
<span className="flex flex-row gap-2 items-center justify-start text-gray-400 animate-pulse"> <span className="flex flex-row gap-2 items-center justify-start text-gray-400 animate-pulse">
@@ -77,27 +83,13 @@ export default function SidePanel() {
<h2 className="text-inherit text-xs">Tuned In</h2> <h2 className="text-inherit text-xs">Tuned In</h2>
<p className="text-slate-300 text-xs ml-auto">{`${ <p className="text-slate-300 text-xs ml-auto">{`${allChannels?.length || 0}/3`}</p>
toggleTunedLines?.length || 0
}/3`}</p>
</span> </span>
</div> </div>
</Tooltip> </Tooltip>
{/* list of toggle tuned lines */}
<div className="flex flex-col mt-2">
{toggleTunedLines.map((masterLineData) => (
<LineRow
key={`terminalListLines-${masterLineData.lineDetails._id.toString()}`}
line={masterLineData}
handleSelectLine={handleSelectLine}
isSelected={masterLineData.lineDetails._id.toString() === selectedLineId}
/>
))}
</div>
</div> </div>
{!(allLines.length > 0) && !(toggleTunedLines.length > 0) && ( {!(allChannels.length > 0) && (
<span className="text-gray-300 text-sm my-5 text-center"> <span className="text-gray-300 text-sm my-5 text-center">
You have no lines! <br /> Create one to connect to your team instantly. You have no lines! <br /> Create one to connect to your team instantly.
</span> </span>
@@ -108,8 +100,9 @@ export default function SidePanel() {
{initialRoomsFetch.loading ? ( {initialRoomsFetch.loading ? (
<Skeleton /> <Skeleton />
) : ( ) : (
allLines.map((masterLineData) => ( allChannels.map((masterLineData, index) => (
<LineRow <LineRow
index={index}
key={`terminalListLines-${masterLineData.lineDetails._id.toString()}`} key={`terminalListLines-${masterLineData.lineDetails._id.toString()}`}
line={masterLineData} line={masterLineData}
handleSelectLine={handleSelectLine} handleSelectLine={handleSelectLine}