1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-03 14:24:23 +01:00

(feat) add product to cart in product page

This commit is contained in:
Du Peng 2022-09-08 16:27:34 +02:00
parent 8d414a3172
commit aeae5f7aa0
6 changed files with 37 additions and 22 deletions

View File

@ -28,7 +28,9 @@ const CartButton: React.FC = () => {
return ( return (
<div className="cart-button" onClick={showCart}> <div className="cart-button" onClick={showCart}>
<i className="fas fa-cart-arrow-down" /> <i className="fas fa-cart-arrow-down" />
<span>{cart?.order_items_attributes?.length}</span> {cart && cart.order_items_attributes.length > 0 &&
<span>{cart.order_items_attributes.length}</span>
}
<p>{t('app.public.cart_button.my_cart')}</p> <p>{t('app.public.cart_button.my_cart')}</p>
</div> </div>
); );

View File

@ -11,13 +11,14 @@ import noImage from '../../../../images/no_image.png';
interface StoreProductItemProps { interface StoreProductItemProps {
product: Product, product: Product,
cart: Order, cart: Order,
onSuccessAddProductToCart: (cart: Order) => void onSuccessAddProductToCart: (cart: Order) => void,
onError: (message: string) => void
} }
/** /**
* This component shows a product item in store * This component shows a product item in store
*/ */
export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, cart, onSuccessAddProductToCart }) => { export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, cart, onSuccessAddProductToCart, onError }) => {
const { t } = useTranslation('public'); const { t } = useTranslation('public');
/** /**
@ -37,7 +38,7 @@ export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, car
const addProductToCart = (e: React.BaseSyntheticEvent) => { const addProductToCart = (e: React.BaseSyntheticEvent) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
CartAPI.addItem(cart, product.id, 1).then(onSuccessAddProductToCart); CartAPI.addItem(cart, product.id, 1).then(onSuccessAddProductToCart).catch(onError);
}; };
/** /**

View File

@ -7,24 +7,30 @@ import { Loader } from '../base/loader';
import { IApplication } from '../../models/application'; import { IApplication } from '../../models/application';
import _ from 'lodash'; import _ from 'lodash';
import { Product } from '../../models/product'; import { Product } from '../../models/product';
import { User } from '../../models/user';
import ProductAPI from '../../api/product'; import ProductAPI from '../../api/product';
import CartAPI from '../../api/cart';
import noImage from '../../../../images/no_image.png'; import noImage from '../../../../images/no_image.png';
import { FabButton } from '../base/fab-button'; import { FabButton } from '../base/fab-button';
import useCart from '../../hooks/use-cart';
import { FilePdf, Minus, Plus } from 'phosphor-react'; import { FilePdf, Minus, Plus } from 'phosphor-react';
declare const Application: IApplication; declare const Application: IApplication;
interface StoreProductProps { interface StoreProductProps {
productSlug: string, productSlug: string,
onSuccess: (message: string) => void,
onError: (message: string) => void, onError: (message: string) => void,
currentUser?: User
} }
/** /**
* This component shows a product * This component shows a product
*/ */
export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError }) => { export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, currentUser, onSuccess, onError }) => {
const { t } = useTranslation('public'); const { t } = useTranslation('public');
const { cart, setCart } = useCart(currentUser);
const [product, setProduct] = useState<Product>(); const [product, setProduct] = useState<Product>();
const [showImage, setShowImage] = useState<number>(null); const [showImage, setShowImage] = useState<number>(null);
const [toCartCount, setToCartCount] = useState<number>(0); const [toCartCount, setToCartCount] = useState<number>(0);
@ -36,11 +42,13 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
ProductAPI.get(productSlug).then(data => { ProductAPI.get(productSlug).then(data => {
setProduct(data); setProduct(data);
const productImage = _.find(data.product_images_attributes, { is_main: true }); const productImage = _.find(data.product_images_attributes, { is_main: true });
if (productImage) {
setShowImage(productImage.id); setShowImage(productImage.id);
}
setToCartCount(data.quantity_min ? data.quantity_min : 1); setToCartCount(data.quantity_min ? data.quantity_min : 1);
setDisplayToggle(descContainer.current.offsetHeight < descContainer.current.scrollHeight); setDisplayToggle(descContainer.current.offsetHeight < descContainer.current.scrollHeight);
}).catch(() => { }).catch((e) => {
onError(t('app.public.store_product.unexpected_error_occurred')); onError(t('app.public.store_product.unexpected_error_occurred') + e);
}); });
}, []); }, []);
@ -107,7 +115,10 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
* Add product to cart * Add product to cart
*/ */
const addToCart = () => { const addToCart = () => {
console.log('Add', toCartCount, 'to cart'); CartAPI.addItem(cart, product.id, toCartCount).then(data => {
setCart(data);
onSuccess(t('app.public.store.add_to_cart_success'));
}).catch(onError);
}; };
if (product) { if (product) {
@ -187,12 +198,12 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
return null; return null;
}; };
const StoreProductWrapper: React.FC<StoreProductProps> = ({ productSlug, onError }) => { const StoreProductWrapper: React.FC<StoreProductProps> = (props) => {
return ( return (
<Loader> <Loader>
<StoreProduct productSlug={productSlug} onError={onError} /> <StoreProduct {...props} />
</Loader> </Loader>
); );
}; };
Application.Components.component('storeProduct', react2angular(StoreProductWrapper, ['productSlug', 'onError'])); Application.Components.component('storeProduct', react2angular(StoreProductWrapper, ['productSlug', 'currentUser', 'onSuccess', 'onError']));

