стадия торг

This commit is contained in:
Вячеслав Иванов 2023-11-15 23:17:59 +04:00
parent 231d8fea1f
commit f1d991fb7c
24 changed files with 762 additions and 188 deletions

View File

@ -2,12 +2,12 @@
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/logo.png" href="src/Images/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Каталог</title> <title>Каталог</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root" class="h-100 d-flex flex-column"></div>
<script type="module" src="/src/main.jsx"></script> <script type="module" src="/src/main.jsx"></script>
</body> </body>
</html> </html>

93
lab4/package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"bootstrap": "^5.3.2", "bootstrap": "^5.3.2",
"mdb-react-ui-kit": "^7.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.9.1", "react-bootstrap": "^2.9.1",
@ -388,6 +389,21 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.18.20", "version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
@ -1072,7 +1088,6 @@
"version": "18.2.15", "version": "18.2.15",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz",
"integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==", "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==",
"dev": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
} }
@ -1455,6 +1470,14 @@
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
}, },
"node_modules/clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
"engines": {
"node": ">=6"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -2294,6 +2317,29 @@
"is-callable": "^1.1.3" "is-callable": "^1.1.3"
} }
}, },
"node_modules/framer-motion": {
"version": "10.16.5",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.5.tgz",
"integrity": "sha512-GEzVjOYP2MIpV9bT/GbhcsBNoImG3/2X3O/xVNWmktkv9MdJ7P/44zELm/7Fjb+O3v39SmKFnoDQB32giThzpg==",
"dependencies": {
"tslib": "^2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -3084,6 +3130,32 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/mdb-react-ui-kit": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/mdb-react-ui-kit/-/mdb-react-ui-kit-7.0.0.tgz",
"integrity": "sha512-ke23u6Ux63nrmi3PFa7H1YlmQe76POT5rNpxuet0MB4+8OjCzw+WviL4EJtzDlNHXhnw9mfU9a5MF8q0swO+wA==",
"dependencies": {
"@popperjs/core": "2.11.5",
"clsx": "1.1.1",
"framer-motion": "^10.16.4",
"react-popper": "2.3.0"
},
"peerDependencies": {
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.3",
"react": "^18.1.0",
"react-dom": "^18.1.0"
}
},
"node_modules/mdb-react-ui-kit/node_modules/@popperjs/core": {
"version": "2.11.5",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz",
"integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -3518,6 +3590,11 @@
"react": "^18.2.0" "react": "^18.2.0"
} }
}, },
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -3528,6 +3605,20 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
}, },
"node_modules/react-popper": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
"dependencies": {
"react-fast-compare": "^3.0.1",
"warning": "^4.0.2"
},
"peerDependencies": {
"@popperjs/core": "^2.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",

View File

@ -10,13 +10,14 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"bootstrap": "^5.3.2", "bootstrap": "^5.3.2",
"mdb-react-ui-kit": "^7.0.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1", "react-bootstrap": "^2.9.1",
"react-bootstrap-icons": "^1.10.3", "react-bootstrap-icons": "^1.10.3",
"prop-types": "^15.8.1" "react-dom": "^18.2.0",
"react-router-dom": "^6.18.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.15", "@types/react": "^18.2.15",
@ -29,4 +30,4 @@
"eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-react-refresh": "^0.4.3",
"vite": "^4.4.5" "vite": "^4.4.5"
} }
} }

View File

@ -1,42 +0,0 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}

View File

@ -7,13 +7,13 @@ import Navigation from './components/navigation/Navigation.jsx';
const App = ({ routes }) => { const App = ({ routes }) => {
return ( return (
<> <div className="d-flex flex-column min-vh-100">
<Navigation routes={routes}></Navigation> <Navigation routes={routes}></Navigation>
<Container className='p-2' as="main" fluid> <Container className="flex-grow-1 p-2" as="main" fluid>
<Outlet /> <Outlet />
</Container> </Container>
<Footer /> <Footer />
</> </div>
); );
}; };

View File

@ -0,0 +1,4 @@
.btn-opaque {
background-color: rgba(255, 255, 255, 0.8); /* You can adjust the alpha value for opacity */
/* You can also set other styles to make the buttons more visible */
}

View File

