теперь фронт точно на месте

This commit is contained in:
Николай 2023-03-31 23:41:00 +04:00
parent 25e327f935
commit b908b68951
13 changed files with 894 additions and 0 deletions

Binary file not shown.

15
front/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script type="module" src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
<title>ReManga</title>
</head>
<body >
<div id="app" class="d-flex flex-column h-100" ></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

37
front/src/App.jsx Normal file
View File

@ -0,0 +1,37 @@
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
import Creator from './components/Creator';
import Reader from './components/Reader';
import Header from './components/Header';
import Manga from './components/Manga';
function Router(props) {
return useRoutes(props.rootRoute);
}
export default function App() {
const routes = [
{ index: true, element: <Creator /> },
{ path: 'creator', element: <Creator />, label: 'Creator' },
{ path: 'reader', element: <Reader />, label: 'Reader' },
{ path: 'manga', element: <Manga />, label: 'Manga' },
];
const links = routes.filter(route => route.hasOwnProperty('label'));
const rootRoute = [
{ path: '/', element: render(links), children: routes }
];
function render(links) {
return (
<>
<Header links={links} />
<Outlet />
</>
);
}
return (
<BrowserRouter>
<Router rootRoute={ rootRoute } />
</BrowserRouter>
);
}

View File

@ -0,0 +1,58 @@
import { useEffect, useState } from "react";
export default function Adding() {
const [outcome, setOutcome] = useState(0);
const [first, setFirst] = useState(0);
const [second, setSecond] = useState(0);
const sum = (e) =>{
e.preventDefault()
fetch('http://localhost:8080/sum?first=' + first + '&second=' + second)
.then(response=>response.text())
.then(result=>setOutcome(result))
}
const ras = (e) =>{
e.preventDefault()
fetch('http://localhost:8080/ras?first=' + first + '&second=' + second)
.then(response=>response.text())
.then(result=>setOutcome(result))
}
const del = (e) =>{
e.preventDefault()
fetch('http://localhost:8080/del?first=' + first + '&second=' + second)
.then(response=>response.text())
.then(result=>setOutcome(result))
}
const pros = (e) =>{
e.preventDefault()
fetch('http://localhost:8080/pros?first=' + first + '&second=' + second)
.then(response=>response.text())
.then(result=>setOutcome(result))
}
return (
<main className="flex-shrink-0">
<div className="p-2">
<form>
<div className="form-group">
<label>Первое число</label>
<input type='number' value = {first} onChange={event => setFirst(event.target.value)} className="form-control"/>
</div>
<div className="form-group">
<label >Второе число</label>
<input type='number' value = {second} onChange={event => setSecond(event.target.value)} className="form-control"/>
</div>
<button onClick={sum} type="submit" className="btn btn-primary">Sum</button>
<button onClick={ras} type="submit" className="btn btn-primary">-</button>
<button onClick={del} type="submit" className="btn btn-primary">/</button>
<button onClick={pros} type="submit" className="btn btn-primary">*</button>
{outcome}
</form>
</div>
</main>
);
}

View File

