Магазин на JavaScript, часть 11 из 19. Компоненты Signup и Login, компоненты Shop и Basket
24.12.2021
Теги: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • БазаДанных • ИнтернетМагазин • КаталогТоваров • Корзина • Фреймворк
Теперь будет немного верстки — нам нужно создать все страницы приложения. Для начала страницы ренистрации и авторизации, которые будут очень похожи. Потом главную страницу магазина со списком всех товаров каталога. Наконец, страницу просмотра одного товара и страницу корзины покупателя.
Компоненты Signup и Login
Файл pages/Signup.js
:
import { AppContext } from '../components/AppContext.js' import { useContext } from 'react' import { Link, useNavigate } from 'react-router-dom' import { Container, Row, Card, Form, Button } from 'react-bootstrap' const Signup = () => { const { user } = useContext(AppContext) const navigate = useNavigate() // если пользователь авторизован — ему здесь делать нечего useEffect(() => { if (user.isAdmin) navigate('/admin', {replace: true}) if (user.isAuth) navigate('/user', {replace: true}) }, []) return ( <Container className="d-flex justify-content-center"> <Card style={{width: '50%'}} className="p-2 mt-5 bg-light"> <h3 className="m-auto">Регистрация</h3> <Form className="d-flex flex-column"> <Form.Control className="mt-3" placeholder="Введите ваш email..." value="" /> <Form.Control className="mt-3" placeholder="Введите ваш пароль..." value="" /> <div className="d-flex justify-content-between mt-3 pl-3 pr-3"> <Button type="submit">Регистрация</Button> <p>Уже есть аккаунт? <Link to="/login">Войдите!</Link></p> </div> </Form> </Card> </Container> ) } export default Signup
Файл pages/Login.js
:
import { AppContext } from '../components/AppContext.js' import { useContext } from 'react' import { Link, useNavigate } from 'react-router-dom' import { Container, Row, Card, Form, Button } from 'react-bootstrap' const Login = () => { const { user } = useContext(AppContext) const navigate = useNavigate() // если пользователь авторизован — ему здесь делать нечего useEffect(() => { if (user.isAdmin) navigate('/admin', {replace: true}) if (user.isAuth) navigate('/user', {replace: true}) }, []) return ( <Container className="d-flex justify-content-center"> <Card style={{width: '50%'}} className="p-2 mt-5 bg-light"> <h3 className="m-auto">Авторизация</h3> <Form className="d-flex flex-column"> <Form.Control className="mt-3" placeholder="Введите ваш email..." value="" /> <Form.Control className="mt-3" placeholder="Введите ваш пароль..." value="" /> <Row className="d-flex justify-content-between mt-3 pl-3 pr-3"> <Button type="submit">Войти</Button> <p>Нет аккаунта? <Link to="/signup">Зарегистрирутесь!</Link></p> </Row> </Form> </Card> </Container> ) } export default Login
Компонент Shop
Это будет очень большой компонент — слева будет меню со списком всех категорий. Справа — меню со списком всех брендов, а под ним — список всех товаров. При клике на категорию и/или бренд — будет происходить фильтрация товаров. Но прежде добавим в контекст товары, категории и бренды — чтобы было проще верстать.
import React from 'react' const AppContext = React.createContext() // контекст, который будем передавать const context = { user: { email: 'ivanov@mail.ru', isAuth: true, isAdmin: false, }, products: [ {id: 1, name: 'Холодильник раз', price: 12345, rating: 0, image: '', categoryId: 1, brandId: 1}, {id: 2, name: 'Холодильник два', price: 23456, rating: 0, image: '', categoryId: 1, brandId: 2}, {id: 3, name: 'Телевизор раз', price: 34567, rating: 0, image: '', categoryId: 2, brandId: 1}, {id: 4, name: 'Телевизор два', price: 45678, rating: 0, image: '', categoryId: 2, brandId: 2}, {id: 5, name: 'Смартфон раз', price: 56789, rating: 0, image: '', categoryId: 3, brandId: 3}, {id: 6, name: 'Смартфон два', price: 67890, rating: 0, image: '', categoryId: 3, brandId: 4}, {id: 7, name: 'Планшет раз', price: 78901, rating: 0, image: '', categoryId: 4, brandId: 3}, {id: 8, name: 'Планшет два', price: 89012, rating: 0, image: '', categoryId: 4, brandId: 4}, ], categories: [ {id: 1, name: 'Холодильники'}, {id: 2, name: 'Телевизоры'}, {id: 3, name: 'Смартфоны'}, {id: 4, name: 'Планшеты'}, ], brands: [ {id: 1, name: 'Samsung'}, {id: 2, name: 'Philips'}, {id: 3, name: 'Siemens'}, {id: 4, name: 'Xiaomi'}, ], } const AppContextProvider = (props) => { return ( <AppContext.Provider value={context}> {props.children} </AppContext.Provider> ); } export {AppContext, AppContextProvider}
Файл pages/Shop.js
:
import { Container, Row, Col } from 'react-bootstrap' import CategoryBar from '../components/CategoryBar.js' import BrandBar from '../components/BrandBar.js' import ProductList from '../components/ProductList.js' const Shop = () => { return ( <Container> <Row className="mt-2"> <Col md={3}> <CategoryBar /> </Col> <Col md={9}> <BrandBar /> <ProductList /> </Col> </Row> </Container> ) } export default Shop
Файл components/CategoryBar.js
:
import { useContext } from 'react' import { AppContext } from './AppContext.js' import { ListGroup } from 'react-bootstrap' const CategoryBar = () => { const { categories } = useContext(AppContext) return ( <ListGroup> {categories.map(item => <ListGroup.Item key={item.id} active={false} onClick={() => alert('Фильтрация, только товары категории')} style={{cursor: 'pointer'}} > {item.name} </ListGroup.Item> )} </ListGroup> ) } export default CategoryBar
Файл components/BrandBar.js
:
import { useContext } from 'react' import { AppContext } from './AppContext.js' import { ListGroup } from 'react-bootstrap'; const BrandBar = () => { const { brands } = useContext(AppContext) return ( <ListGroup horizontal> {brands.map(item => <ListGroup.Item key={item.id} active={false} onClick={() => alert('Фильтрация, только товары бренда')} style={{cursor: 'pointer'}} > {item.name} </ListGroup.Item> )} </ListGroup> ) } export default BrandBar
Файл components/ProductList.js
:
import { useContext } from 'react' import { AppContext } from './AppContext.js' import { Row } from 'react-bootstrap' import ProductItem from './ProductItem.js' const ProductList = () => { const { products } = useContext(AppContext) return ( <Row className="d-flex"> {products.map(item => <ProductItem key={item.id} data={item}/> )} </Row> ); } export default ProductList
Файл components/ProductItem.js
:
import { Card, Col } from 'react-bootstrap' const ProductItem = ({data}) => { return ( <Col md={3} className="mt-3" onClick={() => alert('Переход на страницу товара')}> <Card style={{width: 200, cursor: 'pointer'}}> <Card.Img variant="top" src="http://via.placeholder.com/200" /> <Card.Body style={{height: 100, overflow: 'hidden'}}> <p>Бренд: Samsung</p> <strong>{data.name}</strong> </Card.Body> </Card> </Col> ) } export default ProductItem
Компонент Basket
Будет во многом похож на компонент ProductList
, потому что тоже показывает список, только в виде таблицы. Для начала добавим в контекст содержимое корзины.
import React from 'react' const AppContext = React.createContext() // контекст, который будем передавать const context = { user: { email: 'ivanov@mail.ru', isAuth: true, isAdmin: false, }, /* .......... */ basket: [ {product_id: 1, name: 'Смартфон раз', price: 56789, quantity: 2}, {product_id: 8, name: 'Планшет два', price: 89012, quantity: 1}, ], } const AppContextProvider = (props) => { return ( <AppContext.Provider value={context}> {props.children} </AppContext.Provider> ); } export {AppContext, AppContextProvider}
Файл pages/Basket.js
:
import BasketList from '../components/BasketList.js' import { Container } from 'react-bootstrap' const Basket = () => { return ( <Container> <h1>Корзина</h1> <BasketList /> </Container> ) } export default Basket
Файл components/BasketList.js
:
import { useContext } from 'react' import { AppContext } from './AppContext.js' import { Table } from 'react-bootstrap' import BasketItem from './BasketItem.js' const BasketList = () => { const { basket } = useContext(AppContext) // общая стоимость товаров в корзине const cost = basket.reduce((sum, item) => sum + item.price * item.quantity, 0) return ( <> {basket.length ? ( <Table bordered hover size="sm" className="mt-3"> <thead> <tr> <th>Наименование</th> <th>Количество</th> <th>Цена</th> <th>Сумма</th> <th>Удалить</th> </tr> </thead> <tbody> {basket.map(item => <BasketItem key={item.product_id} {...item} />)} <tr> <th colSpan="3">Итого</th> <th>{cost}</th> <th>руб.</th> </tr> </tbody> </Table> ) : ( <p>Ваша корзина пуста</p> )} </> ) } export default BasketList
Файл components/BasketItem.js
:
const BasketItem = (props) => { return ( <tr> <td>{props.name}</td> <td>{props.quantity}</td> <td>{props.price}</td> <td>{props.price * props.quantity}</td> <td>Удалить</td> </tr> ); } export default BasketItem
- Магазин на JavaScript, часть 19 из 19. Редактирование характеристик и рефакторинг приложения
- Магазин на JavaScript, часть 18 из 19. Панель управления: редактирование категорий и брендов
- Магазин на JavaScript, часть 17 из 19. Панель управления: список заказов, категорий и брендов
- Магазин на JavaScript, часть 15 из 19. Работа с заказами на сервере, оформление заказа
- Магазин на JavaScript, часть 14 из 19. Кнопка «Назад», страница товара, корзина покупателя
- Магазин на JavaScript, часть 13 из 19. Хранилище каталога, компонент витрины, кнопка «Назад»
- Магазин на JavaScript, часть12 из 19. Запросы на сервер, состояние приложения, Signup и Login
Поиск: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • База данных • Интернет магазин • Каталог товаров • Корзина • Фреймворк