group posts
This commit is contained in:
1436
package-lock.json
generated
1436
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,14 @@
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.9.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"monaco-editor": "^0.54.0",
|
||||
"monaco-editor": "^0.53.0",
|
||||
"postcss": "^8.4.47",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.9.4",
|
||||
"react-toastify": "^11.0.5",
|
||||
"rehype-highlight": "^7.0.2",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"rehype-sanitize": "^6.0.0",
|
||||
@@ -45,6 +46,6 @@
|
||||
"globals": "^15.9.0",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.0.1",
|
||||
"vite": "^5.4.1"
|
||||
"vite": "^7.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ export const SearchInput: React.FC<searchInputProps> = ({
|
||||
return (
|
||||
<label
|
||||
className={cn(
|
||||
'relative bg-liquid-lighter w-[200px] h-[40px] rounded-full px-[16px] pl-[50px] py-[8px] cursor-text',
|
||||
'relative bg-liquid-lighter w-[200px] h-[40px] flex rounded-full px-[16px] pl-[50px] cursor-text',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<input
|
||||
className={cn(
|
||||
'placeholder:text-liquid-light h-[28px] w-[200px] bg-transparent outline-none text-liquid-white ',
|
||||
'placeholder:text-liquid-light h-[28px] w-[200px] bg-transparent outline-none text-liquid-white my-[6px]',
|
||||
)}
|
||||
value={value}
|
||||
name={name}
|
||||
|
||||
34
src/lib/toastNotification.ts
Normal file
34
src/lib/toastNotification.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
export const toastSuccess = (mes: string, autoClose: number = 3000) => {
|
||||
toast.success(mes, {
|
||||
position: 'top-right',
|
||||
autoClose: autoClose,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const toastWarning = (mes: string, autoClose: number = 3000) => {
|
||||
toast.warning(mes, {
|
||||
position: 'top-right',
|
||||
autoClose: autoClose,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const toastError = (mes: string, autoClose: number = 3000) => {
|
||||
toast.error(mes, {
|
||||
position: 'top-right',
|
||||
autoClose: autoClose,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
});
|
||||
};
|
||||
@@ -6,11 +6,13 @@ import './styles/palette/theme-light.css';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './redux/store';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<BrowserRouter>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
<ToastContainer />
|
||||
</Provider>
|
||||
</BrowserRouter>,
|
||||
);
|
||||
|
||||
@@ -19,6 +19,11 @@ import { MissionsRightPanel } from '../views/home/rightpanel/Missions';
|
||||
import { ArticlesRightPanel } from '../views/home/rightpanel/Articles';
|
||||
import { GroupRightPanel } from '../views/home/rightpanel/Group';
|
||||
import GroupInvite from '../views/home/groupinviter/GroupInvite';
|
||||
import {
|
||||
toastError,
|
||||
toastSuccess,
|
||||
toastWarning,
|
||||
} from '../lib/toastNotification';
|
||||
|
||||
const Home = () => {
|
||||
const name = useAppSelector((state) => state.auth.username);
|
||||
@@ -75,6 +80,30 @@ const Home = () => {
|
||||
>
|
||||
выйти
|
||||
</PrimaryButton>
|
||||
|
||||
<div className="flex mt-[20px] gap-[20px]">
|
||||
<PrimaryButton
|
||||
color="success"
|
||||
text="Toast"
|
||||
onClick={() => {
|
||||
toastSuccess('Success');
|
||||
}}
|
||||
/>
|
||||
<PrimaryButton
|
||||
color="warning"
|
||||
text="Toast"
|
||||
onClick={() => {
|
||||
toastWarning('Warning');
|
||||
}}
|
||||
/>
|
||||
<PrimaryButton
|
||||
color="error"
|
||||
text="Toast"
|
||||
onClick={() => {
|
||||
toastError('Error');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
@import './latex-container.css';
|
||||
@import './toast.css';
|
||||
|
||||
* {
|
||||
-webkit-tap-highlight-color: transparent; /* Отключаем выделение синим при тапе на телефоне*/
|
||||
|
||||
32
src/styles/toast.css
Normal file
32
src/styles/toast.css
Normal file
@@ -0,0 +1,32 @@
|
||||
.Toastify__progress-bar--success {
|
||||
background: #10be59 !important;
|
||||
}
|
||||
|
||||
.Toastify__toast--success .Toastify__toast-icon svg path {
|
||||
fill: #10be59 !important;
|
||||
}
|
||||
|
||||
.Toastify__progress-bar--error {
|
||||
background: #f13e5f !important;
|
||||
}
|
||||
|
||||
.Toastify__toast--error .Toastify__toast-icon svg path {
|
||||
fill: #f13e5f !important;
|
||||
}
|
||||
|
||||
.Toastify__progress-bar--success {
|
||||
background: #10be59 !important;
|
||||
}
|
||||
|
||||
.Toastify__toast--success .Toastify__toast-icon svg path {
|
||||
fill: #10be59 !important;
|
||||
}
|
||||
|
||||
.Toastify__toast {
|
||||
background: #292929 !important;
|
||||
color: var(--color-liquid-white);
|
||||
}
|
||||
|
||||
.Toastify__toast > button > svg {
|
||||
fill: var(--color-liquid-white);
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import { FC, useEffect } from 'react';
|
||||
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';
|
||||
|
||||
interface PostsProps {
|
||||
groupId: number;
|
||||
@@ -12,28 +14,59 @@ interface PostsProps {
|
||||
export const Posts: FC<PostsProps> = ({ groupId }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [isAdmin, setIsAdmin] = useState<boolean>(false);
|
||||
const { pages, status } = useAppSelector(
|
||||
(state) => state.groupfeed.fetchPosts,
|
||||
);
|
||||
const { id: userId } = useAppSelector((state) => state.auth);
|
||||
|
||||
const { group, status: statusGroup } = useAppSelector(
|
||||
(state) => state.groups.fetchGroupById,
|
||||
);
|
||||
|
||||
// Загружаем только первую страницу
|
||||
useEffect(() => {
|
||||
dispatch(fetchGroupPosts({ groupId, page: 0, pageSize: 20 }));
|
||||
dispatch(fetchGroupById(groupId));
|
||||
}, [groupId]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActiveGroupPage('home'));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!group) return;
|
||||
|
||||
const isUserAdmin =
|
||||
group.members?.some(
|
||||
(m) =>
|
||||
Number(m.userId) === Number(userId) &&
|
||||
m.role.includes('Administrator'),
|
||||
) || false;
|
||||
|
||||
setIsAdmin(isUserAdmin);
|
||||
}, [group, userId]);
|
||||
|
||||
const page0 = pages[0];
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-y-scroll thin-dark-scrollbar">
|
||||
<div className="h-[40px] mb-[20px]">
|
||||
<div className="h-[40px] mb-[20px] relative">
|
||||
<SearchInput
|
||||
className="w-[216px]"
|
||||
onChange={(v) => {}}
|
||||
placeholder="Поиск сообщений"
|
||||
/>
|
||||
{isAdmin && (
|
||||
<div className=" h-[40px] w-[200px] absolute top-0 right-0 flex items-center">
|
||||
<SecondaryButton
|
||||
onClick={() => {
|
||||
// setModalActive(true);
|
||||
}}
|
||||
text="Добавить задачу"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{status === 'loading' && <div>Загрузка...</div>}
|
||||
|
||||
Reference in New Issue
Block a user