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 Footer from './components/footer/Footer.jsx';
import Navigation from './components/navigation/Navigation.jsx';
import { CartProvider } from './components/cart/CartContext.jsx';
export const App = ({ routes }) => {
return (
<>
<CartProvider>
<Navigation routes={routes}></Navigation>
<main className='w-100 flex-fill d-flex justify-content-center p-0 m-0'>
<Outlet />
</main>
<Footer />
</CartProvider>
</>
);
};

View File

@ -5,4 +5,14 @@
.cart-item {
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 { DashLg, PlusLg, XLg } from 'react-bootstrap-icons';
import { Link } from 'react-router-dom';
import './Cart.css';
import useCart from './CartHook';
import Select from '../../input/Select.jsx';
import useTypeFilter from '../hooks/LinesFilterHook';
const Cart = () => {
const { types, currentFilter, handleFilterChange } = useTypeFilter();
const {
cart,
getCartSum,
@ -17,51 +15,48 @@ const Cart = () => {
return (
<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='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>
<Button variant='danger' onClick={() => clearCart()}>
<XLg /> Очистить
</Button>
<div className='button-overlayAdd'>
<Button onClick={() => clearCart()}>
<XLg /> Очистить
</Button>
</div>
</div>
{
cart.map((cartItem) =>
<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'>
<div className='cart-item flex-fill'>
cart.map((cartItem) =>
<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'>
<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" />
{cartItem.ItName}
&nbsp;&nbsp;||&nbsp;&nbsp;
{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 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>
<ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter">
<Button variant="primary" onClick={() => addToCart(cartItem)}>
<PlusLg />
</Button>
<Button variant="danger" onClick={() => removeFromCart(cartItem)}>
<DashLg />
</Button>
</ButtonGroup>
</div>
</Card.Body>
</Card>)
<ButtonGroup className='mt-2 mt-sm-1' aria-label="Cart counter">
<Button style={{backgroundColor: '#5233ff', color: 'aqua;'}} onClick={() => addToCart(cartItem)}>
<PlusLg />
</Button>
<Button style={{backgroundColor: '#ff5500'}} 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>
</div>
</div>

View File

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

View File

@ -32,30 +32,33 @@ export const saveCart = (cart) => {
localStorage.setItem(CART_KEY, JSON.stringify(cart));
};
// Функция для загрузки данных корзины из LocalStorage
export const loadCart = (initialValue = []) => {
const cartData = localStorage.getItem(CART_KEY);
if (cartData) {
return JSON.parse(cartData);
}
return initialValue;
const cartData = localStorage.getItem(CART_KEY);
if (cartData) {
return JSON.parse(cartData);
}
return initialValue;
};
// Редюсер для обработки действий с корзиной
export const cartReducer = (cart, action) => {
const { item } = action;
switch (action.type) {
case CART_ADD: {
return addToCart(cart, item);
}
case CART_REMOVE: {
return removeFromCart(cart, item);
}
case CART_CLEAR: {
return [];
}
default: {
throw Error(`Unknown action: ${action.type}`);
}
const { item } = action;
switch (action.type) {
case CART_ADD: {
return addToCart(cart, item);
}
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) => ({

View File

@ -29,6 +29,9 @@ const LinesItemForm = ({ item, handleChange }) => {
<Input name='price' label='Цена' value={item.price} onChange={handleChange}
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}
required />

View File

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

View File

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

View File

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

View File

@ -3,6 +3,8 @@ import { Link } from 'react-router-dom';
import useTypeFilter from '../hooks/LinesFilterHook';
import useLines from '../hooks/LinesHook';
import usePlaces from '../../types/hooks/PlacesHook.js';
import useCart from '../../cart/CartHook.js';
import { Button } from 'react-bootstrap';
import './Catalog.css';
const Catalog = () => {
@ -10,8 +12,7 @@ const Catalog = () => {
const { types, currentFilter, handleFilterChange } = useTypeFilter();
const { lines } = useLines(currentFilter, places);
console.log(lines);
const { addToCart } = useCart();
return (
<>
@ -42,7 +43,9 @@ const Catalog = () => {
<p>Price: {product.price}</p>
<p>Place: {product.place.name}</p>
<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>
@ -54,4 +57,4 @@ const Catalog = () => {
);
};
export default Catalog;
export default Catalog;

View File

@ -18,8 +18,6 @@ const Lines = () => {
const { lines, handleLinesChange } = useLines(currentFilter, places);
console.log(lines);
const {
isDeleteModalShow,
showDeleteModal,
@ -37,7 +35,6 @@ const Lines = () => {
handleFormClose,
} = useLinesFormModal(handleLinesChange);
console.log("Лайнс куррент итем"+currentItem);
return (
<>
<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'></th>
<th scope='col'></th>

View File

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