LabWork04-05 Additions
@ -22,20 +22,6 @@
|
||||
}
|
||||
],
|
||||
"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",
|
||||
"price": "10.00",
|
||||
@ -112,13 +98,112 @@
|
||||
"amount": "1",
|
||||
"total": "10.00",
|
||||
"id": 35
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"name": "Максим",
|
||||
"email": "masenkin73@gmail.com",
|
||||
"text": "Я устал",
|
||||
"date": "2024-01-05",
|
||||
"flag": "true",
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"typeId": "2",
|
||||
"price": "30.00",
|
||||
"amount": "3",
|
||||
"total": "90.00",
|
||||
"id": 36
|
||||
"name": "Максим",
|
||||
"email": "masenkin73@gmail.com",
|
||||
"text": "Я мухожук",
|
||||
"date": "2024-01-05",
|
||||
"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 }) => {
|
||||
return (
|
||||
<>
|
||||
<div className='wrapper'>
|
||||
<Header routes={routes} />
|
||||
<Container className='wrapper' as='main' fluid>
|
||||
<Container as='main' fluid>
|
||||
<Outlet />
|
||||
</Container>
|
||||
<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 {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 30px 0px;
|
||||
|
@ -13,6 +13,9 @@ const Footer = () => {
|
||||
<li className="nav__item">
|
||||
<Link to="/contact_us" className="nav__link">Contact us</Link>
|
||||
</li>
|
||||
<li className="nav__item">
|
||||
<Link to="/admin_messages" className="nav__link">Admin messages</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div className="footer__privacy">
|
||||
|
@ -37,7 +37,7 @@
|
||||
.fields__price,
|
||||
.fields__amount,
|
||||
.fields__name,
|
||||
.fields__email
|
||||
.fields__email,
|
||||
.fields__number,
|
||||
.fields__password,
|
||||
.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 {
|
||||
display: inline-block;;
|
||||
width: calc(1/6 * 100%);
|
||||
width: calc(1/7 * 100%);
|
||||
}
|
||||
.nav__item:not(:last-child) {
|
||||
margin-right: 20px;
|
||||
|
@ -10,8 +10,8 @@ const Navigation = ({ routes }) => {
|
||||
return (
|
||||
<Navbar className='header__nav nav'>
|
||||
<Container fluid>
|
||||
<Navbar.Collapse id='main-navbar'>
|
||||
<Nav activeKey={location.pathname}>
|
||||
<Navbar.Collapse id='main-navbar' expand='md'>
|
||||
<Nav activeKey={location.pathname} className='nav__list'>
|
||||
{pages.map((page) => (
|
||||
<Nav.Item className='nav__item' key={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 './Table.css';
|
||||
|
||||
const Table = () => {
|
||||
const Table = ({ data }) => {
|
||||
return (
|
||||
<div className='main__table table'>
|
||||
<Row name="protection" labels={['Protection 4', 'Protection 3', 'Protection 2', 'Protection 1']} />
|
||||
<Row name="unbreaking" labels={['Unbreaking 3', 'Unbreaking 2', 'Unbreaking 1']} />
|
||||
<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']} />
|
||||
{data.map((rowData, index) => (
|
||||
<Row key={index} name={rowData.name} labels={rowData.labels} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Table.propTypes = {
|
||||
data: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
};
|
||||
|
||||
export default Table;
|
||||
|
@ -101,7 +101,6 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
._container {
|
||||
max-width: 1680px;
|
||||
|
@ -7,10 +7,16 @@ import './index.css'
|
||||
import ErrorPage from "./pages/ErrorPage.jsx";
|
||||
import HomePage from './pages/HomePage.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 ShopPage from './pages/ShopPage.jsx';
|
||||
import AboutUsPage from './pages/AbousUsPage.jsx';
|
||||
import ContactUsPage from './pages/ContactUsPage.jsx';
|
||||
import AdminMessagesPage from './pages/AdminMessagesPage.jsx';
|
||||
import MessagesPage from './pages/MessagesPage.jsx';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -25,23 +31,23 @@ const routes = [
|
||||
title: 'Armor',
|
||||
},
|
||||
{
|
||||
path: '/error',
|
||||
element: <ErrorPage />,
|
||||
path: '/tools',
|
||||
element: <ToolsPage />,
|
||||
title: 'Tools',
|
||||
},
|
||||
{
|
||||
path: '/error',
|
||||
element: <ErrorPage />,
|
||||
path: '/sword',
|
||||
element: <SwordPage />,
|
||||
title: 'Sword',
|
||||
},
|
||||
{
|
||||
path: '/error',
|
||||
element: <ErrorPage />,
|
||||
path: '/bow',
|
||||
element: <BowPage />,
|
||||
title: 'Bow',
|
||||
},
|
||||
{
|
||||
path: '/error',
|
||||
element: <ErrorPage />,
|
||||
path: '/trident',
|
||||
element: <TridentPage />,
|
||||
title: 'Trident',
|
||||
},
|
||||
{
|
||||
@ -64,6 +70,15 @@ const routes = [
|
||||
path: '/shop/:id?',
|
||||
element: <ShopPage />,
|
||||
},
|
||||
{
|
||||
path: '/admin_messages',
|
||||
element: <AdminMessagesPage />,
|
||||
},
|
||||
{
|
||||
path: '/messages',
|
||||
element: <MessagesPage />,
|
||||
title: 'Messages',
|
||||
},
|
||||
];
|
||||
|
||||
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';
|
||||
|
||||
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 (
|
||||
<main className="main_armor">
|
||||
<div className="main__container _container">
|
||||
@ -14,7 +24,7 @@ const ArmorPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Table />
|
||||
<Table data={tableData} />
|
||||
</div>
|
||||
</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 { Form } from 'react-bootstrap';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import MessagesForm from '../components/messages/form/MessagesForm.jsx';
|
||||
import './css/ContactUsPage.css';
|
||||
|
||||
const ContactUsPage = () => {
|
||||
const { id } = useParams();
|
||||
|
||||
return (
|
||||
<main className="main_contact">
|
||||
<div className="main__container _container">
|
||||
<Form className="main__form form needs-validation" action="contact_us.html" method="get" noValidate>
|
||||
<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>
|
||||
<MessagesForm id={id} />
|
||||
<div className="main__info info_table">
|
||||
<div className="info_table__row">
|
||||
<div className="info_table__column">
|
||||
|
@ -7,14 +7,16 @@ const ErrorPage = () => {
|
||||
const error = useRouteError();
|
||||
|
||||
return (
|
||||
<Container fluid className='container'>
|
||||
<div className="main__container">
|
||||
<Container fluid className='container'>
|
||||
<Alert className='alert' variant='danger'>
|
||||
{error?.message ?? 'Page not found 404'}
|
||||
</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'
|
||||
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 {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-top: 7%;
|
||||
background-color: #2c2a2a;
|
||||
border: solid 3px #a721fa;
|
||||
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;
|
||||
}
|