From f1d9a308f61e67f4c896608e73ac8413f61fa8af Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 11 Oct 2023 10:22:11 +0700 Subject: Add breadcrumb on detail product, search, brand, category page --- src/lib/brand/components/Brand.jsx | 4 +- src/lib/brand/components/Breadcrumb.jsx | 40 ++++++++++++ src/lib/category/components/Breadcrumb.jsx | 56 +++++++++++++++++ src/lib/category/components/Category.jsx | 2 +- src/lib/product/components/Product/Breadcrumb.jsx | 69 +++++++++++++++++++++ src/lib/product/components/Product/Product.jsx | 38 +++++------- .../product/components/Product/ProductDesktop.jsx | 71 +++++++++++----------- .../product/components/Product/ProductMobile.jsx | 2 + src/lib/product/components/ProductSearch.jsx | 4 +- .../promotinProgram/components/PromotionType.jsx | 2 +- src/pages/shop/brands/[slug].jsx | 3 + src/pages/shop/cart.jsx | 15 +++++ src/pages/shop/category/[slug].jsx | 4 ++ src/pages/shop/search.jsx | 20 ++++++ 14 files changed, 267 insertions(+), 63 deletions(-) create mode 100644 src/lib/brand/components/Breadcrumb.jsx create mode 100644 src/lib/category/components/Breadcrumb.jsx create mode 100644 src/lib/product/components/Product/Breadcrumb.jsx (limited to 'src') diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx index 3c411969..3985b888 100644 --- a/src/lib/brand/components/Brand.jsx +++ b/src/lib/brand/components/Brand.jsx @@ -84,7 +84,7 @@ const Brand = ({ id }) => { -
+
{brand.isLoading && } {brand.data?.banners?.length == 0 && ( @@ -117,6 +117,7 @@ const Brand = ({ id }) => { ))} +
Produk dari brand:
{brand?.data?.logo && ( @@ -137,7 +138,6 @@ const Brand = ({ id }) => { )}
-
diff --git a/src/lib/brand/components/Breadcrumb.jsx b/src/lib/brand/components/Breadcrumb.jsx new file mode 100644 index 00000000..0fec2dad --- /dev/null +++ b/src/lib/brand/components/Breadcrumb.jsx @@ -0,0 +1,40 @@ +import { Breadcrumb as ChakraBreadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' + +/** + * Renders a breadcrumb component with links to navigate through different pages. + * + * @param {Object} props - The props object containing the brand name. + * @param {string} props.brandName - The name of the brand to display in the breadcrumb. + * @return {JSX.Element} The rendered breadcrumb component. + */ +const Breadcrumb = ({ brandName }) => { + return ( +
+ + + + Home + + + + + + Brands + + + + + {brandName} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/lib/category/components/Breadcrumb.jsx b/src/lib/category/components/Breadcrumb.jsx new file mode 100644 index 00000000..127904ee --- /dev/null +++ b/src/lib/category/components/Breadcrumb.jsx @@ -0,0 +1,56 @@ +import odooApi from '@/core/api/odooApi' +import { createSlug } from '@/core/utils/slug' +import { + Breadcrumb as ChakraBreadcrumb, + BreadcrumbItem, + BreadcrumbLink, + Skeleton +} from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' +import { useQuery } from 'react-query' + +/** + * Render a breadcrumb component. + * + * @param {object} categoryId - The ID of the category. + * @return {JSX.Element} The breadcrumb component. + */ +const Breadcrumb = ({ categoryId }) => { + const breadcrumbs = useQuery( + `category-breadcrumbs/${categoryId}`, + async () => await odooApi('GET', `/api/v1/category/${categoryId}/category-breadcrumb`) + ) + + return ( +
+ + + + + Home + + + + {breadcrumbs.data?.map((category, index) => ( + + {index === breadcrumbs.data.length - 1 ? ( + {category.name} + ) : ( + + {category.name} + + )} + + ))} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx index af696d42..e6ea5acf 100644 --- a/src/lib/category/components/Category.jsx +++ b/src/lib/category/components/Category.jsx @@ -30,7 +30,7 @@ const Category = () => { return (
- {categories.map((category) => ( + {categories?.map((category) => (
{ + const categories = useQuery( + `detail/categories/${productId}`, + async () => await odooApi('GET', `/api/v1/product/${productId}/category-breadcrumb`), + { + enabled: !!productId + } + ) + + return ( + + + + + Home + + + + {categories.data?.map((category) => ( + + + {category.name} + + + ))} + + + {productName} + + + + ) +} + +export default Breadcrumb diff --git a/src/lib/product/components/Product/Product.jsx b/src/lib/product/components/Product/Product.jsx index 54490c26..6e983c2e 100644 --- a/src/lib/product/components/Product/Product.jsx +++ b/src/lib/product/components/Product/Product.jsx @@ -36,29 +36,21 @@ const Product = ({ product, isVariant = false }) => { } }, [product, isVariant]) - if (isVariant == true) { - return ( - <> - - - - ) - } else { - return ( - <> - - - - ) - } + return isVariant == true ? ( + <> + + + + ) : ( + <> + + + + ) } export default Product diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 47e98c1a..ceb0cad7 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -24,6 +24,7 @@ import ColumnsSLA from './ColumnsSLA' import { useProductCartContext } from '@/contexts/ProductCartContext' import { Box, Skeleton, Tooltip } from '@chakra-ui/react' import { Info } from 'lucide-react' +import Breadcrumb from './Breadcrumb' const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const router = useRouter() @@ -199,47 +200,49 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { return (
+
- {product?.flashSale?.remainingTime > 0 && lowestPrice?.price.discountPercentage > 0 && ( -
-
- -
-
-
-
- - {Math.floor(product.lowestPrice.discountPercentage)}% - -
-
- - - {product?.flashSale?.tag != 'false' || product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - -
-
- + {product?.flashSale?.remainingTime > 0 && + lowestPrice?.price.discountPercentage > 0 && ( +
+
+ +
+
+
+
+ + {Math.floor(product.lowestPrice.discountPercentage)}% + +
+
+ + + {product?.flashSale?.tag != 'false' || product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + +
+
+ +
-
- )} + )} {product.name} { const router = useRouter() @@ -160,6 +161,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return ( +
{product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && (
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index df9aa91b..f6987051 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -117,7 +117,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { <> {productSearch.isLoading && } -
+

Produk

@@ -178,7 +178,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { -
+
{ const programs = await getPromotionProgram({ id }) - if (programs.length > 0) { + if (programs?.length > 0) { setPromotionList(programs) setActiveTitle(programs?.[0].type.value) } diff --git a/src/pages/shop/brands/[slug].jsx b/src/pages/shop/brands/[slug].jsx index 88f19bc0..d75475b7 100644 --- a/src/pages/shop/brands/[slug].jsx +++ b/src/pages/shop/brands/[slug].jsx @@ -3,6 +3,7 @@ import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' import { useRouter } from 'next/router' import _ from 'lodash' import Seo from '@/core/components/Seo' +import Breadcrumb from '@/lib/brand/components/Breadcrumb' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -26,6 +27,8 @@ export default function BrandDetail() { ]} /> + + {!_.isEmpty(router.query) && ( import('@/core/components/layouts/AppLayout')) const CartComponent = dynamic(() => import('@/lib/cart/components/Cart')) @@ -22,6 +24,19 @@ export default function Cart() { +
+ + + + Home + + + + + Keranjang + + +
diff --git a/src/pages/shop/category/[slug].jsx b/src/pages/shop/category/[slug].jsx index dbc17c06..e3650235 100644 --- a/src/pages/shop/category/[slug].jsx +++ b/src/pages/shop/category/[slug].jsx @@ -3,6 +3,7 @@ import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' import { useRouter } from 'next/router' import _ from 'lodash' import Seo from '@/core/components/Seo' +import Breadcrumb from '@/lib/category/components/Breadcrumb' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -16,6 +17,7 @@ export default function CategoryDetail() { const query = { fq: `manufacture_id_i:${categoryId}` } + return ( + + {!_.isEmpty(router.query) && ( )} diff --git a/src/pages/shop/search.jsx b/src/pages/shop/search.jsx index 907465b7..db3b449a 100644 --- a/src/pages/shop/search.jsx +++ b/src/pages/shop/search.jsx @@ -2,6 +2,8 @@ import dynamic from 'next/dynamic' import { useRouter } from 'next/router' import _ from 'lodash-contrib' import Seo from '@/core/components/Seo' +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -13,6 +15,24 @@ export default function Search() { +
+ {router.query?.q && ( + + + + Home + + + + + + Cari: {router.query.q || ''} + + + + )} +
+ {!_.isEmpty(router.query) && }
) -- cgit v1.2.3 From cff358b2a7bb310e2b65cba5d843e9ffdda0f699 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 11 Oct 2023 14:07:58 +0700 Subject: Fix description and brand banner skeleton --- src/lib/brand/components/Brand.jsx | 121 ++++++++++++--------- .../product/components/Product/ProductDesktop.jsx | 2 +- src/pages/shop/product/[slug].jsx | 7 +- 3 files changed, 69 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx index 3985b888..4afbcb3e 100644 --- a/src/lib/brand/components/Brand.jsx +++ b/src/lib/brand/components/Brand.jsx @@ -6,10 +6,10 @@ import { Pagination, Autoplay } from 'swiper' import 'swiper/css' import 'swiper/css/pagination' import 'swiper/css/autoplay' -import Divider from '@/core/components/elements/Divider/Divider' -import ImageSkeleton from '@/core/components/elements/Skeleton/ImageSkeleton' import MobileView from '@/core/components/views/MobileView' import DesktopView from '@/core/components/views/DesktopView' +import { Skeleton } from '@chakra-ui/react' +import classNames from 'classnames' const swiperBanner = { pagination: { dynamicBullets: true }, @@ -28,65 +28,77 @@ const Brand = ({ id }) => { <>
- {brand.isLoading && } - {brand.data?.banners?.length == 0 && ( - Brand - Indoteknik - )} - {brand.data && ( - <> - - {brand.data?.banners?.map((banner, index) => ( - + + {brand.data?.banners?.length == 0 && ( + Brand - Indoteknik + )} + + {brand.data && ( + <> + + {brand.data?.banners?.map((banner, index) => ( + + {`Brand + + ))} + +
+
Produk dari brand:
+ {brand?.data?.logo && ( {`Brand - - ))} - -
-
Produk dari brand:
- {brand?.data?.logo && ( - {brand?.data?.name} - )} - {!brand?.data?.logo && ( -
- {brand?.data?.name} -
- )} -
- - )} + )} + {!brand?.data?.logo && ( +
+ {brand?.data?.name} +
+ )} +
+ + )} +
-
-
- {brand.isLoading && } + {brand.data?.banners?.length == 0 && ( { className='w-full h-auto' /> )} + {brand.data && ( <> {
)} -
+
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index ceb0cad7..855c9f75 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -393,7 +393,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { ))}
-
+
]+)>)/gi - const regexHtmlTagsExceptP = /<\/?(?!p\b)[^>]*>/g - product.description = product.description - .replace(regexHtmlTagsExceptP, ' ') - .replace(regexHtmlTags, ' ') - .trim() } else { product = null } @@ -45,6 +39,7 @@ export async function getServerSideProps(context) { } export default function ProductDetail({ product }) { + console.log(product); const router = useRouter() const { setProduct } = useProductContext() -- cgit v1.2.3 From 80295b97150495f56bd236a5345c2ddeb8313267 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 11 Oct 2023 16:51:03 +0700 Subject: Add product weight information and total weight on checkout page --- .../elements/Product/cartProductsList.jsx | 5 +- src/lib/checkout/components/Checkout.jsx | 79 +++++++++++++++------- src/lib/variant/components/VariantCard.jsx | 2 +- 3 files changed, 57 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Product/cartProductsList.jsx b/src/core/components/elements/Product/cartProductsList.jsx index 32df992b..9662cd3b 100644 --- a/src/core/components/elements/Product/cartProductsList.jsx +++ b/src/core/components/elements/Product/cartProductsList.jsx @@ -15,7 +15,6 @@ const CardProdcuctsList = ({ updateQuantity = () => {}, setDeleteConfirmation = () => {} }) => { - return ( @@ -144,7 +143,9 @@ const CardProdcuctsList = ({ {product?.code}{' '} {product?.attributes.length > 0 ? `| ${product?.attributes.join(', ')}` : ''} -
Berat item : {product?.weight} Kg
+
+ Berat item : {product?.weight} Kg x {product?.quantity} Barang +
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index e2c1a85b..35236e79 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -33,6 +33,8 @@ import { useQuery } from 'react-query' import { gtagPurchase } from '@/core/utils/googleTag' import { findVoucher, getVoucher } from '../api/getVoucher' import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList' +import { Spinner } from '@chakra-ui/react' +import { AnimatePresence, motion } from 'framer-motion' const SELF_PICKUP_ID = 32 @@ -110,6 +112,7 @@ const Checkout = () => { const [buttonTerapkan, SetButtonTerapkan] = useState(false) const [checkoutValidation, setCheckoutValidation] = useState(false) const [loadingVoucher, setLoadingVoucher] = useState(true) + const [loadingRajaOngkir, setLoadingRajaOngkir] = useState(false) const expedisiValidation = useRef(null) @@ -211,6 +214,7 @@ const Checkout = () => { useEffect(() => { setCheckoutValidation(false) const loadServiceRajaOngkir = async () => { + setLoadingRajaOngkir(true) const body = { origin: 2127, destination: selectedAddress.shipping.rajaongkirCityId, @@ -221,6 +225,7 @@ const Checkout = () => { } setBiayaKirim(0) const dataService = await axios('/api/rajaongkir-service?body=' + JSON.stringify(body)) + setLoadingRajaOngkir(false) setListServiceExpedisi(dataService.data[0].costs) if (dataService.data[0].costs[0]) { setBiayaKirim(dataService.data[0].costs[0]?.cost[0].value) @@ -259,9 +264,8 @@ const Checkout = () => { useEffect(() => { if (selectedExpedisi) { let serviceType = selectedExpedisi.split(',') - if (serviceType[0] === 0) { - setSelectedExpedisi(0) - } + if (serviceType[0] === 0) return + setselectedCarrier(serviceType[0]) setselectedCarrierId(serviceType[1]) setListServiceExpedisi([]) @@ -723,6 +727,7 @@ const Checkout = () => { checkWeigth={checkWeigth} checkoutValidation={checkoutValidation} expedisiValidation={expedisiValidation} + loadingRajaOngkir={loadingRajaOngkir} /> { checkWeigth={checkWeigth} checkoutValidation={checkoutValidation} expedisiValidation={expedisiValidation} + loadingRajaOngkir={loadingRajaOngkir} /> {
Detail Pesanan
- + {/* @@ -1158,7 +1164,9 @@ const Checkout = () => {
Ringkasan Pesanan
-
{products?.length} Barang
+
+ {products?.length} Barang - {cartCheckout?.totalWeight.kg} Kg +

@@ -1403,32 +1411,51 @@ const SectionExpedisi = ({ setSelectedExpedisi, checkWeigth, checkoutValidation, - expedisiValidation + expedisiValidation, + loadingRajaOngkir }) => address?.rajaongkirCityId > 0 && (
-
Pilih Expedisi :
+
Pilih Ekspedisi:
- setSelectedExpedisi(e.target.value)} + required + > + + + {checkWeigth != true && + listExpedisi.map((expedisi) => ( + + ))} + + + + {loadingRajaOngkir && ( + - {' '} - {expedisi.label.toUpperCase()}{' '} - - ))} - + + + )} + +
{checkoutValidation && ( *silahkan pilih expedisi )} @@ -1459,7 +1486,7 @@ const SectionListService = ({ listserviceExpedisi, setSelectedServiceType }) => <>
-
Service Type Expedisi :
+
Tipe Layanan Ekspedisi: