adding deboucing and cleaning up flow

This commit is contained in:
talksik
2022-05-05 06:17:07 -05:00
parent 11cd498a2f
commit 699cc6c559
8 changed files with 142 additions and 81 deletions
@@ -1,9 +1,10 @@
import { Avatar, Tooltip } from "antd";
import { FaAngleRight } from "react-icons/fa";
import { ReactElement } from "react";
import { Tooltip } from "antd";
import { User } from "@nirvana/core/models/user.model";
export default function UserRow({
export default function BasicUserRow({
user,
rightJsx,
}: {
@@ -13,20 +14,19 @@ export default function UserRow({
return (
<span
key={user._id.toString() + new Date().toDateString()}
className="border-t border-t-zinc-500 py-3 px-2 flex flex-row justify-start
items-center w-full hover:bg-zinc-600 cursor-pointer group"
className="border-t border-t-gray-200 py-3 px-2 flex flex-row justify-start
items-center w-full hover:bg-gray-300 cursor-pointer group"
>
<span className="relative mx-5">
<img
src={user.picture}
className="rounded-lg h-8 hover:bg-zinc-200 hover:cursor-pointer hover:scale-110"
alt=""
/>
<span className="absolute bottom-0 -right-1.5 rounded-full bg-emerald-600 h-3 w-3"></span>
</span>
<Avatar
key={`searchUsers-${user._id.toString()}`}
shape="square"
src={user.picture}
size="default"
className="shadow-lg mx-5"
/>
<span className="flex flex-col items-start">
<span className="text-zinc-200 text-lg font-semibold">{user.name}</span>
<span className="text-gray-500 text-lg font-semibold">{user.name}</span>
<span className="text-zinc-300">{user.email}</span>
</span>
@@ -153,6 +153,7 @@ export default function NirvanaHeader({
{userDetailsRes?.user?.picture &&
mediaSettings.mode === "audio" && (
<Avatar
key={`userHeaderProfilePicture`}
className="mr-1 shadow-md"
alt={userDetailsRes?.user?.givenName}
src={userDetailsRes?.user?.picture}
@@ -14,8 +14,13 @@ export default function LineIcon({ sourceImages }: { sourceImages: string[] }) {
}}
className="shadow-lg"
>
{sourceImages?.map((avatarSrc) => (
<Avatar src={avatarSrc} shape="square" size={"default"} />
{sourceImages?.map((avatarSrc, index) => (
<Avatar
key={`lineIcon-${avatarSrc}-${index}`}
src={avatarSrc}
shape="square"
size={"default"}
/>
))}
</Avatar.Group>
);
@@ -54,8 +54,13 @@ export default function LineRow({
}}
className="shadow-lg"
>
{lineDetails.profilePicsLiveBroadcasters.map((avatarSrc) => (
<Avatar src={avatarSrc} shape="square" size={"small"} />
{lineDetails.profilePicsLiveBroadcasters.map((avatarSrc, index) => (
<Avatar
key={`lineListActivitySection-${avatarSrc}-${index}`}
src={avatarSrc}
shape="square"
size={"small"}
/>
))}
</Avatar.Group>
);
+21
View File
@@ -6,11 +6,32 @@ import ProtectedRoute from "../components/ProtectedRoute";
import { ReactQueryDevtools } from "react-query/devtools";
import { RecoilRoot } from "recoil";
import { Toaster } from "react-hot-toast";
import { configure } from "react-hotkeys";
import io from "socket.io-client";
import testConnection from "@nirvana/core";
testConnection();
configure({
// TODO: put back to default from docs: https://github.com/greena13/react-hotkeys#Configuration
/**
* The HTML tags that React HotKeys should ignore key events from. This only works
* if you are using the default ignoreEventsCondition function.
* @type {String[]}
*/
ignoreTags: [],
/**
* The function used to determine whether a key event should be ignored by React
* Hotkeys. By default, keyboard events originating elements with a tag name in
* ignoreTags, or a isContentEditable property of true, are ignored.
*
* @type {Function<KeyboardEvent>}
*/
// ignoreEventsCondition: function,
});
// Create a client
export const queryClient = new QueryClient();
@@ -15,7 +15,7 @@ export default function NirvanaTerminal({
}: {
allLines: ILineDetails[];
}) {
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [isModalVisible, setIsModalVisible] = useState<boolean>(true);
const setSelectedLineId = useSetRecoilState($selectedLineId);
const setDesktopMode = useSetRecoilState($desktopMode);
@@ -1,7 +1,11 @@
import { Avatar, Modal } from "antd";
import { HotKeys, KeyMap } from "react-hotkeys";
import { useCallback, useState } from "react";
import Search from "antd/lib/input/Search";
import { useState } from "react";
import BasicUserRow from "../../../components/User/basicUserDetailsRow";
import { FiSearch } from "react-icons/fi";
import { User } from "@nirvana/core/models";
import { useUserSearch } from "../../../controller/index";
export default function NewLineModal({
open,
@@ -10,7 +14,17 @@ export default function NewLineModal({
open: boolean;
handleClose: () => void;
}) {
const [selectedPeople, setSelectedPeople] = useState<User[]>([]);
const [peopleSearchValue, setPeopleSearchValue] = useState<string>("");
// the actual state that goes to query...the debounced one so to speak
const [searchQuery, setSearchQuery] = useState<string>("");
const { refetch, data: searchRes } = useUserSearch(searchQuery);
const handleSubmit = () => {
// ensure that we don't have a one on one chat already with x person if it's one person selected
// upon success,
// make sure that the list of lines updates for this client and others so that it shows this new line
// select the line so that it shows up in the line details for this client
@@ -23,8 +37,43 @@ export default function NewLineModal({
handleClose();
};
const onSearch = () => {
console.log("searching for people in database");
const onSearch = useCallback(() => {
if (peopleSearchValue) {
console.log("searching for people in database");
setSearchQuery(peopleSearchValue);
}
}, [setSearchQuery]);
const selectUser = useCallback(
(userToAdd: User) => {
setSelectedPeople((prevSelectedUsers) => [
...prevSelectedUsers,
userToAdd,
]);
},
[setSelectedPeople]
);
const unSelectUser = useCallback(
(userIdToRemove: string) => {
setSelectedPeople((prevSelectedUsers) => {
return prevSelectedUsers.filter(
(prevUser) => prevUser._id.toString() !== userIdToRemove
);
});
},
[setSelectedPeople]
);
const keyMap: KeyMap = {
HANDLE_SEARCH: {
name: "handle search on enter",
sequence: "enter",
action: "keypress",
},
};
const handlers = {
HANDLE_SEARCH: onSearch,
};
return (
@@ -49,68 +98,62 @@ export default function NewLineModal({
</button>
</div>
}
className={"gap-5"}
className={"flex flex-col gap-5"}
>
<div className="flex flex-col items-start">
<HotKeys handlers={handlers} keyMap={keyMap} />
<div className="flex flex-col items-start gap-2 mb-5">
<p className="text-gray-300 text-sm">People</p>
<Search
placeholder="Search for anyone by name or email."
allowClear
enterButton="Search"
size="large"
onSearch={onSearch}
/>
</div>
<span className="flex flex-row gap-1 w-full items-center border border-gray-200 p-2 shadow">
<FiSearch className="text-gray-300" />
{/* search results */}
<div className="flex flex-col border border-gray-200 shadow-md max-h-[500px]">
<div className="flex flex-row border-b-100 p-2 items-center">
<Avatar
shape="square"
size="default"
src={
"data:image/jpeg;base64,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"
}
<input
className="placeholder:text-gray-300 outline-none placeholder:text-sm border-0 flex-1"
value={peopleSearchValue}
onChange={(e) => setPeopleSearchValue(e.target.value)}
placeholder="search by name or email"
/>
<div className="flex flex-col items-start">
<span className="text-lg font-semibold">Jeremy Leon</span>
<span className="text-gray-400 text-sm">
jeremyleon@level.com
</span>
</div>
<span className="text-xs text-gray-200">enter to search</span>
</span>
<button className="ml-auto">add</button>
{/* search results */}
<div className="flex flex-col border border-gray-200 shadow-md max-h-[500px] w-full overflow-y-auto">
{searchRes?.users?.map((user) => (
<BasicUserRow
user={user}
rightJsx={<button onClick={() => selectUser(user)}>Add</button>}
/>
))}
</div>
</div>
{/* selected people */}
<div className="flex flex-col">
<p className="text-gray-300 text-sm">People</p>
<div className="flex flex-row border-b-100 p-2 items-center">
<Avatar
shape="square"
size="default"
src={
"data:image/jpeg;base64,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"
}
/>
<div className="flex flex-col gap-2 mb-5">
<p className="text-gray-300 text-sm">Selected People</p>
<div className="flex flex-col items-start">
<span className="text-lg font-semibold">Jeremy Leon</span>
<span className="text-gray-400 text-sm">
jeremyleon@level.com
</span>
</div>
<button className="ml-auto">remove</button>
<div className="flex flex-col w-full">
{selectedPeople.map((selectedUser) => (
<BasicUserRow
user={selectedUser}
rightJsx={
<button
onClick={() => unSelectUser(selectedUser._id.toString())}
>
Remove
</button>
}
/>
))}
</div>
</div>
<div className="flex flex-col">
<div className="flex flex-col gap-2">
<p className="text-gray-300 text-sm">Line Name (optional)</p>
<input
className="placeholder:text-gray-300 outline-none placeholder:text-sm flex-1
border p-2 border-gray-200"
placeholder={"ex. Engineering, Sprint 7, Follow up on present..."}
/>
</div>
-14
View File
@@ -79,13 +79,6 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.17.2":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
dependencies:
regenerator-runtime "^0.13.4"
"@cspotcode/[email protected]":
version "0.8.0"
resolved "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz"
@@ -469,13 +462,6 @@
dependencies:
cross-spawn "^7.0.1"
"@mui/icons-material@^5.6.2":
version "5.6.2"
resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.6.2.tgz#239c40fc5841dc7c6af7d00e4e988550de170fcd"
integrity sha512-9QdI7axKuBAyaGz4mtdi7Uy1j73/thqFmEuxpJHxNC7O8ADEK1Da3t2veK2tgmsXsUlAHcAG63gg+GvWWeQNqQ==
dependencies:
"@babel/runtime" "^7.17.2"
"@next/[email protected]":
version "12.1.4"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.4.tgz#5af629b43075281ecd7f87938802b7cf5b67e94b"