Правки
This commit is contained in:
parent
3a3b1e6bde
commit
8d8129715b
@ -1,25 +0,0 @@
|
|||||||
#banner {
|
|
||||||
margin: 2px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner img {
|
|
||||||
border: 1px solid #3c3c3f;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner img.banner-show {
|
|
||||||
width: 100%;
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 1s, visibility 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
#banner img.banner-hide {
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 1s, visibility 0s 1s;
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import './Banner.css';
|
|
||||||
import useBannerHook from './BannerHook';
|
|
||||||
|
|
||||||
const Banner = () => {
|
|
||||||
const { banners, getBannerClass } = useBannerHook();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id='banner'>
|
|
||||||
{
|
|
||||||
banners.map((banner, index) =>
|
|
||||||
<img key={index} className={getBannerClass(index)} src={banner} alt={`banner${index}`} />)
|
|
||||||
}
|
|
||||||
</div >
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Banner;
|
|
@ -1,36 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import banner1 from '../../assets/banner1.png';
|
|
||||||
import banner2 from '../../assets/banner2.png';
|
|
||||||
import banner3 from '../../assets/banner3.png';
|
|
||||||
|
|
||||||
const useBannerHook = () => {
|
|
||||||
const [currentBanner, setCurrentBanner] = useState(0);
|
|
||||||
const banners = [banner1, banner2, banner3];
|
|
||||||
|
|
||||||
const getBannerClass = (index) => {
|
|
||||||
return currentBanner === index ? 'banner-show' : 'banner-hide';
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const bannerInterval = setInterval(
|
|
||||||
() => {
|
|
||||||
console.info('Banner changed');
|
|
||||||
let current = currentBanner + 1;
|
|
||||||
if (current === banners.length) {
|
|
||||||
current = 0;
|
|
||||||
}
|
|
||||||
setCurrentBanner(current);
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
);
|
|
||||||
return () => clearInterval(bannerInterval);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
banners,
|
|
||||||
getBannerClass,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useBannerHook;
|
|
@ -1,8 +0,0 @@
|
|||||||
.cart-image {
|
|
||||||
width: 3.1rem;
|
|
||||||
padding: .25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import { Button, ButtonGroup, Card } from 'react-bootstrap';
|
|
||||||
import { DashLg, PlusLg, XLg } from 'react-bootstrap-icons';
|
|
||||||
import imgPlaceholder from '../../assets/200.png';
|
|
||||||
import './Cart.css';
|
|
||||||
import useCart from './CartHook';
|
|
||||||
|
|
||||||
const Cart = () => {
|
|
||||||
const {
|
|
||||||
cart,
|
|
||||||
getCartSum,
|
|
||||||
addToCart,
|
|
||||||
removeFromCart,
|
|
||||||
clearCart,
|
|
||||||
} = useCart();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<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'>
|
|
||||||
<strong className='flex-fill'>Корзина</strong>
|
|
||||||
<Button variant='danger' onClick={() => clearCart()}>
|
|
||||||
<XLg /> Очистить
|
|
||||||
</Button>
|
|
||||||
</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'>
|
|
||||||
<img className='cart-image' src={cartItem.image || imgPlaceholder} alt="Cart Image" />
|
|
||||||
{cartItem.type.name}
|
|
||||||
</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>)
|
|
||||||
}
|
|
||||||
<div className='mb-2 col-12 col-md-8 col-lg-6 d-flex justify-content-end'>
|
|
||||||
<strong>Итого: {getCartSum()} ₽</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Cart;
|
|
@ -1,29 +0,0 @@
|
|||||||
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]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CartContext.Provider value={{ cart, dispatch }}>
|
|
||||||
{children}
|
|
||||||
</CartContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CartProvider.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CartContext;
|
|
@ -1,26 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import CartContext from './CartContext.jsx';
|
|
||||||
import { cartAdd, cartClear, cartRemove } from './CartReducer';
|
|
||||||
|
|
||||||
const useCart = () => {
|
|
||||||
const { cart, dispatch } = useContext(CartContext);
|
|
||||||
|
|
||||||
const cartSum = () => {
|
|
||||||
return parseFloat(
|
|
||||||
cart?.reduce((sum, cartItem) => {
|
|
||||||
return sum + (cartItem.price * cartItem.count);
|
|
||||||
}, 0)
|
|
||||||
?? 0,
|
|
||||||
).toFixed(2);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
cart,
|
|
||||||
getCartSum: () => cartSum(),
|
|
||||||
addToCart: (item) => dispatch(cartAdd(item)),
|
|
||||||
removeFromCart: (item) => dispatch(cartRemove(item)),
|
|
||||||
clearCart: () => dispatch(cartClear()),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useCart;
|
|
@ -1,71 +0,0 @@
|
|||||||
const setCartCount = (cart, item, value) => {
|
|
||||||
return cart.map((cartItem) => {
|
|
||||||
if (cartItem.id === item.id) {
|
|
||||||
return { ...cartItem, count: cartItem.count + value };
|
|
||||||
}
|
|
||||||
return cartItem;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const addToCart = (cart, item) => {
|
|
||||||
const existsItem = cart.find((cartItem) => cartItem.id === item.id);
|
|
||||||
if (existsItem !== undefined) {
|
|
||||||
return setCartCount(cart, item, 1);
|
|
||||||
}
|
|
||||||
return [...cart, { ...item, count: 1 }];
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeFromCart = (cart, item) => {
|
|
||||||
const existsItem = cart.find((cartItem) => cartItem.id === item.id);
|
|
||||||
if (existsItem !== undefined && existsItem.count > 1) {
|
|
||||||
return setCartCount(cart, item, -1);
|
|
||||||
}
|
|
||||||
return cart.filter((cartItem) => cartItem.id !== item.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const CART_KEY = 'localCart';
|
|
||||||
const CART_ADD = 'cart/add';
|
|
||||||
const CART_REMOVE = 'cart/remove';
|
|
||||||
const CART_CLEAR = 'cart/clear';
|
|
||||||
|
|
||||||
export const saveCart = (cart) => {
|
|
||||||
localStorage.setItem(CART_KEY, JSON.stringify(cart));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const loadCart = (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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const cartAdd = (item) => ({
|
|
||||||
type: CART_ADD, item,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cartRemove = (item) => ({
|
|
||||||
type: CART_REMOVE, item,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cartClear = () => ({
|
|
||||||
type: CART_CLEAR,
|
|
||||||
});
|
|
@ -1,29 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Form } from 'react-bootstrap';
|
|
||||||
|
|
||||||
const Select = ({
|
|
||||||
values, name, label, value, onChange, className, ...rest
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Form.Group className={`mb-2 ${className || ''}`} controlId={name}>
|
|
||||||
<Form.Label className='form-label'>{label}</Form.Label>
|
|
||||||
<Form.Select name={name || ''} value={value || ''} onChange={onChange} {...rest}>
|
|
||||||
<option value=''>Выберите значение</option>
|
|
||||||
{
|
|
||||||
values.map((type) => <option key={type.id} value={type.id}>{type.name}</option>)
|
|
||||||
}
|
|
||||||
</Form.Select>
|
|
||||||
</Form.Group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Select.propTypes = {
|
|
||||||
values: PropTypes.array,
|
|
||||||
name: PropTypes.string,
|
|
||||||
label: PropTypes.string,
|
|
||||||
value: PropTypes.string,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Select;
|
|
Loading…
Reference in New Issue
Block a user