add unknown chats modal

This commit is contained in:
Ren Amamiya 2023-07-25 16:12:52 +07:00
parent 1362dfadda
commit a4e03a59eb
4 changed files with 139 additions and 27 deletions

View File

@ -1,15 +1,15 @@
import { useQuery } from '@tanstack/react-query';
import { useCallback } from 'react';
import { ChatsListItem } from '@app/chats/components/item';
import { NewMessageModal } from '@app/chats/components/modal';
import { ChatsListSelfItem } from '@app/chats/components/self';
import { UnknownsModal } from '@app/chats/components/unknowns';
import { getChats } from '@libs/storage';
import { StrangersIcon } from '@shared/icons';
import { useAccount } from '@utils/hooks/useAccount';
import { compactNumber } from '@utils/number';
import { Chats } from '@utils/types';
export function ChatsList() {
const { account } = useAccount();
@ -21,6 +21,15 @@ export function ChatsList() {
return await getChats();
});
const renderItem = useCallback(
(item: Chats) => {
if (account.pubkey !== item.sender_pubkey) {
return <ChatsListItem key={item.sender_pubkey} data={item} />;
}
},
[chats]
);
if (status === 'loading') {
return (
<div className="flex flex-col">
@ -46,24 +55,8 @@ export function ChatsList() {
<div className="h-3 w-full animate-pulse rounded-sm bg-zinc-800" />
</div>
)}
{chats.follows.map((item) => {
if (account.pubkey !== item.sender_pubkey) {
return <ChatsListItem key={item.sender_pubkey} data={item} />;
}
})}
<button
type="button"
className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5"
>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900">
<StrangersIcon className="h-3 w-3 text-zinc-200" />
</div>
<div>
<h5 className="font-medium text-zinc-400">
{compactNumber.format(chats.unknown)} strangers
</h5>
</div>
</button>
{chats.follows.map((item) => renderItem(item))}
{chats.unknowns.length > 0 && <UnknownsModal data={chats.unknowns} />}
<NewMessageModal />
{isFetching && (
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5">

View File

@ -78,9 +78,9 @@ export function NewMessageModal() {
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
>
<CancelIcon width={20} height={20} className="text-zinc-300" />
<CancelIcon className="h-4 w-4 text-zinc-300" />
</button>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
@ -104,7 +104,7 @@ export function NewMessageModal() {
<button
type="button"
onClick={() => openChat(follow)}
className="inline-flex w-max translate-x-20 transform rounded border-t border-zinc-600/50 bg-zinc-700 px-3 py-1.5 text-sm transition-transform duration-150 ease-in-out hover:bg-fuchsia-500 group-hover:translate-x-0"
className="hidden w-max rounded-md bg-zinc-700 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
>
Chat
</button>

View File

@ -0,0 +1,117 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { User } from '@app/auth/components/user';
import { CancelIcon, StrangersIcon } from '@shared/icons';
import { compactNumber } from '@utils/number';
import { Chats } from '@utils/types';
export function UnknownsModal({ data }: { data: Chats[] }) {
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
const openChat = (pubkey: string) => {
closeModal();
navigate(`/app/chats/${pubkey}`);
};
return (
<>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 items-center gap-2.5 rounded-md px-2.5"
>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900">
<StrangersIcon className="h-3 w-3 text-zinc-200" />
</div>
<div>
<h5 className="font-medium text-zinc-400">
{compactNumber.format(data.length)} unknowns
</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
{data.length} unknowns
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
>
<CancelIcon className="h-4 w-4 text-zinc-300" />
</button>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
All messages from people you not follow
</Dialog.Description>
</div>
</div>
<div className="flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-5">
{data.map((user) => (
<div
key={user.event_id}
className="group flex items-center justify-between px-4 py-3 hover:bg-zinc-800"
>
<User pubkey={user.sender_pubkey} />
<div>
<button
type="button"
onClick={() => openChat(user.sender_pubkey)}
className="hidden w-max rounded-md bg-zinc-700 px-3 py-1 text-sm font-medium hover:bg-fuchsia-500 group-hover:inline-flex"
>
Chat
</button>
</div>
</div>
))}
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
);
}

View File

@ -308,9 +308,9 @@ export async function getChats() {
const follows =
typeof account.follows === 'string' ? JSON.parse(account.follows) : account.follows;
const chats: { follows: Array<Chats> | null; unknown: number } = {
const chats: { follows: Array<Chats> | null; unknowns: Array<Chats> | null } = {
follows: [],
unknown: 0,
unknowns: [],
};
let result: Array<Chats> = await db.select(
@ -326,7 +326,9 @@ export async function getChats() {
});
});
chats.unknown = result.length - chats.follows.length;
chats.unknowns = result.filter(
(el) => !chats.follows.includes(el) && el.sender_pubkey !== account.pubkey
);
return chats;
}