Commit 8bfffab6 authored by Рахметова Альбина's avatar Рахметова Альбина

Merge branch '#28' into 'dev'

Внесены незначительные изменения

See merge request !32
parents 93956466 7b0a9395
import React, {FunctionComponent, ReactElement} from 'react'; import React, { FunctionComponent, ReactElement } from 'react';
import {NavLink, Outlet} from 'react-router-dom'; import { NavLink, Outlet } from 'react-router-dom';
import {useAppDispatch, useAppSelector} from '../store/hooks'; import { useAppDispatch, useAppSelector } from '../store/hooks';
import {setInitialUser} from '../store/users/users.slice'; import { setInitialUser } from '../store/users/users.slice';
import {useDispatch} from 'react-redux';
const Layout: FunctionComponent = (): ReactElement => { const Layout: FunctionComponent = (): ReactElement => {
const {user} = useAppSelector((state) => state.user); const { user } = useAppSelector((state) => state.user);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
return ( return (
<div className="bg-gray-50 dark:bg-gray-900"> <div className="bg-gray-100 flex">
<div className="flex justify-between container mx-auto"> <div className="w-1/6">
<p>Forum</p> <div className="container mx-auto py-4">
<p className="text-lg font-medium mb-8">Forum</p>
{!user.username ? ( {!user.username ? (
<div> <div>
<NavLink className={'mr-3'} to={'register'}> <NavLink className="text-gray-700 hover:text-gray-900" to={'register'}>
Register Register
</NavLink> </NavLink>
</div> </div>
) : ( ) : (
<div className="flex items-center"> <div className="flex flex-col">
<p>{user.username}</p> <p className="text-gray-700 mb-4">
<NavLink className={'mx-4'} to={'/'}> Hello
Add new Post <span className="text-indigo-600"> {user.username}!</span>
</p>
<NavLink to={'/'} className=" mb-4">Add new Post
</NavLink> </NavLink>
<NavLink <NavLink
onClick={() => { onClick={() => {
...@@ -29,14 +31,21 @@ const Layout: FunctionComponent = (): ReactElement => { ...@@ -29,14 +31,21 @@ const Layout: FunctionComponent = (): ReactElement => {
dispatch(setInitialUser()); dispatch(setInitialUser());
}} }}
to={'/'} to={'/'}
className="text-gray-700 hover:text-gray-900"
> >
Log out Log out
</NavLink> </NavLink>
</div> </div>
)} )}
</div> </div>
</div>
<div className="w-3/4">
<div className="container mx-auto py-8">
<Outlet /> <Outlet />
</div> </div>
</div>
</div>
); );
}; };
......
import React, { FunctionComponent, MutableRefObject, ReactElement, useRef } from "react";
import IPost from "../../interfaces/IPost";
import defaultImage from '../../assets/default-image.jpg'
import IUser from "../../interfaces/IUser";
interface IPostProps {
post: IPost;
}
const Post: FunctionComponent<IPostProps> = ({ post }): ReactElement => {
return (
<div className=" rounded-lg shadow-md flex flex-col justify-between mb-5">
<img
className="object-cover w-full h-80 rounded-t-lg"
src={`${import.meta.env.VITE_BASE_URL}uploads/${post.image}`}
alt={post.title}
onError={(e) => {
e.currentTarget.src = defaultImage;
}}
/>
<div className="p-4">
<p className="text-gray-400 text-xs">{post.datetime}</p>
<p className="text-lg font-bold mb-2">{post.title}</p>
<p className="text-sm mb-2">{post.description}</p>
<p className="text-sm mb-2 text-gray-400">Посмотреть все комментарии</p>
</div>
<div className="border-t p-4">
</div>
</div>
)
}
export default Post
\ No newline at end of file
import React, { FunctionComponent, ReactElement } from "react";
import IPost from "../../interfaces/IPost";
import Post from "../Post/Post";
interface IPostListProps {
posts: IPost[]
}
const PostsList: FunctionComponent<IPostListProps> = (posts): ReactElement => {
return (
<div className="flex justify-center items-center">
<div >
{posts.posts.length ? (
posts.posts.map((p) => {
return <Post key={p._id} post={p} />;
})
) : (
<h1 className="text-center text-2xl font-bold mt-10">
No Posts
</h1>
)}
</div>
</div>
)
}
export default PostsList
\ No newline at end of file
...@@ -2,19 +2,33 @@ import {FunctionComponent, ReactElement, useEffect} from 'react'; ...@@ -2,19 +2,33 @@ import {FunctionComponent, ReactElement, useEffect} from 'react';
import {shallowEqual, useDispatch} from 'react-redux'; import {shallowEqual, useDispatch} from 'react-redux';
import {useAppDispatch, useAppSelector} from '../store/hooks'; import {useAppDispatch, useAppSelector} from '../store/hooks';
import {getUser} from '../store/users/users.slice'; import {getUser} from '../store/users/users.slice';
import { useSelector } from 'react-redux';
import PostsList from '../components/PostList/PostList';
import { AppState } from '../store/store';
import { getPosts } from '../store/posts/posts.slice';
const HomePage: FunctionComponent = (): ReactElement => { const HomePage: FunctionComponent = (): ReactElement => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const {posts} = useSelector((state: AppState) => state.posts, shallowEqual)
const { user } = useSelector((state: AppState) => state.user,shallowEqual);
useEffect(() => { useEffect(() => {
const token = window.sessionStorage.getItem('token'); const token = window.sessionStorage.getItem('token');
if (token) { if (token) {
dispatch(getUser(token)); dispatch(getUser(token));
dispatch(getPosts())
}
},[]);
if (!user) {
return <div>Loading...</div>;
} }
});
return ( return (
<div className="bg-gray-50 dark:bg-gray-900 h-screen w-full container mx-auto"> <div className="bg-gray-50 dark:bg-gray-900 h-screen w-full container mx-auto">
homepage <PostsList posts={posts}/>
</div> </div>
); );
}; };
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
} }
* { * {
color: white;
} }
@tailwind base; @tailwind base;
......
import IPost from "../../interfaces/IPost"
export default interface IPostState {
posts: IPost[]
post: IPost
loadingPosts: boolean
messagePosts: string
}
\ No newline at end of file
import { createSlice } from '@reduxjs/toolkit' import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import IPost from '../../interfaces/IPost' import IPost from '../../interfaces/IPost'
import IPostState from './IPostState'
import { createAppAsyncThunk } from '../createAppAsyncThunk'
import { postApi } from '../../api/postApi' import { postApi } from '../../api/postApi'
import IResponse from '../../interfaces/IResponse' import IResponse from '../../interfaces/IResponse'
interface IPostState {
posts: IPost[]
post: IPost
loadingPosts: boolean
messagePosts: string
}
const initialState:IPostState = {
posts: [] as IPost[],
post: {} as IPost,
loadingPosts: false,
messagePosts: ''
}
const namespace = 'posts' const namespace = 'posts'
export const getPosts = createAppAsyncThunk( export const getPosts = createAsyncThunk(
`${namespace}/getPosts`, `${namespace}/getPosts`,
async (): Promise<IResponse<IPost[] | undefined>> => { async (): Promise<IResponse<IPost[] | undefined>> => {
return postApi.getPosts() return postApi.getPosts()
} }
) )
export const getPostById = createAppAsyncThunk( export const getPostById = createAsyncThunk(
`${namespace}/getPostById`, `${namespace}/getPostById`,
async (id: string): Promise<IResponse<IPost | undefined>> => { async (id: string): Promise<IResponse<IPost | undefined>> => {
return postApi.getPostById(id) return postApi.getPostById(id)
} }
) )
export const createPost = createAppAsyncThunk( export const createPost = createAsyncThunk(
`${namespace}/createPost`, `${namespace}/createPost`,
async (post: FormData) => { async (post: FormData) => {
return postApi.createPost(post) return postApi.createPost(post)
} }
) )
export const deletePostById = createAppAsyncThunk( export const deletePostById = createAsyncThunk(
`${namespace}/deletePostById`, `${namespace}/deletePostById`,
async (id: string) => { async (id: string) => {
return postApi.deletePostById(id) return postApi.deletePostById(id)
...@@ -38,12 +49,7 @@ export const deletePostById = createAppAsyncThunk( ...@@ -38,12 +49,7 @@ export const deletePostById = createAppAsyncThunk(
export const postsSlice = createSlice({ export const postsSlice = createSlice({
name: namespace, name: namespace,
initialState: { initialState,
posts: [] as IPost[],
post: {},
loadingPosts: false,
messagePosts: ''
} as IPostState,
reducers: {}, reducers: {},
extraReducers: (builder) => { extraReducers: (builder) => {
builder builder
...@@ -91,3 +97,5 @@ export const postsSlice = createSlice({ ...@@ -91,3 +97,5 @@ export const postsSlice = createSlice({
}) })
} }
}) })
export default postsSlice.reducer;
\ No newline at end of file
import {configureStore} from '@reduxjs/toolkit'; import {configureStore} from '@reduxjs/toolkit';
import userSlice from './users/users.slice'; import userSlice from './users/users.slice';
<<<<<<< frontend/src/store/store.ts
import { postsSlice } from './posts/posts.slice';
=======
import commentsSlice from './comments/comments.slice'; import commentsSlice from './comments/comments.slice';
>>>>>>> frontend/src/store/store.ts
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
user: userSlice, user: userSlice,
<<<<<<< frontend/src/store/store.ts
posts: postsSlice.reducer,
=======
comments: commentsSlice comments: commentsSlice
>>>>>>> frontend/src/store/store.ts
}, },
}); });
export type RootState = ReturnType<typeof store.getState>; export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch; export type AppDispatch = typeof store.dispatch;
export type AppStore = ReturnType<typeof store.getState>;
export type AppState = ReturnType<typeof store.getState>;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment