commit front 3

This commit is contained in:
dasha 2023-04-09 15:33:08 +04:00
parent 1331a59414
commit 83f8e345fe
21 changed files with 1251 additions and 0 deletions

View File

@ -0,0 +1,81 @@
import { React, useEffect, useState } from 'react'
import ContentBlock from './components/ContentBlock'
import { useParams } from 'react-router-dom'
import axios from 'axios'
export default function FilmPage() {
const params = useParams()
const [items, setItems] = useState({});
useEffect(() => {
fetch("http://localhost:8080/cinema/" + params.id)
.then(function (response) {
return response.json();
})
.then(function (data) {
console.info('Get film success');
setItems(data);
})
.catch(function (error) {
console.error('Error:', error);
throw "Can't get film";
});
}, []);
const content = (
<div>
<div className="container pt-4">
<div className="container d-block text-start">
<img className="row posterFilmPage img-fluid float-start me-3 mt-3" src={items.image} alt={items.name} align="left" />
<a className="col text-white fw-bold fs-2" onClick={() => window.location.reload()} style={{ cursor: "pointer" }}>{items.name}, 2020 г. </a>
<span className="col badge green-mark text-white fw-bold fs-5 mx-2 p-2">9.2</span>
<button className="col badge willSee text-white fw-bold fs-5 mx-2 p-2 border border-0">
Буду смотреть
</button>
</div>
<div className="container table text-start fs-4">
<div className="row text-white fw-bold fs-3">О фильме</div>
<div className="row">
<div className="col-xs-6 col-sm-3">Год производства</div>
<div className="col-xs-6 col-sm-3">1000</div>
</div>
<div className="row">
<div className="col-xs-6 col-sm-3">Страна</div>
<div className="col-xs-6 col-sm-3">Россия</div>
</div>
<div className="row">
<div className="col-xs-6 col-sm-3">Жанр</div>
<div className="col-xs-6 col-sm-3">Драма</div>
</div>
<div className="row">
<div className="col-xs-6 col-sm-3">Длительность</div>
<div className="col-xs-6 col-sm-3">189 мин. / 03:09</div>
</div>
<div className="row">
<div className="col-xs-6 col-sm-3">Возраст</div>
<div className="col-xs-6 col-sm-3">16+</div>
</div>
</div>
<h3 className="text-white fw-bold m-auto p-1 fs-3 text-start">Описание</h3>
<div className="description text-start fs-4">
Пол Эджкомб начальник блока смертников в тюрьме «Холодная гора», каждыйиз узников которого однажды проходит «зеленую милю» по пути к месту казни. Пол повидал много заключённых
и надзирателей за время работы. Однако гигант Джон Коффи, обвинённый в страшном преступлении,
стал одним из самых необычных обитателей блока.
</div>
</div>
<hr className="border border-0 bg-black" />
<div className="container">
<h1 className="fs-1 fw-bold text-white ms-2 text-start">Трейлер</h1>
<nav className="ratio ratio-16x9">
<iframe className="p-2" src="https://www.youtube.com/embed/Ca3mUSDJlgM" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
</nav>
</div>
</div>
);
return (
<div>
<ContentBlock valueBlock={content} title='Страница фильма' />
</div>
)
}

177
front/src/pages/Films.jsx Normal file
View File