@ -0,0 +1,175 @@
import { useEffect, useState } from "react";
import TableCreator from './TableCreator';
export default function Creator() {
const host = "http://localhost:8080";
const [creatorId, setCreatorId] = useState(0);
const [creatorName, setCreatorName] = useState("");
const [password, setPassword] = useState("");
const [data, setData] = useState([]);
const table = document.getElementById("tbody");
useEffect(() => {
getData()
.then(_data =>setData(_data)) ;
console.log(2);
},[]);
const getData = async function () {
const response = await fetch(host + "/creator");
const _data = await response.json()
console.log(data);
return _data;
//table.innerHTML = "";
// data.forEach(Creator => {
// let temp = "<select>";
// Creator.mangas.forEach(Manga => {
// temp += `<option>${Manga.mangaName + " " + Manga.chapterCount}</option>>`
// })
// temp += "</select>"
// table.innerHTML +=
// `<tr>
// <th scope="row">${Creator.id}</th>
// <td>${Creator.creatorName}</td>
// <td>${Creator.hashedPassword}</td>
// <td>${temp}</td>
// </tr>`;
// })
}
const create = async function (){
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/creator?creatorName=${creatorName}&password=${password}`, requestParams);
getData();
}
const remove = async function (){
console.info('Try to remove item');
if (creatorId !== 0) {
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
}
const requestParams = {
method: "DELETE",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/creator/` + creatorId, requestParams);
console.log("REMOVE");
getData();
return await response.json();
}
const removeAll = async function (){
console.info('Try to remove item');
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
const requestParams = {
method: "DELETE",
};
await fetch(host + `/creator/`, requestParams);
}
const update = async function (){
console.info('Try to update item');
if (creatorId === 0 || creatorName == null || password === 0) {
return;
}
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/creator/${creatorId}?creatorName=${creatorName}&password=${password}`, requestParams);
getData();
return await response.json();
}
const createButton = (e) =>{
e.preventDefault()
create();
}
const removeButton = (e) =>{
e.preventDefault()
remove();
}
const updateButton = (e) =>{
e.preventDefault()
update();
}
return (
<main>
<div className="container" id="root-div">
<div className="content">
<h1>Creator</h1>
<form id="form">
<div className="d-flex justify-content-evenly mt-3">
<div className="col-sm-2">
<label htmlFor="creatorId" className="form-label">creatorId</label>
<input type='number' value = {creatorId} onChange={event => setCreatorId(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="creatorName" className="form-label">creatorName</label>
<input type='text' value = {creatorName} onChange={event => setCreatorName(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="password" className="form-label">password</label>
<input type='text' value = {password} onChange={event => setPassword(event.target.value)} className="form-control"/>
</div>
</div>
<div className="row mt-3">
<div className="d-grid col-sm-3 mx-auto">
<button type="submit" onClick={createButton} className="btn btn-success">Добавить</button>
</div>
<div className="d-grid col-sm-3 mx-auto">
<button type="submit" onClick={updateButton} className="btn btn-success" id="btnUpdate" >Обновить</button>
</div>
<div className="d-grid col-sm-3 mx-auto">
<button id="btnRemove" onClick={removeButton} className="btn btn-success">Удалить</button>
</div>
</div>
</form>
<div className="row table-responsive text-white">
<table className="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">CreatorName</th>
<th scope="col">Password</th>
<th scope="col">Mangs</th>
</tr>
</thead>
<TableCreator items = {data}/>
{/* <tbody id="tbody">
</tbody> */}
</table>
</div>
</div>
</div>
</main>
);
}

View File

@ -0,0 +1,27 @@
import { NavLink } from 'react-router-dom';
export default function Header(props) {
return (
<nav className="navbar navbar-expand-lg bg-light">
<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="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
{props.links.map(route =>
<li key={route.path}
className="nav-item">
<NavLink className="nav-link" to={route.path}>
{route.label}
</NavLink>
</li>
)}
</ul>
</div>
</div>
</nav >
);
}

View File

@ -0,0 +1,171 @@
import { useEffect, useState } from "react";
import TableManga from './TableManga';
export default function Manga() {
const host = "http://localhost:8080";
const [creatorId, setCreatorId] = useState(0);
const [mangaId, setMangaId] = useState(0);
const [mangaName, setMangaName] = useState("");
const [chapterCount, setChapterCount] = useState(0);
const [data, setData] = useState([]);
const table = document.getElementById("tbody");
useEffect(() => {
getData();
},[]);
const getData = async function () {
const response = await fetch(host + "/manga");
setData(await response.json())
console.log(data);
//table.innerHTML = "";
// data.forEach(Manga => {
// let temp = "<select>";
// Manga.mangas.forEach(Manga => {
// temp += `<option>${Manga.mangaName + " " + Manga.chapterCount}</option>>`
// })
// temp += "</select>"
// table.innerHTML +=
// `<tr>
// <th scope="row">${Manga.id}</th>
// <td>${Manga.mangaName}</td>
// <td>${Manga.hashedPassword}</td>
// <td>${temp}</td>
// </tr>`;
// })
}
const create = async function (){
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/manga?creatorId=${creatorId}&chapterCount=${chapterCount}&mangaName=${mangaName}`, requestParams);
return await response.json();
}
const remove = async function (){
console.info('Try to remove item');
if (mangaId !== 0) {
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
}
const requestParams = {
method: "DELETE",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/manga/` + mangaIdInput.value, requestParams);
console.log("REMOVE");
getData();
}
const update = async function (){
console.info('Try to update item');
if (mangaId === 0 || mangaName == null || password === 0) {
return;
}
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/manga/${mangaIdInput.value}?chapterCount=${chapterCountInput.value}`, requestParams);
return await response.json();
}
const createButton = (e) =>{
e.preventDefault()
create().then((result) => {
getData();
alert(`Manga[id=${result.id}, mangaName=${result.mangaName}, chapterCount=${result.chapterCount}]`);
});
}
const removeButton = (e) =>{
e.preventDefault()
remove();
getData();
}
const updateButton = (e) =>{
e.preventDefault()
update();
getData();
}
return (
<main>
<div className="container" id="root-div">
<div className="content">
<h1>Manga</h1>
<form id="form">
<div className="d-flex justify-content-evenly mt-3">
<div className="col-sm-2">
<label htmlFor="mangaId" className="form-label">creatorId</label>
<input type='number' value = {creatorId} onChange={event => setCreatorId(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="mangaId" className="form-label">mangaId</label>
<input type='number' value = {mangaId} onChange={event => setMangaId(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="mangaName" className="form-label">mangaName</label>
<input type='text' value = {mangaName} onChange={event => setMangaName(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="chapterCount" className="form-label">chapterCount</label>
<input type='number' value = {chapterCount} onChange={event => setChapterCount(event.target.value)} className="form-control"/>
</div>
</div>
<div className="row mt-3">
<div className="d-grid col-sm-3 mx-auto">
<button type="submit" onClick={createButton} className="btn btn-success">Добавить</button>
</div>
<div className="d-grid col-sm-3 mx-auto">
<button type="submit" onClick={updateButton} className="btn btn-success" id="btnUpdate" >Обновить</button>
</div>
<div className="d-grid col-sm-3 mx-auto">
<button id="btnRemove" onClick={removeButton} className="btn btn-success">Удалить</button>
</div>
</div>
</form>
<div className="row table-responsive text-white">
<table className="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">mangaName</th>
<th scope="col">chapterCount</th>
<th scope="col">mangaId</th>
<th scope="col">readers</th>
</tr>
</thead>
<TableManga items = {data}/>
{/* <tbody id="tbody">
</tbody> */}
</table>
</div>
</div>
</div>
</main>
);
}

View File

@ -0,0 +1,226 @@
import { useEffect, useState } from "react";
import TableReader from './TableReader';
export default function Reader() {
const host = "http://localhost:8080";
const [readerId, setReaderId] = useState(0);
const [mangaId, setMangaId] = useState(0);
const [readerName, setReaderName] = useState("");
const [password, setPassword] = useState("");
const [data, setData] = useState([]);
const table = document.getElementById("tbody");
useEffect(() => {
getData();
console.log(2);
},[]);
const getData = async function () {
const response = await fetch(host + "/reader");
setData(await response.json())
console.log(data);
//table.innerHTML = "";
// data.forEach(Reader => {
// let temp = "<select>";
// Reader.mangas.forEach(Manga => {
// temp += `<option>${Manga.mangaName + " " + Manga.chapterCount}</option>>`
// })
// temp += "</select>"
// table.innerHTML +=
// `<tr>
// <th scope="row">${Reader.id}</th>
// <td>${Reader.readerName}</td>
// <td>${Reader.hashedPassword}</td>
// <td>${temp}</td>
// </tr>`;
// })
}
const create = async function (){
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/reader?readerName=${readerName}&password=${password}`, requestParams);
getData();
}
const remove = async function (){
console.info('Try to remove item');
if (readerId !== 0) {
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
}
const requestParams = {
method: "DELETE",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/reader/` + readerId, requestParams);
getData();
return await response.json();
}
const removeAll = async function (){
console.info('Try to remove item');
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
const requestParams = {
method: "DELETE",
};
await fetch(host + `/reader/`, requestParams);
getData();
}
const update = async function (){
console.info('Try to update item');
if (readerId === 0 || readerName == null || password === 0) {
return;
}
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json",
}
};
const response = await fetch(host + `/reader/${readerId}?readerName=${readerName}&password=${password}`, requestParams);
getData();
return await response.json();
}
const removeManga = async function (){
console.info('Try to remove item');
if (!confirm('Do you really want to remove this item?')) {
console.info('Canceled');
return;
}
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json",
}
};
console.log(host + `/reader/${readerId}/removeManga?mangaId=${mangaId}`, requestParams);
const response = await fetch(host + `/reader/${readerId}/removeManga?mangaId=${mangaId}`, requestParams);
return await response.json();
}
const addManga = async function () {
const requestParams = {
method: "PUT",
headers: {
"Content-Type": "application/json",
}
};
console.log(host + `/reader/${readerId}/addManga?mangaId=${mangaId}`, requestParams);
const response = await fetch(host + `/reader/${readerId}/addManga?mangaId=${mangaId}`, requestParams);
return await response.json();
}
const createButton = (e) =>{
e.preventDefault()
create();
}
const removeButton = (e) =>{
e.preventDefault()
remove();
}
const updateButton = (e) =>{
e.preventDefault()
update();
}
const removeMangaButton = (e) =>{
e.preventDefault()
removeManga();
}
const addMangaButton = (e) =>{
e.preventDefault()
addManga();
}
return (
<main>
<div className="container" id="root-div">
<div className="content">
<h1>Reader</h1>
<form id="form">
<div className="d-flex justify-content-evenly mt-3">
<div className="col-sm-2">
<label htmlFor="readerId" className="form-label">readerId</label>
<input type='number' value = {readerId} onChange={event => setReaderId(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="mangaId" className="form-label">mangaId</label>
<input type='number' value = {mangaId} onChange={event => setMangaId(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="readerName" className="form-label">readerName</label>
<input type='text' value = {readerName} onChange={event => setReaderName(event.target.value)} className="form-control"/>
</div>
<div className="col-sm-2">
<label htmlFor="password" className="form-label">password</label>
<input type='text' value = {password} onChange={event => setPassword(event.target.value)} className="form-control"/>
</div>
</div>
<div className="row m-3">
<div className="d-grid col-sm-3 m-3 mx-auto">
<button onClick={createButton} className="btn btn-success">Добавить</button>
</div>
<div className="d-grid col-sm-3 m-3 mx-auto">
<button onClick={updateButton} className="btn btn-success">Обновить</button>
</div>
<div className="d-grid col-sm-3 m-3 mx-auto">
<button onClick={removeButton} className="btn btn-success">Удалить</button>
</div>
<div className="d-grid col-sm-2 m-3 mx-auto">
<button onClick={removeMangaButton} className="btn btn-success">Удалить мангу</button>
</div>
<div className="d-grid col-sm-2 m-3 mx-auto">
<button onClick={addMangaButton} className="btn btn-success">Добавить мангу</button>
</div>
</div>
</form>
<div className="row table-responsive text-white">
<table className="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">readerName</th>
<th scope="col">Password</th>
<th scope="col">Mangs</th>
</tr>
</thead>
<TableReader items = {data}/>
{/* <tbody id="tbody">
</tbody> */}
</table>
</div>
</div>
</div>
</main>
);
}

View File

@ -0,0 +1,26 @@
import { useState } from 'react';
export default function TableCreator(props) {
return (
<tbody>
{
props.items.map((item, index) =>
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.creatorName}</td>
<td>{item.hashedPassword}</td>
<td>
<select>{item.mangas.map(manga =>
<option key={manga.mangaName } >{manga.mangaName + " " +manga.chapterCount}</option>)}
</select>
</td>
</tr>
)
}
</tbody >
);
}

View File

@ -0,0 +1,25 @@
import { useState } from 'react';
export default function TableCreator(props) {
return (
<tbody>
{
props.items.map((item, index) =>
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.mangaName}</td>
<td>{item.chapterCount}</td>
<td>{item.creatorId}</td>
<td>
<select>{item.readers.map(reader =>
<option key={reader}>{reader}</option>)}
</select>
</td>
</tr>
)
}
</tbody >
);
}

View File

@ -0,0 +1,24 @@
import { useState } from 'react';
export default function TableReader(props) {
return (
<tbody>
{
props.items.map((item, index) =>
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.readerName}</td>
<td>{item.hashedPassword}</td>
<td>
<select>{item.mangas.map(manga =>
<option key={manga}>{manga}</option>)}
</select>
</td>
</tr>
)
}
</tbody >
);
}

