LabWork04-05 Additions
@ -22,20 +22,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lines": [
|
"lines": [
|
||||||
{
|
|
||||||
"typeId": "3",
|
|
||||||
"price": "25.00",
|
|
||||||
"amount": "4",
|
|
||||||
"total": "100.00",
|
|
||||||
"id": 23
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"typeId": "5",
|
|
||||||
"price": "10.00",
|
|
||||||
"amount": "1",
|
|
||||||
"total": "10.00",
|
|
||||||
"id": 24
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"typeId": "5",
|
"typeId": "5",
|
||||||
"price": "10.00",
|
"price": "10.00",
|
||||||
@ -112,13 +98,112 @@
|
|||||||
"amount": "1",
|
"amount": "1",
|
||||||
"total": "10.00",
|
"total": "10.00",
|
||||||
"id": 35
|
"id": 35
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "Я устал",
|
||||||
|
"date": "2024-01-05",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"typeId": "2",
|
"name": "Максим",
|
||||||
"price": "30.00",
|
"email": "masenkin73@gmail.com",
|
||||||
"amount": "3",
|
"text": "Я мухожук",
|
||||||
"total": "90.00",
|
"date": "2024-01-05",
|
||||||
"id": 36
|
"flag": "false",
|
||||||
|
"id": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С Новым годом",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С наступающим Рождеством",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "false",
|
||||||
|
"id": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С 23 февраля",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С 8 марта",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "false",
|
||||||
|
"id": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С Пасхой",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "Христос Воскрес",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "false",
|
||||||
|
"id": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "Воистину Воскрес",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "С Днём рождения",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "false",
|
||||||
|
"id": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "Счастья здоровья",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "Здоровья погибшим",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "false",
|
||||||
|
"id": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Максим",
|
||||||
|
"email": "masenkin73@gmail.com",
|
||||||
|
"text": "В ходе выполнения лабораторной работы пострадал один человек",
|
||||||
|
"date": "2024-01-06",
|
||||||
|
"flag": "true",
|
||||||
|
"id": 13
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -7,13 +7,13 @@ import Footer from './components/footer/Footer.jsx';
|
|||||||
|
|
||||||
const App = ({ routes }) => {
|
const App = ({ routes }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className='wrapper'>
|
||||||
<Header routes={routes} />
|
<Header routes={routes} />
|
||||||
<Container className='wrapper' as='main' fluid>
|
<Container as='main' fluid>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Container>
|
</Container>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BIN
LabWork_04-05/src/assets/bow.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
LabWork_04-05/src/assets/creeper.png
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 748 B |
BIN
LabWork_04-05/src/assets/skeleton.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
LabWork_04-05/src/assets/slime.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
LabWork_04-05/src/assets/steve.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
LabWork_04-05/src/assets/sword.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
LabWork_04-05/src/assets/trident.png
Normal file
After Width: | Height: | Size: 659 B |
BIN
LabWork_04-05/src/assets/zombie.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
@ -1,7 +1,7 @@
|
|||||||
/* Футер */
|
/* Футер */
|
||||||
/* Обертка футера */
|
/* Обертка футера */
|
||||||
.footer {
|
.footer {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 30px 0px;
|
padding: 30px 0px;
|
||||||
|
@ -13,6 +13,9 @@ const Footer = () => {
|
|||||||
<li className="nav__item">
|
<li className="nav__item">
|
||||||
<Link to="/contact_us" className="nav__link">Contact us</Link>
|
<Link to="/contact_us" className="nav__link">Contact us</Link>
|
||||||
</li>
|
</li>
|
||||||
|
<li className="nav__item">
|
||||||
|
<Link to="/admin_messages" className="nav__link">Admin messages</Link>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="footer__privacy">
|
<div className="footer__privacy">
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
.fields__price,
|
.fields__price,
|
||||||
.fields__amount,
|
.fields__amount,
|
||||||
.fields__name,
|
.fields__name,
|
||||||
.fields__email
|
.fields__email,
|
||||||
.fields__number,
|
.fields__number,
|
||||||
.fields__password,
|
.fields__password,
|
||||||
.fields__password_repeat {
|
.fields__password_repeat {
|
||||||
|
44
LabWork_04-05/src/components/messages/card/MessageCard.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.message__card {
|
||||||
|
width: 40%;
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
margin-right: 30px;
|
||||||
|
border: solid 3px #a721fa;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #2c2a2a;
|
||||||
|
}
|
||||||
|
.message__avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
.message__content {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.message__username {
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: #a721fa;
|
||||||
|
}
|
||||||
|
.message__text {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.message__date {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #666;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.message__card {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
26
LabWork_04-05/src/components/messages/card/MessageCard.jsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import './MessageCard.css';
|
||||||
|
|
||||||
|
const MessageCard = ({
|
||||||
|
avatar, username, text, date,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className='message__card'>
|
||||||
|
<img className='message__avatar' src={avatar} alt="avatar.png" />
|
||||||
|
<div className='message__content'>
|
||||||
|
<div className='message__username'>{username}</div>
|
||||||
|
<div className='message__text'>{text}</div>
|
||||||
|
<div className='message__date'>{date}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageCard.propTypes = {
|
||||||
|
avatar: PropTypes.object,
|
||||||
|
username: PropTypes.string,
|
||||||
|
text: PropTypes.string,
|
||||||
|
date: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessageCard;
|
11
LabWork_04-05/src/components/messages/card/MessageTable.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.messages__column {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 1060px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.messages__column {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
35
LabWork_04-05/src/components/messages/card/MessageTable.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import MessageCard from './MessageCard';
|
||||||
|
import useMessages from '../hooks/MessagesHook';
|
||||||
|
import Steve from '../../../assets/steve.png';
|
||||||
|
import Creeper from '../../../assets/creeper.png';
|
||||||
|
import Zombie from '../../../assets/zombie.png';
|
||||||
|
import Skeleton from '../../../assets/skeleton.png';
|
||||||
|
import Slime from '../../../assets/slime.png';
|
||||||
|
import './MessageTable.css';
|
||||||
|
|
||||||
|
const MessagesTable = () => {
|
||||||
|
const { messages } = useMessages('true');
|
||||||
|
|
||||||
|
const avatars = [Steve, Creeper, Zombie, Skeleton, Slime];
|
||||||
|
|
||||||
|
const getRandomIndex = () => {
|
||||||
|
const index = Math.floor(Math.random() * avatars.length);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="messages__table">
|
||||||
|
<div className="messages__column">
|
||||||
|
{messages.map((message, index) => (
|
||||||
|
<MessageCard key={index}
|
||||||
|
avatar={avatars[getRandomIndex()]}
|
||||||
|
username={message.name}
|
||||||
|
text={message.text}
|
||||||
|
date={message.date} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesTable;
|
71
LabWork_04-05/src/components/messages/form/Form.css
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
.form {
|
||||||
|
width: 28%;
|
||||||
|
max-width: 550px;
|
||||||
|
margin-right: 50px;
|
||||||
|
border: solid 5px #a721fa;
|
||||||
|
border-radius: 70px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #2c2a2a;
|
||||||
|
}
|
||||||
|
.form__header {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
.fields {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 11% 15%;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
.fields__name,
|
||||||
|
.fields__email {
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
.fields__message {
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 200px;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
.fields__input_checkbox {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
.fields__checkbox {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.fields__label {
|
||||||
|
padding-left: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.fields__submit {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 30px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #a721fa;
|
||||||
|
}
|
||||||
|
.fields__submit:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 10px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.fields__submit:active {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 10px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1180px) {
|
||||||
|
.form {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import Input from '../../input/Input.jsx';
|
||||||
|
import './Form.css';
|
||||||
|
|
||||||
|
const MessagesItemEditForm = ({ message, handleChange }) => {
|
||||||
|
const [isChecked, setIsChecked] = useState(message.flag);
|
||||||
|
|
||||||
|
const handleCheckboxChange = (event) => {
|
||||||
|
setIsChecked(event.target.checked);
|
||||||
|
handleChange(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input name='text' placeholder='Enter yor message' value={message.text} onChange={handleChange} className='fields__message' type='text' required />
|
||||||
|
<div className='fields__input_checkbox'>
|
||||||
|
<input name='flag' value={isChecked.toString()} onChange={handleCheckboxChange} className='fields__checkbox' type='checkbox' checked={isChecked || message.flag == 'true'}/>
|
||||||
|
<label className='fields__label' htmlFor="flag">Publish</label>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessagesItemEditForm.propTypes = {
|
||||||
|
message: PropTypes.object,
|
||||||
|
handleChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesItemEditForm;
|
45
LabWork_04-05/src/components/messages/form/MessagesForm.jsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Form } from 'react-bootstrap';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import useMessagesItemForm from '../hooks/MessagesItemFormHook';
|
||||||
|
import MessagesItemForm from './MessagesItemForm.jsx';
|
||||||
|
import './Form.css';
|
||||||
|
|
||||||
|
const MessagesForm = ({ id }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const {
|
||||||
|
message,
|
||||||
|
validated,
|
||||||
|
handleSubmit,
|
||||||
|
handleChange,
|
||||||
|
} = useMessagesItemForm(id);
|
||||||
|
|
||||||
|
const onSubmit = async (event) => {
|
||||||
|
if (await handleSubmit(event)) {
|
||||||
|
navigate('/messages');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form className='main__form form' noValidate validated={validated} onSubmit={onSubmit}>
|
||||||
|
<h2 className="form__header">Contact us</h2>
|
||||||
|
<div className='form__fields fields'>
|
||||||
|
<MessagesItemForm message={message} handleChange={handleChange} />
|
||||||
|
<Form.Group className='row justify-content-center m-0 mt-3'>
|
||||||
|
<Button className='fields__submit' type='submit' variant='primary'>
|
||||||
|
Send message
|
||||||
|
</Button>
|
||||||
|
</Form.Group>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessagesForm.propTypes = {
|
||||||
|
id: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesForm;
|
@ -0,0 +1,21 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Input from '../../input/Input.jsx';
|
||||||
|
import './Form.css';
|
||||||
|
|
||||||
|
const MessagesItemForm = ({ message, handleChange }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input name ='name' placeholder='Enter your name' value={message.name} onChange={handleChange} className='fields__name'type='text' required />
|
||||||
|
<Input name='email' placeholder='Enter your valid email' value={message.email} onChange={handleChange} className='fields__email' type='email' required />
|
||||||
|
<Input name='text' placeholder='Enter yor message' value={message.text} onChange={handleChange} className='fields__message' type='text' required />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessagesItemForm.propTypes = {
|
||||||
|
message: PropTypes.object,
|
||||||
|
handleChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesItemForm;
|
@ -0,0 +1,34 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import useModal from '../../messages/modal/ModalHook';
|
||||||
|
import MessagesApiService from '../service/MessagesApiService';
|
||||||
|
|
||||||
|
const useMessagesDeleteModal = (messagesChangeHandle) => {
|
||||||
|
const { isModalShow, showModal, hideModal } = useModal();
|
||||||
|
const [currentId, setCurrentId] = useState(0);
|
||||||
|
|
||||||
|
const showModalDialog = (id) => {
|
||||||
|
showModal();
|
||||||
|
setCurrentId(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
hideModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDelete = async () => {
|
||||||
|
await MessagesApiService.delete(currentId);
|
||||||
|
messagesChangeHandle();
|
||||||
|
toast.success('Сообщение успешно удалено', { id: 'MessagesTable' });
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDeleteModalShow: isModalShow,
|
||||||
|
showDeleteModal: showModalDialog,
|
||||||
|
handleDeleteConfirm: onDelete,
|
||||||
|
handleDeleteCancel: onClose,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMessagesDeleteModal;
|
@ -0,0 +1,45 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import useModal from '../../messages/modal/ModalHook';
|
||||||
|
import useMessagesItemForm from './MessagesItemFormHook';
|
||||||
|
|
||||||
|
const useMessagesFormModal = (messagesChangeHandle) => {
|
||||||
|
const { isModalShow, showModal, hideModal } = useModal();
|
||||||
|
const [currentId, setCurrentId] = useState(0);
|
||||||
|
|
||||||
|
const {
|
||||||
|
message,
|
||||||
|
validated,
|
||||||
|
handleSubmit,
|
||||||
|
handleChange,
|
||||||
|
resetValidity,
|
||||||
|
} = useMessagesItemForm(currentId, messagesChangeHandle);
|
||||||
|
|
||||||
|
const showModalDialog = (id) => {
|
||||||
|
setCurrentId(id);
|
||||||
|
resetValidity();
|
||||||
|
showModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
setCurrentId(-1);
|
||||||
|
hideModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (event) => {
|
||||||
|
if (await handleSubmit(event)) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isFormModalShow: isModalShow,
|
||||||
|
isFormValidated: validated,
|
||||||
|
showFormModal: showModalDialog,
|
||||||
|
currentMessage: message,
|
||||||
|
handleMessageChange: handleChange,
|
||||||
|
handleFormSubmit: onSubmit,
|
||||||
|
handleFormClose: onClose,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMessagesFormModal;
|
29
LabWork_04-05/src/components/messages/hooks/MessagesHook.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import MessagesApiService from '../service/MessagesApiService';
|
||||||
|
|
||||||
|
const useMessages = (typeFilter) => {
|
||||||
|
const [messagesRefresh, setMessagesRefresh] = useState(false);
|
||||||
|
const [messages, setMessages] = useState([]);
|
||||||
|
const handleMessagesChange = () => setMessagesRefresh(!messagesRefresh);
|
||||||
|
|
||||||
|
const getMessages = async () => {
|
||||||
|
let expand = '';
|
||||||
|
if (typeFilter) {
|
||||||
|
expand = `${expand}?flag=${typeFilter}`
|
||||||
|
}
|
||||||
|
const data = await MessagesApiService.getAll(expand);
|
||||||
|
setMessages(data ?? []);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getMessages();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [messagesRefresh, typeFilter]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
messages,
|
||||||
|
handleMessagesChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMessages;
|
@ -0,0 +1,67 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import MessagesApiService from '../service/MessagesApiService';
|
||||||
|
import useMessagesItem from './MessagesitemHook';
|
||||||
|
|
||||||
|
const useMessagesItemForm = (id, messagesChangeHandle) => {
|
||||||
|
const { message, setMessage } = useMessagesItem(id);
|
||||||
|
|
||||||
|
const [validated, setValidated] = useState(false);
|
||||||
|
|
||||||
|
const resetValidity = () => {
|
||||||
|
setValidated(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMessageObject = (formData) => {
|
||||||
|
const name = formData.name;
|
||||||
|
const email = formData.email;
|
||||||
|
const text = formData.text;
|
||||||
|
const date = formData.date;
|
||||||
|
const flag = Boolean(formData.flag);
|
||||||
|
return {
|
||||||
|
name: name.toString(),
|
||||||
|
email: email.toString(),
|
||||||
|
text: text.toString(),
|
||||||
|
date: date.toString(),
|
||||||
|
flag: flag.toString(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const inputName = event.target.name;
|
||||||
|
const inputValue = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
|
||||||
|
setMessage({
|
||||||
|
...message,
|
||||||
|
[inputName]: inputValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (event) => {
|
||||||
|
const form = event.currentTarget;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
const body = getMessageObject(message);
|
||||||
|
if (form.checkValidity()) {
|
||||||
|
if (id === undefined) {
|
||||||
|
await MessagesApiService.create(body);
|
||||||
|
} else {
|
||||||
|
await MessagesApiService.update(id, body);
|
||||||
|
}
|
||||||
|
if (messagesChangeHandle) messagesChangeHandle();
|
||||||
|
toast.success('Комментарий успешно добавлен', { id: 'MessagesTable' });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setValidated(true);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
validated,
|
||||||
|
handleSubmit,
|
||||||
|
handleChange,
|
||||||
|
resetValidity,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMessagesItemForm;
|
@ -0,0 +1,37 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import MessagesApiService from '../service/MessagesApiService';
|
||||||
|
|
||||||
|
const useMessagesItem = (id) => {
|
||||||
|
const currentDate = new Date().toISOString().split('T')[0];
|
||||||
|
|
||||||
|
const emptyMessage = {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
text: '',
|
||||||
|
date: currentDate,
|
||||||
|
flag: false,
|
||||||
|
};
|
||||||
|
const [message, setMessage] = useState({ ...emptyMessage });
|
||||||
|
|
||||||
|
const getMessage = async (messageId = undefined) => {
|
||||||
|
if (messageId && messageId > 0) {
|
||||||
|
const data = await MessagesApiService.get(messageId);
|
||||||
|
setMessage(data);
|
||||||
|
} else {
|
||||||
|
setMessage({ ...emptyMessage });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getMessage(id);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
setMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMessagesItem;
|
41
LabWork_04-05/src/components/messages/modal/ModalConfirm.jsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Modal } from 'react-bootstrap';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
|
const ModalConfirm = ({
|
||||||
|
show, title, message, onConfirm, onClose,
|
||||||
|
}) => {
|
||||||
|
return createPortal(
|
||||||
|
<Modal show={show} backdrop='static' onHide={() => onClose()}>
|
||||||
|
<Modal.Header className='pt-2 pb-2 ps-3 pe-3' closeButton>
|
||||||
|
<Modal.Title>{title}</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
|
||||||
|
<Modal.Body>
|
||||||
|
{message}
|
||||||
|
</Modal.Body>
|
||||||
|
|
||||||
|
<Modal.Footer className='m-0 pt-2 pb-2 ps-3 pe-3 row justify-content-center'>
|
||||||
|
<Button variant='secondary' className='col-5 m-0 me-2'
|
||||||
|
onClick={() => onClose()}>
|
||||||
|
No
|
||||||
|
</Button>
|
||||||
|
<Button variant='primary' className='col-5 m-0 ms-2'
|
||||||
|
onClick={() => onConfirm()}>
|
||||||
|
Yes
|
||||||
|
</Button>
|
||||||
|
</Modal.Footer>
|
||||||
|
</Modal>,
|
||||||
|
document.body,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ModalConfirm.propTypes = {
|
||||||
|
show: PropTypes.bool,
|
||||||
|
title: PropTypes.string,
|
||||||
|
message: PropTypes.string,
|
||||||
|
onConfirm: PropTypes.func,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalConfirm;
|
42
LabWork_04-05/src/components/messages/modal/ModalForm.jsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Form, Modal } from 'react-bootstrap';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
|
const ModalForm = ({
|
||||||
|
show, title, validated, onSubmit, onClose, children,
|
||||||
|
}) => {
|
||||||
|
return createPortal(
|
||||||
|
<Modal show={show} backdrop='static' onHide={() => onClose()}>
|
||||||
|
<Modal.Header className='pt-2 pb-2 ps-3 pe-3' closeButton>
|
||||||
|
<Modal.Title>{title}</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Form className='m-0' noValidate validated={validated} onSubmit={onSubmit}>
|
||||||
|
<Modal.Body>
|
||||||
|
{children}
|
||||||
|
</Modal.Body>
|
||||||
|
|
||||||
|
<Modal.Footer className='m-0 pt-2 pb-2 ps-3 pe-3 row justify-content-center'>
|
||||||
|
<Button variant='secondary' className='col-5 m-0 me-2'
|
||||||
|
onClick={() => onClose()}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button variant='primary' className='col-5 m-0 ms-2' type='submit'>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</Modal.Footer>
|
||||||
|
</Form>
|
||||||
|
</Modal>,
|
||||||
|
document.body,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ModalForm.propTypes = {
|
||||||
|
show: PropTypes.bool,
|
||||||
|
title: PropTypes.string,
|
||||||
|
validated: PropTypes.bool,
|
||||||
|
onSubmit: PropTypes.func,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalForm;
|
21
LabWork_04-05/src/components/messages/modal/ModalHook.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const useModal = () => {
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
|
const showModalDialog = () => {
|
||||||
|
setShowModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideModalDialog = () => {
|
||||||
|
setShowModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isModalShow: showModal,
|
||||||
|
showModal: showModalDialog,
|
||||||
|
hideModal: hideModalDialog,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useModal;
|
@ -0,0 +1,5 @@
|
|||||||
|
import ApiService from '../../api/ApiService';
|
||||||
|
|
||||||
|
const MessagesApiService = new ApiService('messages');
|
||||||
|
|
||||||
|
export default MessagesApiService;
|
62
LabWork_04-05/src/components/messages/table/Messages.css
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
.admin_messages_table {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 600px;
|
||||||
|
padding: 3% 3%;
|
||||||
|
border: solid 5px #a721fa;
|
||||||
|
border-radius: 70px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #2c2a2a;
|
||||||
|
}
|
||||||
|
.table__messages {
|
||||||
|
max-height: 550px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.table__row_header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.table_messages__row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 30px;
|
||||||
|
background-color: #363434;
|
||||||
|
}
|
||||||
|
.table__column_index,
|
||||||
|
.table__column_name,
|
||||||
|
.table__column_email,
|
||||||
|
.table__column_text,
|
||||||
|
.table__column_date,
|
||||||
|
.table__column_flag,
|
||||||
|
.table__column_actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 50px;
|
||||||
|
width: calc(100% / 7);
|
||||||
|
word-wrap: break-word;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1240px) {
|
||||||
|
.table {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table__row_header {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.table__row {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
58
LabWork_04-05/src/components/messages/table/Messages.jsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import ModalConfirm from '../../messages/modal/ModalConfirm.jsx';
|
||||||
|
import ModalForm from '../../messages/modal/ModalForm.jsx';
|
||||||
|
import useMessagesDeleteModal from '../hooks/MessagesDeleteModalHook';
|
||||||
|
import useMessagesFormModal from '../hooks/MessagesFormModalHook';
|
||||||
|
import useMessages from '../hooks/MessagesHook';
|
||||||
|
import MessagesTable from './MessagesTable.jsx';
|
||||||
|
import MessagesTableRow from './MessagesTableRow.jsx';
|
||||||
|
import MessagesItemEditForm from '../form/MessageItemEditForm.jsx';
|
||||||
|
import './Messages.css';
|
||||||
|
|
||||||
|
const Messages = () => {
|
||||||
|
const { messages, handleMessagesChange } = useMessages();
|
||||||
|
|
||||||
|
const {
|
||||||
|
isDeleteModalShow,
|
||||||
|
showDeleteModal,
|
||||||
|
handleDeleteConfirm,
|
||||||
|
handleDeleteCancel,
|
||||||
|
} = useMessagesDeleteModal(handleMessagesChange);
|
||||||
|
|
||||||
|
const {
|
||||||
|
isFormModalShow,
|
||||||
|
isFormValidated,
|
||||||
|
showFormModal,
|
||||||
|
currentMessage,
|
||||||
|
handleMessageChange,
|
||||||
|
handleFormSubmit,
|
||||||
|
handleFormClose,
|
||||||
|
} = useMessagesFormModal(handleMessagesChange);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MessagesTable>
|
||||||
|
{
|
||||||
|
messages.map((message, index) =>
|
||||||
|
<MessagesTableRow key={message.id}
|
||||||
|
index={index}
|
||||||
|
message={message}
|
||||||
|
onDelete={() => showDeleteModal(message.id)}
|
||||||
|
onEdit={() => showFormModal(message.id)}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
|
</MessagesTable>
|
||||||
|
|
||||||
|
<ModalConfirm show={isDeleteModalShow}
|
||||||
|
onConfirm={handleDeleteConfirm} onClose={handleDeleteCancel}
|
||||||
|
title='Delete' message='Delete message?' />
|
||||||
|
|
||||||
|
<ModalForm show={isFormModalShow} validated={isFormValidated}
|
||||||
|
onSubmit={handleFormSubmit} onClose={handleFormClose}
|
||||||
|
title='Edit message'>
|
||||||
|
<MessagesItemEditForm message={currentMessage} handleChange={handleMessageChange} />
|
||||||
|
</ModalForm>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Messages;
|
@ -0,0 +1,30 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const MessagesTable = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<div className='admin_messages_table'>
|
||||||
|
<table>
|
||||||
|
<thead className='table__row_header'>
|
||||||
|
<tr className='table__row_header'>
|
||||||
|
<th className='table__column_index' scope='col'>№</th>
|
||||||
|
<th className='table__column_name' scope='col'>Name</th>
|
||||||
|
<th className='table__column_email' scope='col'>Email</th>
|
||||||
|
<th className='table__column_text' scope='col'>Text</th>
|
||||||
|
<th className='table__column_date' scope='col'>Date</th>
|
||||||
|
<th className='table__column_flag' scope='col'>Flag</th>
|
||||||
|
<th className='table__column_actions' scope='col'>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className='table__messages'>
|
||||||
|
{children}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessagesTable.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesTable;
|
@ -0,0 +1,35 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { PencilSquare, Trash3 } from 'react-bootstrap-icons';
|
||||||
|
|
||||||
|
const MessagesTableRow = ({
|
||||||
|
index, message, onDelete, onEdit,
|
||||||
|
}) => {
|
||||||
|
const handleAnchorClick = (event, action) => {
|
||||||
|
event.preventDefault();
|
||||||
|
action();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr className='table_messages__row'>
|
||||||
|
<th className='table__column_index' scope="row">{index + 1}</th>
|
||||||
|
<td className='table__column_name'>{message.name}</td>
|
||||||
|
<td className='table__column_email'>{message.email}</td>
|
||||||
|
<td className='table__column_text'>{message.text}</td>
|
||||||
|
<td className='table__column_date'>{message.date}</td>
|
||||||
|
<td className='table__column_flag'>{message.flag}</td>
|
||||||
|
<td className='table__column_actions'>
|
||||||
|
<a href="#" onClick={(event) => handleAnchorClick(event, onEdit)}><PencilSquare /></a>
|
||||||
|
<a href="#" onClick={(event) => handleAnchorClick(event, onDelete)}><Trash3 /></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MessagesTableRow.propTypes = {
|
||||||
|
index: PropTypes.number,
|
||||||
|
message: PropTypes.object,
|
||||||
|
onDelete: PropTypes.func,
|
||||||
|
onEdit: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesTableRow;
|
@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
.header *> .nav__item {
|
.header *> .nav__item {
|
||||||
display: inline-block;;
|
display: inline-block;;
|
||||||
width: calc(1/6 * 100%);
|
width: calc(1/7 * 100%);
|
||||||
}
|
}
|
||||||
.nav__item:not(:last-child) {
|
.nav__item:not(:last-child) {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
@ -10,8 +10,8 @@ const Navigation = ({ routes }) => {
|
|||||||
return (
|
return (
|
||||||
<Navbar className='header__nav nav'>
|
<Navbar className='header__nav nav'>
|
||||||
<Container fluid>
|
<Container fluid>
|
||||||
<Navbar.Collapse id='main-navbar'>
|
<Navbar.Collapse id='main-navbar' expand='md'>
|
||||||
<Nav activeKey={location.pathname}>
|
<Nav activeKey={location.pathname} className='nav__list'>
|
||||||
{pages.map((page) => (
|
{pages.map((page) => (
|
||||||
<Nav.Item className='nav__item' key={page.path}>
|
<Nav.Item className='nav__item' key={page.path}>
|
||||||
<Nav.Link as={Link} className="nav__link" to={page.path ?? '/'}>
|
<Nav.Link as={Link} className="nav__link" to={page.path ?? '/'}>
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
import Row from '../shopTable/Row.jsx';
|
import Row from '../shopTable/Row.jsx';
|
||||||
import './Table.css';
|
import './Table.css';
|
||||||
|
|
||||||
const Table = () => {
|
const Table = ({ data }) => {
|
||||||
return (
|
return (
|
||||||
<div className='main__table table'>
|
<div className='main__table table'>
|
||||||
<Row name="protection" labels={['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1']} />
|
{data.map((rowData, index) => (
|
||||||
<Row name="unbreaking" labels={['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1']} />
|
<Row key={index} name={rowData.name} labels={rowData.labels} />
|
||||||
<Row name="mending" labels={['Mending']} />
|
))}
|
||||||
<Row name="thorns" labels={['Thorns 3', 'Thorns 2', 'Thorns 1']} />
|
|
||||||
<Row name="swift_sneak" labels={['Swift Sneak 2', 'Swift Sneak 1']} />
|
|
||||||
<Row name="feather_falling" labels={['Feather Falling 4', 'Feather Falling 3','Feather Falling 2', 'Feather Falling 1']} />
|
|
||||||
<Row name="soul_speed" labels={['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1']} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Table.propTypes = {
|
||||||
|
data: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
|
})
|
||||||
|
).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default Table;
|
export default Table;
|
||||||
|
@ -101,7 +101,6 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
._container {
|
._container {
|
||||||
max-width: 1680px;
|
max-width: 1680px;
|
||||||
|
@ -7,10 +7,16 @@ import './index.css'
|
|||||||
import ErrorPage from "./pages/ErrorPage.jsx";
|
import ErrorPage from "./pages/ErrorPage.jsx";
|
||||||
import HomePage from './pages/HomePage.jsx';
|
import HomePage from './pages/HomePage.jsx';
|
||||||
import ArmorPage from './pages/ArmorPage.jsx';
|
import ArmorPage from './pages/ArmorPage.jsx';
|
||||||
|
import ToolsPage from './pages/ToolsPage.jsx';
|
||||||
|
import SwordPage from './pages/SwordPage.jsx';
|
||||||
|
import BowPage from './pages/BowPage.jsx';
|
||||||
|
import TridentPage from './pages/TridentPage.jsx';
|
||||||
import AccountPage from './pages/AccountPage.jsx';
|
import AccountPage from './pages/AccountPage.jsx';
|
||||||
import ShopPage from './pages/ShopPage.jsx';
|
import ShopPage from './pages/ShopPage.jsx';
|
||||||
import AboutUsPage from './pages/AbousUsPage.jsx';
|
import AboutUsPage from './pages/AbousUsPage.jsx';
|
||||||
import ContactUsPage from './pages/ContactUsPage.jsx';
|
import ContactUsPage from './pages/ContactUsPage.jsx';
|
||||||
|
import AdminMessagesPage from './pages/AdminMessagesPage.jsx';
|
||||||
|
import MessagesPage from './pages/MessagesPage.jsx';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@ -25,23 +31,23 @@ const routes = [
|
|||||||
title: 'Armor',
|
title: 'Armor',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/error',
|
path: '/tools',
|
||||||
element: <ErrorPage />,
|
element: <ToolsPage />,
|
||||||
title: 'Tools',
|
title: 'Tools',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/error',
|
path: '/sword',
|
||||||
element: <ErrorPage />,
|
element: <SwordPage />,
|
||||||
title: 'Sword',
|
title: 'Sword',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/error',
|
path: '/bow',
|
||||||
element: <ErrorPage />,
|
element: <BowPage />,
|
||||||
title: 'Bow',
|
title: 'Bow',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/error',
|
path: '/trident',
|
||||||
element: <ErrorPage />,
|
element: <TridentPage />,
|
||||||
title: 'Trident',
|
title: 'Trident',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -64,6 +70,15 @@ const routes = [
|
|||||||
path: '/shop/:id?',
|
path: '/shop/:id?',
|
||||||
element: <ShopPage />,
|
element: <ShopPage />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/admin_messages',
|
||||||
|
element: <AdminMessagesPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/messages',
|
||||||
|
element: <MessagesPage />,
|
||||||
|
title: 'Messages',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
|
14
LabWork_04-05/src/pages/AdminMessagesPage.jsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import Messages from "../components/messages/table/Messages";
|
||||||
|
import './css/AdminMessagesPage.css';
|
||||||
|
|
||||||
|
const AdminMessagesPage = () => {
|
||||||
|
return (
|
||||||
|
<main className="main__admin_messages">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<Messages />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminMessagesPage;
|
@ -3,6 +3,16 @@ import Table from '../components/shopTable/Table';
|
|||||||
import './css/ArmorPage.css';
|
import './css/ArmorPage.css';
|
||||||
|
|
||||||
const ArmorPage = () => {
|
const ArmorPage = () => {
|
||||||
|
const tableData = [
|
||||||
|
{ name: "protection", labels: ['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1'] },
|
||||||
|
{ name: "unbreaking", labels: ['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1'] },
|
||||||
|
{ name: "mending", labels: ['Mending'] },
|
||||||
|
{ name: "thorns", labels: ['Thorns 3', 'Thorns 2', 'Thorns 1'] },
|
||||||
|
{ name: "swift_sneak", labels: ['Swift Sneak 2', 'Swift Sneak 1'] },
|
||||||
|
{ name: "feather_falling", labels: ['Feather Falling 4', 'Feather Falling 3', 'Feather Falling 2', 'Feather Falling 1'] },
|
||||||
|
{ name: "soul_speed", labels: ['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1'] },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main_armor">
|
<main className="main_armor">
|
||||||
<div className="main__container _container">
|
<div className="main__container _container">
|
||||||
@ -14,7 +24,7 @@ const ArmorPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Table />
|
<Table data={tableData} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
33
LabWork_04-05/src/pages/BowPage.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Bow from '../assets/bow.png';
|
||||||
|
import Table from '../components/shopTable/Table';
|
||||||
|
import './css/BowPage.css';
|
||||||
|
|
||||||
|
const BowPage = () => {
|
||||||
|
const tableData = [
|
||||||
|
{ name: "protection", labels: ['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1'] },
|
||||||
|
{ name: "unbreaking", labels: ['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1'] },
|
||||||
|
{ name: "mending", labels: ['Mending'] },
|
||||||
|
{ name: "thorns", labels: ['Thorns 3', 'Thorns 2', 'Thorns 1'] },
|
||||||
|
{ name: "swift_sneak", labels: ['Swift Sneak 2', 'Swift Sneak 1'] },
|
||||||
|
{ name: "feather_falling", labels: ['Feather Falling 4', 'Feather Falling 3', 'Feather Falling 2', 'Feather Falling 1'] },
|
||||||
|
{ name: "soul_speed", labels: ['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="main_bow">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<div className="main__banner banner">
|
||||||
|
<div className="banner__square1"></div>
|
||||||
|
<div className="banner__square2">
|
||||||
|
<div className="banner__img">
|
||||||
|
<img src={Bow} alt="bow.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table data={tableData} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BowPage;
|
@ -1,20 +1,14 @@
|
|||||||
import Input from '../components/input/Input.jsx';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Form } from 'react-bootstrap';
|
import MessagesForm from '../components/messages/form/MessagesForm.jsx';
|
||||||
import './css/ContactUsPage.css';
|
import './css/ContactUsPage.css';
|
||||||
|
|
||||||
const ContactUsPage = () => {
|
const ContactUsPage = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main_contact">
|
<main className="main_contact">
|
||||||
<div className="main__container _container">
|
<div className="main__container _container">
|
||||||
<Form className="main__form form needs-validation" action="contact_us.html" method="get" noValidate>
|
<MessagesForm id={id} />
|
||||||
<h2 className="form__header">Contact us</h2>
|
|
||||||
<div className="form__fields fields">
|
|
||||||
<Input name="name" placeholder="Enter your name" className="fields__name" type="text" required/>
|
|
||||||
<Input name="email" placeholder="Enter your valid email" className="fields__email" type="email" required/>
|
|
||||||
<Input name="message" placeholder="Enter your message" className="fields__message" type="text" required/>
|
|
||||||
<Input name="submit" className="fields__submit" type="submit" value="Send message" required/>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
<div className="main__info info_table">
|
<div className="main__info info_table">
|
||||||
<div className="info_table__row">
|
<div className="info_table__row">
|
||||||
<div className="info_table__column">
|
<div className="info_table__column">
|
||||||
|
@ -7,14 +7,16 @@ const ErrorPage = () => {
|
|||||||
const error = useRouteError();
|
const error = useRouteError();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container fluid className='container'>
|
<div className="main__container">
|
||||||
|
<Container fluid className='container'>
|
||||||
<Alert className='alert' variant='danger'>
|
<Alert className='alert' variant='danger'>
|
||||||
{error?.message ?? 'Page not found 404'}
|
{error?.message ?? 'Page not found 404'}
|
||||||
</Alert>
|
</Alert>
|
||||||
<iframe className='video' src="https://www.youtube.com/embed/dQw4w9WgXcQ" title="Never Gonna Give You Up" allow="accelerometer autoplay clipboard-write encrypted-media gyroscope picture-in-picture" allowfullscreen></iframe>
|
<iframe className='video' src="https://www.youtube.com/embed/dQw4w9WgXcQ" title="Never Gonna Give You Up" ></iframe>
|
||||||
<Button className='button' variant='primary'
|
<Button className='button' variant='primary'
|
||||||
onClick={() => navigate(-1)}>Back</Button>
|
onClick={() => navigate(-1)}>Back</Button>
|
||||||
</Container>
|
</Container>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
14
LabWork_04-05/src/pages/MessagesPage.jsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import MessagesTable from "../components/messages/card/MessageTable.jsx";
|
||||||
|
import './css/MessagesPage.css';
|
||||||
|
|
||||||
|
const MessagesPage = () => {
|
||||||
|
return (
|
||||||
|
<main className="main__messages">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<MessagesTable />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MessagesPage;
|
33
LabWork_04-05/src/pages/SwordPage.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Sword from '../assets/sword.png';
|
||||||
|
import Table from '../components/shopTable/Table';
|
||||||
|
import './css/SwordPage.css';
|
||||||
|
|
||||||
|
const SwordPage = () => {
|
||||||
|
const tableData = [
|
||||||
|
{ name: "protection", labels: ['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1'] },
|
||||||
|
{ name: "unbreaking", labels: ['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1'] },
|
||||||
|
{ name: "mending", labels: ['Mending'] },
|
||||||
|
{ name: "thorns", labels: ['Thorns 3', 'Thorns 2', 'Thorns 1'] },
|
||||||
|
{ name: "swift_sneak", labels: ['Swift Sneak 2', 'Swift Sneak 1'] },
|
||||||
|
{ name: "feather_falling", labels: ['Feather Falling 4', 'Feather Falling 3', 'Feather Falling 2', 'Feather Falling 1'] },
|
||||||
|
{ name: "soul_speed", labels: ['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="main_sword">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<div className="main__banner banner">
|
||||||
|
<div className="banner__square1"></div>
|
||||||
|
<div className="banner__square2">
|
||||||
|
<div className="banner__img">
|
||||||
|
<img src={Sword} alt="sword.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table data={tableData} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SwordPage;
|
33
LabWork_04-05/src/pages/ToolsPage.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Pickaxe from '../assets/pickaxe.png';
|
||||||
|
import Table from '../components/shopTable/Table';
|
||||||
|
import './css/ToolsPage.css';
|
||||||
|
|
||||||
|
const ToolsPage = () => {
|
||||||
|
const tableData = [
|
||||||
|
{ name: "protection", labels: ['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1'] },
|
||||||
|
{ name: "unbreaking", labels: ['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1'] },
|
||||||
|
{ name: "mending", labels: ['Mending'] },
|
||||||
|
{ name: "thorns", labels: ['Thorns 3', 'Thorns 2', 'Thorns 1'] },
|
||||||
|
{ name: "swift_sneak", labels: ['Swift Sneak 2', 'Swift Sneak 1'] },
|
||||||
|
{ name: "feather_falling", labels: ['Feather Falling 4', 'Feather Falling 3', 'Feather Falling 2', 'Feather Falling 1'] },
|
||||||
|
{ name: "soul_speed", labels: ['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="main_tools">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<div className="main__banner banner">
|
||||||
|
<div className="banner__square1"></div>
|
||||||
|
<div className="banner__square2">
|
||||||
|
<div className="banner__img">
|
||||||
|
<img src={Pickaxe} alt="pickaxe.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table data={tableData} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToolsPage;
|
33
LabWork_04-05/src/pages/TridentPage.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Trident from '../assets/trident.png';
|
||||||
|
import Table from '../components/shopTable/Table';
|
||||||
|
import './css/TridentPage.css';
|
||||||
|
|
||||||
|
const TridentPage = () => {
|
||||||
|
const tableData = [
|
||||||
|
{ name: "protection", labels: ['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1'] },
|
||||||
|
{ name: "unbreaking", labels: ['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1'] },
|
||||||
|
{ name: "mending", labels: ['Mending'] },
|
||||||
|
{ name: "thorns", labels: ['Thorns 3', 'Thorns 2', 'Thorns 1'] },
|
||||||
|
{ name: "swift_sneak", labels: ['Swift Sneak 2', 'Swift Sneak 1'] },
|
||||||
|
{ name: "feather_falling", labels: ['Feather Falling 4', 'Feather Falling 3', 'Feather Falling 2', 'Feather Falling 1'] },
|
||||||
|
{ name: "soul_speed", labels: ['Soul Speed 3', 'Soul Speed 2', 'Soul Speed 1'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="main_trident">
|
||||||
|
<div className="main__container _container">
|
||||||
|
<div className="main__banner banner">
|
||||||
|
<div className="banner__square1"></div>
|
||||||
|
<div className="banner__square2">
|
||||||
|
<div className="banner__img">
|
||||||
|
<img src={Trident} alt="trident.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table data={tableData} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TridentPage;
|
0
LabWork_04-05/src/pages/css/AdminMessagesPage.css
Normal file
14
LabWork_04-05/src/pages/css/BowPage.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* Bow page */
|
||||||
|
/* Баннер */
|
||||||
|
.main_bow *> .banner__square1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.main_bow *> .banner__square2 {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: -10px -10px 10px 10px rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
.main_bow *> .banner__img {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
|
.main__container {
|
||||||
|
padding-top: 75px;
|
||||||
|
}
|
||||||
.container {
|
.container {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: 7%;
|
|
||||||
background-color: #2c2a2a;
|
background-color: #2c2a2a;
|
||||||
border: solid 3px #a721fa;
|
border: solid 3px #a721fa;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
|
3
LabWork_04-05/src/pages/css/MessagesPage.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.main__messages ._container {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
14
LabWork_04-05/src/pages/css/SwordPage.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* Sword page */
|
||||||
|
/* Баннер */
|
||||||
|
.main_sword *> .banner__square1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.main_sword *> .banner__square2 {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: -10px -10px 10px 10px rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
.main_sword *> .banner__img {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
14
LabWork_04-05/src/pages/css/ToolsPage.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* Tools page */
|
||||||
|
/* Баннер */
|
||||||
|
.main_tools *> .banner__square1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.main_tools *> .banner__square2 {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: -10px -10px 10px 10px rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
.main_tools *> .banner__img img {
|
||||||
|
width: 150%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
14
LabWork_04-05/src/pages/css/TridentPage.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* Trident page */
|
||||||
|
/* Баннер */
|
||||||
|
.main_trident *> .banner__square1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.main_trident *> .banner__square2 {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: -10px -10px 10px 10px rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
.main_trident *> .banner__img img {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|