Files
desktop/app/views/GroupInfo/GroupInfo.tsx
rosetta 83f38dc63f 'init'
2026-01-30 05:01:05 +02:00

168 lines
8.4 KiB
TypeScript

import { ActionAvatar } from "@/app/components/ActionAvatar/ActionAvatar";
import { Breadcrumbs } from "@/app/components/Breadcrumbs/Breadcrumbs";
import { GroupInvite } from "@/app/components/GroupInvite/GroupInvite";
import { InternalScreen } from "@/app/components/InternalScreen/InternalScreen";
import { KeyImage } from "@/app/components/KeyImage/KeyImage";
import { SettingsInput } from "@/app/components/SettingsInput/SettingsInput";
import { SettingsPaper } from "@/app/components/SettingsPaper/SettingsPaper";
import { SettingsText } from "@/app/components/SettingsText/SettingsText";
import { SettingsTitle } from "@/app/components/SettingsTitle/SettingsTitle";
import { UsersTable } from "@/app/components/UsersTable/UsersTable";
import { VerifiedBadge } from "@/app/components/VerifiedBadge/VerifiedBadge";
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
import { useGroupMembers } from "@/app/providers/InformationProvider/useGroupMembers";
import { useGroups } from "@/app/providers/DialogProvider/useGroups";
import { useGroupInformation } from "@/app/providers/InformationProvider/useGroupInformation";
import { Button, Flex, Paper, Skeleton, Text, useMantineTheme } from "@mantine/core";
import { IconBan, IconDoorExit, IconMessage } from "@tabler/icons-react";
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { modals } from "@mantine/modals";
export function GroupInfo() {
const params = useParams();
const {groupInfo} = useGroupInformation(params.id!);
const {members, loading: membersLoading} = useGroupMembers(params.id!, true);
const publicKey = usePublicKey();
const isAdmin = members.length > 0 && members[0] == publicKey;
const colors = useRosettaColors();
const navigate = useNavigate();
const [groupKey, setGroupKey] = useState<string>('');
const {getGroupKey, leaveGroup, banUserOnGroup, loading, getPrefix} = useGroups();
const theme = useMantineTheme();
useEffect(() => {
initGroupKey();
}, [params.id]);
const initGroupKey = async () => {
const key = await getGroupKey(groupInfo.groupId);
setGroupKey(key);
}
const leaveGroupWithModal = () => {
modals.openConfirmModal({
title: 'Leave group',
centered: true,
children: (
<Text size="sm">
You are attempting to leave the group. Are you sure you want to proceed?
</Text>
),
withCloseButton: false,
labels: { confirm: 'Leave', cancel: "Cancel" },
confirmProps: { color: 'red' },
onConfirm: () => {
leaveGroup(groupInfo.groupId);
}
});
}
const banUserWithModal = (userPublicKey: string) => {
modals.openConfirmModal({
title: 'Ban user from group',
centered: true,
children: (
<Text size="sm">
You are attempting to ban this user from the group.
</Text>
),
withCloseButton: false,
labels: { confirm: 'Ban', cancel: "Cancel" },
confirmProps: { color: 'red' },
onConfirm: () => {
confirmBan(userPublicKey);
}
});
}
const confirmBan = (userPublicKey: string) => {
banUserOnGroup(userPublicKey, groupInfo.groupId);
}
return (
<>
<Breadcrumbs text={groupInfo.title} rightSection={
<Button loading={loading} color={'red'} leftSection={<IconDoorExit size={15} />} onClick={leaveGroupWithModal} p={0} pr={6} variant={'transparent'}>Leave</Button>
}></Breadcrumbs>
<InternalScreen>
{(members.length > 0 || !membersLoading) && (
<>
<Paper radius="md" p="lg" bg={'transparent'}>
<ActionAvatar
forceChangeable={isAdmin}
title={groupInfo.title}
publicKey={getPrefix() + groupInfo.groupId} />
<Flex align={'center'} mt={'md'} justify={'center'} gap={5}>
<Text ta="center" fz="lg" fw={500}>{groupInfo.title.trim()}</Text>
</Flex>
<Text ta="center" c="dimmed" fz="sm">
{members.length} member{members.length !== 1 ? 's' : ''}
</Text>
</Paper>
{groupInfo.description.trim().length > 0 && (
<SettingsPaper p="xs">
<Text fw={500} pl={'xs'} fz={'xs'} c={'blue'}>Information</Text>
<Text pl={'xs'} fz={12} mt={3} c={'dimmed'}>
{groupInfo.description.trim()}
</Text>
</SettingsPaper>
)}
{isAdmin && (
<GroupInvite groupId={groupInfo.groupId} mt={'sm'}></GroupInvite>
)}
<SettingsInput.Clickable mt={'sm'} onClick={() => navigate('/main/groupencrypt/' + groupKey)} hit="Encryption key" settingsIcon={
<KeyImage radius={0} colors={[
theme.colors.blue[1],
theme.colors.blue[2],
theme.colors.blue[3],
theme.colors.blue[4],
theme.colors.blue[5]
]} size={18} keyRender={groupKey}></KeyImage>
}></SettingsInput.Clickable>
<SettingsText>Click to see encryption key for secure group communication</SettingsText>
{members.length > 0 && isAdmin && (
<>
<SettingsTitle mt={'sm'}>Group Members</SettingsTitle>
<UsersTable rightSection={(userPublicKey: string) => (
<>
<IconMessage onClick={() => navigate('/main/chat/' + userPublicKey)} stroke={1.4} size={20} color={colors.brandColor}></IconMessage>
{publicKey == userPublicKey && (
<IconDoorExit onClick={leaveGroupWithModal} stroke={1.4} size={20} color={colors.error}></IconDoorExit>
)}
{publicKey != userPublicKey && isAdmin && (
<IconBan onClick={() => banUserWithModal(userPublicKey)} stroke={1.4} size={20} color={colors.error}></IconBan>
)}
</>
)} usersPublicKeys={members} />
<SettingsText>
Members are listed in order of group creation. The first member is the group admin and can manage group settings.
</SettingsText>
</>
)}
{!isAdmin && (
<Flex mt={'lg'} gap={5} align={'center'}>
<Text fz={10} pl={'xs'} c={'gray'}>
Group administrator has marked in messages with
</Text>
<VerifiedBadge size={17} color={'gold'} verified={3}></VerifiedBadge>
</Flex>
)}
</>
)}
{membersLoading && members.length <= 0 && (
<>
<Flex direction={'column'} w={'100%'}>
<Skeleton h={150}></Skeleton>
<Skeleton h={50} mt={'sm'}></Skeleton>
<Skeleton h={50} mt={'sm'}></Skeleton>
<Skeleton h={50} mt={'sm'}></Skeleton>
</Flex>
</>
)}
</InternalScreen>
</>
);
}