{
useEffect(() => {
dispatch(setMenuActiveGroupPage('chat'));
}, []);
- return <>>;
+ return (
+
+ {' '}
+ Пока пусто :(
+
+ );
};
diff --git a/src/views/home/group/contests/Contests.tsx b/src/views/home/group/contests/Contests.tsx
index 39faea4..5df4e25 100644
--- a/src/views/home/group/contests/Contests.tsx
+++ b/src/views/home/group/contests/Contests.tsx
@@ -8,5 +8,10 @@ export const Contests = () => {
useEffect(() => {
dispatch(setMenuActiveGroupPage('contests'));
}, []);
- return <>>;
+ return (
+
+ {' '}
+ Пока пусто :(
+
+ );
};
diff --git a/src/views/home/groups/ModalInvite.tsx b/src/views/home/groups/ModalInvite.tsx
index a00cfec..7983671 100644
--- a/src/views/home/groups/ModalInvite.tsx
+++ b/src/views/home/groups/ModalInvite.tsx
@@ -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
= ({
if (!inviteLink) return;
try {
await navigator.clipboard.writeText(inviteLink);
+ toastSuccess('Приглашение скопировано в буфер обмена!');
setActive(false);
} catch (err) {
console.error('Не удалось скопировать ссылку:', err);
diff --git a/src/views/home/rightpanel/Group.tsx b/src/views/home/rightpanel/Group.tsx
deleted file mode 100644
index 28b26fb..0000000
--- a/src/views/home/rightpanel/Group.tsx
+++ /dev/null
@@ -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 (
-
-
- Пользователи
-
-
- {items.map((v, i) => {
- return (
- <>
- {
-
-
-
-
- {v.name}
-
-
- {v.role}
-
-
-
- }
- {i + 1 != items.length && (
-
- )}
- >
- );
- })}
-
- );
-};
diff --git a/src/views/home/rightpanel/group/Group.tsx b/src/views/home/rightpanel/group/Group.tsx
new file mode 100644
index 0000000..f1f9d7f
--- /dev/null
+++ b/src/views/home/rightpanel/group/Group.tsx
@@ -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 ;
+ }
+
+ const dispatch = useAppDispatch();
+
+ const [user, setUser] = useState();
+ const [myUser, setMyUser] = useState();
+ const [isAdmin, setIsAdmin] = useState(false);
+ const [modalLeaveActive, setModalLeaveActive] = useState(false);
+ const [modalUpdateActive, setModalUpdateActive] = useState(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 (
+
+
+ Пользователи
+
+
+ {group?.members.map((v, i) => {
+ return (
+ <>
+ {
+
+
+
+
+ {v.username}
+
+
+ {v.role +
+ (Number(userId) == v.userId
+ ? ' (Вы)'
+ : '')}
+
+
+ {(isAdmin || Number(userId) == v.userId) &&
+ !v.role.includes('Creator') && (
+
{
+ if (
+ Number(userId) == v.userId
+ ) {
+ setModalLeaveActive(true);
+ return;
+ }
+ if (isAdmin) {
+ setUser(v);
+ setModalUpdateActive(true);
+ return;
+ }
+ }}
+ >
+ {Number(userId) == v.userId ? (
+

+ ) : isAdmin ? (
+

+ ) : (
+ <>>
+ )}
+
+ )}
+
+ }
+ {i + 1 != group?.members.length && (
+
+ )}
+ >
+ );
+ })}
+
+
+
+
+ );
+};
diff --git a/src/views/home/rightpanel/group/ModalLeave.tsx b/src/views/home/rightpanel/group/ModalLeave.tsx
new file mode 100644
index 0000000..5427b2f
--- /dev/null
+++ b/src/views/home/rightpanel/group/ModalLeave.tsx
@@ -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 = ({
+ active,
+ setActive,
+ groupName,
+ groupId,
+ userId,
+}) => {
+ const statusLeave = useAppSelector(
+ (state) => state.groups.removeGroupMember.status,
+ );
+ const dispatch = useAppDispatch();
+ const navigate = useNavigate();
+
+ const [modalConfirmActive, setModalConfirmActive] =
+ useState(false);
+
+ useEffect(() => {
+ if (statusLeave == 'successful') {
+ dispatch(
+ setGroupsStatus({ key: 'removeGroupMember', status: 'idle' }),
+ );
+ setActive(false);
+ navigate('/home/groups');
+ }
+ }, [statusLeave]);
+
+ return (
+ <>
+
+
+
+ Вы действительно хотите покинуть группу:
+
+
+ "{groupName}" #{groupId}?
+
+
+
{
+ setModalConfirmActive(true);
+ }}
+ text={
+ statusLeave == 'loading'
+ ? 'Покинуть...'
+ : 'Покинуть'
+ }
+ disabled={statusLeave == 'loading'}
+ color="error"
+ />
+ {
+ setActive(false);
+ }}
+ text="Отмена"
+ />
+
+
+ {
+ dispatch(
+ removeGroupMember({
+ groupId,
+ memberId: userId,
+ }),
+ );
+ }}
+ />
+
+ >
+ );
+};
+
+export default ModalLeave;
diff --git a/src/views/home/rightpanel/group/ModalUpdate.tsx b/src/views/home/rightpanel/group/ModalUpdate.tsx
new file mode 100644
index 0000000..3062cd2
--- /dev/null
+++ b/src/views/home/rightpanel/group/ModalUpdate.tsx
@@ -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 = ({
+ 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(false);
+ const [modalConfirmRoleActive, setModalConfirmRoleActive] =
+ useState(false);
+ const [userRole, setUserRole] = useState('');
+
+ 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 (
+
+
+
+ Управление участниками группы:
+
+
+ "{groupName}" #{groupId}
+
+
Пользователь: {user?.username}
+
Текущая роль: {user?.role}
+
+
+ {
+ return { text: v, value: v };
+ })}
+ onChange={(v) => {
+ setUserRole(v);
+ }}
+ />
+
+
{
+ setModalConfirmRoleActive(true);
+ }}
+ text={
+ statusUpdate == 'loading'
+ ? 'Назначить...'
+ : 'Назначить'
+ }
+ disabled={statusUpdate == 'loading'}
+ color="secondary"
+ />
+
+
+
+
+ Исключить пользователя?
+
+
{
+ setModalConfirmDeleteUser(true);
+ }}
+ text={
+ statusLeave == 'loading'
+ ? 'Исключить...'
+ : 'Исключить'
+ }
+ disabled={statusLeave == 'loading'}
+ color="error"
+ />
+
+
+
+ {
+ setActive(false);
+ }}
+ text="Отмена"
+ />
+
+
+
+ {
+ if (user) {
+ dispatch(
+ removeGroupMember({
+ groupId,
+ memberId: user.userId,
+ }),
+ );
+ }
+ }}
+ />
+
+ {
+ if (user) {
+ dispatch(
+ addGroupMember({
+ groupId,
+ userId: user.userId,
+ role:
+ userRole == 'Creator'
+ ? 'Administrator, Creator'
+ : userRole,
+ }),
+ );
+ }
+ }}
+ />
+
+ );
+};
+
+export default ModalUpdate;
diff --git a/tsconfig.app.tsbuildinfo b/tsconfig.app.tsbuildinfo
index f725851..22d984f 100644
--- a/tsconfig.app.tsbuildinfo
+++ b/tsconfig.app.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/app.tsx","./src/axios.ts","./src/main.tsx","./src/vite-env.d.ts","./src/assets/icons/account/index.ts","./src/assets/icons/auth/index.ts","./src/assets/icons/filters/index.ts","./src/assets/icons/groups/index.ts","./src/assets/icons/header/index.ts","./src/assets/icons/input/index.ts","./src/assets/icons/menu/index.ts","./src/assets/icons/missions/index.ts","./src/assets/logos/index.ts","./src/components/button/primarybutton.tsx","./src/components/button/reversebutton.tsx","./src/components/button/secondarybutton.tsx","./src/components/checkbox/checkbox.tsx","./src/components/drop-down-list/dropdownlist.tsx","./src/components/drop-down-list/filter.tsx","./src/components/drop-down-list/sorter.tsx","./src/components/input/daterangeinput.tsx","./src/components/input/input.tsx","./src/components/input/searchinput.tsx","./src/components/modal/modal.tsx","./src/components/router/protectedroute.tsx","./src/components/switch/switch.tsx","./src/config/colors.ts","./src/hooks/useclickoutside.ts","./src/hooks/usequery.ts","./src/lib/cn.ts","./src/pages/article.tsx","./src/pages/articleeditor.tsx","./src/pages/contesteditor.tsx","./src/pages/home.tsx","./src/pages/mission.tsx","./src/redux/hooks.ts","./src/redux/store.ts","./src/redux/slices/articles.ts","./src/redux/slices/auth.ts","./src/redux/slices/contests.ts","./src/redux/slices/groups.ts","./src/redux/slices/missions.ts","./src/redux/slices/store.ts","./src/redux/slices/submit.ts","./src/views/article/header.tsx","./src/views/articleeditor/editor.tsx","./src/views/articleeditor/header.tsx","./src/views/articleeditor/marckdownpreview.tsx","./src/views/home/account/account.tsx","./src/views/home/account/accoutmenu.tsx","./src/views/home/account/rightpanel.tsx","./src/views/home/account/articles/articlesblock.tsx","./src/views/home/account/contests/contests.tsx","./src/views/home/account/contests/contestsblock.tsx","./src/views/home/account/contests/mycontestitem.tsx","./src/views/home/account/contests/registercontestitem.tsx","./src/views/home/account/missions/missions.tsx","./src/views/home/account/missions/missionsblock.tsx","./src/views/home/account/missions/mymissionitem.tsx","./src/views/home/articles/articleitem.tsx","./src/views/home/articles/articles.tsx","./src/views/home/articles/filter.tsx","./src/views/home/auth/login.tsx","./src/views/home/auth/register.tsx","./src/views/home/contest/contest.tsx","./src/views/home/contest/missionitem.tsx","./src/views/home/contest/missions.tsx","./src/views/home/contest/submissionitem.tsx","./src/views/home/contest/submissions.tsx","./src/views/home/contests/contestitem.tsx","./src/views/home/contests/contests.tsx","./src/views/home/contests/contestsblock.tsx","./src/views/home/contests/filter.tsx","./src/views/home/contests/modalcreate.tsx","./src/views/home/groups/filter.tsx","./src/views/home/groups/group.tsx","./src/views/home/groups/groupitem.tsx","./src/views/home/groups/groups.tsx","./src/views/home/groups/groupsblock.tsx","./src/views/home/groups/modalcreate.tsx","./src/views/home/groups/modalupdate.tsx","./src/views/home/menu/menu.tsx","./src/views/home/menu/menuitem.tsx","./src/views/home/missions/filter.tsx","./src/views/home/missions/missionitem.tsx","./src/views/home/missions/missions.tsx","./src/views/home/missions/modalcreate.tsx","./src/views/mission/codeeditor/codeeditor.tsx","./src/views/mission/statement/header.tsx","./src/views/mission/statement/latextcontainer.tsx","./src/views/mission/statement/missionsubmissions.tsx","./src/views/mission/statement/statement.tsx","./src/views/mission/statement/submissionitem.tsx","./src/views/mission/submission/submission.tsx"],"version":"5.6.2"}
\ No newline at end of file
+{"root":["./src/app.tsx","./src/axios.ts","./src/main.tsx","./src/vite-env.d.ts","./src/assets/icons/account/index.ts","./src/assets/icons/auth/index.ts","./src/assets/icons/filters/index.ts","./src/assets/icons/group/index.ts","./src/assets/icons/groups/index.ts","./src/assets/icons/header/index.ts","./src/assets/icons/input/index.ts","./src/assets/icons/menu/index.ts","./src/assets/icons/missions/index.ts","./src/assets/logos/index.ts","./src/components/button/primarybutton.tsx","./src/components/button/reversebutton.tsx","./src/components/button/secondarybutton.tsx","./src/components/checkbox/checkbox.tsx","./src/components/drop-down-list/dropdownlist.tsx","./src/components/drop-down-list/filter.tsx","./src/components/drop-down-list/sorter.tsx","./src/components/input/daterangeinput.tsx","./src/components/input/input.tsx","./src/components/input/searchinput.tsx","./src/components/modal/confirmmodal.tsx","./src/components/modal/modal.tsx","./src/components/router/protectedroute.tsx","./src/components/switch/switch.tsx","./src/config/colors.ts","./src/hooks/useclickoutside.ts","./src/hooks/usequery.ts","./src/lib/cn.ts","./src/lib/toastnotification.ts","./src/pages/article.tsx","./src/pages/articleeditor.tsx","./src/pages/contesteditor.tsx","./src/pages/home.tsx","./src/pages/mission.tsx","./src/redux/hooks.ts","./src/redux/store.ts","./src/redux/slices/articles.ts","./src/redux/slices/auth.ts","./src/redux/slices/contests.ts","./src/redux/slices/groupfeed.ts","./src/redux/slices/groups.ts","./src/redux/slices/missions.ts","./src/redux/slices/store.ts","./src/redux/slices/submit.ts","./src/views/article/header.tsx","./src/views/articleeditor/editor.tsx","./src/views/articleeditor/header.tsx","./src/views/articleeditor/marckdownpreview.tsx","./src/views/home/account/account.tsx","./src/views/home/account/accoutmenu.tsx","./src/views/home/account/rightpanel.tsx","./src/views/home/account/articles/articlesblock.tsx","./src/views/home/account/contests/contests.tsx","./src/views/home/account/contests/contestsblock.tsx","./src/views/home/account/contests/mycontestitem.tsx","./src/views/home/account/contests/registercontestitem.tsx","./src/views/home/account/missions/missions.tsx","./src/views/home/account/missions/missionsblock.tsx","./src/views/home/account/missions/mymissionitem.tsx","./src/views/home/articles/articleitem.tsx","./src/views/home/articles/articles.tsx","./src/views/home/articles/filter.tsx","./src/views/home/auth/login.tsx","./src/views/home/auth/register.tsx","./src/views/home/contest/contest.tsx","./src/views/home/contest/missionitem.tsx","./src/views/home/contest/missions.tsx","./src/views/home/contest/submissionitem.tsx","./src/views/home/contest/submissions.tsx","./src/views/home/contests/contestitem.tsx","./src/views/home/contests/contests.tsx","./src/views/home/contests/contestsblock.tsx","./src/views/home/contests/filter.tsx","./src/views/home/contests/modalcreate.tsx","./src/views/home/group/group.tsx","./src/views/home/group/groupmenu.tsx","./src/views/home/group/chat/chat.tsx","./src/views/home/group/contests/contests.tsx","./src/views/home/group/posts/modalcreate.tsx","./src/views/home/group/posts/modalupdate.tsx","./src/views/home/group/posts/postitem.tsx","./src/views/home/group/posts/posts.tsx","./src/views/home/groupinviter/groupinvite.tsx","./src/views/home/groups/filter.tsx","./src/views/home/groups/groupitem.tsx","./src/views/home/groups/groups.tsx","./src/views/home/groups/groupsblock.tsx","./src/views/home/groups/modalcreate.tsx","./src/views/home/groups/modalinvite.tsx","./src/views/home/groups/modalupdate.tsx","./src/views/home/menu/menu.tsx","./src/views/home/menu/menuitem.tsx","./src/views/home/missions/filter.tsx","./src/views/home/missions/missionitem.tsx","./src/views/home/missions/missions.tsx","./src/views/home/missions/modalcreate.tsx","./src/views/home/rightpanel/articles.tsx","./src/views/home/rightpanel/missions.tsx","./src/views/home/rightpanel/group/group.tsx","./src/views/home/rightpanel/group/modalleave.tsx","./src/views/home/rightpanel/group/modalupdate.tsx","./src/views/mission/codeeditor/codeeditor.tsx","./src/views/mission/statement/header.tsx","./src/views/mission/statement/latextcontainer.tsx","./src/views/mission/statement/missionsubmissions.tsx","./src/views/mission/statement/statement.tsx","./src/views/mission/statement/submissionitem.tsx","./src/views/mission/submission/submission.tsx"],"errors":true,"version":"5.6.2"}
\ No newline at end of file