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 {NavLink, Outlet} from 'react-router-dom';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {setInitialUser} from '../store/users/users.slice';
import {useDispatch} from 'react-redux';
import React, { FunctionComponent, ReactElement } from 'react';
import { NavLink, Outlet } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '../store/hooks';
import { setInitialUser } from '../store/users/users.slice';
const Layout: FunctionComponent = (): ReactElement => {
const {user} = useAppSelector((state) => state.user);
const { user } = useAppSelector((state) => state.user);
const dispatch = useAppDispatch();
return (
<div className="bg-gray-50 dark:bg-gray-900">
<div className="flex justify-between container mx-auto">
<p>Forum</p>
{!user.username ? (
<div>
<NavLink className={'mr-3'} to={'register'}>
Register
</NavLink>
</div>
) : (
<div className="flex items-center">
<p>{user.username}</p>
<NavLink className={'mx-4'} to={'/'}>
Add new Post
</NavLink>
<NavLink
onClick={() => {
window.sessionStorage.setItem('token', '');
dispatch(setInitialUser());
}}
to={'/'}
>
Log out
</NavLink>
</div>
)}
<div className="bg-gray-100 flex">
<div className="w-1/6">
<div className="container mx-auto py-4">
<p className="text-lg font-medium mb-8">Forum</p>
{!user.username ? (
<div>
<NavLink className="text-gray-700 hover:text-gray-900" to={'register'}>
Register
</NavLink>
</div>
) : (
<div className="flex flex-col">
<p className="text-gray-700 mb-4">
Hello
<span className="text-indigo-600"> {user.username}!</span>
</p>
<NavLink to={'/'} className=" mb-4">Add new Post
</NavLink>
<NavLink
onClick={() => {
window.sessionStorage.setItem('token', '');
dispatch(setInitialUser());
}}
to={'/'}
className="text-gray-700 hover:text-gray-900"
>
Log out
</NavLink>
</div>
)}
</div>
</div>
<div className="w-3/4">
<div className="container mx-auto py-8">
<Outlet />
</div>
</div>
<Outlet />
</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';
import {shallowEqual, useDispatch} from 'react-redux';
import {useAppDispatch, useAppSelector} from '../store/hooks';
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 dispatch = useAppDispatch();
const {posts} = useSelector((state: AppState) => state.posts, shallowEqual)
const { user } = useSelector((state: AppState) => state.user,shallowEqual);
useEffect(() => {
const token = window.sessionStorage.getItem('token');
if (token) {
dispatch(getUser(token));
dispatch(getPosts())
}
});
},[]);
if (!user) {
return <div>Loading...</div>;
}
return (
<div className="bg-gray-50 dark:bg-gray-900 h-screen w-full container mx-auto">
homepage
<PostsList posts={posts}/>
</div>
);
};
......
......@@ -5,7 +5,7 @@
}
* {
color: white;
}
@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 IPostState from './IPostState'
import { createAppAsyncThunk } from '../createAppAsyncThunk'
import { postApi } from '../../api/postApi'
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'
export const getPosts = createAppAsyncThunk(
export const getPosts = createAsyncThunk(
`${namespace}/getPosts`,
async (): Promise<IResponse<IPost[] | undefined>> => {
return postApi.getPosts()
}
)
export const getPostById = createAppAsyncThunk(
export const getPostById = createAsyncThunk(
`${namespace}/getPostById`,
async (id: string): Promise<IResponse<IPost | undefined>> => {
return postApi.getPostById(id)
}
)
export const createPost = createAppAsyncThunk(
export const createPost = createAsyncThunk(
`${namespace}/createPost`,
async (post: FormData) => {
return postApi.createPost(post)
}
)
export const deletePostById = createAppAsyncThunk(
export const deletePostById = createAsyncThunk(
`${namespace}/deletePostById`,
async (id: string) => {
return postApi.deletePostById(id)
......@@ -38,12 +49,7 @@ export const deletePostById = createAppAsyncThunk(
export const postsSlice = createSlice({
name: namespace,
initialState: {
posts: [] as IPost[],
post: {},
loadingPosts: false,
messagePosts: ''
} as IPostState,
initialState,
reducers: {},
extraReducers: (builder) => {
builder
......@@ -90,4 +96,6 @@ export const postsSlice = createSlice({
state.messagePosts = action.payload.message
})
}
})
\ No newline at end of file
})
export default postsSlice.reducer;
\ No newline at end of file
import {configureStore} from '@reduxjs/toolkit';
import userSlice from './users/users.slice';
<<<<<<< frontend/src/store/store.ts
import { postsSlice } from './posts/posts.slice';
=======
import commentsSlice from './comments/comments.slice';
>>>>>>> frontend/src/store/store.ts
export const store = configureStore({
reducer: {
user: userSlice,
<<<<<<< frontend/src/store/store.ts
posts: postsSlice.reducer,
=======
comments: commentsSlice
>>>>>>> frontend/src/store/store.ts
},
});
export type RootState = ReturnType<typeof store.getState>;
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