@ -0,0 +1,41 @@
import { useState } from 'react';
import { Card, Col, Row, Form } from 'react-bootstrap';
const BasketCard = () => {
const [quantity, setQuantity] = useState(2);
const handleQuantityChange = (event) => {
setQuantity(event.target.value);
};
return (
<Card className="rounded-3 mb-4">
<Card.Body className="p-4">
<Row className="d-flex justify-content-between align-items-center">
<Col md={2} lg={2} xl={2}>
<img src="./src/Images/pizza.png" className="img-fluid rounded-3" alt="Cotton T-shirt" />
</Col>
<Col md={3} lg={3} xl={3}>
<p className="lead fw-normal mb-2">Название пиццы</p>
</Col>
<Col md={3} lg={3} xl={2} className="d-flex align-items-center">
<Form.Control
id="form1"
min="0"
name="quantity"
value={quantity}
type="number"
className="form-control form-control-sm text-center"
onChange={handleQuantityChange}
/>
</Col>
<Col md={3} lg={2} xl={2} offset-lg={1}>
<h5 className="mb-0">Цена </h5>
</Col>
</Row>
</Card.Body>
</Card>
);
};
export default BasketCard;

View File

View File

@ -0,0 +1,20 @@
import { Col, Card, Button } from 'react-bootstrap';
const ProductCard = () => {
return (
<Col lg={3} md={4} sm={6} xs={12} className="mb-4">
<Card>
<Card.Img src="./src/Images/pizza.png" alt="Product Image" className="card-img-top" />
<Card.Body>
<Card.Title>Название</Card.Title>
</Card.Body>
<Card.Footer>
<div className="text-warning font-weight-bold">Цена </div>
<Button variant="warning">В корзину</Button>
</Card.Footer>
</Card>
</Col>
);
};
export default ProductCard;

View File

@ -0,0 +1,21 @@
import { Col, Card } from 'react-bootstrap';
const StockCard = () => {
return (
<Col lg={4} md={6} sm={12} className="mb-4">
<Card>
<Card.Img src="./src/Images/stock.png" alt="Stock Image" className="card-img-top" />
<Card.Body>
<Card.Title>Дарим кибер-призы</Card.Title>
<Card.Text>
Вот так ачивка! Закажите Кибер-комбо и получите доступ к играм от MY.GAMES, а еще кокосовый батончик и
шоколадное печенье «Cyber» от Bite. А также станьте автоматическим участником розыгрыша игровых ключей и
больших пицц 29 июня.
</Card.Text>
</Card.Body>
</Card>
</Col>
);
};
export default StockCard;

View File

@ -1,3 +1,4 @@
.my-footer { .my-footer {
background-color: #D9D9D9; background-color: #D9D9D9;
height: 32px;
} }

View File

