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 { 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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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}
|
||||||
|
||
|
||||||
{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()} ₽</strong>
|
<strong>Итого: {getCartSum()} ₽</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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;
|
@ -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 = () => {
|
||||||
|
@ -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) => ({
|
||||||
|
@ -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 />
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ const useLinesFormModal = (linesChangeHandle) => {
|
|||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log("лйанс форм модал итем"+item);
|
|
||||||
return {
|
return {
|
||||||
isFormModalShow: isModalShow,
|
isFormModalShow: isModalShow,
|
||||||
isFormValidated: validated,
|
isFormValidated: validated,
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@ const useLinesItem = (id) => {
|
|||||||
typeId: '',
|
typeId: '',
|
||||||
date: '',
|
date: '',
|
||||||
price: '0',
|
price: '0',
|
||||||
|
count: '0',
|
||||||
placeId: '',
|
placeId: '',
|
||||||
image: '',
|
image: '',
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user