8
front/src/main.jsx Normal file
View File

@ -0,0 +1,8 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './style.css'
ReactDOM.createRoot(document.getElementById('app')).render(
<App />
)

102
front/src/style.css Normal file
View File

@ -0,0 +1,102 @@
/* html,
body {
background-color: #000000;
color: #ffffff;
padding: 0;
margin: 0;
font-family: sans-serif;
line-height: 1.15;
height: 100%;
}
header {
background-color: #3c3c3c;
color: #ffffff;
}
header a {
color: #ffffff;
text-decoration: none;
margin: 0 0.5em;
}
header a:hover {
text-decoration: underline;
}
#logo {
margin-left: 0.5em;
}
article a {
color: #ffffff;
text-decoration: none;
margin: 0.5em 0.5em;
}
header a:hover {
text-decoration: underline;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.25em;
}
h3 {
font-size: 1.1em;
}
footer {
background-color: #9c9c9c;
color: #ffffff;
height: 32px;
padding: 0.5em;
}
.manga_pages{
display: flex;
flex-direction: column;
align-items: center;
}
.catalog_wrapper{
display: flex;
width: 73%;
flex-direction: column;
}
.catalog_article{
display: flex;
}
.poster{
width:140px;
}
th {
border: 0px solid rgb(255, 255, 255);
}
.added_manga{
display: flex;
flex-direction: column;
}
@media (min-width: 992px) {
.manga_pages img{
max-width: 900px;
width: auto;
height: auto;
}
}
.flex_grow {
flex-grow: 1;
display: flex;
align-items: center;
}
@media (min-width: 1024px){
.article_1 {
max-width: -webkit-calc(1600px + (100vw/64*7)*2);
max-width: -moz-calc(1600px + (100vw/64*7)*2);
max-width: calc(1600px + (100vw/64*7)*2);
padding-left: -webkit-calc(100vw/64*7);
padding-left: -moz-calc(100vw/64*7);
padding-left: calc(100vw/64*7);
padding-right: -webkit-calc(100vw/64*7);
padding-right: -moz-calc(100vw/64*7);
padding-right: calc(100vw/64*7);
}
}
.registration_div {
width: 100%;
height: 100%;
} */