better display of status and all separately
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
import { User, UserStatus } from "@nirvana/core/models";
|
||||||
|
|
||||||
|
export default function UserAvatarWithStatus(props: { user: User }) {
|
||||||
|
return (
|
||||||
|
<span className="relative">
|
||||||
|
<img
|
||||||
|
src={props.user.picture}
|
||||||
|
className="rounded-lg h-8 hover:bg-slate-200 hover:cursor-pointer hover:scale-110"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UserStatusBubble status={props.user.status} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserStatusBubble(props: { status: UserStatus }) {
|
||||||
|
switch (props.status) {
|
||||||
|
case UserStatus.ONLINE:
|
||||||
|
return (
|
||||||
|
<span className="absolute bottom-0 -right-1.5 rounded-full bg-emerald-600 h-3 w-3"></span>
|
||||||
|
);
|
||||||
|
case UserStatus.OFFLINE:
|
||||||
|
return (
|
||||||
|
<span className="absolute bottom-0 -right-1.5 rounded-full bg-slate-400 h-3 w-3"></span>
|
||||||
|
);
|
||||||
|
case UserStatus.FLOW_STATE:
|
||||||
|
return (
|
||||||
|
<span className="absolute bottom-0 -right-1.5 rounded-full bg-pink-400 h-3 w-3"></span>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<span className="absolute bottom-0 -right-1.5 rounded-full bg-pink-400 h-3 w-3"></span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { UserStatus } from "@nirvana/core/models";
|
||||||
|
|
||||||
|
export default function UserStatusText(props: { status: UserStatus }) {
|
||||||
|
switch (props.status) {
|
||||||
|
case UserStatus.ONLINE:
|
||||||
|
return <span className="text-emerald-600 text-sm lowercase">ONLINE</span>;
|
||||||
|
case UserStatus.OFFLINE:
|
||||||
|
return <></>;
|
||||||
|
case UserStatus.FLOW_STATE:
|
||||||
|
return (
|
||||||
|
<span className="text-pink-400 text-sm lowercase">FLOW STATE</span>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,32 @@
|
|||||||
import { Add, LinkRounded } from "@mui/icons-material";
|
import { Add, LinkRounded } from "@mui/icons-material";
|
||||||
|
|
||||||
|
import { $selectedConversation } from "../../../controller/recoil";
|
||||||
import { Avatar } from "antd";
|
import { Avatar } from "antd";
|
||||||
import { FaVolumeUp } from "react-icons/fa";
|
import { FaVolumeUp } from "react-icons/fa";
|
||||||
import SkeletonLoader from "../../../components/loading/skeleton";
|
import SkeletonLoader from "../../../components/loading/skeleton";
|
||||||
|
import UserAvatarWithStatus from "../../../components/User/userAvatarWithStatus";
|
||||||
|
import UserStatusText from "../../../components/User/userStatusText";
|
||||||
import { useGetAllContactBasicDetails } from "../../../controller";
|
import { useGetAllContactBasicDetails } from "../../../controller";
|
||||||
|
import { useRecoilState } from "recoil";
|
||||||
|
|
||||||
export default function Conversations() {
|
export default function Conversations() {
|
||||||
const { data: contactDetailsListResponse, isLoading } =
|
const { data: contactDetailsListResponse, isLoading } =
|
||||||
useGetAllContactBasicDetails();
|
useGetAllContactBasicDetails();
|
||||||
|
const [selectedConvo, setSelectedConvo] = useRecoilState(
|
||||||
|
$selectedConversation
|
||||||
|
);
|
||||||
|
|
||||||
/** Data we need: have this huge data store client side to be able to access
|
// todo: show conversations with activity/new content for me first...then the rest of the contacts
|
||||||
* for now, need a simple list of contacts
|
|
||||||
* - first list is the live/pinned
|
const selectContact = async (googleUserId: string) => {
|
||||||
* - second list is the pending invites, out going or incoming? or this on a separate page?
|
// if this person is already selected, unselect
|
||||||
* - third list is just the rest of my contacts
|
if (selectedConvo === googleUserId) {
|
||||||
*
|
setSelectedConvo(null);
|
||||||
* web sockets for all of my active contacts
|
return;
|
||||||
* - actually play messages if pinned contact for me
|
}
|
||||||
*/
|
|
||||||
|
setSelectedConvo(googleUserId);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -48,16 +57,28 @@ export default function Conversations() {
|
|||||||
|
|
||||||
{isLoading ? <SkeletonLoader /> : null}
|
{isLoading ? <SkeletonLoader /> : null}
|
||||||
<div className="flex flex-col m-5 p-4">
|
<div className="flex flex-col m-5 p-4">
|
||||||
|
<span className="flex flex-row justify-start items-center mb-2">
|
||||||
|
<span className="ml-2 tracking-wider text-slate-100 uppercase text-sm font-semibold">
|
||||||
|
Inbox
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
{contactDetailsListResponse?.contactsDetails.map((contactDetail) => {
|
{contactDetailsListResponse?.contactsDetails.map((contactDetail) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row items-center">
|
<div
|
||||||
<Avatar src={contactDetail.otherUser.picture} />
|
onClick={() => selectContact(contactDetail.otherUser.googleId)}
|
||||||
|
className="flex flex-row items-center hover:bg-slate-600 group border-t border-t-slate-500
|
||||||
|
py-4 px-2 cursor-pointer"
|
||||||
|
>
|
||||||
|
<UserAvatarWithStatus user={contactDetail.otherUser} />
|
||||||
|
|
||||||
<span className="text-white font-semibold ml-2">
|
<span className="text-white font-semibold ml-2">
|
||||||
{contactDetail.otherUser.name}
|
{contactDetail.otherUser.name}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className="ml-2">{contactDetail.otherUser.status}</span>
|
<span className="ml-2">
|
||||||
|
<UserStatusText status={contactDetail.otherUser.status} />
|
||||||
|
</span>
|
||||||
|
|
||||||
<span className="ml-auto">speaking...</span>
|
<span className="ml-auto">speaking...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useRecoilState, useSetRecoilState } from "recoil";
|
|||||||
|
|
||||||
import { GlobalHotKeys } from "react-hotkeys";
|
import { GlobalHotKeys } from "react-hotkeys";
|
||||||
import { STORE_ITEMS } from "../../../electron/constants";
|
import { STORE_ITEMS } from "../../../electron/constants";
|
||||||
|
import UserAvatarWithStatus from "../../../components/User/userAvatarWithStatus";
|
||||||
import { useGetUserDetails } from "../../../controller/index";
|
import { useGetUserDetails } from "../../../controller/index";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ export default function Header() {
|
|||||||
<>
|
<>
|
||||||
<GlobalHotKeys handlers={handlers} keyMap={keyMap}></GlobalHotKeys>
|
<GlobalHotKeys handlers={handlers} keyMap={keyMap}></GlobalHotKeys>
|
||||||
|
|
||||||
<div className="flex flex-row items-center bg-slate-800 h-20">
|
<div className="flex flex-row items-center bg-slate-800 h-20 px-5">
|
||||||
<Logo type={LogoType.small} className="scale-[0.4]" />
|
<Logo type={LogoType.small} className="scale-[0.4]" />
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
@@ -58,18 +59,13 @@ export default function Header() {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button className="ml-auto hover:scale-110 bg-slate-600 text-teal-500 py-1 px-2 rounded-lg text-sm">
|
<button className="ml-auto mr-2 hover:scale-110 bg-slate-600 text-teal-500 py-1 px-2 rounded-lg text-sm">
|
||||||
flow state
|
flow state
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Dropdown overlay={ProfileMenu} trigger={["click"]}>
|
<Dropdown overlay={ProfileMenu} trigger={["click"]}>
|
||||||
<span className="relative mx-5">
|
<span className="px-5">
|
||||||
<img
|
<UserAvatarWithStatus user={user} />
|
||||||
src={user.picture}
|
|
||||||
className="rounded-lg h-8 hover:bg-slate-200 hover:cursor-pointer hover:scale-110"
|
|
||||||
alt="cannot find"
|
|
||||||
/>
|
|
||||||
<span className="absolute bottom-0 -right-1.5 rounded-full bg-emerald-600 h-3 w-3"></span>
|
|
||||||
</span>
|
</span>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user