@ -0,0 +1,177 @@
import { React, useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import FilmItem from './components/FilmItem'
import ContentBlock from './components/ContentBlock'
import ModalEdit from './components/ModalEdit'
import Banner from './components/Banner'
import '../styles/banner.css'
import CinemaDto from './models/CinemaDto'
import Service from './services/Service'
export default function Films() {
const navigate = useNavigate();
const fileReader = new FileReader()
const [items, setItems] = useState([]);
const [modalTable, setModalTable] = useState(false);
const [selectedImage, setSelectedImage] = useState();
// для инпутов
const [filmName, setFilmName] = useState('');
const [filmNameEdit, setFilmNameEdit] = useState('');
// хук для запоминания индекса элемента, вызвавшего модальное окно
const [currEditItem, setCurrEditItem] = useState(0);
// фильмы, страны, жанры
useEffect(() => {
Service.readAll('cinema')
.then(data => setItems(data));
}, []);
function handleDeleteFilm(id) {
console.info('Try to remove item');
Service.delete(`cinema/${id}`)
.then(() => {
setItems(items.filter(elem => elem.id !== id))
console.log("Removed")
});
};
function handleEditFilm(id) {
console.info(`Start edit script`);
Service.read(`cinema/${id}`)
.then(function (data) {
setFilmNameEdit(data.name);
setCurrEditItem(data.id);
setModalTable(true)
console.info('End edit script');
})
};
// принимаем событие от кнопки "добавить"
const handleSubmitCreate = (e) => {
e.preventDefault(); // страница перестает перезагружаться
const itemObject = new CinemaDto(selectedImage, filmName);
console.info('Try to add item');
Service.create('cinema', itemObject)
.then((data) => {
setItems([...items, data]);
setFilmName('');
console.info('Added');
})
.catch(function (error) {
console.error('Error:', error);
throw "Can't add item";
});
};
// принимаем событие от кнопки "сохранить изменения"
const handleSubmitEdit = (e, id) => {
console.info('Start synchronize edit');
e.preventDefault(); // страница перестает перезагружаться
const itemObject = new CinemaDto(selectedImage, filmNameEdit, id);
Service.update("cinema/" + id, itemObject)
.then((data) => {
setItems(
items.map(item =>
item.id === id ? {
...item,
image: data.image,
name: data.name,
} : item)
)
console.info('End synchronize edit');
setModalTable(false)
})
.catch((error) => {
console.error('Error:', error);
});
};
fileReader.onloadend = () => (
setSelectedImage(fileReader.result)
)
function changePicture(e) {
e.preventDefault();
const file = e.target.files[0]
fileReader.readAsDataURL(file)
}
function handleAddFilmToWillSee(data) {
const elem = CinemaDto.createFrom(data)
Service.create('willSee/', data)
}
// форма для добавления данных
const Form = (
<form className="row g-3 fs-4 description fw-bold needs-validation-content" id="frm-items" onSubmit={handleSubmitCreate}>
<div className="col-md-3">
<label className="form-label" htmlFor="filmPicture">Изображение</label>
<input required className="form-control" name="filmPicture" id="filmPicture"
type="file"
onChange={changePicture} />
</div>
<div className="col">
<label className="form-label" htmlFor="filmName">Название</label>
<input required className="form-control" name="filmName" id="filmName" type="text" value={filmName} onChange={e => setFilmName(e.target.value)} placeholder="Введите название" />
</div>
<div className="form-check mx-2">
<input required className="form-check-input" name="film16" id="film16" type="checkbox" />
<label className="form-check-label" htmlFor="film16">Мне уже 16 лет</label>
<div className="invalid-feedback">Подтвердите, что вам уже есть 16 лет</div>
</div>
<div className="text-start">
<button className="willSee p-1 border border-0 rounded text-white fw-bold fs-4" id="btn-add-item" type="submit">Добавить</button>
</div>
</form>
)
const Content = (
<div>
{Form}
<hr className="border border-0 bg-black" />
<table className="table" id="tbl-items">
<tbody>
{items.map((item) =>
<FilmItem
item={item}
key={item.id}
removeFunc={handleDeleteFilm}
editFunc={handleEditFilm}
openFilmPageFunc={(index) => navigate(`/films/${index}`)}
/>
)}
</tbody>
</table>
<ModalEdit visible={modalTable} setVisible={setModalTable}>
<form className="g-3 fs-4 description fw-bold container" id="frm-items-edit" onSubmit={(e) => handleSubmitEdit(e, currEditItem)}>
<div className="row">
<label className="form-label" htmlFor="filmPictureEdit">Изображение</label>
<input required className="form-control" name="filmPictureEdit" id="filmPictureEdit"
type="file"
onChange={changePicture} />
</div>
<div className="row">
<label className="form-label" htmlFor="filmNameEdit">Название</label>
<input value={filmNameEdit} onChange={e => setFilmNameEdit(e.target.value)} className="form-control" name='filmNameEdit' id="filmNameEdit" type="text" placeholder="Введите название" required />
</div>
<div className="text-center mt-3">
<button className="btn btn-primary mx-1" type="submit" id="buttonSaveChanges">Сохранить изменения</button>
<button className="btn btn-secondary mx-1" type="button" data-bs-dismiss="modal" onClick={() => setModalTable(false)}>Отмена</button>
</div>
</form>
</ModalEdit>
</div>
);
return (
<div>
<Banner />
<ContentBlock valueBlock={Content} title='Фильмы' />
</div>
)
}

226
front/src/pages/Orders.jsx Normal file
View File

@ -0,0 +1,226 @@
import { React, useState, useEffect } from 'react'
import ContentBlock from './components/ContentBlock'
import Service from './services/Service';
import ModalEdit from './components/ModalEdit';
import OrderItem from './components/OrderItem';
import OrderSessionItem from './components/OrderSessionItem';
export default function Orders() {
const [users, setUsers] = useState([]);
const [error, setError] = useState(false);
const [modalTable, setModalTable] = useState(false);
// хук для запоминания индекса элемента, вызвавшего модальное окно
const [currEditItem, setCurrEditItem] = useState(0);
// для выпадающих значений
const [customerName, setCustomerName] = useState('');
const [customer, setCustomer] = useState([]);
const [sessionName, setSessionName] = useState('');
const [count, setCount] = useState(1);
const [session, setSession] = useState([]);
const [orderSessions, setOrderSessions] = useState([]);
useEffect(() => {
setError(false)
getAll('customer').then((data) => setCustomer(data))
getAll('session').then((data) => setSession(data))
getAll('order').then((data) => setUsers(data))
}, [])
async function getAll(elem) {
const requestUrl = `http://localhost:8080/${elem}`
const response = await fetch(requestUrl)
const result = await response.json()
return result
}
function handleSubmit(e) {
e.preventDefault();
if (customer.length <= 0) {
setError(true)
throw 'Form not submit'
}
handleSubmitCreate(e)
console.log('Form submit')
setError(false)
setCustomer('')
}
// принимаем событие от кнопки "добавить"
const handleSubmitCreate = async (e) => {
e.preventDefault()
console.info('Try to add item');
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
await fetch(`http://localhost:8080/order?customer=${customerName}`, requestParams)
.then((data) => {
getCustomerOrders(customerName)
getAll('customer').then((data) => setCustomer(data))
})
.catch(function (error) {
console.error('Error:', error);
throw "Can't add order";
});
};
function handleEdit(id) {
console.info(`Start edit script`);
Service.read(`order/${id}`)
.then(function (data) {
setCurrEditItem(data.id);
setOrderSessions(data.sessions)
setModalTable(true)
console.info('End edit script');
})
};
const handleSubmitAdd = async (e, id) => {
console.info('Start add session');
e.preventDefault(); // страница перестает перезагружаться
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = `http://localhost:8080/order/${id}?session=${sessionName}&count=${count}`
const response = await fetch(requestUrl, requestParams)
await response.json()
.then((data) => {
console.log(data.sessions)
setOrderSessions(data.sessions)
console.info('End add session');
})
.catch((error) => {
console.error('Error:', error);
});
};
const handleSubmitDelete = async (e, id) => {
console.info('Start delete session');
e.preventDefault(); // страница перестает перезагружаться
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = `http://localhost:8080/order/${id}?session=${sessionName}&count=-${count}`
const response = await fetch(requestUrl, requestParams)
await response.json()
.then((data) => {
console.info('End delete session')
setOrderSessions(data.sessions)
})
.catch((error) => {
console.error('Error:', error);
});
};
function handleDelete(id) {
console.info('Try to remove item');
Service.delete(`order/${id}`)
.then(() => {
setUsers(users.filter(elem => elem.id !== id))
console.log("Removed")
});
};
async function getCustomerOrders(id) {
Service.read(`customer/${id}`)
.then(function (data) {
setUsers(data.orders);
console.info('End');
})
.catch(e => { console.log('Error get orders') })
}
const Content = (
<>
<select required className="form-select" name="customer" id="customer" value={customer.value} onChange={e => {
setCustomerName(e.target.value)
getCustomerOrders(e.target.value)
}} >
<option value='' defaultValue disabled>Выберите значение</option>
{customer ? customer.map(elem =>
<option key={elem.id} value={elem.id}>{elem.login}</option>
) : null}
</select>
<form className="d-flex flex-column fs-4 fw-bold text-white text-center align-items-center">
<div>
<button className="btn btn-success my-3" type="button" onClick={handleSubmit}>Добавить</button>
</div>
</form>
<table className="table mt-3 text-white">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Customer</th>
<th scope="col">DateOfPurchase</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="tbody">
{users.map((user) => (
<OrderItem
item={user}
key={user.id}
editFunc={handleEdit}
removeFunc={handleDelete}
/>
))}
</tbody>
</table>
<ModalEdit visible={modalTable} setVisible={setModalTable}>
<form className="fs-4 description fw-bold d-flex flex-column align-items-center" id="frm-items-edit">
<div className="col-6">
<label className="form-label" htmlFor="session">Сеанс</label>
<select required className="form-control" name="session" id="session" value={session.value} onChange={e => setSessionName(e.target.value)} >
<option value='' defaultValue disabled>Выберите значение</option>
{session ? session.map(elem =>
<option key={elem.id} value={elem.id}>{elem.cinema.name} {new Date(elem.timestamp).toLocaleString('RU-ru')}</option>
) : null}
</select>
</div>
<div className="col-6">
<label className="form-label" htmlFor="count">Количество</label>
<input required className="form-control" name="count" id="count" type="number" min="1" value={count} onChange={e => setCount(e.target.value)} placeholder="Введите количество" />
</div>
<div className="text-center mt-3">
<button className="btn btn-success mx-1" type="button" onClick={e => handleSubmitAdd(e, currEditItem)}>Добавить</button>
<button className="btn btn-danger mx-1" type="button" onClick={e => handleSubmitDelete(e, currEditItem)}>Удалить</button>
<button className="btn btn-secondary mx-1" type="button" data-bs-dismiss="modal" onClick={() => setModalTable(false)}>Отмена</button>
</div>
<p>Мои сеансы</p>
<table className="table fs-6 table-bordered" id="tbl-items">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Price</th>
<th scope="col">Cinema</th>
<th scope="col">Timestamp</th>
<th scope="col">Count</th>
</tr>
</thead>
<tbody>
{orderSessions ? orderSessions.map((item) =>
<OrderSessionItem
item={item}
key={parseInt(item.sessionId+''+item.orderId)}
/>
) : null}
</tbody>
</table>
</form>
</ModalEdit>
</>
)
return (
<ContentBlock className="d-flex justify-content-center flex-wrap" valueBlock={Content} title='Заказы' />
)
}

View File

@ -0,0 +1,169 @@
import { React, useState, useEffect } from 'react'
import ContentBlock from './components/ContentBlock'
import Service from './services/Service';
import ModalEdit from './components/ModalEdit';
import MyButton from './components/MyButton';
import UserItem from './components/UserItem';
export default function Registration() {
const [login, setLogin] = useState('');
const [password, setPassword] = useState('');
const [loginEdit, setLoginEdit] = useState('');
const [passwordEdit, setPasswordEdit] = useState('');
const [users, setUsers] = useState([]);
const [error, setError] = useState(false);
const [modalTable, setModalTable] = useState(false);
// хук для запоминания индекса элемента, вызвавшего модальное окно
const [currEditItem, setCurrEditItem] = useState(0);
useEffect(() => {
setError(false)
getAll()
}, [])
async function getAll() {
const requestUrl = "http://localhost:8080/customer"
const response = await fetch(requestUrl)
const temp = await response.json()
setUsers(temp)
}
function handleSubmit(e) {
e.preventDefault();
if (login.length <= 0 || password.length <= 0) {
setError(true)
throw 'Form not submit'
}
handleSubmitCreate(e)
console.log('Form submit')
setError(false)
setLogin('')
setPassword('')
}
// принимаем событие от кнопки "добавить"
const handleSubmitCreate = async (e) => {
e.preventDefault()
console.info('Try to add item');
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
await fetch(`http://localhost:8080/customer?login=${login}&password=${password}`, requestParams)
.then(() => {
getAll()
})
};
function handleEdit(id) {
console.info(`Start edit script`);
Service.read(`customer/${id}`)
.then(function (data) {
setLoginEdit(data.login);
setPasswordEdit(data.password);
setCurrEditItem(data.id);
setModalTable(true)
console.info('End edit script');
})
};
const handleSubmitEdit = async (e, id) => {
console.info('Start synchronize edit');
e.preventDefault(); // страница перестает перезагружаться
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = `http://localhost:8080/customer/${id}?login=${loginEdit}&password=${passwordEdit}`
const response = await fetch(requestUrl, requestParams)
const temp = await response.json()
.then((data) => {
setUsers(
users.map(item =>
item.id === id ? {
...item,
login: data.login,
password: data.password
} : item)
)
console.info('End synchronize edit');
setModalTable(false)
})
.catch((error) => {
console.error('Error:', error);
});
};
function handleDelete(id) {
console.info('Try to remove item');
Service.delete(`customer/${id}`)
.then(() => {
setUsers(users.filter(elem => elem.id !== id))
console.log("Removed")
});
};
const Content = (
<>
<form onSubmit={handleSubmit} className="d-flex flex-column fs-4 fw-bold text-white text-center align-items-center">
<div>
<label className="form-label">Логин</label>
<input className="form-control mainInput" type="text" value={login} onChange={e => setLogin(e.target.value)} placeholder="Введите логин" />
</div>
{error && login.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод логина</label> : null}
<div>
<label className="form-label">Пароль</label>
<input className="form-control mainInput" type="text" value={password} onChange={e => setPassword(e.target.value)} placeholder="Введите пароль" />
</div>
{error && password.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод пароля</label> : null}
<div>
<button className="btn btn-success my-3" type="submit">Регистрация</button>
</div>
</form>
<table className="table mt-3 text-white">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Login</th>
<th scope="col">Password</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="tbody">
{users.map((user) => (
<UserItem
item={user}
key={user.id}
editFunc={handleEdit}
removeFunc={handleDelete} />
))}
</tbody>
</table>
<ModalEdit visible={modalTable} setVisible={setModalTable}>
<form className="g-3 fs-4 description fw-bold container" id="frm-items-edit" onSubmit={(e) => handleSubmitEdit(e, currEditItem)}>
<div className="row">
<label className="form-label" htmlFor="loginEdit">Логин</label>
<input value={loginEdit} onChange={e => setLoginEdit(e.target.value)} className="form-control" name='loginEdit' id="loginEdit" type="text" placeholder="Введите логин" required />
</div>
<div className="row">
<label className="form-label" htmlFor="passwordEdit">Пароль</label>
<input value={passwordEdit} onChange={e => setPasswordEdit(e.target.value)} className="form-control" name='passwordEdit' id="passwordEdit" type="text" placeholder="Введите пароль" required />
</div>
<div className="text-center mt-3">
<button className="btn btn-primary mx-1" type="submit" id="buttonSaveChanges">Сохранить изменения</button>
<button className="btn btn-secondary mx-1" type="button" data-bs-dismiss="modal" onClick={() => setModalTable(false)}>Отмена</button>
</div>
</form>
</ModalEdit>
</>
)
return (
<ContentBlock className="d-flex justify-content-center flex-wrap" valueBlock={Content} title='Регистрация' />
)
}

View File

@ -0,0 +1,53 @@
import { React, useState, useEffect } from 'react'
import FilmItem from './components/FilmItem'
import { useParams, useNavigate } from "react-router-dom";
import ContentBlock from './components/ContentBlock';
export default function SearchSame() {
const navigate = useNavigate();
// массив полученных фильмов
const [searchResult, setSearchResult] = useState([]);
const params = useParams()
const [items, setItems] = useState([])
useEffect(() => {
let temp = JSON.stringify(searchResult);
temp = JSON.parse(temp);
setItems(temp.filter(elem => elem.name.toLowerCase().includes(params.request.toLowerCase())));
}, [searchResult, params]);
useState(() => {
const fetchData = async () => {
const url = new URL('http://localhost:8080/cinema')
try {
const response = await fetch(url.href);
const json = await response.json();
setSearchResult(json);
console.info('Search success');
} catch (error) {
return;
}
};
fetchData();
}, [])
const Content = (
<table className="table" id="tbl-items">
<tbody>
{items.map((item) =>
<FilmItem
item={item}
key={item.id}
openFilmPageFunc={(index) => navigate(`/films/${index}`)}
/>
)}
</tbody>
</table>
)
return (
<div>
<ContentBlock valueBlock={Content} title='Похожие результаты'/>
</div>
)
}

View File

@ -0,0 +1,191 @@
import { React, useState, useEffect } from 'react'
import ContentBlock from './components/ContentBlock'
import Service from './services/Service';
import ModalEdit from './components/ModalEdit';
import SessionItem from './components/SessionItem';
import CinemaDto from './models/CinemaDto'
export default function Sessions() {
const [price, setPrice] = useState(1);
const [timestamp, setTimestamp] = useState(new Date());
const [maxCount, setMaxCount] = useState(1);
const [priceEdit, setPriceEdit] = useState('');
const [users, setUsers] = useState([]);
const [error, setError] = useState(false);
const [modalTable, setModalTable] = useState(false);
// хук для запоминания индекса элемента, вызвавшего модальное окно
const [currEditItem, setCurrEditItem] = useState(0);
// для выпадающих значений
const [cinemaName, setCinemaName] = useState('');
const [cinema, setCinema] = useState([]);
useEffect(() => {
setError(false)
getAll('cinema').then((data) => setCinema(data))
getAll('session').then((data) => setUsers(data))
}, [])
async function getAll(elem) {
const requestUrl = `http://localhost:8080/${elem}`
const response = await fetch(requestUrl)
const result = await response.json()
return result
}
function handleSubmit(e) {
e.preventDefault();
if (price.length <= 0 || cinema.length <= 0) {
setError(true)
throw 'Form not submit'
}
handleSubmitCreate(e)
console.log('Form submit')
setError(false)
setPrice('')
setCinema('')
}
// принимаем событие от кнопки "добавить"
const handleSubmitCreate = async (e) => {
e.preventDefault()
console.info('Try to add item');
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
await fetch(`http://localhost:8080/session?price=${price}&timestamp=${timestamp}&cinemaid=${cinemaName}&capacity=${maxCount}`, requestParams)
.then(() => {
getAll('session').then((data) => setUsers(data))
getAll('cinema').then((data) => setCinema(data))
})
.catch(function (error) {
console.error('Error:', error);
throw "Can't add session";
});
};
function handleEdit(id) {
console.info(`Start edit script`);
Service.read(`session/${id}`)
.then(function (data) {
setPriceEdit(data.price);
setCurrEditItem(data.id);
setModalTable(true)
console.info('End edit script');
})
};
const handleSubmitEdit = async (e, id) => {
console.info('Start synchronize edit');
e.preventDefault(); // страница перестает перезагружаться
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = `http://localhost:8080/session/${id}?price=${priceEdit}`
const response = await fetch(requestUrl, requestParams)
await response.json()
.then((data) => {
setUsers(
users.map(item =>
item.id === id ? {
...item,
price: data.price
} : item)
)
console.info('End synchronize edit');
setModalTable(false)
})
.catch((error) => {
console.error('Error:', error);
});
};
function handleDelete(id) {
console.info('Try to remove item');
Service.delete(`session/${id}`)
.then(() => {
setUsers(users.filter(elem => elem.id !== id))
console.log("Removed")
});
};
const Content = (
<>
<form className="d-flex flex-column fs-4 fw-bold text-white text-center align-items-center">
<div>
<label className="form-label">Цена</label>
<input className="form-control mainInput" min="1" type="number" step="0.01" value={price} onChange={e => setPrice(e.target.value)} placeholder="Введите цену" />
</div>
{error && price.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод цены</label> : null}
<div>
<label className="form-label">Фильм</label>
<select required className="form-select" name="filmCountry" id="filmCountry" value={cinema.value} onChange={e => setCinemaName(e.target.value)} >
<option value='' defaultValue disabled>Выберите значение</option>
{cinema ? cinema.map(elem =>
<option key={elem.id} value={elem.id}>{elem.name}</option>
) : null }
</select>
</div>
{error && cinema.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод фильма</label> : null}
<div>
<label className="form-label">Кол-во сеансов</label>
<input className="form-control mainInput" min="1" type="number" value={maxCount} onChange={e => setMaxCount(e.target.value)} placeholder="Введите количество" />
</div>
{error && price.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод цены</label> : null}
<div>
<label className="form-label">Дата</label>
<input className="form-control mainInput" type="datetime-local" value={timestamp} onChange={e => setTimestamp(e.target.value)} placeholder="Введите дату" />
</div>
{error && timestamp.length <= 0 ? <label className="fs-6 text-danger">Неправильный ввод даты</label> : null}
<div>
<button className="btn btn-success my-3" type="button" onClick={handleSubmit}>Сохранить</button>
</div>
</form>
<table className="table mt-3 text-white">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Price</th>
<th scope="col">Cinema</th>
<th scope="col">Timestamp</th>
<th scope="col">Capacity</th>
<th scope="col">MaxCount</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="tbody">
{users.map((user) => (
<SessionItem
item={user}
key={user.id}
editFunc={handleEdit}
removeFunc={handleDelete}
/>
))}
</tbody>
</table>
<ModalEdit visible={modalTable} setVisible={setModalTable}>
<form className="g-3 fs-4 description fw-bold container" id="frm-items-edit" onSubmit={(e) => handleSubmitEdit(e, currEditItem)}>
<div className="row">
<label className="form-label" htmlFor="priceEdit">Цена</label>
<input value={priceEdit} onChange={e => setPriceEdit(e.target.value)} className="form-control" name='priceEdit' id="priceEdit" type="number" step="0.01" min="1" placeholder="Введите цену" required />
</div>
<div className="text-center mt-3">
<button className="btn btn-primary mx-1" type="submit" id="buttonSaveChanges">Сохранить изменения</button>
<button className="btn btn-secondary mx-1" type="button" data-bs-dismiss="modal" onClick={() => setModalTable(false)}>Отмена</button>
</div>
</form>
</ModalEdit>
</>
)
return (
<ContentBlock className="d-flex justify-content-center flex-wrap" valueBlock={Content} title='Сеансы' />
)
}

View File

@ -0,0 +1,46 @@
import { React, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import banner1 from '../../images/banner1.jpg'
import banner2 from '../../images/banner2.jpg'
import banner3 from '../../images/banner3.jpg'
export default function Banner() {
const length = 3;
var old = 0;
var current = 1;
const navigate = useNavigate();
const [bannerState, setBannerState] = useState(['show', 'hide', 'hide']);
useEffect(() => {
const timer = window.setInterval(() => {
setBannerState([...bannerState, bannerState[current] = 'show', bannerState[old] = 'hide']);
console.info('Banner changed');
old = current;
current++;
if (current === length) {
current = 0;
}
}, 5000)
return () => {
window.clearInterval(timer);
}
}, [])
return (
<div className="d-flex align-items-center flex-column" id="banner">
<a className={bannerState[0]} onClick={() => navigate("/films/0")} style={{ cursor: "pointer" }}>
<img src={banner1} />
</a>
<a className={bannerState[1]} onClick={() => navigate("/films/0")} style={{ cursor: "pointer" }}>
<img src={banner2} />
</a>
<a className={bannerState[2]} onClick={() => navigate("/films/0")} style={{ cursor: "pointer" }}>
<img src={banner3} />
</a>
</div>
)
}

View File

@ -0,0 +1,15 @@
import React from 'react'
import '../../styles/styleBlock.css'
export default function ContentBlock(props) {
return (
<div className="container rounded my-5 p-4 content">
<div className="content_header rounded-top p-2 mb-2">
<h1 className="fs-1 fw-bold text-white ms-5">{props.title}</h1>
</div>
{props.valueBlock}
</div>
)
}

View File

@ -0,0 +1,27 @@
import React from "react"
import '../../styles/styleFilmItem.css'
import MyButton from './MyButton'
export default function FilmItem(props) {
return (
<tr>
<td>
<img className="posterItem me-3" src={props.item.image} alt={props.item.name} align="left" />
<div className="d-flex flex-row flex-wrap flex-grow-1 align-items-center">
<div className="pt-3 description d-flex flex-column justify-content-start align-items-center mb-3 fs-6 fw-bold">
<p className="text-start description">
<a className="text-white fs-5 fw-bold pt-3" onClick={() => props.openFilmPageFunc(props.item.id)} style={{ cursor: "pointer" }}>
{props.item.name}
</a>
</p>
</div>
<div id="rightPanel" className="d-flex flex-wrap justify-content-end text-white fw-bold fs-4 flex-grow-1">
<div className="rounded p-1 mx-2 green-mark">9.2</div>
<MyButton value={props}/>
</div>
</div>
<hr className="border border-0 bg-black" />
</td>
</tr>
)
}

View File

@ -0,0 +1,11 @@
import React from 'react'
import vk from '../../images/vk.jpg'
import '../../styles/styleFooter.css'
export default function Footer() {
return (
<footer className="d-flex align-items-center fw-bold fs-4 p-2 ps-5">2022 г.
<nav className="d-flex justify-content-center flex-grow-1"><a href="https://vk.com/id0" target="_blank"><img className="icon" src={vk} alt="VK" /></a></nav>
</footer>
)
}

View File

@ -0,0 +1,43 @@
import { React, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import searchImage from '../../images/search.jpg'
import '../../styles/styleHeader.css'
export default function Header() {
const navigate = useNavigate();
const [searchName, setSearchName] = useState('');
function handleSubmit(e) {
console.info('Try to search data');
e.preventDefault();
navigate(`/search-same/${searchName}`)
setSearchName('');
}
return (
<div>
<header className="fs-4 fw-bold p-1">
<nav className="navbar navbar-expand-md navbar-dark">
<div className="container-fluid">
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="navbar-collapse collapse justify-content-end" id="navbarNav">
<div id="main"> <a onClick={() => navigate("/films")} className="text-decoration-none mx-5" style={{ cursor: "pointer" }}>Главная</a></div>
<form onSubmit={handleSubmit} className="col d-flex align-items-center needs-validation">
<input value={searchName} onChange={e => setSearchName(e.target.value)} className="form-control mainInput" type="text" name="text" search="true" rounded="true" required placeholder="Введите название" />
<button className="border border-0 p-0 ms-2" type="submit"><img className="icon" src={searchImage} alt="Поиск" /></button>
</form>
<div className="d-flex justify-content-end flex-grow-1 navbar-nav">
<a onClick={() => navigate("/registration")} className="text-decoration-none mx-3" style={{ cursor: "pointer" }}>Регистрация</a>
<a onClick={() => navigate("/orders")} className="text-decoration-none mx-3" style={{ cursor: "pointer" }}>Заказы</a>
<a onClick={() => navigate("/sessions")} className="text-decoration-none mx-3" style={{ cursor: "pointer" }}>Сеансы</a>
</div>
</div>
</div>
</nav>
</header>
</div>
)
}

View File

@ -0,0 +1,18 @@
import React from 'react'
import * as classes from "../../styles/ModalEdit.module.css"
export default function ModalEdit({children, visible, setVisible}) {
const rootClasses = [classes.myModal]
if (visible) {
rootClasses.push(classes.active);
}
//onClick={()=>setVisible(false)}
return (
<div className={rootClasses.join(' ')} >
<div className={classes.myModalContent}>
{children}
</div>
</div>
)
}

View File

@ -0,0 +1,26 @@
import React from "react"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEdit } from "@fortawesome/free-solid-svg-icons"
import { faRemove } from "@fortawesome/free-solid-svg-icons"
export default function MyButton({ value }) {
const delButton = (
<button onClick={() => value.removeFunc(value.item.id)} type="button" className="m-1 btn btn-danger">
<FontAwesomeIcon icon={faRemove} />
</button>
)
const editButton = (
<button onClick={() => value.editFunc(value.item.id)} type="button" className="m-1 btn btn-primary">
<FontAwesomeIcon icon={faEdit} />
</button>
)
return (
<div>
{value.editFunc ? editButton : null}
{value.removeFunc ? delButton : null}
</div>
)
}

View File

@ -0,0 +1,27 @@
import React, { useEffect, useState } from "react"
import MyButton from './MyButton'
import CustomerDto from "../models/CustomerDto";
import Service from "../services/Service";
export default function OrderItem(props) {
const [customer, setCustomer] = useState(new CustomerDto());
useEffect(() => {
Service.read("customer/" + props.item.customer.id)
.then((data) => {
setCustomer(data)
})
.catch((error) => {
console.error('Error:', error);
});
}, [])
return (
<tr>
<td>{props.item.id}</td>
<td>{customer.login}</td>
<td>{props.item.dateOfPurchase}</td>
<td><MyButton value={props} /></td>
</tr>
)
}

View File

@ -0,0 +1,37 @@
import React, { useEffect, useState } from "react"
import CinemaDto from "../models/CinemaDto";
import Service from "../services/Service";
export default function OrderSessionItem(props) {
const [item, setItem] = useState(new CinemaDto())
const [load, setLoad] = useState(false)
const [date, setDate] = useState(new Date())
useEffect(() => {
Service.read("session/" + props.item.sessionId)
.then((data) => {
setItem(data)
setLoad(true)
setDate(new Date(data.timestamp).toLocaleString('RU-ru'))
})
.catch((error) => {
console.error('Error:', error);
});
return () => {
setLoad(false)
}
}, [])
return (
<>
{load ?
<tr>
<td>{item.id}</td>
<td>{item.price}</td>
<td>{item.cinema.name}</td>
<td>{date}</td>
<td>{props.item.count}</td>
</tr> : null}
</>
)
}

View File

@ -0,0 +1,18 @@
import React, { useEffect, useState } from "react"
import MyButton from './MyButton'
export default function SessionItem(props) {
const date = new Date(props.item.timestamp).toLocaleString('RU-ru')
return (
<tr>
<td>{props.item.id}</td>
<td>{props.item.price}</td>
<td>{props.item.cinema.name}</td>
<td>{date}</td>
<td>{props.item.capacity}</td>
<td>{props.item.maxCount}</td>
<td><MyButton value={props} /></td>
</tr>
)
}

View File

@ -0,0 +1,13 @@
import React from "react"
import MyButton from './MyButton'
export default function UserItem(props) {
return (
<tr>
<td>{props.item.id}</td>
<td>{props.item.login}</td>
<td>{props.item.password}</td>
<td><MyButton value={props} /></td>
</tr>
)
}

View File

@ -0,0 +1,10 @@
export default class CinemaDto {
constructor(image, name, id) {
this.image = image;
this.name = name;
this.id = parseInt(id);
}
static createFrom(item) {
return new CinemaDto(item.image, item.name, item.id);
}
}

View File

@ -0,0 +1,10 @@
export default class CustomerDto {
constructor(login, password, id) {
this.login = login;
this.password = password;
this.id = parseInt(id);
}
static createFrom(item) {
return new CustomerDto(item.login, item.password, item.id);
}
}

View File

@ -0,0 +1,11 @@
export default class SessionDto {
constructor(price, timestamp, maxCount, id) {
this.price = parseFloat(price);
this.timestamp = Date.parse(timestamp);
this.maxCount = parseInt(maxCount);
this.id = parseInt(id);
}
static createFrom(item) {
return new SessionDto(item.image, item.name, item.id);
}
}

View File

@ -0,0 +1,42 @@
import axios from 'axios'
function toJSON(data) {
const jsonObj = {};
const fields = Object.getOwnPropertyNames(data);
for (const field of fields) {
if (data[field] === undefined) {
continue;
}
jsonObj[field] = data[field];
}
return jsonObj;
}
export default class Service {
static dataUrlPrefix = 'http://localhost:8080/';
static async readAll(url) {
const response = await axios.get(this.dataUrlPrefix + url);
return response.data;
}
static async read(url) {
const response = await axios.get(this.dataUrlPrefix + url);
return response.data;
}
static async create(url, data) {
const response = await axios.post(this.dataUrlPrefix + url, toJSON(data));
return response.data;
}
static async update(url, data) {
const response = await axios.put(this.dataUrlPrefix + url, toJSON(data));
return response.data;
}
static async delete(url) {
const response = await axios.delete(this.dataUrlPrefix + url);
return response.data.id ? response.data.id : response.error;
}
}