184 lines
8.9 KiB
TypeScript
184 lines
8.9 KiB
TypeScript
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
|
import { OnlineState } from "@/app/providers/ProtocolProvider/protocol/packets/packet.onlinestate";
|
|
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
|
|
import { useBlacklist } from "@/app/providers/BlacklistProvider/useBlacklist";
|
|
import { useDialog } from "@/app/providers/DialogProvider/useDialog";
|
|
import { useUserInformation } from "@/app/providers/InformationProvider/useUserInformation";
|
|
import { ProtocolState } from "@/app/providers/ProtocolProvider/ProtocolProvider";
|
|
import { useProtocolState } from "@/app/providers/ProtocolProvider/useProtocolState";
|
|
import { Avatar, Box, Divider, Flex, Loader, Text, Tooltip, useComputedColorScheme, useMantineTheme } from "@mantine/core";
|
|
import { modals } from "@mantine/modals";
|
|
import { IconBookmark, IconLockAccess, IconLockCancel, IconTrashX } from "@tabler/icons-react";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { VerifiedBadge } from "../VerifiedBadge/VerifiedBadge";
|
|
import { usePacket } from "@/app/providers/ProtocolProvider/usePacket";
|
|
import { PacketTyping } from "@/app/providers/ProtocolProvider/protocol/packets/packet.typeing";
|
|
import { useAvatars } from "@/app/providers/AvatarProvider/useAvatars";
|
|
import { useReplyMessages } from "@/app/providers/DialogProvider/useReplyMessages";
|
|
import { ReplyHeader } from "../ReplyHeader/ReplyHeader";
|
|
import { useRosettaBreakpoints } from "@/app/hooks/useRosettaBreakpoints";
|
|
import { BackToDialogs } from "../BackToDialogs/BackToDialogs";
|
|
import { useSystemAccounts } from "@/app/providers/SystemAccountsProvider/useSystemAccounts";
|
|
|
|
|
|
export function ChatHeader() {
|
|
const colors = useRosettaColors();
|
|
const computedTheme = useComputedColorScheme();
|
|
const navigate = useNavigate();
|
|
const publicKey = usePublicKey();
|
|
const {deleteMessages, dialog} = useDialog();
|
|
const theme = useMantineTheme();
|
|
const [blocked, blockUser, unblockUser] = useBlacklist(dialog);
|
|
const [opponent, ___, forceUpdateUserInformation] = useUserInformation(dialog);
|
|
const protocolState = useProtocolState();
|
|
const [userTypeing, setUserTypeing] = useState(false);
|
|
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
const avatars = useAvatars(dialog);
|
|
const {replyMessages} = useReplyMessages();
|
|
const {lg} = useRosettaBreakpoints();
|
|
const systemAccounts = useSystemAccounts();
|
|
const isSystemAccount = systemAccounts.find((acc) => acc.publicKey == dialog) != undefined;
|
|
|
|
|
|
useEffect(() => {
|
|
forceUpdateUserInformation();
|
|
setUserTypeing(false);
|
|
clearTimeout(timeoutRef.current);
|
|
}, [dialog]);
|
|
|
|
usePacket(0x0B, (packet : PacketTyping) => {
|
|
if(packet.getFromPublicKey() == dialog && packet.getToPublicKey() == publicKey){
|
|
setUserTypeing(true);
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = setTimeout(() => {
|
|
setUserTypeing(false);
|
|
}, 3000);
|
|
}
|
|
}, [dialog]);
|
|
|
|
const clearMessages = async () => {
|
|
deleteMessages();
|
|
modals.closeAll();
|
|
}
|
|
|
|
const onClickClearMessages = () => {
|
|
modals.openConfirmModal({
|
|
title: 'Clear all messages?',
|
|
centered: true,
|
|
children: (
|
|
<Text size="sm">
|
|
Are you sure you want to clear all messages? This action cannot be undone.
|
|
</Text>
|
|
),
|
|
withCloseButton: false,
|
|
labels: { confirm: 'Continue', cancel: "Cancel" },
|
|
confirmProps: { color: 'red' },
|
|
onConfirm: clearMessages
|
|
});
|
|
}
|
|
|
|
const onClickBlockUser = () => {
|
|
if(opponent.publicKey != "DELETED"
|
|
&& opponent.publicKey != publicKey){
|
|
blockUser();
|
|
}
|
|
}
|
|
|
|
const onClickUnblockUser = () => {
|
|
if(opponent.publicKey != "DELETED"
|
|
&& opponent.publicKey != publicKey){
|
|
unblockUser();
|
|
}
|
|
}
|
|
|
|
const onClickProfile = () => {
|
|
if(opponent.publicKey != "DELETED" && opponent.publicKey != publicKey){
|
|
navigate("/main/profile/" + opponent.publicKey);
|
|
}
|
|
}
|
|
|
|
|
|
return (<>
|
|
<Box bg={colors.boxColor} style={{
|
|
userSelect: 'none',
|
|
}} h={60}>
|
|
{(replyMessages.messages.length <= 0 || replyMessages.inDialogInput) && <Flex p={'sm'} h={'100%'} justify={'space-between'} align={'center'} gap={'sm'}>
|
|
<Flex style={{
|
|
cursor: 'pointer'
|
|
}} h={'100%'} align={'center'} gap={'sm'}>
|
|
{!lg && <BackToDialogs></BackToDialogs>}
|
|
{
|
|
publicKey == opponent.publicKey ? <Avatar
|
|
size={'md'}
|
|
color={'blue'}
|
|
variant={'filled'}
|
|
onClick={onClickProfile}
|
|
>
|
|
<IconBookmark stroke={2} size={20}></IconBookmark>
|
|
</Avatar> : <Avatar onClick={onClickProfile} color={'initials'} src={avatars.length > 0 ? avatars[0].avatar : undefined} name={opponent.title}></Avatar>
|
|
}
|
|
<Flex direction={'column'} onClick={onClickProfile}>
|
|
<Flex align={'center'} gap={3}>
|
|
<Text size={'sm'} c={computedTheme == 'light' ? 'black' : 'white'} fw={500}>
|
|
{(
|
|
publicKey == opponent.publicKey ? "Saved messages" : opponent.title
|
|
)}
|
|
</Text>
|
|
{(opponent.verified > 0 && publicKey != opponent.publicKey) && <VerifiedBadge size={17} verified={opponent.verified}></VerifiedBadge>}
|
|
</Flex>
|
|
{(publicKey != opponent.publicKey && protocolState == ProtocolState.CONNECTED && !userTypeing) && <>
|
|
{(
|
|
opponent.online == OnlineState.ONLINE ?
|
|
<Text c={theme.colors.green[7]} fz={12}>online</Text> :
|
|
<Text c={theme.colors.gray[5]} fz={12}>{isSystemAccount ? 'official account' : 'offline'}</Text>
|
|
)}
|
|
</>}
|
|
{userTypeing && publicKey != opponent.publicKey && protocolState == ProtocolState.CONNECTED && <>
|
|
<Flex gap={5} align={'center'}>
|
|
<Text c={theme.colors.blue[3]} fz={12}>typing </Text>
|
|
<Loader size={15} color={theme.colors.blue[3]} type={'dots'}></Loader>
|
|
</Flex>
|
|
</>}
|
|
{protocolState != ProtocolState.CONNECTED &&
|
|
<Flex gap={'xs'} align={'center'}>
|
|
<Loader size={8} color={colors.chevrons.active}></Loader>
|
|
<Text c={theme.colors.gray[5]} fz={12}>connecting...</Text>
|
|
</Flex>
|
|
}
|
|
</Flex>
|
|
</Flex>
|
|
<Flex h={'100%'} align={'center'} gap={'sm'}>
|
|
<Tooltip onClick={onClickClearMessages} withArrow position={'bottom'} label={"Clear all messages"}>
|
|
<IconTrashX
|
|
style={{
|
|
cursor: 'pointer'
|
|
}} stroke={1.5} color={theme.colors.blue[7]} size={24}></IconTrashX>
|
|
</Tooltip>
|
|
{publicKey != opponent.publicKey && !blocked && !isSystemAccount && (
|
|
<Tooltip onClick={onClickBlockUser} withArrow position={'bottom'} label={"Block user"}>
|
|
<IconLockCancel
|
|
style={{
|
|
cursor: 'pointer'
|
|
}} stroke={1.5} color={theme.colors.red[7]} size={24}
|
|
>
|
|
</IconLockCancel>
|
|
</Tooltip>
|
|
)}
|
|
{blocked && !isSystemAccount && (
|
|
<Tooltip onClick={onClickUnblockUser} withArrow position={'bottom'} label={"Unblock user"}>
|
|
<IconLockAccess
|
|
style={{
|
|
cursor: 'pointer'
|
|
}} stroke={1.5} color={theme.colors.green[7]} size={24}
|
|
>
|
|
</IconLockAccess>
|
|
</Tooltip>
|
|
)}
|
|
</Flex>
|
|
</Flex>}
|
|
{replyMessages.messages.length > 0 && !replyMessages.inDialogInput && <ReplyHeader></ReplyHeader>}
|
|
</Box>
|
|
<Divider color={colors.borderColor}></Divider>
|
|
</>)
|
|
} |