Compare commits
No commits in common. "58b6d1387defe7f147ab650f5029c448ac09cef2" and "750b571374c05b915d136af481fe93bf966bac39" have entirely different histories.
58b6d1387d
...
750b571374
@ -28,8 +28,6 @@
|
|||||||
"webpack-dev-server": "^5.0.2"
|
"webpack-dev-server": "^5.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ckeditor/ckeditor5-build-classic": "^41.4.2",
|
|
||||||
"@ckeditor/ckeditor5-react": "^7.0.0",
|
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
.main {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 4% 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
width: 100%;
|
|
||||||
height: 10%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: end;
|
|
||||||
padding: 0 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.listArticles {
|
|
||||||
box-shadow: 0 0 5px 1px rgb(200, 200, 200);
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-top: 5%;
|
|
||||||
height: 70%;
|
|
||||||
width: 100%;
|
|
||||||
&__columns {
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 2%;
|
|
||||||
height: 15%;
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: 1px solid rgb(220, 220, 220);
|
|
||||||
&__item {
|
|
||||||
width: 33.3%;
|
|
||||||
font-size: 15px;
|
|
||||||
// text-align: center;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__forms {
|
|
||||||
width: 100%;
|
|
||||||
height: 85%;
|
|
||||||
overflow-y: auto;
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 7px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(200, 200, 200);
|
|
||||||
}
|
|
||||||
&__item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 2%;
|
|
||||||
height: 25%;
|
|
||||||
width: 100%;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
position: relative;
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(240, 240, 240, 0.8);
|
|
||||||
}
|
|
||||||
&__title {
|
|
||||||
width: 33.3%;
|
|
||||||
// text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__date {
|
|
||||||
width: 33.3%;
|
|
||||||
// text-align: center;
|
|
||||||
}
|
|
||||||
&__author {
|
|
||||||
width: 33.3%;
|
|
||||||
// text-align: center;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 15px;
|
|
||||||
right: 30px;
|
|
||||||
top: calc(50% - 7px);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
li {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,31 +30,5 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
<<<<<<< HEAD
|
|
||||||
&__green {
|
|
||||||
color: white;
|
|
||||||
background-color: rgb(150, 209, 158);
|
|
||||||
}
|
|
||||||
&__white {
|
|
||||||
color: black;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
&:hover {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__transparent {
|
|
||||||
background-color: rgba(0, 0, 0, 0);
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0);
|
|
||||||
transition: 0.3s;
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(180, 180, 180, 0.5);
|
|
||||||
color: white;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
=======
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>>>>>>> 750b571374c05b915d136af481fe93bf966bac39
|
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
.main {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 4% 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
height: 8%;
|
|
||||||
&__listInput {
|
|
||||||
width: 40%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
&__date {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: relative;
|
|
||||||
span {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 8px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
top: -40%;
|
|
||||||
left: 2%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__title {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: relative;
|
|
||||||
span {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 8px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
top: -40%;
|
|
||||||
left: 2%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__listBtn {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags {
|
|
||||||
width: 100%;
|
|
||||||
margin: 30px 0;
|
|
||||||
&__wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: start;
|
|
||||||
&__input {
|
|
||||||
position: relative;
|
|
||||||
&__title {
|
|
||||||
top: -40%;
|
|
||||||
left: 2px;
|
|
||||||
position: absolute;
|
|
||||||
font-size: 8px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
color: rgb(100, 100, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__list {
|
|
||||||
width: 100%;
|
|
||||||
// height: 100%;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 5px;
|
|
||||||
&__item {
|
|
||||||
padding: 0 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid rgb(100, 100, 100);
|
|
||||||
margin: 1px 3px;
|
|
||||||
position: relative;
|
|
||||||
span {
|
|
||||||
font-size: 13px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
color: rgb(100, 100, 100);
|
|
||||||
}
|
|
||||||
&:hover span {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
&:hover i {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
color: rgb(239, 73, 73);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
.main {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: 90%;
|
|
||||||
height: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
width: 100%;
|
|
||||||
height: 10%;
|
|
||||||
&__wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid rgb(180, 180, 180);
|
|
||||||
border-bottom: none;
|
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
padding: 0 5px;
|
|
||||||
&__article {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
&__title {
|
|
||||||
width: 20%;
|
|
||||||
height: 75%;
|
|
||||||
display: flex;
|
|
||||||
border-right: 1px solid rgb(180, 180, 180);
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
&__name {
|
|
||||||
position: absolute;
|
|
||||||
top: -20%;
|
|
||||||
left: 3px;
|
|
||||||
font-size: 8px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
}
|
|
||||||
&__text {
|
|
||||||
font-size: 15px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__tags {
|
|
||||||
width: 60%;
|
|
||||||
height: 75%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
padding: 0 5px;
|
|
||||||
position: relative;
|
|
||||||
overflow-y: auto;
|
|
||||||
// &::-webkit-scrollbar {
|
|
||||||
// width: 10px;
|
|
||||||
// }
|
|
||||||
// &::-webkit-scrollbar-thumb {
|
|
||||||
// background-color: rgb(200, 200, 200);
|
|
||||||
// }
|
|
||||||
// &::-webkit-scrollbar-button:single-button {
|
|
||||||
// background-color: #bbbbbb;
|
|
||||||
// display: block;
|
|
||||||
// border-style: solid;
|
|
||||||
// height: 10px;
|
|
||||||
// width: 16px;
|
|
||||||
// }
|
|
||||||
&__item {
|
|
||||||
padding: 0 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid rgb(100, 100, 100);
|
|
||||||
margin: 1px 3px;
|
|
||||||
span {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__owner {
|
|
||||||
width: 20%;
|
|
||||||
height: 75%;
|
|
||||||
border-left: 1px solid rgb(180, 180, 180);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
&__name {
|
|
||||||
position: absolute;
|
|
||||||
top: -20%;
|
|
||||||
right: 3px;
|
|
||||||
font-size: 8px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
}
|
|
||||||
&__text {
|
|
||||||
font-size: 15px;
|
|
||||||
font-family: "Montserrat", sans-serif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__tags {
|
|
||||||
width: 100%;
|
|
||||||
height: 50%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: start;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 20px;
|
|
||||||
&__item {
|
|
||||||
padding: 0 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid rgb(100, 100, 100);
|
|
||||||
margin: 1px 3px;
|
|
||||||
span {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
width: 100%;
|
|
||||||
height: 90%;
|
|
||||||
&__wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid rgb(180, 180, 180);
|
|
||||||
padding: 5px;
|
|
||||||
// border-radius: 0 0 5px 5px;
|
|
||||||
overflow: auto;
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 7px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
height: 7px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(200, 200, 200);
|
|
||||||
}
|
|
||||||
&__article {
|
|
||||||
max-width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// .image {
|
|
||||||
// width: 400px;
|
|
||||||
// height: 200px;
|
|
||||||
// border: 4px solid red
|
|
||||||
// img {
|
|
||||||
// width: 400px;
|
|
||||||
// height: 200px;
|
|
||||||
// aspect-ratio: 1000/700;
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -4,7 +4,7 @@ import classes from "../assets/styles/components/myButton.module.scss"
|
|||||||
const MyButton = (props) => {
|
const MyButton = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.main} style={props.mainStyle}>
|
<div className={classes.main}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={classes[props.class]}
|
className={classes[props.class]}
|
||||||
|
@ -14,8 +14,7 @@ const NavBar = ({navigate, auth, setAuth}) => {
|
|||||||
auth ?
|
auth ?
|
||||||
auth.is_admin ?
|
auth.is_admin ?
|
||||||
<><span onClick={() => navigate("/forms")}>Мои формы</span>
|
<><span onClick={() => navigate("/forms")}>Мои формы</span>
|
||||||
<span onClick={() => navigate("/admin")}>Админ панель</span>
|
<span onClick={() => navigate("/admin")}>Админ панель</span></> :
|
||||||
<span onClick={() => navigate("/articles")}>Мои статьи</span></> :
|
|
||||||
<span></span> :
|
<span></span> :
|
||||||
<span></span>
|
<span></span>
|
||||||
}
|
}
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { CKEditor } from '@ckeditor/ckeditor5-react';
|
|
||||||
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
|
||||||
|
|
||||||
const TextEditor = ({data, setData}) => {
|
|
||||||
return (
|
|
||||||
<div className="App">
|
|
||||||
<h2>Редактор статьи</h2>
|
|
||||||
<CKEditor
|
|
||||||
editor={ ClassicEditor }
|
|
||||||
data={data}
|
|
||||||
config = {{
|
|
||||||
mediaEmbed: {previewsInData: true }
|
|
||||||
}}
|
|
||||||
onReady={ editor => {
|
|
||||||
// You can store the "editor" and use when it is needed.
|
|
||||||
console.log( 'Editor is ready to use!', editor );
|
|
||||||
} }
|
|
||||||
onChange={ ( event, editor ) => {
|
|
||||||
setData(editor.getData())
|
|
||||||
}}
|
|
||||||
onBlur={ ( event, editor ) => {
|
|
||||||
console.log( 'Blur.', editor );
|
|
||||||
} }
|
|
||||||
onFocus={ ( event, editor ) => {
|
|
||||||
console.log( 'Focus.', editor );
|
|
||||||
} }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TextEditor;
|
|
@ -1,144 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
|
|
||||||
|
|
||||||
async function createArticleApi(token, data) {
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`https://api.minerva.krbl.ru/articles/new`,
|
|
||||||
{
|
|
||||||
"tags": [],
|
|
||||||
"title": "Новая статья"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function getListArticlesApi(token) {
|
|
||||||
try {
|
|
||||||
const response = await axios.get(`https://api.minerva.krbl.ru/articles/list`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function getArticleApi(token, articleId) {
|
|
||||||
try {
|
|
||||||
const response = await axios.get(`https://api.minerva.krbl.ru/articles/${articleId}/view`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function editTagsApi(token, articleId, tags, flag) {
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`https://api.minerva.krbl.ru/articles/edit/${articleId}/tags`,
|
|
||||||
{
|
|
||||||
"delete_flag": flag,
|
|
||||||
"tags": tags,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function editTitleArticleApi(token, articleId, title) {
|
|
||||||
console.log('set')
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`https://api.minerva.krbl.ru/articles/edit/${articleId}/setTitle`,
|
|
||||||
{
|
|
||||||
"title": title,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function addArticleApi(token, articleId, content) {
|
|
||||||
console.log('add')
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`https://api.minerva.krbl.ru/articles/edit/${articleId}/add`,
|
|
||||||
{
|
|
||||||
"data": content,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function editArticleApi(token, articleId, content) {
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`https://api.minerva.krbl.ru/articles/edit/${articleId}/set`,
|
|
||||||
{
|
|
||||||
"order": 0,
|
|
||||||
"data": content,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Token ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export {
|
|
||||||
createArticleApi,
|
|
||||||
getArticleApi,
|
|
||||||
getListArticlesApi,
|
|
||||||
editTagsApi,
|
|
||||||
editTitleArticleApi,
|
|
||||||
addArticleApi,
|
|
||||||
editArticleApi
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
import React, { useState, useContext, useEffect } from "react";
|
|
||||||
import { useCookies } from "react-cookie";
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import classes from "../assets/styles/articles.module.scss"
|
|
||||||
import MyButton from "../components/MyButton.jsx";
|
|
||||||
import MyInput from "../components/MyInput.jsx";
|
|
||||||
import { UserData } from "../context";
|
|
||||||
import CheckModal from "../components/CheckModal.jsx";
|
|
||||||
import { createArticleApi, getListArticlesApi } from "../hooks/api/articleApi.js";
|
|
||||||
|
|
||||||
|
|
||||||
const Articles = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const {user, setUser} = useContext(UserData);
|
|
||||||
const [stateLoading, setStateLoading] = useState(false);
|
|
||||||
|
|
||||||
const [listArticles, setListArticles] = useState([]);
|
|
||||||
|
|
||||||
const [cookies, _, __] = useCookies(["user"]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getListArticles() {
|
|
||||||
const response = await getListArticlesApi(cookies.token)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
setListArticles(response.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getListArticles()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
async function createArticle() {
|
|
||||||
const response = await createArticleApi(cookies.token)
|
|
||||||
|
|
||||||
console.log(response)
|
|
||||||
if (response.status === 200) {
|
|
||||||
navigate(`/articles/${response.data.id}/edit`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.main}>
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.panel}>
|
|
||||||
<MyInput placeholder={'Поиск...'}/>
|
|
||||||
<MyButton click={createArticle} class={"main__green"} otherStyle={{width: '200px'}} text={
|
|
||||||
stateLoading ? <div class="spinner-border text-light" role="status">
|
|
||||||
<span class="visually-hidden">Загрузка...</span>
|
|
||||||
</div> : 'Создать'
|
|
||||||
}/>
|
|
||||||
</div>
|
|
||||||
<div className={classes.listArticles}>
|
|
||||||
<div className={classes.listArticles__columns}>
|
|
||||||
<div className={classes.listArticles__columns__item}>Название</div>
|
|
||||||
<div className={classes.listArticles__columns__item}>Дата публикации</div>
|
|
||||||
<div className={classes.listArticles__columns__item}>Автор</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.listArticles__forms}>
|
|
||||||
{listArticles.map(item => <div className={classes.listArticles__forms__item}>
|
|
||||||
<div className={classes.listArticles__forms__item__title} onClick={() => navigate(`/articles/${item.id}/edit`)}>{item.title}</div>
|
|
||||||
<div className={classes.listArticles__forms__item__date}>24.06.24</div>
|
|
||||||
<div className={classes.listArticles__forms__item__author}>kuwsh1n</div>
|
|
||||||
<i class="fa-solid fa-ellipsis-vertical" id="action" data-bs-toggle="dropdown"></i>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="action">
|
|
||||||
<li><a class="dropdown-item" onClick={() => navigate(`/articles/${item.id}/`)}>Открыть</a></li>
|
|
||||||
<li><a class="dropdown-item" data-bs-toggle="modal" data-bs-target={`#checkModaltest`}>Удалить</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<CheckModal
|
|
||||||
postfix={'test'}
|
|
||||||
message={`Вы хотетите удалить статью <Test article>?`}
|
|
||||||
action={{
|
|
||||||
execute: () => {},
|
|
||||||
cancel: () => {}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Articles;
|
|
@ -1,143 +0,0 @@
|
|||||||
import React, { useState, useContext, useEffect } from "react";
|
|
||||||
import { useNavigate, useLocation, useParams } from 'react-router-dom';
|
|
||||||
import { useCookies } from "react-cookie";
|
|
||||||
import classes from "../assets/styles/newArticle.module.scss";
|
|
||||||
import MyButton from "../components/MyButton.jsx";
|
|
||||||
import Loading from "../components/Loading.jsx";
|
|
||||||
import MyInput from "../components/MyInput.jsx";
|
|
||||||
import TextEditor from "../components/TextEditor.jsx";
|
|
||||||
import { getArticleApi, editTagsApi, editTitleArticleApi, editArticleApi, addArticleApi } from "../hooks/api/articleApi.js";
|
|
||||||
|
|
||||||
const NewArticle = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
|
||||||
const { articleId } = useParams();
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
const [title, setTitle] = useState("");
|
|
||||||
const [tags, setTags] = useState([]);
|
|
||||||
const [newTag, setNewTag] = useState("")
|
|
||||||
const [ownerId, setOwnerId] = useState("");
|
|
||||||
|
|
||||||
const [contentArticle, setContentArticle] = useState('');
|
|
||||||
const [blocks, setBlocks] = useState('');
|
|
||||||
|
|
||||||
const [cookies, _, __] = useCookies(["user"]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getArticle() {
|
|
||||||
const response = await getArticleApi(cookies.token, articleId)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
console.log(response)
|
|
||||||
setTitle(response.data.article.title)
|
|
||||||
setTags(response.data.article.tags ? response.data.article.tags : [])
|
|
||||||
setOwnerId(response.data.article.owner_id)
|
|
||||||
setContentArticle(response.data.blocks ? response.data.blocks[0].data : '')
|
|
||||||
setBlocks(response.data.blocks ? response.data.blocks : false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getArticle()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
async function addTag() {
|
|
||||||
if (newTag.length > 0 && !tags.find(item => item === newTag)) {
|
|
||||||
const response = await editTagsApi(cookies.token, articleId, [newTag], false)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
setTags([...tags, newTag])
|
|
||||||
setNewTag("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeTag(item, index) {
|
|
||||||
const response = await editTagsApi(cookies.token, articleId, [item], true)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const cTags = [...tags]
|
|
||||||
cTags.splice(index, 1)
|
|
||||||
setTags(cTags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveArticle() {
|
|
||||||
const responseTitle = await editTitleArticleApi(cookies.token, articleId, title)
|
|
||||||
console.log(blocks)
|
|
||||||
const responseContentArticle = blocks ?
|
|
||||||
await editArticleApi(cookies.token, articleId, contentArticle) :
|
|
||||||
await addArticleApi(cookies.token, articleId, contentArticle)
|
|
||||||
|
|
||||||
console.log(responseContentArticle)
|
|
||||||
|
|
||||||
if (responseTitle.status === 200 && responseContentArticle.status === 200) {
|
|
||||||
navigate("/articles")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.main}>
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.header}>
|
|
||||||
<div className={classes.header__listInput}>
|
|
||||||
<div className={classes.header__listInput__date}>
|
|
||||||
<span>Дата создания</span>
|
|
||||||
<MyInput type={"datetime-local"}/>
|
|
||||||
</div>
|
|
||||||
<div className={classes.header__listInput__title}>
|
|
||||||
<span>Название статьи</span>
|
|
||||||
<MyInput type={"text"} value={title} change={setTitle}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.header__listBtn}>
|
|
||||||
{/* <MyButton text={'Предпросмотр'} class={"main__white"}/> */}
|
|
||||||
<MyButton text={'Опубликовать'} class={"main__green"} click={() => saveArticle()}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.tags}>
|
|
||||||
<div className={classes.tags__wrapper}>
|
|
||||||
<div className={classes.tags__wrapper__input}>
|
|
||||||
<span className={classes.tags__wrapper__input__title}>Добавить тэг</span>
|
|
||||||
<MyInput
|
|
||||||
type={"text"}
|
|
||||||
otherMainStyle={{border: "1px solid rgb(180, 180, 180)", borderRadius: "5px"}}
|
|
||||||
otherInputStyle={{border: "0px solid rgb(180, 180, 180)", width: "85%"}}
|
|
||||||
value={newTag}
|
|
||||||
change={setNewTag}
|
|
||||||
/>
|
|
||||||
<MyButton
|
|
||||||
type={"button"}
|
|
||||||
text={<i class="fa-solid fa-arrow-right"></i>}
|
|
||||||
class={"main__transparent"}
|
|
||||||
mainStyle={
|
|
||||||
{
|
|
||||||
position: "absolute",
|
|
||||||
right: "0",
|
|
||||||
top: "0",
|
|
||||||
height: "100%",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
otherStyle={{borderRadius: "0 5px 5px 0", padding: "3px 7px 0 7px"}}
|
|
||||||
click={() => addTag()}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={classes.tags__wrapper__list}>
|
|
||||||
{tags ? tags.map((item, i) =>
|
|
||||||
<div className={classes.tags__wrapper__list__item} key={i}>
|
|
||||||
<span>#{item}</span>
|
|
||||||
<i class="fa-solid fa-circle-xmark" onClick={() => removeTag(item, i)}></i>
|
|
||||||
</div>
|
|
||||||
) : <></>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<TextEditor data={contentArticle} setData={setContentArticle}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NewArticle;
|
|
@ -1,78 +0,0 @@
|
|||||||
import React, { useState, useContext, useEffect, useLocation } from "react";
|
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
|
||||||
import { useCookies } from "react-cookie";
|
|
||||||
import classes from "../assets/styles/viewArticle.module.scss";
|
|
||||||
import { FormsData, TypeAnswerData, answersData, UserData } from "../context";
|
|
||||||
import MyButton from "../components/MyButton.jsx";
|
|
||||||
import { getArticleApi } from "../hooks/api/articleApi.js";
|
|
||||||
import { getListUserApi } from "../hooks/api/profileApi.js";
|
|
||||||
|
|
||||||
|
|
||||||
const ViewArticle = () => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
// const location = useLocation();
|
|
||||||
const { articleId } = useParams();
|
|
||||||
|
|
||||||
const [title, setTitle] = useState("");
|
|
||||||
const [tags, setTags] = useState([]);
|
|
||||||
const [newTag, setNewTag] = useState("")
|
|
||||||
const [owner, setOwner] = useState("");
|
|
||||||
|
|
||||||
const [contentArticle, setContentArticle] = useState('');
|
|
||||||
|
|
||||||
const [cookies, _, __] = useCookies(["user"]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getArticle() {
|
|
||||||
const response = await getArticleApi(cookies.token, articleId)
|
|
||||||
const user = await getListUserApi(cookies.token)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
console.log(response)
|
|
||||||
setTitle(response.data.article.title)
|
|
||||||
setTags(response.data.article.tags ? response.data.article.tags : [])
|
|
||||||
setOwner(user.status === 200 ? user.data.find(item => item.id === response.data.article.owner_id).login : response.data.article.owner_id)
|
|
||||||
setContentArticle(response.data.blocks ? response.data.blocks[0].data : '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getArticle()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.main}>
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.header}>
|
|
||||||
<div className={classes.header__wrapper}>
|
|
||||||
<div className={classes.header__wrapper__article}>
|
|
||||||
<div className={classes.header__wrapper__article__title}>
|
|
||||||
<span className={classes.header__wrapper__article__title__name}>Название</span>
|
|
||||||
<span className={classes.header__wrapper__article__title__text}>{title}</span>
|
|
||||||
</div>
|
|
||||||
<div className={classes.header__wrapper__article__tags}>
|
|
||||||
{/* <span className={classes.header__wrapper__article__tags__name}>Тэги</span> */}
|
|
||||||
{tags.map(item => <div className={classes.header__wrapper__tags__item}>
|
|
||||||
<span>#{item}</span>
|
|
||||||
</div>)}
|
|
||||||
</div>
|
|
||||||
<div className={classes.header__wrapper__article__owner}>
|
|
||||||
<span className={classes.header__wrapper__article__owner__name}>Автор</span>
|
|
||||||
<span className={classes.header__wrapper__article__owner__text}>{owner}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<div className={classes.content__wrapper}>
|
|
||||||
<div className="classes.content__wrapper__article" dangerouslySetInnerHTML={{__html: contentArticle}}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default ViewArticle
|
|
@ -10,9 +10,6 @@ import ViewForm from "../pages/ViewForm.jsx";
|
|||||||
import AdminPanel from '../pages/AdminPanel.jsx';
|
import AdminPanel from '../pages/AdminPanel.jsx';
|
||||||
import AnswersForm from '../pages/AnswersForm.jsx';
|
import AnswersForm from '../pages/AnswersForm.jsx';
|
||||||
import TokensForm from '../pages/TokensForm.jsx';
|
import TokensForm from '../pages/TokensForm.jsx';
|
||||||
import Articles from '../pages/Articles.jsx';
|
|
||||||
import NewArticle from '../pages/NewArticle.jsx';
|
|
||||||
import ViewArticle from '../pages/ViewArticle.jsx';
|
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -53,18 +50,6 @@ const router = createBrowserRouter([
|
|||||||
{
|
{
|
||||||
path: "/tokens/:formId",
|
path: "/tokens/:formId",
|
||||||
element: <TokensForm/>
|
element: <TokensForm/>
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/articles",
|
|
||||||
element: <Articles/>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/articles/:articleId/edit",
|
|
||||||
element: <NewArticle/>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/articles/:articleId/",
|
|
||||||
element: <ViewArticle/>
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user