ReactUpdate

This commit is contained in:
Sergey Kozyrev 2024-01-07 21:44:00 +04:00
parent 728e4bb398
commit afac6d221b
19 changed files with 1947 additions and 223 deletions

View File

@ -2,9 +2,8 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My shop</title>
<title>Тарелька</title>
</head>
<body>

1696
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,29 +4,35 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"rest": "json-server data.json",
"vite": "vite",
"dev": "npm-run-all --parallel rest vite",
"prod": "npm-run-all lint 'vite build' --parallel rest 'vite preview'"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"axios": "^1.6.2",
"bootstrap": "^5.3.2",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-bootstrap-icons": "^1.10.3",
"prop-types": "^15.8.1"
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.18.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/react-dom": "^18.2.15",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"json-server": "^0.17.4",
"npm-run-all": "^4.1.5",
"vite": "^4.4.5"
}
}

View File

@ -1,20 +1,23 @@
import PropTypes from 'prop-types';
import { useNavigate } from 'react-router-dom';
function Button(Image) {
function Button({ line }) {
const navigator = useNavigate();
const RedirectVideo = () => {
navigator('/Watch');
navigator(`/Watch/${line.id}`);
};
return (
<>
<button onClick={RedirectVideo} className="vid">
<img src={Image.img} style={{ maxWidth: '100%', maxHeight: '100%' }} />
<h1 className="text-center">НАЗВАНИЕ ВИДЕО</h1>
<img src={line.image} style={{ maxWidth: '100%', maxHeight: '50%' }} />
<h1 className="text-center">{line.title}</h1>
</button>
</>
);
}
Button.propTypes = {
line: PropTypes.object,
};
export default Button;

View File

@ -1,20 +1,25 @@
import PropTypes from 'prop-types';
import { useNavigate } from 'react-router-dom';
function Button100(Image) {
function Button100({ line }) {
const navigator = useNavigate();
const RedirectVideo = () => {
navigator('/Watch');
navigator(`/Watch/${line.id}`);
};
return (
<>
<button onClick={RedirectVideo} className="vid" style={{ width: '100%' }}>
<img src={Image.img} style={{ maxWidth: '100%', maxHeight: '100%' }} />
<h1 className="text-center">НАЗВАНИЕ ВИДЕО</h1>
<img src={line.image} style={{ maxWidth: '100%', maxHeight: '50%' }} />
<h1 className="text-center">{line.title}</h1>
</button>
</>
);
}
Button100.propTypes = {
line: PropTypes.object,
};
export default Button100;

View File

@ -1,6 +1,6 @@
import { useNavigate } from 'react-router-dom';
function ButtonSearch(Image) {
function ButtonSearch(line) {
const navigator = useNavigate();
const RedirectVideo = () => {
navigator('/Watch');
@ -8,10 +8,10 @@ function ButtonSearch(Image) {
return (
<>
<button className="vid-row" onClick={RedirectVideo}>
<img src={Image.img} style={{ maxWidth: '50%' }} />
<img src={line.img} style={{ maxWidth: '50%' }} />
<div className="columns">
<div className="vid-search-text-big">НАЗВАНИЕ ВИДЕО</div>
<div className="vid-search-text-small">ОПИСАНИЕ ВИДЕО</div>
<div className="vid-search-text-big">{line.title}</div>
<div className="vid-search-text-small">{line.description}</div>
</div>
</button>
</>

View File

@ -1,17 +1,22 @@
import PropTypes from 'prop-types';
import { Person } from 'react-bootstrap-icons';
import { useNavigate } from 'react-router-dom';
function ChanelDop(Image) {
function ChanelDop({ chanel }) {
const navigator = useNavigate();
const RedirectChanel = () => {
navigator('/chanel');
navigator(`/chanel/${chanel.id}`);
};
return (
<>
<div className="row m-3"> <button onClick={RedirectChanel} className="subscribed" >{Image.name}<Person style={{ float: 'right' }}></Person></button></div>
<div className="row m-3"> <button onClick={RedirectChanel} className="subscribed" >{chanel.name}<Person style={{ float: 'right' }}></Person></button></div>
</>
);
}
ChanelDop.propTypes = {
chanel: PropTypes.object,
};
export default ChanelDop;

View File

@ -6,14 +6,23 @@ import { Link, useNavigate } from 'react-router-dom';
const Navigation = ({ routes }) => {
const navigate = useNavigate();
const indexPageLink = routes.filter((route) => route.index === false).shift();
let userId = localStorage.getItem('EnabledUser');
const RedirectChanel = () => {
navigate('/chanel');
userId = localStorage.getItem('EnabledUser');
if (userId !== null) {
navigate('/Admin');
}
};
const RedirectSearch = () => {
navigate('/search');
};
const RedirectLogin = () => {
navigate('/login');
userId = localStorage.getItem('EnabledUser');
if (userId !== null) {
navigate('/account');
} else {
navigate('/login');
}
};
return (
<header>
@ -27,13 +36,12 @@ const Navigation = ({ routes }) => {
<Navbar.Collapse id='main-navbar' style={{ flexGrow: '0' }}>
<Nav className="navbar-nav">
<div className="row" style={{ flexWrap: 'nowrap', margin: '5px 20px 5px 0px' }}>
<input className="form-control me-1 nav-link" type="search" style={{ width: '90%' }} placeholder="Search" aria-label="Search" />
<button onClick={RedirectSearch} className="back" type="submit" >
<Search className="fa-solid" />
</button>
</div>
<div className="row" style={{ flexWrap: 'nowrap', margin: '5px 20px 5px 0px' }}>
<button onClick={RedirectLogin} className="login nav-link me-1" style={{ width: '90%' }} >Войти/Зарегистрироватся</button>
<button onClick={RedirectLogin} className="login nav-link me-1" style={{ width: '90%' }} >Войти/Аккаунт</button>
<button onClick={RedirectChanel} className="user nav-link" type="submit">
<Person className="fa-solid fa-user" />
</button>

View File

@ -271,9 +271,9 @@ button:not(:disabled) {
@media (max-width: 500px) {
.register-table
{
height: 70%;
height: 50%;
width:70%;
top: 10%;
top: 20%;
left: 20%;
overflow: auto;
position: fixed;
@ -331,12 +331,11 @@ button:not(:disabled) {
@media (min-width: 500px) {
.register-table
{
height: 500px;
height: 400px;
width: 300px;
top:10%;
top:20%;
left: 35%;
overflow: auto;
display: flex;
position: fixed;
background-color: #87B650;
}

View File

@ -13,6 +13,7 @@ import Admin from './pages/Admin.jsx';
import Repair from './pages/Repair.jsx';
import Search from './pages/Search.jsx';
import Watch from './pages/Watch.jsx';
import Redact from './pages/Redact.jsx';
const routes = [
{
@ -22,35 +23,43 @@ const routes = [
title: 'Главная страница',
},
{
path: '/chanel',
path: '/chanel/:id?',
element: <Chanel />,
title: 'Вторая страница',
title: 'Канал',
},
{
path: '/login',
element: <Login />,
title: 'Третья страница',
title: 'Вход',
},
{
path: '/regist',
element: <Register />,
title: 'Четвертая страница',
title: 'Регистрация',
},
{
path: '/admin',
element: <Admin />,
title: 'Админ Панель',
},
{
path: '/repair',
path: '/account',
element: <Repair />,
title: 'Аккаунт',
},
{
path: '/search',
element: <Search />,
title: 'Поиск',
},
{
path: '/watch',
path: '/watch/:id?',
element: <Watch />,
title: 'Видео',
},
{
path: '/redact/:id?',
element: <Redact />,
},
];

View File

@ -1,7 +1,13 @@
import { Person } from 'react-bootstrap-icons';
import Prev from '../assets/fon.jpg';
import Lines from '../components/lines/table/Lines.jsx';
import useType from '../components/types/hooks/TypeHook';
import LinesUser from '../components/lines/table/LinesUser.jsx';
const Admin = () => {
const { id } = localStorage.getItem('EnabledUser');
const { type } = useType(id);
if (localStorage.getItem('EnabledUser') === '1') {
return (
<>
<div style={{ width: '100%', height: '20%' }}>
@ -12,29 +18,30 @@ const Admin = () => {
<Person style={{ margin: '35% 0 0 35%' }} />
</div>
<div className="chanel-text column">
<div>НАЗВАНИЕ КАНАЛА</div>
<div>{type.name}</div>
</div>
<button className="chanel-subscribe" >
Редактировать
</button>
</div>
<div>
<table id="items-table" className="table table-striped">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" className="w-25">Автор</th>
<th scope="col" className="w-25">Название</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<Lines />
</>
);
}
return (
<>
<div style={{ width: '100%', height: '20%' }}>
<img src={Prev} style={{ width: '100%', height: '100%' }} />
</div>
<div className="chanel rows" style={{ bsGutterX: '0' }}>
<div className="chanel-user">
<Person style={{ margin: '35% 0 0 35%' }} />
</div>
<div className="chanel-text column">
<div>{type.name}</div>
</div>
</div>
<LinesUser idUser={id} />
</>
);
};
export default Admin;

View File

@ -1,9 +1,15 @@
import { useParams } from 'react-router-dom';
import { Person } from 'react-bootstrap-icons';
import Photo from '../assets/maxresdefault.jpg';
import PropTypes from 'prop-types';
import Prev from '../assets/fon.jpg';
import Button from '../components/Button/Button.jsx';
import useLines from '../components/lines/hooks/LinesHook';
import useType from '../components/types/hooks/TypeHook';
const Chanel = () => {
const { id } = useParams();
const { lines } = useLines(id);
const { type } = useType(id);
return (
<>
<div style={{ width: '100%' }}>
@ -14,25 +20,25 @@ const Chanel = () => {
<Person style={{ margin: '35% 0 0 35%' }} />
</div>
<div className="chanel-text">
НАЗВАНИЕ КАНАЛА
{type.name}
</div>
<button className="chanel-subscribe">
Подписаться
</button>
</div>
<div className="rows images">
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
{
lines.map((line) =>
<Button key={line.id} line={line} />)
}
</div>
</>
);
};
Chanel.propTypes = {
type: PropTypes.object,
Button: PropTypes.func,
};
export default Chanel;

View File

@ -1,37 +1,72 @@
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import { Button, Form } from 'react-bootstrap';
import usePersonL from '../components/types/hooks/LoginHooks';
const Login = () => {
const navigator = useNavigate();
const RedirectRegist = () => {
navigator('/regist');
};
const RedirectRepair = () => {
navigator('/regist');
const [validated, setValidated] = useState(false);
const [formData, setFormData] = useState({
email: '',
password: '',
});
const { user, handlerLoginChanged } = usePersonL(formData.email);
const handleSubmit = (event) => {
const form = event.currentTarget;
event.preventDefault();
event.stopPropagation();
if (form.checkValidity() !== false) {
console.log(formData);
}
if (user === null) {
return;
}
if (user.password === formData.password) {
const ind = user.id;
localStorage.setItem('EnabledUser', JSON.stringify(user.id));
navigator(`/Chanel/${ind}`);
}
setValidated(true);
};
const RedirectAdmin = () => {
navigator('/admin');
const handleChange = (event) => {
const inputName = event.target.name;
const inputValue = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
setFormData({
...formData,
[inputName]: inputValue,
});
if (inputName === 'email') {
handlerLoginChanged(inputValue);
}
};
return (
<>
<div className="container-fluid w-2 register-table text-center col">
<div className="register-table-text">
Войти в аккаунт
<Form className='container-fluid w-2 register-table text-center col' noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Group className='mb-2' controlId='email'>
<Form.Label>E-mail</Form.Label>
<Form.Control type='email' name='email' placeholder='name@example.ru' required
value={formData.email} onChange={handleChange} />
</Form.Group>
<Form.Group className='mb-2' controlId='password'>
<Form.Label>Пароль</Form.Label>
<Form.Control type='password' name='password' required
value={formData.password} onChange={handleChange} />
</Form.Group>
<div className='text-center'>
<Button className='w-50' variant='primary' type='submit'>Войти</Button>
</div>
<div className="register-table-column">
<div className="register-table-input2">
<input className="form-control me-2 orange" type="email" placeholder="Почта" aria-label="Mail" />
<div className='text-center'>
<Button className='w-50' variant='primary' onClick={RedirectRegist} >Регистрация</Button>
</div>
<div className="register-table-input3">
<input className="form-control me-2 orange" type="password" placeholder="Пароль" aria-label="Mail" />
</div>
</div>
<div className="register-table-button column">
<button onClick={RedirectRepair} className="reg_button">Забыл пароль</button>
<button onClick={RedirectRegist} className="reg_button">Регистрация</button>
<button onClick={RedirectAdmin} className="reg_button">Войти</button>
</div>
</div>
</Form>
</>
);
};

View File

@ -1,33 +1,39 @@
import Photo from '../assets/maxresdefault.jpg';
import Button from '../components/Button/Button.jsx';
import PropTypes from 'prop-types';
import useLines from '../components/lines/hooks/LinesHook';
import useTypeFilter from '../components/lines/hooks/LinesFilterHook';
import ChanelDop from '../components/Button/ChanelDop.jsx';
import Button from '../components/Button/Button.jsx';
import useTypes from '../components/types/hooks/TypesHook';
const MainPage = () => {
const { currentFilter } = useTypeFilter();
const { lines } = useLines(currentFilter);
const { types } = useTypes();
return (
<>
<div className="container-fluid w-100" style={{ bsGutterX: '0' }}>
<div className="container-fluid w-2 left-blank text-center column mobdel">
<ChanelDop name="НАЗВАНИЕ КАНАЛА"/>
<ChanelDop name="НАЗВАНИЕ КАНАЛА"/>
<ChanelDop name="НАЗВАНИЕ КАНАЛА"/>
<ChanelDop name="НАЗВАНИЕ КАНАЛА"/>
<ChanelDop name="НАЗВАНИЕ КАНАЛА"/>
{
types.map((type) =>
<ChanelDop key={type.id} chanel={type} />)
}
</div>
<div className="right-blank row images">
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
<Button img={ Photo }/>
</div>
{
lines.map((line) =>
<Button key={line.id} line={line} />)
}
</div>
</div>
</>
);
};
MainPage.propTypes = {
Button: PropTypes.func,
ChanelDop: PropTypes.func,
};
export default MainPage;

View File

@ -1,33 +1,10 @@
import { useParams } from 'react-router-dom';
import LinesForm from '../components/lines/form/LinesForm.jsx';
const Redact = () => {
const { id } = useParams();
return (
<>
<main className="container-fluid p-2">
<div className="text-center">
<img id="image-preview" src="https://via.placeholder.com/200" className="rounded rounded-0" alt="placeholder"/>
</div>
<form id="items-form" className="needs-validation" noValidate>
<div className="mb-2">
<label htmlFor="item" className="form-label">Канал</label>
<select id="item" className="form-select" name="chanel" required>
</select>
</div>
<div className="mb-2">
<label className="form-label" htmlFor="title">Название</label>
<input id="title" name="title" className="form-control" type="text" required/>
</div>
<div className="mb-2">
<label className="form-label" htmlFor="image">Изображение</label>
<input id="image" type="file" name="image" className="form-control" accept="image/*"/>
</div>
<div className="mb-2">
<label className="form-label" htmlFor="video">Видео</label>
<input id="video" type="file" name="video" className="form-control" accept="video/*"/>
</div>
<a href="/adminchanel.html" className="btn btn-secondary">Назад</a>
<button type="submit" className="btn btn-primary">Сохранить</button>
</form>
</main>
</>
<LinesForm id={id} />
);
};

View File

@ -1,35 +1,11 @@
import { useNavigate } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import TypesForm from '../components/user/TypesForm.jsx';
const Register = () => {
const navigator = useNavigate();
const RedirectChanel = () => {
navigator('/chanel');
};
const { id } = useParams();
return (
<>
<div className="container-fluid w-2 register-table text-center col">
<div className="register-table-text">
Регистрация аккаунта
</div>
<div className="register-table-column">
<div className="register-table-input1">
<input className="form-control me-2 orange" type="text" placeholder="Никнейм" aria-label="Mail" />
</div>
<div className="register-table-input2">
<input className="form-control me-2 orange" type="email" placeholder="Почта" aria-label="Mail" />
</div>
<div className="register-table-input3">
<input className="form-control me-2 orange" type="password" placeholder="Пароль" aria-label="Mail" />
</div>
<div className="register-table-input4">
<input className="form-control me-2 orange" type="password" placeholder="Повтор пароля" aria-label="Mail" />
</div>
</div>
<div className="register-table-button">
<button onClick={RedirectChanel} className="reg_button">Регистрация</button>
</div>
</div>
<TypesForm id={id} />
</>
);

View File

@ -1,21 +1,24 @@
import { useNavigate } from 'react-router-dom';
import useType from '../components/types/hooks/TypeHook';
const Repair = () => {
const navigator = useNavigate();
const RedirectChanel = () => {
navigator('/chanel');
localStorage.removeItem('EnabledUser');
navigator('/');
};
const id = localStorage.getItem('EnabledUser');
const { type } = useType(id);
return (
<>
<div className="container-fluid w-2 register-table text-center col">
<div className="register-table-text">
Восстановление аккаунта
</div>
<div className="register-table-input1">
<input className="form-control me-2 orange" type="email" placeholder="Почта" aria-label="Mail" />
Информация об аккаунте
</div>
<div className="text-center register-table-input1">{type.name}</div>
<div className="text-center register-table-input2">{type.mail}</div>
<div className="register-table-button">
<button onClick={RedirectChanel} className="reg_button">Восстановить</button>
<button onClick={RedirectChanel} className="reg_button">Выйти из аккаунта</button>
</div>
</div>
</>

View File

@ -1,17 +1,42 @@
import Photo from '../assets/maxresdefault.jpg';
import { useParams } from 'react-router-dom';
import { useState } from 'react';
import ButtonSearch from '../components/Button/ButtonSearch.jsx';
import SearchVideos from '../components/types/hooks/SearchHook';
import Input from '../components/input/Input.jsx';
const Search = () => {
const { text } = useParams();
const { files, handlerVideoSearch } = SearchVideos(text);
let videos = [];
const [formData, setFormData] = useState({
search: '',
});
const handleChange = (event) => {
const inputName = event.target.name;
const inputValue = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
setFormData({
...formData,
[inputName]: inputValue,
});
if (inputName === 'search') {
handlerVideoSearch(inputValue);
}
if (files === null) {
videos = [];
} else {
videos = files;
}
};
return (
<>
<Input label='Название' name='search' onChange={handleChange} value={formData.search}/>
<div className="columns" style={{ margin: '5% 5% 5% 5%' }}>
<ButtonSearch img={Photo}/>
<ButtonSearch img={Photo}/>
<ButtonSearch img={Photo}/>
<ButtonSearch img={Photo}/>
<ButtonSearch img={Photo}/>
<ButtonSearch img={Photo}/>
{
videos.map((line) =>
<ButtonSearch key={line.id} line={line} />)
}
</div>
</>
);

View File

@ -1,34 +1,43 @@
import Photo from '../assets/maxresdefault.jpg';
import { useParams } from 'react-router-dom';
import Button100 from '../components/Button/Button100.jsx';
import Video from '../assets/Rick.mp4';
import useLinesItemForm from '../components/lines/hooks/LinesItemFormHook';
import useTypeFilter from '../components/lines/hooks/LinesFilterHook';
import useLines from '../components/lines/hooks/LinesHook';
const Watch = () => {
const { id } = useParams();
const {
item,
} = useLinesItemForm(id);
const { currentFilter } = useTypeFilter();
const { lines } = useLines(currentFilter);
return (
<>
<div className="w-100 rows">
<div className="w-75 columns vid-worker-big">
<video controls src={Video} className="vid-player"></video>
<div className="vid-text-big">НАЗВАНИЕ ВИДЕОРОЛИКА</div>
<div className="vid-text-small">ОПИСАНИЕ ЭТОЙ ВЕЩИ</div>
<video controls src={item.video} className="vid-player"></video>
<div className="vid-text-big">{item.title}</div>
<div className="vid-text-small">{item.description}</div>
</div>
<div className="w-25 columns vid-worker-big">
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
{
lines.map((line) =>
<Button100 key={line.id} line={line} />)
}
</div>
<div className="w-100 columns vid-worker-small">
<div>
<video controls src={Video} className="vid-player"></video>
<div className="vid-text-big">НАЗВАНИЕ ВИДЕОРОЛИКА</div>
<div className="vid-text-small">ОПИСАНИЕ ЭТОЙ ВЕЩИ</div>
<video controls src={item.video} className="vid-player"></video>
<div className="vid-text-big">{item.title}</div>
<div className="vid-text-small">{item.description}</div>
</div>
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
<Button100 img={Photo} />
{
lines.map((line) =>
<Button100 key={line.id} line={line} />)
}
</div>
</div>
</>