add error toasts
This commit is contained in:
@@ -23,7 +23,11 @@ const Account = () => {
|
||||
const username = query.get('username') ?? myname ?? '';
|
||||
|
||||
useEffect(() => {
|
||||
if (username == myname) dispatch(setMenuActivePage('account'));
|
||||
if (username == myname) {
|
||||
dispatch(setMenuActivePage('account'));
|
||||
} else {
|
||||
dispatch(setMenuActivePage(''));
|
||||
}
|
||||
dispatch(
|
||||
fetchProfileMissions({
|
||||
username: username,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { PrimaryButton } from '../../../components/button/PrimaryButton';
|
||||
import { ReverseButton } from '../../../components/button/ReverseButton';
|
||||
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
|
||||
import { logout } from '../../../redux/slices/auth';
|
||||
@@ -77,13 +76,13 @@ const RightPanel = () => {
|
||||
)}`}
|
||||
</div>
|
||||
|
||||
{username == myname && (
|
||||
{/* {username == myname && (
|
||||
<PrimaryButton
|
||||
onClick={() => {}}
|
||||
text="Редактировать"
|
||||
className="w-full"
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
<div className="h-[1px] w-full bg-liquid-lighter"></div>
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
setMissionsStatus,
|
||||
} from '../../../../redux/slices/missions';
|
||||
import ConfirmModal from '../../../../components/modal/ConfirmModal';
|
||||
import { fetchProfileMissions } from '../../../../redux/slices/profile';
|
||||
import { useQuery } from '../../../../hooks/useQuery';
|
||||
|
||||
interface ItemProps {
|
||||
count: number;
|
||||
@@ -50,6 +52,10 @@ const Missions = () => {
|
||||
(state) => state.profile.missions,
|
||||
);
|
||||
|
||||
const myname = useAppSelector((state) => state.auth.username);
|
||||
const query = useQuery();
|
||||
const username = query.get('username') ?? myname ?? '';
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActiveProfilePage('missions'));
|
||||
}, []);
|
||||
@@ -115,7 +121,17 @@ const Missions = () => {
|
||||
confirmColor="error"
|
||||
confirmText="Удалить"
|
||||
onConfirmClick={() => {
|
||||
dispatch(deleteMission(taskdeleteId));
|
||||
dispatch(deleteMission(taskdeleteId))
|
||||
.unwrap()
|
||||
.then(() => {
|
||||
dispatch(
|
||||
fetchProfileMissions({
|
||||
username: username,
|
||||
recentPageSize: 1,
|
||||
authoredPageSize: 100,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ import GroupMenu from './GroupMenu';
|
||||
import { Posts } from './posts/Posts';
|
||||
import { Chat } from './chat/Chat';
|
||||
import { Contests } from './contests/Contests';
|
||||
import { setMenuActivePage } from '../../../redux/slices/store';
|
||||
|
||||
interface GroupsBlockProps {}
|
||||
|
||||
@@ -20,6 +21,7 @@ const Group: FC<GroupsBlockProps> = () => {
|
||||
const group = useAppSelector((state) => state.groups.fetchGroupById.group);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActivePage('groups'));
|
||||
dispatch(fetchGroupById(groupId));
|
||||
}, [groupId]);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { FC, useEffect, useState } from 'react';
|
||||
|
||||
import { useAppSelector, useAppDispatch } from '../../../../redux/hooks';
|
||||
import { fetchGroupPosts } from '../../../../redux/slices/groupfeed';
|
||||
import { SearchInput } from '../../../../components/input/SearchInput';
|
||||
import { setMenuActiveGroupPage } from '../../../../redux/slices/store';
|
||||
import { fetchGroupById } from '../../../../redux/slices/groups';
|
||||
import { SecondaryButton } from '../../../../components/button/SecondaryButton';
|
||||
@@ -57,13 +56,6 @@ export const Posts: FC<PostsProps> = ({ groupId }) => {
|
||||
<div className="h-full relative">
|
||||
<div className="grid grid-rows-[40px,1fr,40px] h-full relative min-h-0 gap-[20px]">
|
||||
<div className="h-[40px] mb-[20px] relative">
|
||||
<SearchInput
|
||||
className="w-[216px]"
|
||||
onChange={(v) => {
|
||||
v;
|
||||
}}
|
||||
placeholder="Поиск сообщений"
|
||||
/>
|
||||
{isAdmin && (
|
||||
<div className=" h-[40px] w-[180px] absolute top-0 right-0 flex items-center">
|
||||
<SecondaryButton
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
Account,
|
||||
Clipboard,
|
||||
Cup,
|
||||
Home,
|
||||
Openbook,
|
||||
Users,
|
||||
} from '../../../assets/icons/menu';
|
||||
@@ -12,7 +11,6 @@ import { useAppSelector } from '../../../redux/hooks';
|
||||
|
||||
const Menu = () => {
|
||||
const menuItems = [
|
||||
{ text: 'Главная', href: '/home', icon: Home, page: 'home' },
|
||||
{
|
||||
text: 'Задачи',
|
||||
href: '/home/missions',
|
||||
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
setMissionsStatus,
|
||||
uploadMission,
|
||||
} from '../../../redux/slices/missions';
|
||||
import { toastSuccess } from '../../../lib/toastNotification';
|
||||
import { cn } from '../../../lib/cn';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { NumberInput } from '../../../components/input/NumberInput';
|
||||
|
||||
interface ModalCreateProps {
|
||||
active: boolean;
|
||||
@@ -24,6 +28,8 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
const status = useAppSelector((state) => state.missions.statuses.upload);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [clickSubmit, setClickSubmit] = useState<boolean>(false);
|
||||
|
||||
const addTag = () => {
|
||||
const newTag = tagInput.trim();
|
||||
if (newTag && !tags.includes(newTag)) {
|
||||
@@ -43,13 +49,14 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!file) return alert('Выберите файл миссии!');
|
||||
setClickSubmit(true);
|
||||
if (!file) return;
|
||||
dispatch(uploadMission({ file, name, difficulty, tags }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'successful') {
|
||||
alert('Миссия успешно загружена!');
|
||||
toastSuccess('Миссия создана!');
|
||||
setName('');
|
||||
setDifficulty(1);
|
||||
setTags([]);
|
||||
@@ -60,9 +67,18 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
}, [status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (active == true) {
|
||||
setClickSubmit(false);
|
||||
}
|
||||
dispatch(setMissionsStatus({ key: 'upload', status: 'idle' }));
|
||||
}, [active]);
|
||||
|
||||
const getNameErrorMessage = (): string => {
|
||||
if (!clickSubmit) return '';
|
||||
if (name == '') return 'Поле не может быть пустым';
|
||||
return '';
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white"
|
||||
@@ -82,16 +98,17 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
defaultState={name}
|
||||
onChange={setName}
|
||||
placeholder="В яблочко"
|
||||
error={getNameErrorMessage()}
|
||||
/>
|
||||
|
||||
<Input
|
||||
<NumberInput
|
||||
name="difficulty"
|
||||
autocomplete="difficulty"
|
||||
className="mt-[10px]"
|
||||
type="number"
|
||||
label="Сложность"
|
||||
defaultState={'' + difficulty}
|
||||
onChange={(v) => setDifficulty(Number(v))}
|
||||
defaultState={difficulty}
|
||||
minValue={1}
|
||||
maxValue={3500}
|
||||
onChange={(v) => setDifficulty(v)}
|
||||
placeholder="1"
|
||||
/>
|
||||
|
||||
@@ -106,6 +123,16 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
className="hidden"
|
||||
/>
|
||||
</label>
|
||||
{
|
||||
<div
|
||||
className={cn(
|
||||
'text-liquid-red text-[14px] h-auto text-left mt-[5px] whitespace-pre-line overflow-hidden ',
|
||||
(!clickSubmit || file) && 'h-0 mt-0',
|
||||
)}
|
||||
>
|
||||
Необходимо выбрать файл задачи
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* Теги */}
|
||||
@@ -148,6 +175,17 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Создать пакет задачи можно на платформе{' '}
|
||||
<Link
|
||||
to={'https://polygon.codeforces.com'}
|
||||
target="_blank"
|
||||
className="text-[#7489ff] hover:text-[#8c9dfd] transition-color duration-300"
|
||||
>
|
||||
polygon
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<PrimaryButton
|
||||
onClick={handleSubmit}
|
||||
@@ -159,8 +197,6 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
text="Отмена"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{status == 'failed' && <div>error</div>}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FC, Fragment, useEffect, useState } from 'react';
|
||||
import { Navigate, useParams } from 'react-router-dom';
|
||||
import { Navigate, useNavigate, useParams } from 'react-router-dom';
|
||||
import { useAppDispatch, useAppSelector } from '../../../../redux/hooks';
|
||||
import { fetchGroupById, GroupMember } from '../../../../redux/slices/groups';
|
||||
import { Edit } from '../../../../assets/icons/input';
|
||||
@@ -13,6 +13,7 @@ export const GroupRightPanel: FC = () => {
|
||||
return <Navigate to="/home/groups" replace />;
|
||||
}
|
||||
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [user, setUser] = useState<GroupMember | undefined>();
|
||||
@@ -56,7 +57,14 @@ export const GroupRightPanel: FC = () => {
|
||||
return (
|
||||
<Fragment key={i}>
|
||||
{
|
||||
<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="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"
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`/home/account/missions?username=${v.username}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
<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">
|
||||
@@ -73,7 +81,8 @@ export const GroupRightPanel: FC = () => {
|
||||
!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={() => {
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (
|
||||
Number(userId) == v.userId
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user