nice hotkey selection of a channel
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
Reference in New Issue
Block a user