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,51 +15,48 @@ 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'>
<XLg /> Очистить <Button onClick={() => clearCart()}>
</Button> <XLg /> Очистить
</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 className='cart-item mt-2 mt-sm-0 d-flex flex-column align-items-center align-items-sm-end'>
<div>
{cartItem.price}
{' * '}
{cartItem.count}
{' = '}
{parseFloat(cartItem.price * cartItem.count).toFixed(2)}
</div> </div>
<div className='cart-item mt-2 mt-sm-0 d-flex flex-column align-items-center align-items-sm-end'> <ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter">
<div> <Button style={{backgroundColor: '#5233ff', color: 'aqua;'}} onClick={() => addToCart(cartItem)}>
{cartItem.price} <PlusLg />
{' * '} </Button>
{cartItem.count} <Button style={{backgroundColor: '#ff5500'}} onClick={() => removeFromCart(cartItem)}>
{' = '} <DashLg />
{parseFloat(cartItem.price * cartItem.count).toFixed(2)} </Button>
</div> </ButtonGroup>
<ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter"> </div>
<Button variant="primary" onClick={() => addToCart(cartItem)}> </Card.Body>
<PlusLg /> </Card>)
</Button>
<Button variant="danger" onClick={() => removeFromCart(cartItem)}>
<DashLg />
</Button>
</ButtonGroup>
</div>
</Card.Body>
</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,29 +1,29 @@
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);
useEffect(() => { const [cart, dispatch] = useReducer(cartReducer, [], loadCart);
saveCart(cart || []);
}, [cart]);
return ( useEffect(() => {
<CartContext.Provider value={{ cart, dispatch }}> saveCart(cart || []);
{children} }, [cart]);
</CartContext.Provider>
); const cartContextValue = { cart, dispatch };
return (
<CartContext.Provider value={cartContextValue}>
{children}
</CartContext.Provider>
);
}; };
CartProvider.propTypes = { CartProvider.propTypes = {
children: PropTypes.node, children: PropTypes.node,
}; };
export default CartContext; export default CartContext;

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,30 +32,33 @@ 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) {
return JSON.parse(cartData); return JSON.parse(cartData);
} }
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) {
case CART_ADD: { case CART_ADD: {
return addToCart(cart, item); return addToCart(cart, item);
}
case CART_REMOVE: {
return removeFromCart(cart, item);
}
case CART_CLEAR: {
return [];
}
default: {
throw Error(`Unknown action: ${action.type}`);
}
} }
case CART_REMOVE: {
return removeFromCart(cart, item);
}
case CART_CLEAR: {
localStorage.removeItem("cart"); // Удаление данных из LocalStorage
return [];
}
default: {
throw Error(`Unknown action: ${action.type}`);
}
}
}; };
export const cartAdd = (item) => ({ export const cartAdd = (item) => ({

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>