View File

@ -11,7 +11,6 @@ import ProductCategoryAPI from '../../api/product-category';
import MachineAPI from '../../api/machine'; import MachineAPI from '../../api/machine';
import { StoreProductItem } from './store-product-item'; import { StoreProductItem } from './store-product-item';
import useCart from '../../hooks/use-cart'; import useCart from '../../hooks/use-cart';
import { emitCustomEvent } from 'react-custom-events';
import { User } from '../../models/user'; import { User } from '../../models/user';
import { Order } from '../../models/order'; import { Order } from '../../models/order';
import { AccordionItem } from './accordion-item'; import { AccordionItem } from './accordion-item';
@ -67,10 +66,6 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
}); });
}, []); }, []);
useEffect(() => {
emitCustomEvent('CartUpdate', cart);
}, [cart]);
/** /**
* Create categories tree (parent/children) * Create categories tree (parent/children)
*/ */
@ -234,7 +229,7 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
/> />
<div className="products-grid"> <div className="products-grid">
{products.map((product) => ( {products.map((product) => (
<StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={addToCart} /> <StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={addToCart} onError={onError} />
))} ))}
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { emitCustomEvent } from 'react-custom-events';
import { Order } from '../models/order'; import { Order } from '../models/order';
import CartAPI from '../api/cart'; import CartAPI from '../api/cart';
import { getCartToken, setCartToken } from '../lib/cart-token'; import { getCartToken, setCartToken } from '../lib/cart-token';
@ -13,7 +14,7 @@ export default function useCart (user?: User) {
async function createCart () { async function createCart () {
const currentCartToken = getCartToken(); const currentCartToken = getCartToken();
const data = await CartAPI.create(currentCartToken); const data = await CartAPI.create(currentCartToken);
setCart(data); _setCart(data);
setLoading(false); setLoading(false);
setCartToken(data.token); setCartToken(data.token);
} }
@ -30,7 +31,7 @@ export default function useCart (user?: User) {
setLoading(true); setLoading(true);
const currentCartToken = getCartToken(); const currentCartToken = getCartToken();
const data = await CartAPI.create(currentCartToken); const data = await CartAPI.create(currentCartToken);
setCart(data); _setCart(data);
setLoading(false); setLoading(false);
}; };
@ -40,5 +41,10 @@ export default function useCart (user?: User) {
} }
}, [user]); }, [user]);
return { loading, cart, error, setCart, reloadCart }; const _setCart = (data: Order) => {
setCart(data);
emitCustomEvent('CartUpdate', data);
};
return { loading, cart, error, setCart: _setCart, reloadCart };
} }

View File

@ -13,5 +13,5 @@
</div> </div>
<section class="m-lg"> <section class="m-lg">
<store-product product-slug="productSlug" on-error="onError" on-success="onSuccess" /> <store-product product-slug="productSlug" current-user="currentUser" on-error="onError" on-success="onSuccess" />
</section> </section>