Работает редактирование постов
This commit is contained in:
parent
47e7bb64f1
commit
0b6d5a93fe
21
data.json
21
data.json
@ -38,13 +38,6 @@
|
||||
}
|
||||
],
|
||||
"posts": [
|
||||
{
|
||||
"id": 1,
|
||||
"userId": 1,
|
||||
"pubDate": "Jan 08 2024 16:03:17 GMT+0400 (GMT+04:00)",
|
||||
"image": null,
|
||||
"html": "Привет, друзья! 👫\nСегодня хочу поделиться с вами одним интересным событием, которое произошло со мной на днях. 🚴♂️\nЯ недавно записался на участие в велопробеге, который будет проходить через месяц в нашем городе. 🌐\nЭто будет не просто гонка, а целое приключение, так как маршрут проложен через самые живописные места нашей области. 🌲🌳🏞️\nНадеюсь, что смогу преодолеть все дистанции и получить массу положительных эмоций! 😁💪\nА вы когда-нибудь участвовали в подобных мероприятиях? Расскажите в комментариях! 💬"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"userId": 2,
|
||||
@ -52,13 +45,6 @@
|
||||
"image": "https://bye-bye-calories.ru/wp-content/uploads/4/2/3/4234c2bc5dd8f7087701a819ea20464b.jpeg",
|
||||
"html": "Сегодня я хочу поделиться с вами своим любимым рецептом. Я готовлю это блюдо уже много лет и всегда получаю комплименты от гостей. Вот ингредиенты, которые вам понадобятся:\n– 400 г куриного филе\n– 200 г шампиньонов\n– 1 луковица\n– 3 зубчика чеснока\n– 100 мл сливок\n– соль, перец по вкусу\n– растительное масло для жарки\nНарежьте куриное филе небольшими кусочками и обжарьте на растительном масле до золотистого цвета. Затем добавьте нарезанный лук и чеснок, обжаривайте еще пару минут. Добавьте нарезанные шампиньоны и жарьте до тех пор, пока вся жидкость не испарится. Влейте сливки, посолите и поперчите по вкусу, перемешайте и тушите на медленном огне еще 5-7 минут. Ваше блюдо готово! Подавайте с гарниром на ваш выбор. Приятного аппетита!"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"userId": 1,
|
||||
"pubDate": "Jan 08 2024 11:03:17 GMT+0400 (GMT+04:00)",
|
||||
"image": "https://primelens.ru/800/600/https/pixnio.com/free-images/2017/08/12/2017-08-12-18-17-42.jpg",
|
||||
"html": "Привет, друзья!\nСегодня я хочу рассказать вам о моем увлечении, которое стало для меня настоящим хобби. \nЭто фотография. \nЯ начал заниматься этим искусством около года назад и с тех пор не могу остановиться. \nМне нравится находить красивые места для съемки, экспериментировать с ракурсами и светом. \nНадеюсь, мои работы вдохновят и вас! \nДелитесь своими фотографиями в комментариях, буду рад посмотреть."
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"userId": 3,
|
||||
@ -100,6 +86,13 @@
|
||||
"pubDate": "Jun 08 2023 18:03:17 GMT+0400 (GMT+04:00)",
|
||||
"image": "https://blog.smarthealthshop.com/wp-content/uploads/2019/01/5-Ways-Healthy-Cooking-Classes-Can-Help-With-Your-Diet.jpg",
|
||||
"html": "Недавно я увлекся новым хобби - кулинарией. И это было просто потрясающе! Я научился готовить множество новых блюд, от простых закусок до сложных десертов. А самое главное - я смог порадовать свою семью и друзей своими кулинарными шедеврами. Если вы тоже хотите освоить это искусство, не бойтесь экспериментировать и пробовать новые рецепты. Ведь кулинария - это не только вкусно, но и очень увлекательно!"
|
||||
},
|
||||
{
|
||||
"userId": 1,
|
||||
"html": "Привет, друзья! 👫\nСегодня хочу поделиться с вами одним интересным событием, которое произошло со мной на днях. 🚴♂️\nЯ недавно записался на участие в велопробеге, который будет проходить через месяц в нашем городе. 🌐\nЭто будет не просто гонка, а целое приключение, так как маршрут проложен через самые живописные места нашей области. 🌲🌳🏞️\nНадеюсь, что смогу преодолеть все дистанции и получить массу положительных эмоций! 😁💪\nА вы когда-нибудь участвовали в подобных мероприятиях? Расскажите в комментариях! 💬",
|
||||
"image": null,
|
||||
"pubDate": "2024-01-09T07:46:30.695Z",
|
||||
"id": 10
|
||||
}
|
||||
],
|
||||
"subscribes": [
|
||||
|
78
package-lock.json
generated
78
package-lock.json
generated
@ -15,7 +15,9 @@
|
||||
"react-bootstrap": "^2.9.2",
|
||||
"react-bootstrap-icons": "^1.10.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-router-dom": "^6.19.0",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"universal-cookie": "^6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -3758,6 +3760,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/goober": {
|
||||
"version": "2.1.13",
|
||||
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz",
|
||||
"integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==",
|
||||
"peerDependencies": {
|
||||
"csstype": "^3.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
@ -6219,6 +6229,21 @@
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hot-toast": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
|
||||
"integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==",
|
||||
"dependencies": {
|
||||
"goober": "^2.1.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16",
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -6268,6 +6293,22 @@
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-textarea-autosize": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz",
|
||||
"integrity": "sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"use-composed-ref": "^1.3.0",
|
||||
"use-latest": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
@ -7359,6 +7400,43 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-composed-ref": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz",
|
||||
"integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-isomorphic-layout-effect": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-latest": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz",
|
||||
"integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==",
|
||||
"dependencies": {
|
||||
"use-isomorphic-layout-effect": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
|
@ -14,15 +14,17 @@
|
||||
"prod": "npm-run-all build --parallel serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.9.2",
|
||||
"react-bootstrap-icons": "^1.10.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-router-dom": "^6.19.0",
|
||||
"universal-cookie": "^6.1.1",
|
||||
"axios": "^1.6.1"
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"universal-cookie": "^6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.15",
|
||||
|
@ -1,22 +1,47 @@
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Trash } from 'react-bootstrap-icons';
|
||||
import { Trash, Pencil } from 'react-bootstrap-icons';
|
||||
|
||||
import './post.css';
|
||||
import { getUserAvatarImg, getUserLink } from '../../utils/user';
|
||||
import { useCurrentUser } from '../../hooks/UserHooks';
|
||||
import PostsApiService from '../../services/PostsApiService';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const options = { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||||
|
||||
const Post = ({ post, handlePostsChange }) => {
|
||||
const Post = ({ post, handlePostsChange, postInputFormState }) => {
|
||||
const currentUser = useCurrentUser();
|
||||
|
||||
if (!postInputFormState) return;
|
||||
|
||||
const { postImage,
|
||||
setPostImage,
|
||||
onImageChange,
|
||||
postText,
|
||||
setPostText,
|
||||
onTextChange,
|
||||
postId,
|
||||
setPostId,
|
||||
imageCheck,
|
||||
onFormSubmit,
|
||||
postInputForm,
|
||||
handlePostInputFormChange,
|
||||
setImage } = postInputFormState;
|
||||
|
||||
const onPostDelete = async () => {
|
||||
await PostsApiService.delete(post.id);
|
||||
toast.success("Пост удален");
|
||||
handlePostsChange();
|
||||
};
|
||||
|
||||
const onPostEdit = async () => {
|
||||
setPostId(post.id);
|
||||
setPostText(post.html);
|
||||
setImage(post.image, false);
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="post mb-2 mb-sm-4 w-100 d-flex flex-column border rounded-2" id={'post-' + post.id}>
|
||||
@ -34,11 +59,18 @@ const Post = ({ post, handlePostsChange }) => {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
{
|
||||
currentUser.id == post.userId ? <a onClick={onPostDelete} title='Удалить пост'>
|
||||
<Trash className='fs-6' fill='red' />
|
||||
</a> : ''
|
||||
}
|
||||
<div className='d-flex'>
|
||||
{
|
||||
currentUser.id == post.userId ? <a className='me-3' onClick={onPostEdit} title='Редактировать пост'>
|
||||
<Pencil className='fs-6' fill='yellow' />
|
||||
</a> : ''
|
||||
}
|
||||
{
|
||||
currentUser.id == post.userId ? <a onClick={onPostDelete} title='Удалить пост'>
|
||||
<Trash className='fs-6' fill='red' />
|
||||
</a> : ''
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="post-body">
|
||||
@ -72,7 +104,8 @@ const Post = ({ post, handlePostsChange }) => {
|
||||
|
||||
Post.propTypes = {
|
||||
post: PropTypes.object,
|
||||
handlePostsChange: PropTypes.func
|
||||
handlePostsChange: PropTypes.func,
|
||||
postInputFormState: PropTypes.object
|
||||
};
|
||||
|
||||
export default Post;
|
@ -1,65 +1,29 @@
|
||||
import './postinputform.css';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { Camera } from 'react-bootstrap-icons';
|
||||
import { useCurrentUser } from '../../hooks/UserHooks';
|
||||
import { useState } from 'react';
|
||||
import { getBase64FromFile } from '../../utils/base64';
|
||||
import PostsApiService from '../../services/PostsApiService';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
|
||||
const PostInputForm = ({ handlePostsChange }) => {
|
||||
const user = useCurrentUser();
|
||||
|
||||
const [postImage, setPostImage] = useState(null);
|
||||
|
||||
const onImageChange = async (event) => {
|
||||
if (event.target.files.length != 0) {
|
||||
setPostImage(await getBase64FromFile(event.target.files[0]));
|
||||
}
|
||||
else {
|
||||
setPostImage(null);
|
||||
}
|
||||
document.getElementById('check-title-image').checked = true;
|
||||
};
|
||||
|
||||
const onPublish = async () => {
|
||||
const postInputText = document.getElementById('post-editor');
|
||||
const postInputImage = document.getElementById('selected-title-image');
|
||||
const postImageChanged = document.getElementById('check-title-image').checked;
|
||||
const postId = document.getElementById('post-input-id').value;
|
||||
|
||||
const postImage = postInputImage ? postInputImage.src : null;
|
||||
|
||||
let post = {
|
||||
userId: user.id,
|
||||
pubDate: new Date(),
|
||||
html: postInputText.value
|
||||
};
|
||||
|
||||
if (postImageChanged) {
|
||||
post = {
|
||||
...post,
|
||||
image: postImage
|
||||
}
|
||||
}
|
||||
|
||||
if (postId) {
|
||||
await PostsApiService.update(postId, post);
|
||||
}
|
||||
else {
|
||||
await PostsApiService.create(post);
|
||||
}
|
||||
|
||||
postInputText.value = '';
|
||||
setPostImage(null);
|
||||
handlePostsChange();
|
||||
};
|
||||
const PostInputForm = ({ postInputFormState }) => {
|
||||
const { postImage,
|
||||
setPostImage,
|
||||
onImageChange,
|
||||
postText,
|
||||
setPostText,
|
||||
onTextChange,
|
||||
postId,
|
||||
setPostId,
|
||||
imageCheck,
|
||||
onFormSubmit,
|
||||
postInputForm,
|
||||
handlePostInputFormChange,
|
||||
onFormCanceled } = postInputFormState;
|
||||
|
||||
return (
|
||||
<>
|
||||
<textarea placeholder="Что нового?" id="post-editor" className="border rounded-2 mb-2 p-2"></textarea>
|
||||
<input id='post-input-id' className='d-none' type='number' />
|
||||
<TextareaAutosize placeholder="Что нового?" id="post-editor" onChange={onTextChange} defaultValue={postText} className="border rounded-2 mb-2 p-2" />
|
||||
<input id='post-input-id' className='d-none' readOnly value={postId ?? ''} type='number' />
|
||||
<div id="title-image-block">
|
||||
<input id="check-title-image" type="checkbox" style={{ display: "none" }} />
|
||||
<input id="check-title-image" type="checkbox" readOnly value={imageCheck} style={{ display: "none" }} />
|
||||
<input onChange={onImageChange} id="input-title-image" className='border' name="titleImage" accept="image/*" type="file" />
|
||||
<label id="title-image-preview" htmlFor="input-title-image" title="Добавить изображение" className="border rounded-2 mb-2">
|
||||
{
|
||||
@ -68,23 +32,24 @@ const PostInputForm = ({ handlePostsChange }) => {
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<button onClick={onPublish} className="btn btn-primary mb-2" id="post-publication-button">
|
||||
Опубликовать
|
||||
</button>
|
||||
<div className="d-none d-flex mb-2 w-100" id="edit-block">
|
||||
<button className="btn btn-danger me-2 w-100" id="edit-post-button-cancel">
|
||||
Отмена
|
||||
{
|
||||
postId != null ? <div className="d-flex mb-2 w-100" id="edit-block">
|
||||
<button onClick={onFormCanceled} className="btn btn-danger me-2 w-100" id="edit-post-button-cancel">
|
||||
Отмена
|
||||
</button>
|
||||
<button onClick={onFormSubmit} className="btn btn-success w-100" id="edit-post-button-accept">
|
||||
Применить
|
||||
</button>
|
||||
</div > : <button onClick={onFormSubmit} className="btn btn-primary mb-2" id="post-publication-button">
|
||||
Опубликовать
|
||||
</button>
|
||||
<button className="btn btn-success w-100" id="edit-post-button-accept">
|
||||
Применить
|
||||
</button>
|
||||
</div >
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
PostInputForm.propTypes = {
|
||||
handlePostsChange: PropTypes.func
|
||||
postInputFormState: PropTypes.object
|
||||
};
|
||||
|
||||
export default PostInputForm;
|
@ -67,25 +67,3 @@ export const usePosts = () => {
|
||||
handlePostsChange: handlePostsChange,
|
||||
};
|
||||
};
|
||||
|
||||
export const usePostInputForm = (postId) => {
|
||||
const [postsRefresh, setPostsRefresh] = useState(false);
|
||||
const [posts, setPosts] = useState([]);
|
||||
const handlePostsChange = () => setPostsRefresh(!postsRefresh);
|
||||
|
||||
const getPosts = async () => {
|
||||
let expand = "?_expand=user";
|
||||
const data = await PostsApiService.getAll(expand);
|
||||
setPosts(data ?? []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getPosts();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [postsRefresh, postId]);
|
||||
|
||||
return {
|
||||
posts: posts,
|
||||
handlePostsChange: handlePostsChange,
|
||||
};
|
||||
};
|
||||
|
110
src/hooks/PostInputFormHook.js
Normal file
110
src/hooks/PostInputFormHook.js
Normal file
@ -0,0 +1,110 @@
|
||||
import { useState } from "react";
|
||||
import { getBase64FromFile } from "../utils/base64";
|
||||
import PostsApiService from "../services/PostsApiService";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export const usePostInputForm = (user, handlePostsChange) => {
|
||||
const [postInputFormRefresh, setPostInputFormRefresh] = useState(false);
|
||||
const refreshForm = () => setPostInputFormRefresh(!postInputFormRefresh);
|
||||
const [postImage, setPostImage] = useState(null);
|
||||
const [postText, setPostText] = useState("");
|
||||
const [imageCheck, setImageCheck] = useState(false);
|
||||
const [postId, setPostId] = useState(null);
|
||||
|
||||
const postInputForm = {
|
||||
textInput: document.getElementById("post-editor"),
|
||||
imageInput: document.getElementById("input-title-image"),
|
||||
selectedImage: document.getElementById("selected-title-image")
|
||||
? document.getElementById("selected-title-image").src
|
||||
: null,
|
||||
imageCheck: document.getElementById("check-title-image"),
|
||||
postIdInput: document.getElementById("post-input-id"),
|
||||
};
|
||||
|
||||
const handlePostInputFormChange = () =>
|
||||
setPostInputFormRefresh(!postInputFormRefresh);
|
||||
|
||||
const setImage = async (image, isBlob = true) => {
|
||||
if (image) {
|
||||
if (!isBlob) {
|
||||
setPostImage(image);
|
||||
} else {
|
||||
setPostImage(await getBase64FromFile(image));
|
||||
}
|
||||
} else {
|
||||
setPostImage(null);
|
||||
}
|
||||
setImageCheck(true);
|
||||
};
|
||||
|
||||
const onImageChange = async (event) => {
|
||||
await setImage(
|
||||
event.target.files.length != 0 ? event.target.files[0] : null
|
||||
);
|
||||
};
|
||||
|
||||
const onTextChange = (event) => {
|
||||
setPostText(event.target.value);
|
||||
};
|
||||
|
||||
const onFormCanceled = () => {
|
||||
toast.error("Изменения сброшены");
|
||||
onFormClear();
|
||||
};
|
||||
|
||||
const onFormClear = () => {
|
||||
setPostText("");
|
||||
setPostImage(null);
|
||||
setPostId(null);
|
||||
handlePostsChange();
|
||||
refreshForm();
|
||||
};
|
||||
|
||||
const onFormSubmit = async () => {
|
||||
let post = {
|
||||
userId: user.id,
|
||||
html: postText,
|
||||
};
|
||||
|
||||
if (imageCheck) {
|
||||
post = {
|
||||
...post,
|
||||
image: postImage,
|
||||
};
|
||||
}
|
||||
|
||||
if (postText.trim() == "" && postImage == null) {
|
||||
toast.error("Заполните пост");
|
||||
} else {
|
||||
if (postId) {
|
||||
const postObj = await PostsApiService.get(postId);
|
||||
post.pubDate = postObj.pubDate;
|
||||
await PostsApiService.update(postId, post);
|
||||
toast.success("Изменения сохранены");
|
||||
} else {
|
||||
post.pubDate = new Date();
|
||||
await PostsApiService.create(post);
|
||||
toast.success("Пост опубликован");
|
||||
}
|
||||
|
||||
onFormClear();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
postImage,
|
||||
setPostImage,
|
||||
onImageChange,
|
||||
postText,
|
||||
setPostText,
|
||||
onTextChange,
|
||||
postId,
|
||||
setPostId,
|
||||
imageCheck,
|
||||
onFormSubmit,
|
||||
postInputForm,
|
||||
handlePostInputFormChange,
|
||||
setImage,
|
||||
onFormCanceled,
|
||||
};
|
||||
};
|
@ -11,6 +11,7 @@ import App from './App.jsx'
|
||||
import './index.css'
|
||||
import { Person, LayoutTextSidebarReverse, ChatText, People } from 'react-bootstrap-icons';
|
||||
import AuthPage from './pages/AuthPage.jsx'
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -66,6 +67,7 @@ const router = createBrowserRouter([
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<Toaster />
|
||||
<RouterProvider router={router} />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
@ -6,24 +6,28 @@ import { useRequireAuthenticated } from "../hooks/AuthHooks";
|
||||
import { usePosts } from "../hooks/PostHooks";
|
||||
import { useUserSubscribes } from "../hooks/SubscribeHook";
|
||||
import { useCurrentUser } from "../hooks/UserHooks";
|
||||
import { usePostInputForm } from "../hooks/PostInputFormHook";
|
||||
|
||||
const FeedPage = () => {
|
||||
useRequireAuthenticated();
|
||||
let { posts, handlePostsChange } = usePosts();
|
||||
const currentUser = useCurrentUser();
|
||||
const postInputFormState = usePostInputForm(currentUser, handlePostsChange);
|
||||
const { subs } = useUserSubscribes(currentUser.id);
|
||||
const subsIds = subs.map((sub) => sub.userId);
|
||||
posts = posts.filter((post) => subsIds.includes(post.userId) || post.userId == currentUser.id).sort((a, b) => new Date(b.pubDate) - new Date(a.pubDate));
|
||||
|
||||
if (postInputFormState === undefined) return;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Wrapper>
|
||||
<Center>
|
||||
<PostInputForm handlePostsChange={handlePostsChange} />
|
||||
<PostInputForm postInputFormState={postInputFormState} />
|
||||
<div className="posts-wrapper mt-3">
|
||||
{
|
||||
posts.length == 0 ? 'Нет постов' :
|
||||
posts.map((post, index) => <Post post={post} key={index} handlePostsChange={handlePostsChange} />)
|
||||
posts.map((post, index) => <Post post={post} key={index} handlePostsChange={handlePostsChange} postInputFormState={postInputFormState} />)
|
||||
}
|
||||
</div>
|
||||
</Center>
|
||||
|
@ -8,6 +8,7 @@ import { useCurrentUser } from "../hooks/UserHooks";
|
||||
import { useUserPosts } from "../hooks/PostHooks";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useUserByUsername } from "../hooks/UserHooks";
|
||||
import { usePostInputForm } from "../hooks/PostInputFormHook";
|
||||
|
||||
const UserProfilePage = () => {
|
||||
useRequireAuthenticated();
|
||||
@ -19,6 +20,8 @@ const UserProfilePage = () => {
|
||||
|
||||
let { userPosts, handlePostsChange } = useUserPosts(user.id);
|
||||
|
||||
const postInputFormState = usePostInputForm(currentUser, handlePostsChange);
|
||||
|
||||
userPosts = userPosts.sort((a, b) => new Date(b.pubDate) - new Date(a.pubDate));
|
||||
if (params.username) {
|
||||
document.title = user.name + ' ' + user.surname;
|
||||
@ -41,11 +44,11 @@ const UserProfilePage = () => {
|
||||
<Center>
|
||||
<UserProfileBlock user={user} />
|
||||
{
|
||||
user.id == currentUser.id ? <PostInputForm handlePostsChange={handlePostsChange} /> : ''
|
||||
user.id == currentUser.id ? <PostInputForm handlePostsChange={handlePostsChange} postInputFormState={postInputFormState} /> : ''
|
||||
}
|
||||
<div className="posts-wrapper mt-3">
|
||||
{
|
||||
userPosts.map((post, index) => <Post post={post} key={index} handlePostsChange={handlePostsChange} />)
|
||||
userPosts.map((post, index) => <Post post={post} key={index} handlePostsChange={handlePostsChange} postInputFormState={postInputFormState} />)
|
||||
}
|
||||
</div>
|
||||
</Center>
|
||||
|
Loading…
x
Reference in New Issue
Block a user