lab5+cart

This commit is contained in:
Milana Ievlewa 2023-12-23 21:57:37 +03:00
parent ea59a679a7
commit 3e10eea21d
17 changed files with 111 additions and 279 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,15 +2,18 @@ import PropTypes from 'prop-types';
import { Outlet } from 'react-router-dom'; import { Outlet } from 'react-router-dom';
import Footer from './components/footer/Footer.jsx'; import Footer from './components/footer/Footer.jsx';
import Navigation from './components/navigation/Navigation.jsx'; import Navigation from './components/navigation/Navigation.jsx';
import { CartProvider } from './components/cart/CartContext.jsx';
export const App = ({ routes }) => { export const App = ({ routes }) => {
return ( return (
<> <>
<CartProvider>
<Navigation routes={routes}></Navigation> <Navigation routes={routes}></Navigation>
<main className='w-100 flex-fill d-flex justify-content-center p-0 m-0'> <main className='w-100 flex-fill d-flex justify-content-center p-0 m-0'>
<Outlet /> <Outlet />
</main> </main>
<Footer /> <Footer />
</CartProvider>
</> </>
); );
}; };

View File

@ -6,3 +6,13 @@
.cart-item { .cart-item {
height: auto; height: auto;
} }
.button-overlayAdd button{
background-color: #ff5500;
color: #fff;
font-size: 15px;
width: 16vh;
}
.button-overlayAdd button:hover {
background-color: #5233ff;
color:aqua;
}

View File

