lab5+cart
This commit is contained in:
parent
ea59a679a7
commit
3e10eea21d
82
data2.json
82
data2.json
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -6,3 +6,13 @@
|
||||
.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;
|
||||
}
|
@ -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}
|
||||
||
|
||||
{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()} ₽</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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;
|
@ -3,6 +3,7 @@ import CartContext from './CartContext.jsx';
|
||||
import { cartAdd, cartClear, cartRemove } from './CartReducer';
|
||||
|
||||
const useCart = () => {
|
||||
|
||||
const { cart, dispatch } = useContext(CartContext);
|
||||
|
||||
const cartSum = () => {
|
||||
|
@ -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) => ({
|
||||
|
@ -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 />
|
||||
|
||||
|
@ -30,7 +30,6 @@ const useLinesFormModal = (linesChangeHandle) => {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
console.log("лйанс форм модал итем"+item);
|
||||
return {
|
||||
isFormModalShow: isModalShow,
|
||||
isFormValidated: validated,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ const useLinesItem = (id) => {
|
||||
typeId: '',
|
||||
date: '',
|
||||
price: '0',
|
||||
count: '0',
|
||||
placeId: '',
|
||||
image: '',
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user