user role controller
This commit is contained in:
@@ -24,8 +24,6 @@ const Group: FC<GroupsBlockProps> = () => {
|
||||
dispatch(fetchGroupById(groupId));
|
||||
}, [groupId]);
|
||||
|
||||
console.log(group);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -8,5 +8,10 @@ export const Chat = () => {
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActiveGroupPage('chat'));
|
||||
}, []);
|
||||
return <></>;
|
||||
return (
|
||||
<div className="h-full overflow-y-scroll thin-dark-scrollbar flex items-center justify-center font-bold text-liquid-white text-[50px]">
|
||||
{' '}
|
||||
Пока пусто :(
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,5 +8,10 @@ export const Contests = () => {
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActiveGroupPage('contests'));
|
||||
}, []);
|
||||
return <></>;
|
||||
return (
|
||||
<div className="h-full overflow-y-scroll thin-dark-scrollbar flex items-center justify-center font-bold text-liquid-white text-[50px]">
|
||||
{' '}
|
||||
Пока пусто :(
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Modal } from '../../../components/modal/Modal';
|
||||
import { PrimaryButton } from '../../../components/button/PrimaryButton';
|
||||
import { SecondaryButton } from '../../../components/button/SecondaryButton';
|
||||
import { Input } from '../../../components/input/Input';
|
||||
import { toastSuccess } from '../../../lib/toastNotification';
|
||||
|
||||
interface ModalInviteProps {
|
||||
active: boolean;
|
||||
@@ -51,6 +52,7 @@ const ModalInvite: FC<ModalInviteProps> = ({
|
||||
if (!inviteLink) return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(inviteLink);
|
||||
toastSuccess('Приглашение скопировано в буфер обмена!');
|
||||
setActive(false);
|
||||
} catch (err) {
|
||||
console.error('Не удалось скопировать ссылку:', err);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
export const GroupRightPanel: FC = () => {
|
||||
const items = [
|
||||
{
|
||||
name: 'Игнат Герасименко',
|
||||
role: 'Администратор',
|
||||
},
|
||||
{
|
||||
name: 'Алиса Макаренко',
|
||||
role: 'Модератор',
|
||||
},
|
||||
{
|
||||
name: 'Федор Картман',
|
||||
role: 'Модератор',
|
||||
},
|
||||
{
|
||||
name: 'Карина Механаджанович',
|
||||
role: 'Участник',
|
||||
},
|
||||
{
|
||||
name: 'Михаил Ангрский',
|
||||
role: 'Участник',
|
||||
},
|
||||
{
|
||||
name: 'newuser',
|
||||
role: 'Участник (Вы)',
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="h-screen w-full overflow-y-scroll thin-dark-scrollbar p-[20px] gap-[5px] flex flex-col">
|
||||
<div className="text-liquid-white font-bold text-[18px]">
|
||||
Пользователи
|
||||
</div>
|
||||
|
||||
{items.map((v, i) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
<div className="text-liquid-light text-[16px] grid grid-cols-[40px,1fr] gap-[10px] items-center cursor-pointer hover:bg-liquid-lighter transition-all duration-300 rounded-[10px] p-[5px]">
|
||||
<div className="h-[40px] w-[40px] rounded-[10px] bg-[#D9D9D9]"></div>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-liquid-white font-bold text-[16px] leading-5">
|
||||
{v.name}
|
||||
</div>
|
||||
<div className="text-liquid-light font-normal text-[16px] leading-5">
|
||||
{v.role}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{i + 1 != items.length && (
|
||||
<div className="h-[1px] w-full bg-liquid-lighter"></div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
126
src/views/home/rightpanel/group/Group.tsx
Normal file
126
src/views/home/rightpanel/group/Group.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { Navigate, useParams } from 'react-router-dom';
|
||||
import { useAppDispatch, useAppSelector } from '../../../../redux/hooks';
|
||||
import { fetchGroupById, GroupMember } from '../../../../redux/slices/groups';
|
||||
import { Edit } from '../../../../assets/icons/input';
|
||||
import { Logout } from '../../../../assets/icons/group';
|
||||
import ModalLeave from './ModalLeave';
|
||||
import ModalUpdate from './ModalUpdate';
|
||||
|
||||
export const GroupRightPanel: FC = () => {
|
||||
const groupId = Number(useParams<{ groupId: string }>().groupId);
|
||||
if (!groupId) {
|
||||
return <Navigate to="/home/groups" replace />;
|
||||
}
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [user, setUser] = useState<GroupMember | undefined>();
|
||||
const [myUser, setMyUser] = useState<GroupMember | undefined>();
|
||||
const [isAdmin, setIsAdmin] = useState<boolean>(false);
|
||||
const [modalLeaveActive, setModalLeaveActive] = useState<boolean>(false);
|
||||
const [modalUpdateActive, setModalUpdateActive] = useState<boolean>(false);
|
||||
const { id: userId } = useAppSelector((state) => state.auth);
|
||||
|
||||
const { group } = useAppSelector((state) => state.groups.fetchGroupById);
|
||||
useEffect(() => {
|
||||
dispatch(fetchGroupById(groupId));
|
||||
}, [groupId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!group) return;
|
||||
|
||||
const isUserAdmin =
|
||||
group.members?.some(
|
||||
(m) =>
|
||||
Number(m.userId) === Number(userId) &&
|
||||
m.role.includes('Administrator'),
|
||||
) || false;
|
||||
|
||||
setIsAdmin(isUserAdmin);
|
||||
|
||||
const member = group.members?.find(
|
||||
(m) => Number(m.userId) === Number(userId),
|
||||
);
|
||||
|
||||
setMyUser(member);
|
||||
}, [group, userId]);
|
||||
|
||||
return (
|
||||
<div className="h-screen w-full overflow-y-scroll thin-dark-scrollbar p-[20px] gap-[5px] flex flex-col">
|
||||
<div className="text-liquid-white font-bold text-[18px]">
|
||||
Пользователи
|
||||
</div>
|
||||
|
||||
{group?.members.map((v, i) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
<div className="text-liquid-light text-[16px] grid grid-cols-[40px,1fr] gap-[10px] items-center cursor-pointer hover:bg-liquid-lighter transition-all duration-300 rounded-[10px] p-[5px] group">
|
||||
<div className="h-[40px] w-[40px] rounded-[10px] bg-[#D9D9D9]"></div>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-liquid-white font-bold text-[16px] leading-5">
|
||||
{v.username}
|
||||
</div>
|
||||
<div className="text-liquid-light font-normal text-[16px] leading-5">
|
||||
{v.role +
|
||||
(Number(userId) == v.userId
|
||||
? ' (Вы)'
|
||||
: '')}
|
||||
</div>
|
||||
</div>
|
||||
{(isAdmin || Number(userId) == v.userId) &&
|
||||
!v.role.includes('Creator') && (
|
||||
<div
|
||||
className="h-[34px] w-[34px] absolute right-[34px] opacity-0 group-hover:opacity-100 transition-all duration-300 hover:bg-liquid-light rounded-[10px] p-[5px] active:scale-90"
|
||||
onClick={() => {
|
||||
if (
|
||||
Number(userId) == v.userId
|
||||
) {
|
||||
setModalLeaveActive(true);
|
||||
return;
|
||||
}
|
||||
if (isAdmin) {
|
||||
setUser(v);
|
||||
setModalUpdateActive(true);
|
||||
return;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{Number(userId) == v.userId ? (
|
||||
<img src={Logout} />
|
||||
) : isAdmin ? (
|
||||
<img src={Edit} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
{i + 1 != group?.members.length && (
|
||||
<div className="h-[1px] w-full bg-liquid-lighter"></div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
|
||||
<ModalLeave
|
||||
groupId={groupId}
|
||||
groupName={group?.name}
|
||||
userId={Number(userId)}
|
||||
active={modalLeaveActive}
|
||||
setActive={setModalLeaveActive}
|
||||
/>
|
||||
<ModalUpdate
|
||||
groupId={groupId}
|
||||
groupName={group?.name}
|
||||
userId={Number(userId)}
|
||||
user={user}
|
||||
adminUser={myUser}
|
||||
active={modalUpdateActive}
|
||||
setActive={setModalUpdateActive}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
107
src/views/home/rightpanel/group/ModalLeave.tsx
Normal file
107
src/views/home/rightpanel/group/ModalLeave.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { Modal } from '../../../../components/modal/Modal';
|
||||
import { PrimaryButton } from '../../../../components/button/PrimaryButton';
|
||||
import { SecondaryButton } from '../../../../components/button/SecondaryButton';
|
||||
import { Input } from '../../../../components/input/Input';
|
||||
import { useAppDispatch, useAppSelector } from '../../../../redux/hooks';
|
||||
import {
|
||||
deleteGroup,
|
||||
removeGroupMember,
|
||||
setGroupsStatus,
|
||||
updateGroup,
|
||||
} from '../../../../redux/slices/groups';
|
||||
import ConfirmModal from '../../../../components/modal/ConfirmModal';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
interface ModalLeaveProps {
|
||||
active: boolean;
|
||||
setActive: (value: boolean) => void;
|
||||
groupId: number;
|
||||
groupName?: string;
|
||||
userId: number;
|
||||
}
|
||||
|
||||
const ModalLeave: FC<ModalLeaveProps> = ({
|
||||
active,
|
||||
setActive,
|
||||
groupName,
|
||||
groupId,
|
||||
userId,
|
||||
}) => {
|
||||
const statusLeave = useAppSelector(
|
||||
(state) => state.groups.removeGroupMember.status,
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [modalConfirmActive, setModalConfirmActive] =
|
||||
useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (statusLeave == 'successful') {
|
||||
dispatch(
|
||||
setGroupsStatus({ key: 'removeGroupMember', status: 'idle' }),
|
||||
);
|
||||
setActive(false);
|
||||
navigate('/home/groups');
|
||||
}
|
||||
}, [statusLeave]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white"
|
||||
onOpenChange={setActive}
|
||||
open={active}
|
||||
backdrop="blur"
|
||||
>
|
||||
<div className="w-[500px]">
|
||||
<div className="font-bold text-[30px]">
|
||||
Вы действительно хотите покинуть группу:
|
||||
</div>
|
||||
<div className="font-bold text-[20px] mt-[20px]">
|
||||
"{groupName}" #{groupId}?
|
||||
</div>
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
setModalConfirmActive(true);
|
||||
}}
|
||||
text={
|
||||
statusLeave == 'loading'
|
||||
? 'Покинуть...'
|
||||
: 'Покинуть'
|
||||
}
|
||||
disabled={statusLeave == 'loading'}
|
||||
color="error"
|
||||
/>
|
||||
<SecondaryButton
|
||||
onClick={() => {
|
||||
setActive(false);
|
||||
}}
|
||||
text="Отмена"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ConfirmModal
|
||||
active={modalConfirmActive}
|
||||
setActive={setModalConfirmActive}
|
||||
title="Подтвердите действия"
|
||||
message="Вы действительно хотите покинуть группу?"
|
||||
confirmColor="error"
|
||||
confirmText="Покинуть"
|
||||
onConfirmClick={() => {
|
||||
dispatch(
|
||||
removeGroupMember({
|
||||
groupId,
|
||||
memberId: userId,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalLeave;
|
||||
208
src/views/home/rightpanel/group/ModalUpdate.tsx
Normal file
208
src/views/home/rightpanel/group/ModalUpdate.tsx
Normal file
@@ -0,0 +1,208 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { Modal } from '../../../../components/modal/Modal';
|
||||
import { PrimaryButton } from '../../../../components/button/PrimaryButton';
|
||||
import { SecondaryButton } from '../../../../components/button/SecondaryButton';
|
||||
import { Input } from '../../../../components/input/Input';
|
||||
import { useAppDispatch, useAppSelector } from '../../../../redux/hooks';
|
||||
import {
|
||||
addGroupMember,
|
||||
deleteGroup,
|
||||
fetchGroupById,
|
||||
GroupMember,
|
||||
removeGroupMember,
|
||||
setGroupsStatus,
|
||||
updateGroup,
|
||||
} from '../../../../redux/slices/groups';
|
||||
import ConfirmModal from '../../../../components/modal/ConfirmModal';
|
||||
import { DropDownList } from '../../../../components/drop-down-list/DropDownList';
|
||||
import { ReverseButton } from '../../../../components/button/ReverseButton';
|
||||
|
||||
interface ModalUpdateProps {
|
||||
active: boolean;
|
||||
setActive: (value: boolean) => void;
|
||||
groupId: number;
|
||||
userId: number;
|
||||
user?: GroupMember;
|
||||
adminUser?: GroupMember;
|
||||
groupName?: string;
|
||||
}
|
||||
|
||||
const ModalUpdate: FC<ModalUpdateProps> = ({
|
||||
active,
|
||||
setActive,
|
||||
groupId,
|
||||
userId,
|
||||
user,
|
||||
adminUser,
|
||||
groupName,
|
||||
}) => {
|
||||
const statusLeave = useAppSelector(
|
||||
(state) => state.groups.removeGroupMember.status,
|
||||
);
|
||||
const statusUpdate = useAppSelector(
|
||||
(state) => state.groups.addGroupMember.status,
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [modalConfirmDeleteUser, setModalConfirmDeleteUser] =
|
||||
useState<boolean>(false);
|
||||
const [modalConfirmRoleActive, setModalConfirmRoleActive] =
|
||||
useState<boolean>(false);
|
||||
const [userRole, setUserRole] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
}
|
||||
}, [active]);
|
||||
|
||||
useEffect(() => {
|
||||
if (statusLeave == 'successful') {
|
||||
dispatch(
|
||||
setGroupsStatus({ key: 'removeGroupMember', status: 'idle' }),
|
||||
);
|
||||
dispatch(fetchGroupById(groupId));
|
||||
setActive(false);
|
||||
}
|
||||
}, [statusLeave]);
|
||||
|
||||
useEffect(() => {
|
||||
if (statusUpdate == 'successful') {
|
||||
dispatch(
|
||||
setGroupsStatus({ key: 'addGroupMember', status: 'idle' }),
|
||||
);
|
||||
dispatch(fetchGroupById(groupId));
|
||||
setActive(false);
|
||||
}
|
||||
}, [statusUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(user);
|
||||
if (user) {
|
||||
setUserRole(
|
||||
user?.role.includes('Creator') ? 'Creator' : user?.role,
|
||||
);
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
const roles = [
|
||||
'Member',
|
||||
'Administrator',
|
||||
...(adminUser?.role.includes('Creator') ? ['Creator'] : []),
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white"
|
||||
onOpenChange={setActive}
|
||||
open={active}
|
||||
backdrop="blur"
|
||||
>
|
||||
<div className="w-[500px]">
|
||||
<div className="font-bold text-[30px]">
|
||||
Управление участниками группы:
|
||||
</div>
|
||||
<div className="font-bold text-[20px]">
|
||||
"{groupName}" #{groupId}
|
||||
</div>
|
||||
<div className="my-[5px]">Пользователь: {user?.username}</div>
|
||||
<div>Текущая роль: {user?.role}</div>
|
||||
<div className="flex flex-row w-full items-center justify-between mt-[20px] gap-[20px]">
|
||||
<div>
|
||||
<DropDownList
|
||||
defaultState={{ value: userRole, text: userRole }}
|
||||
weight="w-[230px]"
|
||||
items={roles.map((v) => {
|
||||
return { text: v, value: v };
|
||||
})}
|
||||
onChange={(v) => {
|
||||
setUserRole(v);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
setModalConfirmRoleActive(true);
|
||||
}}
|
||||
text={
|
||||
statusUpdate == 'loading'
|
||||
? 'Назначить...'
|
||||
: 'Назначить'
|
||||
}
|
||||
disabled={statusUpdate == 'loading'}
|
||||
color="secondary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row w-full items-center justify-between mt-[20px] gap-[20px]">
|
||||
<div className="font-bold text-[24px]">
|
||||
Исключить пользователя?
|
||||
</div>
|
||||
<ReverseButton
|
||||
onClick={() => {
|
||||
setModalConfirmDeleteUser(true);
|
||||
}}
|
||||
text={
|
||||
statusLeave == 'loading'
|
||||
? 'Исключить...'
|
||||
: 'Исключить'
|
||||
}
|
||||
disabled={statusLeave == 'loading'}
|
||||
color="error"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<SecondaryButton
|
||||
onClick={() => {
|
||||
setActive(false);
|
||||
}}
|
||||
text="Отмена"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ConfirmModal
|
||||
active={modalConfirmDeleteUser}
|
||||
setActive={setModalConfirmDeleteUser}
|
||||
title="Подтвердите действия"
|
||||
message={`Вы действительно хотите исключить пользователя ${user?.username}?`}
|
||||
confirmColor="error"
|
||||
confirmText="Исключить"
|
||||
onConfirmClick={() => {
|
||||
if (user) {
|
||||
dispatch(
|
||||
removeGroupMember({
|
||||
groupId,
|
||||
memberId: user.userId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
active={modalConfirmRoleActive}
|
||||
setActive={setModalConfirmRoleActive}
|
||||
title="Подтвердите действия"
|
||||
message={`Вы действительно хотите назначить пользователя ${user?.username} в качестве ${userRole}?`}
|
||||
confirmText="Назначить"
|
||||
onConfirmClick={() => {
|
||||
if (user) {
|
||||
dispatch(
|
||||
addGroupMember({
|
||||
groupId,
|
||||
userId: user.userId,
|
||||
role:
|
||||
userRole == 'Creator'
|
||||
? 'Administrator, Creator'
|
||||
: userRole,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalUpdate;
|
||||
Reference in New Issue
Block a user