@ -1,12 +1,10 @@
import { Button, ButtonGroup, Card } from 'react-bootstrap'; import { Button, ButtonGroup, Card } from 'react-bootstrap';
import { DashLg, PlusLg, XLg } from 'react-bootstrap-icons'; import { DashLg, PlusLg, XLg } from 'react-bootstrap-icons';
import { Link } from 'react-router-dom';
import './Cart.css'; import './Cart.css';
import useCart from './CartHook'; import useCart from './CartHook';
import Select from '../../input/Select.jsx';
import useTypeFilter from '../hooks/LinesFilterHook';
const Cart = () => { const Cart = () => {
const { types, currentFilter, handleFilterChange } = useTypeFilter();
const { const {
cart, cart,
getCartSum, getCartSum,
@ -17,29 +15,26 @@ const Cart = () => {
return ( return (
<main className="container-fluid ml-2 mr-2"> <main className="container-fluid ml-2 mr-2">
<div className="col-lg-4 mt-0 text-white">
<Select
className={'mt-2'}
values={types}
label="Фильтр по товарам"
value={currentFilter}
onChange={handleFilterChange}
/>
</div>
<div className='d-flex flex-column align-items-center'> <div className='d-flex flex-column align-items-center'>
<div className='mb-2 col-12 col-md-8 col-lg-6 d-flex align-items-center'> <div className='mb-2 mt-2 col-12 col-md-8 col-lg-6 d-flex align-items-center'>
<strong className='flex-fill'>Корзина</strong> <strong className='flex-fill'>Корзина</strong>
<Button variant='danger' onClick={() => clearCart()}> <div className='button-overlayAdd'>
<Button onClick={() => clearCart()}>
<XLg /> Очистить <XLg /> Очистить
</Button> </Button>
</div> </div>
</div>
{ {
cart.map((cartItem) => cart.map((cartItem) =>
<Card key={cartItem.id} className='mb-2 col-12 col-md-8 col-lg-6'> <Card key={cartItem.id} className='mb-2 col-12 col-md-8 col-lg-6'>
<Card.Body className='p-2 d-flex flex-column flex-sm-row align-items-center'> <Card.Body className='p-2 d-flex flex-column flex-sm-row align-items-center'>
<div className='cart-item flex-fill'> <div className='cart-item flex-fill'>
<Link to={`/detailpage/${cartItem.ItName}`} style={{ color: 'black', outline: 'none' }}>
<img className='cart-image' src={cartItem.image} alt="Cart Image" /> <img className='cart-image' src={cartItem.image} alt="Cart Image" />
{cartItem.ItName}
&nbsp;&nbsp;||&nbsp;&nbsp;
{cartItem.type.name} {cartItem.type.name}
</Link>
</div> </div>
<div className='cart-item mt-2 mt-sm-0 d-flex flex-column align-items-center align-items-sm-end'> <div className='cart-item mt-2 mt-sm-0 d-flex flex-column align-items-center align-items-sm-end'>
<div> <div>
@ -50,10 +45,10 @@ const Cart = () => {
{parseFloat(cartItem.price * cartItem.count).toFixed(2)} {parseFloat(cartItem.price * cartItem.count).toFixed(2)}
</div> </div>
<ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter"> <ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter">
<Button variant="primary" onClick={() => addToCart(cartItem)}> <Button style={{backgroundColor: '#5233ff', color: 'aqua;'}} onClick={() => addToCart(cartItem)}>
<PlusLg /> <PlusLg />
</Button> </Button>
<Button variant="danger" onClick={() => removeFromCart(cartItem)}> <Button style={{backgroundColor: '#ff5500'}} onClick={() => removeFromCart(cartItem)}>
<DashLg /> <DashLg />
</Button> </Button>
</ButtonGroup> </ButtonGroup>
@ -61,7 +56,7 @@ const Cart = () => {
</Card.Body> </Card.Body>
</Card>) </Card>)
} }
<div className='mb-2 col-12 col-md-8 col-lg-6 d-flex justify-content-end'> <div className='mb-2 col-12 col-md-8 col-lg-6 d-flex justify-content-end' style={{color: 'white'}}>
<strong>Итого: {getCartSum()} &#8381;</strong> <strong>Итого: {getCartSum()} &#8381;</strong>
</div> </div>
</div> </div>

View File

@ -1,22 +1,22 @@
import { createContext, useEffect, useReducer } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {
createContext,
useEffect,
useReducer,
} from 'react';
import { cartReducer, loadCart, saveCart } from './CartReducer'; import { cartReducer, loadCart, saveCart } from './CartReducer';
// Компонент контекста корзины
const CartContext = createContext(null); const CartContext = createContext(null);
// Провайдер контекста корзины
export const CartProvider = ({ children }) => { export const CartProvider = ({ children }) => {
const [cart, dispatch] = useReducer(cartReducer, [], loadCart); const [cart, dispatch] = useReducer(cartReducer, [], loadCart);
useEffect(() => { useEffect(() => {
saveCart(cart || []); saveCart(cart || []);
}, [cart]); }, [cart]);
const cartContextValue = { cart, dispatch };
return ( return (
<CartContext.Provider value={{ cart, dispatch }}> <CartContext.Provider value={cartContextValue}>
{children} {children}
</CartContext.Provider> </CartContext.Provider>
); );

View File

@ -3,6 +3,7 @@ import CartContext from './CartContext.jsx';
import { cartAdd, cartClear, cartRemove } from './CartReducer'; import { cartAdd, cartClear, cartRemove } from './CartReducer';
const useCart = () => { const useCart = () => {
const { cart, dispatch } = useContext(CartContext); const { cart, dispatch } = useContext(CartContext);
const cartSum = () => { const cartSum = () => {

View File

@ -32,6 +32,7 @@ export const saveCart = (cart) => {
localStorage.setItem(CART_KEY, JSON.stringify(cart)); localStorage.setItem(CART_KEY, JSON.stringify(cart));
}; };
// Функция для загрузки данных корзины из LocalStorage
export const loadCart = (initialValue = []) => { export const loadCart = (initialValue = []) => {
const cartData = localStorage.getItem(CART_KEY); const cartData = localStorage.getItem(CART_KEY);
if (cartData) { if (cartData) {
@ -40,6 +41,7 @@ export const loadCart = (initialValue = []) => {
return initialValue; return initialValue;
}; };
// Редюсер для обработки действий с корзиной
export const cartReducer = (cart, action) => { export const cartReducer = (cart, action) => {
const { item } = action; const { item } = action;
switch (action.type) { switch (action.type) {
@ -50,6 +52,7 @@ export const cartReducer = (cart, action) => {
return removeFromCart(cart, item); return removeFromCart(cart, item);
} }
case CART_CLEAR: { case CART_CLEAR: {
localStorage.removeItem("cart"); // Удаление данных из LocalStorage
return []; return [];
} }
default: { default: {

View File

@ -29,6 +29,9 @@ const LinesItemForm = ({ item, handleChange }) => {
<Input name='price' label='Цена' value={item.price} onChange={handleChange} <Input name='price' label='Цена' value={item.price} onChange={handleChange}
type='number' min='1000.0' step='100' required /> type='number' min='1000.0' step='100' required />
<Input name='count' label='Количество' value={item.count} onChange={handleChange}
type='number' min='0' step='1' required />
<Select values={places} name='placeId' label='Место' value={item.placeId} onChange={handleChange} <Select values={places} name='placeId' label='Место' value={item.placeId} onChange={handleChange}
required /> required />

View File

@ -30,7 +30,6 @@ const useLinesFormModal = (linesChangeHandle) => {
onClose(); onClose();
} }
}; };
console.log("лйанс форм модал итем"+item);
return { return {
isFormModalShow: isModalShow, isFormModalShow: isModalShow,
isFormValidated: validated, isFormValidated: validated,

View File

@ -18,6 +18,7 @@ const useLinesItemForm = (id, linesChangeHandle) => {
const typeId = parseInt(formData.typeId, 10); const typeId = parseInt(formData.typeId, 10);
const date = formData.date; const date = formData.date;
const price = parseFloat(formData.price).toFixed(2); const price = parseFloat(formData.price).toFixed(2);
const count = formData.count;
const placeId = parseInt(formData.placeId, 10); const placeId = parseInt(formData.placeId, 10);
const image = formData.image.startsWith('data:image') ? formData.image : ''; const image = formData.image.startsWith('data:image') ? formData.image : '';
return { return {
@ -25,6 +26,7 @@ const useLinesItemForm = (id, linesChangeHandle) => {
typeId: typeId.toString(), typeId: typeId.toString(),
date: date.toString(), date: date.toString(),
price: price.toString(), price: price.toString(),
count: count.toString(),
placeId: placeId.toString(), placeId: placeId.toString(),
image, image,
}; };

View File

@ -8,6 +8,7 @@ const useLinesItem = (id) => {
typeId: '', typeId: '',
date: '', date: '',
price: '0', price: '0',
count: '0',
placeId: '', placeId: '',
image: '', image: '',
}; };

View File

@ -3,6 +3,8 @@ import { Link } from 'react-router-dom';
import useTypeFilter from '../hooks/LinesFilterHook'; import useTypeFilter from '../hooks/LinesFilterHook';
import useLines from '../hooks/LinesHook'; import useLines from '../hooks/LinesHook';
import usePlaces from '../../types/hooks/PlacesHook.js'; import usePlaces from '../../types/hooks/PlacesHook.js';
import useCart from '../../cart/CartHook.js';
import { Button } from 'react-bootstrap';
import './Catalog.css'; import './Catalog.css';
const Catalog = () => { const Catalog = () => {
@ -10,8 +12,7 @@ const Catalog = () => {
const { types, currentFilter, handleFilterChange } = useTypeFilter(); const { types, currentFilter, handleFilterChange } = useTypeFilter();
const { lines } = useLines(currentFilter, places); const { lines } = useLines(currentFilter, places);
const { addToCart } = useCart();
console.log(lines);
return ( return (
<> <>
@ -42,7 +43,9 @@ const Catalog = () => {
<p>Price: {product.price}</p> <p>Price: {product.price}</p>
<p>Place: {product.place.name}</p> <p>Place: {product.place.name}</p>
<div className="button-overlayAdd"> <div className="button-overlayAdd">
<button className="btn btn-primary" >add to cart</button> <Button variant="primary" className="btn btn-primary" onClick={() => addToCart(product)}>
Добавить товар
</Button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -18,8 +18,6 @@ const Lines = () => {
const { lines, handleLinesChange } = useLines(currentFilter, places); const { lines, handleLinesChange } = useLines(currentFilter, places);
console.log(lines);
const { const {
isDeleteModalShow, isDeleteModalShow,
showDeleteModal, showDeleteModal,
@ -37,7 +35,6 @@ const Lines = () => {
handleFormClose, handleFormClose,
} = useLinesFormModal(handleLinesChange); } = useLinesFormModal(handleLinesChange);
console.log("Лайнс куррент итем"+currentItem);
return ( return (
<> <>
<main className="container-fluid ml-2 mr-2"> <main className="container-fluid ml-2 mr-2">

View File

@ -12,6 +12,7 @@ const LinesTable = ({ children }) => {
<th scope='col' className='w-25'>Тип</th> <th scope='col' className='w-25'>Тип</th>
<th scope='col' className='w-25'>Дата</th> <th scope='col' className='w-25'>Дата</th>
<th scope='col' className='w-25'>Цена</th> <th scope='col' className='w-25'>Цена</th>
<th scope='col' className='w-25'>Количество</th>
<th scope='col' className='w-25'>Место проведения</th> <th scope='col' className='w-25'>Место проведения</th>
<th scope='col'></th> <th scope='col'></th>
<th scope='col'></th> <th scope='col'></th>

View File

@ -16,6 +16,7 @@ const LinesTableRow = ({
<td>{line.type.name}</td> <td>{line.type.name}</td>
<td>{line.date}</td> <td>{line.date}</td>
<td>{parseFloat(line.price).toFixed(2)}</td> <td>{parseFloat(line.price).toFixed(2)}</td>
<td>{line.count}</td>
<td>{line.place.name}</td> <td>{line.place.name}</td>
<td><a href="#" onClick={(event) => handleAnchorClick(event, onEdit)}><PencilFill /></a></td> <td><a href="#" onClick={(event) => handleAnchorClick(event, onEdit)}><PencilFill /></a></td>
<td><a href="#" onClick={(event) => handleAnchorClick(event, onDelete)}><Trash3 /></a></td> <td><a href="#" onClick={(event) => handleAnchorClick(event, onDelete)}><Trash3 /></a></td>