152 lines
7.3 KiB
TypeScript
152 lines
7.3 KiB
TypeScript
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
||
import { useDialog } from "@/app/providers/DialogProvider/useDialog";
|
||
import { ProtocolState } from "@/app/providers/ProtocolProvider/ProtocolProvider";
|
||
import { useProtocolState } from "@/app/providers/ProtocolProvider/useProtocolState";
|
||
import { Avatar, Box, Divider, Flex, Loader, Skeleton, Text, Tooltip, useComputedColorScheme, useMantineTheme } from "@mantine/core";
|
||
import { modals } from "@mantine/modals";
|
||
import { IconTrashX } from "@tabler/icons-react";
|
||
import { useEffect, useState } from "react";
|
||
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 { useGroupInformation } from "@/app/providers/InformationProvider/useGroupInformation";
|
||
import { useNavigate } from "react-router-dom";
|
||
import { useGroupMembers } from "@/app/providers/InformationProvider/useGroupMembers";
|
||
import { useUserInformation } from "@/app/providers/InformationProvider/useUserInformation";
|
||
|
||
|
||
export function GroupHeader() {
|
||
const colors = useRosettaColors();
|
||
const computedTheme = useComputedColorScheme();
|
||
const {deleteMessages, dialog} = useDialog();
|
||
const theme = useMantineTheme();
|
||
const {groupInfo} = useGroupInformation(dialog);
|
||
const protocolState = useProtocolState();
|
||
const [usersTypeing, setUsersTypeing] = useState<{
|
||
timeout: NodeJS.Timeout | null,
|
||
fromPublicKey: string
|
||
}[]>([]);
|
||
const avatars = useAvatars(dialog);
|
||
const {replyMessages} = useReplyMessages();
|
||
const {lg} = useRosettaBreakpoints();
|
||
const [userInfo] = useUserInformation(usersTypeing[0]?.fromPublicKey || '');
|
||
const navigate = useNavigate();
|
||
/**
|
||
* Указывем force для того, чтобы при открытии диалога
|
||
* с группой подгружался сразу актуальный список участников
|
||
* даже если он уже был загружен ранее. Потому что
|
||
* событие добавления/удаления участников могло произойти
|
||
* когда диалог был закрыт.
|
||
*/
|
||
const {members, loading} = useGroupMembers(groupInfo.groupId, true);
|
||
|
||
useEffect(() => {
|
||
clearUsersTypeing();
|
||
}, [dialog]);
|
||
|
||
const clearUsersTypeing = () => {
|
||
usersTypeing.forEach(ut => {
|
||
if(ut.timeout){
|
||
clearTimeout(ut.timeout);
|
||
}
|
||
});
|
||
setUsersTypeing([]);
|
||
}
|
||
|
||
usePacket(0x0B, (packet : PacketTyping) => {
|
||
if(packet.getToPublicKey() == dialog){
|
||
setUsersTypeing((prev) => [...prev, {
|
||
fromPublicKey: packet.getFromPublicKey(),
|
||
timeout: setTimeout(() => {
|
||
setUsersTypeing((prev) => {
|
||
return prev.filter(ut => ut.fromPublicKey != packet.getFromPublicKey());
|
||
});
|
||
}, 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 onClickProfile = () => {
|
||
navigate(`/main/group/${groupInfo.groupId.replace('#group:', '')}`);
|
||
}
|
||
|
||
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>}
|
||
<Avatar onClick={onClickProfile} color={'initials'} src={avatars.length > 0 ? avatars[0].avatar : undefined} name={groupInfo.title}></Avatar>
|
||
<Flex direction={'column'} onClick={onClickProfile}>
|
||
<Flex align={'center'} gap={3}>
|
||
<Text size={'sm'} c={computedTheme == 'light' ? 'black' : 'white'} fw={500}>
|
||
{groupInfo.title}
|
||
</Text>
|
||
</Flex>
|
||
{members.length > 0 && usersTypeing.length <= 0 && protocolState == ProtocolState.CONNECTED && (
|
||
<Text c={theme.colors.gray[5]} fz={12}>{members.length} member{members.length > 1 ? 's' : ''}</Text>
|
||
)}
|
||
{loading && usersTypeing.length <= 0 && protocolState == ProtocolState.CONNECTED && members.length == 0 && (
|
||
<Skeleton height={12} mt={7} width={80} radius="xl" />
|
||
)}
|
||
{!loading && members.length == 0 && (
|
||
<Text c={theme.colors.gray[5]} fz={12}>
|
||
Deleted group
|
||
</Text>
|
||
)}
|
||
{usersTypeing.length > 0 && protocolState == ProtocolState.CONNECTED && <>
|
||
<Flex gap={5} align={'center'}>
|
||
<Text c={theme.colors.blue[3]} fz={12}>{userInfo.title} {usersTypeing.length > 1 && 'and ' + (usersTypeing.length - 1)} 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>
|
||
</Flex>
|
||
</Flex>}
|
||
{replyMessages.messages.length > 0 && !replyMessages.inDialogInput && <ReplyHeader></ReplyHeader>}
|
||
</Box>
|
||
<Divider color={colors.borderColor}></Divider>
|
||
</>)
|
||
} |