@ -2,14 +2,8 @@
background-color: #D9D9D9; background-color: #D9D9D9;
} }
@media (min-width: 768px) { .my-navbar .nav-link {
.my-navbar { text-decoration: none;
height: 100px;
}
}
.my-navbar {
text-decoration: underline;
} }
@media (max-width: 576px) { @media (max-width: 576px) {
@ -20,18 +14,18 @@
@media (min-width: 577px) and (max-width: 992px) { @media (min-width: 577px) and (max-width: 992px) {
.my-navbar img { .my-navbar img {
margin-left: 25px; margin-left: 25px
} }
} }
@media (min-width: 993px) and (max-width: 1200px) { @media (min-width: 993px) and (max-width: 1200px) {
.my-navbar img { .my-navbar img {
margin-left: 150px; margin-left: 150px;
} }
} }
@media (min-width: 1201px) { @media (min-width: 1201px) {
.my-navbar img { .my-navbar img {
margin-left: 235px; margin-left: 235px;
} }
} }

View File

@ -1,43 +1,45 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Container, Nav, Navbar, Button } from 'react-bootstrap'; import { Container, Nav, Navbar, Button } from 'react-bootstrap';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import Image from 'react-bootstrap/Image';
import './Navigation.css'; import './Navigation.css';
const Navigation = ({ routes }) => { const Navigation = ({ routes }) => {
const location = useLocation(); const location = useLocation();
const indexPageLink = routes.filter((route) => route.index === false).shift(); const indexPageLink = routes.find((route) => route.index === true);
const pages = routes.filter((route) => Object.prototype.hasOwnProperty.call(route, 'title')); const pages = routes.filter((route) => Object.prototype.hasOwnProperty.call(route, 'title'));
return ( return (
<header> <Navbar expand='md' className='my-navbar'>
<Navbar expand='md' bg='dark' data-bs-theme='dark' className='my-navbar'>
<Container fluid> <Container fluid>
<Navbar.Brand as={Link} to={indexPageLink?.path ?? '/'}> <Navbar.Brand as={Link} to={indexPageLink?.path ?? '/'}>
<img src="./Images/logo.png" alt="logo" width="128" /> <Image src="./src/Images/logo.png" width="128" alt="Logo" />
</Navbar.Brand> </Navbar.Brand>
<Navbar.Toggle aria-controls='main-navbar' /> <Navbar.Toggle aria-controls='main-navbar' />
<Navbar.Collapse id='main-navbar'> <Navbar.Collapse id='main-navbar'>
<Nav className='me-auto link' activeKey={location.pathname}> <Nav className='me-auto link' activeKey={location.pathname}>
{ {pages.map((page) => (
pages.map((page) => <Nav.Link as={Link} key={page.path} eventKey={page.path} to={page.path ?? '/'}>
<Nav.Link as={Link} key={page.path} eventKey={page.path} to={page.path ?? '/'}> {page.title}
{page.title} </Nav.Link>
</Nav.Link>) ))}
}
</Nav> </Nav>
<Nav> <Nav>
<Button className="custom-btn" as={Link} to="personalAccountLogin.html">Войти</Button> <Button className="custom-btn" as={Link} to="/personalAccountLogin">
<Button variant="warning" as={Link} to="basket.html">Корзина</Button> Войти
</Button>
<Button variant="warning" as={Link} to="/Basket">
Корзина
</Button>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
</Container> </Container>
</Navbar> </Navbar>
</header>
); );
}; };
Navigation.propTypes = { Navigation.propTypes = {
routes: PropTypes.array, routes: PropTypes.array,
}; };
export default Navigation; export default Navigation;

View File

@ -1,69 +1,18 @@
:root { .btn {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; height: 35px;
line-height: 1.5; width: 176px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px; border-radius: 8px;
border: 1px solid transparent; margin-right: 10px;
padding: 0.6em 1.2em; margin-top: 10px;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
} }
@media (prefers-color-scheme: light) { .custom-btn {
:root { color: black;
color: #213547; border: none;
background-color: #ffffff; background-color: #FFA800;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
} }
.btn.custom-btn:hover {
color: black;
background-color: #FFA800 !important;
}

View File

@ -5,34 +5,57 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import App from './App.jsx'; import App from './App.jsx';
import './index.css'; import './index.css';
import ErrorPage from './pages/ErrorPage.jsx'; import ErrorPage from './pages/ErrorPage.jsx';
import Index from './pages/index.jsx'; import Index from './pages/Index.jsx';
import Stock from './pages/Stock.jsx';
import Contacts from './pages/Contacts.jsx';
import PersonalAccountLogin from './pages/PersonalAccountLogin.jsx';
import PersonalAccount from './pages/PersonalAccount.jsx';
import PersonalAccountRegister from './pages/PersonalAccountRegister.jsx';
import PasswordRecovery from './pages/PasswordRecovery.jsx';
import Administrator from './pages/Administrator.jsx';
import Basket from './pages/Basket.jsx';
const routes = [ const routes = [
{ {
index: true, index: true,
path: '/', path: '/',
element: <Index />, element: <Index />,
title: 'Главная страница', title: 'Каталог',
}, },
{ {
path: '/page2', path: '/stock',
element: <Index />, element: <Stock />,
title: 'Вторая страница', title: 'Акции',
}, },
{ {
path: '/page3', path: '/contacts',
element: <Index />, element: <Contacts />,
title: 'Третья страница', title: 'Контакты',
}, },
{ {
path: '/page4', path: '/personalAccountLogin',
element: <Index />, element: <PersonalAccountLogin />,
title: 'Четвертая страница',
}, },
{ {
path: '/page-edit', path: '/personalAccount',
element: <Index />, element: <PersonalAccount />,
}, },
{
path: '/personalAccountRegister',
element: <PersonalAccountRegister/>,
},
{
path: '/PasswordRecovery',
element: <PasswordRecovery/>,
},
{
path: '/Administrator',
element: <Administrator/>,
},
{
path: '/Basket',
element: <Basket/>,
}
]; ];
const router = createBrowserRouter([ const router = createBrowserRouter([
@ -48,4 +71,4 @@ ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode> <React.StrictMode>
<RouterProvider router={router} /> <RouterProvider router={router} />
</React.StrictMode>, </React.StrictMode>,
); );

View File

@ -0,0 +1,50 @@
import { Container, Row, Col, Button, Table } from 'react-bootstrap';
const Administrator = () => {
return (
<Container>
<Row>
<Col>
<h1 className="text-warning text-center font-weight-bold">Панель администратора</h1>
<div className="btn-group" role="group">
<Button variant="warning" href="/page-edit.html">
Добавить товар
</Button>
</div>
</Col>
</Row>
<Row>
<Col>
<h2 className="text-warning text-center font-weight-bold" style={{ paddingTop: '10px' }}>
Таблица данных
</h2>
<Table id="items-table" striped bordered>
<thead>
<tr>
<th scope="col"></th>
<th scope="col" className="w-25">
Товар
</th>
<th scope="col" className="w-25">
Цена
</th>
<th scope="col" className="w-10">
Акция
</th>
<th scope="col" className="w-25">
Количество
</th>
<th scope="col" className="w-25">
Сумма
</th>
</tr>
</thead>
<tbody></tbody>
</Table>
</Col>
</Row>
</Container>
);
};
export default Administrator;

32
lab4/src/pages/Basket.jsx Normal file
View File

@ -0,0 +1,32 @@
import { Container, Row, Col } from 'react-bootstrap';
import BasketCard from '../components/card/BasketCard';
const Basket = () => {
return (
<Container>
<Row>
<Col className="d-flex justify-content-center align-items-center">
<h1 className="text-warning font-weight-bold">Корзина</h1>
</Col>
</Row>
<Row>
<Col xs={10}>
<BasketCard />
<BasketCard />
<BasketCard />
</Col>
</Row>
<div className="d-flex justify-content-start align-items-center">
<div className="text-dark font-weight-bold" style={{ fontSize: '24px' }}>
Сумма заказа:
</div>
<div className="text-end" style={{ color: '#F7D22D', fontSize: '24px' }}>
Сумма
</div>
</div>
<a className="btn btn-warning" style={{ marginLeft: '25px', marginBottom: '10px' }} href="makingAnOrder.html">К оплате</a>
</Container>
);
};
export default Basket;

View File

@ -0,0 +1,36 @@
import { Container, Row, Col } from 'react-bootstrap';
const Contacts = () => {
return (
<Container>
<Row>
<Col className="d-flex justify-content-center align-items-center">
<h1 className="text-warning font-weight-bold">Контакты</h1>
</Col>
</Row>
<Row>
<Col className="d-flex justify-content-center">
<iframe
src="https://yandex.ru/map-widget/v1/?um=constructor%3A0643c92cbdf3809080e5dfb2804b473ea00af31cfabe6fee08676c59d8675f01&amp;source=constructor"
className="img-fluid"
style={{ width: '100%', height: '720px' }}
title="Yandex Map"
></iframe>
</Col>
</Row>
<Row>
<Col>
<a href="tel:71112223344" className="text-warning font-weight-bold" style={{ fontSize: '35px', marginLeft: '10px', marginTop: '10px' }}>
7 111 222 33 44
</a>
<h2 className="font-weight-bold" style={{ fontSize: '35px', marginLeft: '10px', marginTop: '10px' }}>
ул. Северный венец 32
</h2>
<p style={{ fontSize: '25px', marginLeft: '10px', marginTop: '10px' }}>Доставка и самовывоз 10:00 23:00</p>
</Col>
</Row>
</Container>
);
};
export default Contacts;

View File

@ -0,0 +1,61 @@
import { Container, Row, Col, Card, Form, Button } from 'react-bootstrap';
import { useState } from 'react';
const PasswordRecovery = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
};
return (
<Container className="h-100">
<Row className="d-flex justify-content-center align-items-center h-100">
<Col xs={12} md={9} lg={7} xl={6}>
<Card style={{ borderRadius: '15px', borderColor: 'gold' }}>
<Card.Body className="p-5">
<h2 className="text-uppercase text-center mb-5">Восстановление пароля</h2>
<h4 className="text-black text-center mb-5">
Введите свой адрес электронной почты, и мы вышлем вам электронное письмо с инструкциями по сбросу вашего пароля
</h4>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Group className="mb-4">
<Form.Control type="email" id="form3Example3cg" required />
<Form.Control.Feedback>Email заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Email не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example3cg">Ваш адрес электронной почты</Form.Label>
</Form.Group>
<div className="d-flex justify-content-center">
<Button type="submit" className="btn-block btn-warning text-body mb-0">
Сбросить пароль
</Button>
</div>
<p className="text-center text-muted mb-0">
<a href="personalAccountLogin" className="fw-bold text-body">
<u>Войти</u>
</a>
</p>
<p className="text-center text-muted mb-0">
<a href="personalAccountRegister" className="fw-bold text-body">
<u>Регистрация</u>
</a>
</p>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
export default PasswordRecovery;

View File

@ -0,0 +1,81 @@
import { useState } from 'react';
import { Container, Row, Col, Card, Form, Button } from 'react-bootstrap';
const PersonalAccount = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
};
return (
<Container className="h-100">
<Row className="justify-content-center align-items-center h-100">
<Col xs={12} md={9} lg={7} xl={6}>
<Card style={{ borderRadius: '15px', borderColor: 'gold' }}>
<Card.Body className="p-5">
<h2 className="text-uppercase text-center mb-5">Личный кабинет</h2>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Group className="mb-4" controlId="name">
<Form.Control type="text" required />
<Form.Control.Feedback>Имя заполнено</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Имя не заполнено</Form.Control.Feedback>
<Form.Label htmlFor="name">Ваше имя</Form.Label>
</Form.Group>
<Form.Group className="mb-4" controlId="surname">
<Form.Control type="text" required/>
<Form.Control.Feedback>Фамилия заполнена</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Фамилия не заполнена</Form.Control.Feedback>
<Form.Label htmlFor="surname">Ваша фамилия</Form.Label>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control type="email" id="form3Example3cg" required />
<Form.Control.Feedback>Email заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Email не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example3cg">Ваш адрес электронной почты</Form.Label>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control type="date" id="form3Example4cg" required />
<Form.Control.Feedback>Дата рождения заполнена</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Дата рождения не заполнена</Form.Control.Feedback>
<Form.Label htmlFor="form3Example4cg">Дата рождения</Form.Label>
</Form.Group>
<Form.Group className="mb-2">
<Form.Control type="tel" id="form3Example5cg" required />
<Form.Control.Feedback>Номер телефона заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Номер телефона не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example5cg">Номер телефона</Form.Label>
</Form.Group>
<div className="d-flex justify-content-center">
<Button variant="warning" type="submit" id="saveButton">
Сохранить
</Button>
</div>
<div className="d-flex justify-content-center mt-2">
<a className="btn btn-outline-danger" type="button" href="Index">
Выйти
</a>
</div>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
export default PersonalAccount;

View File

@ -0,0 +1,78 @@
import { Container, Row, Col, Card, Form, Button } from 'react-bootstrap';
import { useState } from 'react';
const PersonalAccountLogin = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
};
return (
<Container>
<Row className="d-flex justify-content-center align-items-center h-100">
<Col xs={12} md={9} lg={7} xl={6}>
<Card style={{ borderRadius: '15px', borderColor: 'gold' }}>
<Card.Body className="p-5">
<h2 className="text-uppercase text-center mb-5">Войти</h2>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Group className="mb-4">
<Form.Control type="email" id="form3Example3cg" required />
<Form.Control.Feedback>Email заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Email не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example3cg">Ваш адрес электронной почты</Form.Label>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control type="password" id="form3Example4cg" size="lg" required />
<Form.Control.Feedback>Пароль заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Пароль не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example4cg">Пароль</Form.Label>
</Form.Group>
<Form.Group className="mb-2" controlId="form2Example3cg">
<Form.Check type="checkbox" label="Запомнить меня" />
</Form.Group>
<p className="text-center text-muted mb-0">
Забыли пароль?{' '}
<a href="PasswordRecovery" className="fw-bold text-body">
<u>Восстановление пароля</u>
</a>
</p>
<div className="d-flex justify-content-center">
<Button variant="submit" className="btn-block btn-warning text-body mb-0" href="PersonalAccount">
Вход
</Button>
</div>
<p className="text-center text-muted mb-0">
У вас нет аккаунта?{' '}
<a href="personalAccountRegister" className="fw-bold text-body">
<u>Регистрация</u>
</a>
</p>
<p className="text-center">
<a className="fw-bold text-body" href="Administrator">
Администратор
</a>
</p>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
export default PersonalAccountLogin;

View File

@ -0,0 +1,86 @@
import { Container, Row, Col, Card, Form, Button } from 'react-bootstrap';
import { useState } from 'react';
const PersonalAccountRegister = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
};
return (
<Container className="h-100">
<Row className="justify-content-center align-items-center h-100">
<Col xs={12} md={9} lg={7} xl={6}>
<Card style={{ borderRadius: '15px', borderColor: 'gold' }}>
<Card.Body className="p-5">
<h2 className="text-uppercase text-center mb-5">Создать учетную запись</h2>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Group className="mb-4" controlId="name">
<Form.Control type="text" required />
<Form.Control.Feedback>Имя заполнено</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Имя не заполнено</Form.Control.Feedback>
<Form.Label htmlFor="name">Ваше имя</Form.Label>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control type="email" id="form3Example3cg" required />
<Form.Control.Feedback>Email заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Email не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example3cg">Ваш адрес электронной почты</Form.Label>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control type="password" id="form3Example4cg" size="lg" required />
<Form.Control.Feedback>Пароль заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Пароль не заполнен</Form.Control.Feedback>
<Form.Label htmlFor="form3Example4cg">Пароль</Form.Label>
</Form.Group>
<Form.Group controlId="formRepeatPassword" className="mb-4">
<Form.Control type="password"required/>
<Form.Control.Feedback>Пароль заполнен</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">Пароль не заполнен</Form.Control.Feedback>
<Form.Label>Повторите свой пароль</Form.Label>
</Form.Group>
<Form.Group controlId="formCheckbox" className="d-flex justify-content-center mb-5">
<Form.Check type="checkbox" label={
<span>
Я согласен со всеми утверждениями в{' '}
<a href="#!" className="text-body">
<u>Условиях обслуживания</u>
</a>
</span>
} />
</Form.Group>
<div className="d-flex justify-content-center">
<Button variant="success" type="button" className="btn-block btn-warning text-body mb-0" href="PersonalAccount">
Регистрация
</Button>
</div>
<p className="text-center text-muted mb-0">
У вас уже есть учетная запись?{' '}
<a href="personalAccountLogin" className="fw-bold text-body">
<u>Войдите здесь</u>
</a>
</p>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
export default PersonalAccountRegister;

37
lab4/src/pages/Stock.jsx Normal file
View File

@ -0,0 +1,37 @@
import { Container, Row, Col } from 'react-bootstrap';
import StockCard from '../components/card/StockCard';
const Stock = () => {
return (
<Container>
<Row>
<Col className="d-flex justify-content-center align-items-center">
<h1 className="text-warning font-weight-bold">Акции</h1>
</Col>
</Row>
<Row>
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
<StockCard />
</Row>
</Container>
);
};
export default Stock;

View File

@ -1,33 +1,41 @@
import { Link } from 'react-router-dom'; import { Container, Row, Col } from 'react-bootstrap';
import ProductCard from '../components/card/ProductCard';
const Index = () => { const Index = () => {
return ( return (
<> <Container>
<> <Row>
<h1>Пример web-страницы.</h1> <Col className="d-flex justify-content-center align-items-center">
<h2>1. Структурные элементы</h2> <h1 className="text-warning font-weight-bold">Каталог</h1>
<p><b>Полужирное начертание <i>курсив</i></b></p> </Col>
<p>Абзац 2 <Link to="/Index">Ссылка</Link></p> </Row>
<h3>1.1. Списки</h3> <Row>
<p> <ProductCard />
Список маркированный: <ProductCard />
</p> <ProductCard />
<ul> <ProductCard />
<li><a href="/Index" target="_blank">
Элемент списка 1</a></li> <ProductCard />
<li>Элемент списка 2</li> <ProductCard />
<li>...</li> <ProductCard />
</ul> <ProductCard />
<p>
Список нумерованный: <ProductCard />
</p> <ProductCard />
<ol> <ProductCard />
<li>Элемент списка 1</li> <ProductCard />
<li>Элемент списка 2</li>
<li>...</li> <ProductCard />
</ol> <ProductCard />
</> <ProductCard />
</> <ProductCard />
<ProductCard />
<ProductCard />
<ProductCard />
<ProductCard />
</Row>
</Container>
); );
}; };