summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-02-03 17:03:45 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-02-03 17:03:45 +0700
commitcd01ba82733062db99075ad7690bdb52fb85745a (patch)
treedf86ed690452945463abc77263ac058d5b7f9823
parent87af032177192ed1d5d7c68cab911ed102e647bc (diff)
no message
-rw-r--r--src/components/products/ProductCategories.js56
-rw-r--r--src/components/products/ProductSimilar.js25
-rw-r--r--src/components/variants/VariantCard.js43
-rw-r--r--src/pages/index.js50
-rw-r--r--src/pages/my/invoice/[id].js5
-rw-r--r--src/pages/my/invoices.js2
-rw-r--r--src/pages/my/transaction/[id].js1
-rw-r--r--src/pages/shop/checkout.js2
-rw-r--r--src/pages/shop/product/[slug].js21
-rw-r--r--src/pages/shop/quotation/index.js34
10 files changed, 154 insertions, 85 deletions
diff --git a/src/components/products/ProductCategories.js b/src/components/products/ProductCategories.js
new file mode 100644
index 00000000..dc1325b7
--- /dev/null
+++ b/src/components/products/ProductCategories.js
@@ -0,0 +1,56 @@
+import { useEffect, useState } from "react";
+import ProductSlider from "./ProductSlider";
+import apiOdoo from "@/core/utils/apiOdoo";
+import { LazyLoadComponent } from "react-lazy-load-image-component";
+import { SkeletonProduct } from "../elements/Skeleton";
+
+const ProductCategory = ({ id }) => {
+ const [ content, setContent ] = useState(null);
+
+ useEffect(() => {
+ const loadContent = async () => {
+ if (!content) {
+ const dataContent = await apiOdoo('GET', `/api/v1/categories_homepage?id=${id}`);
+ setContent(dataContent[0]);
+ }
+ }
+ loadContent();
+ }, [id, content]);
+
+ return (
+ <div className="my-6 px-4 pt-4 relative">
+ { content ? (
+ <ProductSlider
+ products={{
+ products: content.products,
+ banner: {
+ image: content.image,
+ name: content.name,
+ url: `/shop/search?category=${content.name}`
+ }
+ }}
+ simpleProductTitleLine
+ bannerMode
+ />
+ ) : <SkeletonProduct /> }
+ </div>
+ );
+}
+
+export default function ProductCategories() {
+ const [ contentIds, setContentIds ] = useState([]);
+
+ useEffect(() => {
+ const getContentIds = async () => {
+ const dataContentIds = await apiOdoo('GET', '/api/v1/categories_homepage/ids');
+ setContentIds(dataContentIds);
+ }
+ getContentIds();
+ }, []);
+
+ return contentIds.map((contentId) => (
+ <LazyLoadComponent key={contentId}>
+ <ProductCategory id={contentId} />
+ </LazyLoadComponent>
+ ));
+} \ No newline at end of file
diff --git a/src/components/products/ProductSimilar.js b/src/components/products/ProductSimilar.js
new file mode 100644
index 00000000..9e2292cb
--- /dev/null
+++ b/src/components/products/ProductSimilar.js
@@ -0,0 +1,25 @@
+import apiOdoo from '@/core/utils/apiOdoo';
+import { useEffect, useState } from 'react';
+import ProductSlider from './ProductSlider';
+
+export default function ProductSimilar({ productId }) {
+ const [similarProducts, setSimilarProducts] = useState(null);
+
+ useEffect(() => {
+ const getSimilarProducts = async () => {
+ if (productId && !similarProducts) {
+ const dataSimilarProducts = await apiOdoo('GET', `/api/v1/product/${productId}/similar?limit=20`);
+ setSimilarProducts(dataSimilarProducts);
+ }
+ }
+ getSimilarProducts();
+ }, [productId, similarProducts]);
+
+
+ return (
+ <div className="p-4">
+ <h2 className="font-bold mb-4">Kamu Mungkin Juga Suka</h2>
+ <ProductSlider products={similarProducts}/>
+ </div>
+ )
+} \ No newline at end of file
diff --git a/src/components/variants/VariantCard.js b/src/components/variants/VariantCard.js
index cb4d8272..2d27371b 100644
--- a/src/components/variants/VariantCard.js
+++ b/src/components/variants/VariantCard.js
@@ -2,12 +2,27 @@ import { createSlug } from "@/core/utils/slug";
import Image from "../elements/Image";
import Link from "../elements/Link";
import currencyFormat from "@/core/utils/currencyFormat";
+import { useRouter } from "next/router";
+import { toast } from "react-hot-toast";
+import { createOrUpdateItemCart } from "@/core/utils/cart";
export default function VariantCard({
data,
- openOnClick = true
+ openOnClick = true,
+ buyMore = false
}) {
let product = data;
+ const router = useRouter();
+
+ const addItemToCart = () => {
+ toast.success('Berhasil menambahkan ke keranjang', { duration: 1500 });
+ createOrUpdateItemCart(product.id, 1);
+ return;
+ };
+
+ const checkoutItem = () => {
+ router.push(`/shop/checkout?product_id=${product.id}&qty=${product.quantity}`);
+ }
const Card = () => (
<div className="flex gap-x-3">
@@ -38,9 +53,29 @@ export default function VariantCard({
if (openOnClick) {
return (
- <Link href={'/shop/product/' + createSlug(product.parent.name, product.parent.id)}>
- <Card />
- </Link>
+ <>
+ <Link href={'/shop/product/' + createSlug(product.parent.name, product.parent.id)}>
+ <Card />
+ </Link>
+ { buyMore && (
+ <div className="flex justify-end gap-x-2 mb-2">
+ <button
+ type="button"
+ onClick={addItemToCart}
+ className="btn-yellow text-gray_r-12 py-2 px-3"
+ >
+ Tambah Keranjang
+ </button>
+ <button
+ type="button"
+ onClick={checkoutItem}
+ className="btn-solid-red py-2 px-3"
+ >
+ Beli Lagi
+ </button>
+ </div>
+ ) }
+ </>
);
}
diff --git a/src/pages/index.js b/src/pages/index.js
index 49300883..fcf47b34 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -16,6 +16,8 @@ import Layout from "@/components/layouts/Layout";
import ManufactureCard from "@/components/manufactures/ManufactureCard";
import Footer from "@/components/layouts/Footer";
import Image from "@/components/elements/Image";
+import ProductCategories from "@/components/products/ProductCategories";
+import { LazyLoadComponent } from "react-lazy-load-image-component";
export async function getServerSideProps() {
const heroBanners = await apiOdoo('GET', `/api/v1/banner?type=index-a-1`);
@@ -26,8 +28,6 @@ export async function getServerSideProps() {
export default function Home({ heroBanners }) {
const [manufactures, setManufactures] = useState(null);
const [popularProducts, setPopularProducts] = useState(null);
- const [categoryProductIds, setCategoryProductIds] = useState(null);
- const [categoryProducts, setCategoryProducts] = useState([]);
useEffect(() => {
const getManufactures = async () => {
@@ -43,33 +43,6 @@ export default function Home({ heroBanners }) {
getPopularProducts();
}, []);
- useEffect(() => {
- const getCategoryProductIds = async () => {
- if (!categoryProductIds) {
- const dataCategoryProductIds = await apiOdoo('GET', '/api/v1/categories_homepage/ids');
- setCategoryProductIds(dataCategoryProductIds)
- }
- }
- getCategoryProductIds();
- }, [ categoryProductIds ]);
-
- useEffect(() => {
- const getCategoryProducts = async () => {
- const currentCategoryId = categoryProductIds ? categoryProductIds[categoryProducts.length] : false;
- if (currentCategoryId) {
- const isAdded = categoryProducts.findIndex((categoryProduct) => categoryProduct.id == currentCategoryId);
- if (isAdded < 0) {
- const dataCategoryProducts = await apiOdoo('GET', `/api/v1/categories_homepage?id=${currentCategoryId}`);
- setCategoryProducts((categoryProducts) => ([
- ...categoryProducts,
- ...dataCategoryProducts
- ]));
- }
- }
- }
- getCategoryProducts();
- }, [ categoryProducts, categoryProductIds ]);
-
return (
<>
<Header title='Home - Indoteknik' />
@@ -104,22 +77,9 @@ export default function Home({ heroBanners }) {
<ProductSlider products={popularProducts} simpleProductTitleLine />
</div>
- { categoryProducts?.map((categoryProduct, index) => (
- <div className="my-6 px-4 pt-4 relative" key={index}>
- <ProductSlider
- products={categoryProduct ? {
- products: categoryProduct.products,
- banner: {
- image: categoryProduct.image,
- name: categoryProduct.name,
- url: `/shop/search?category=${categoryProduct.name}`
- }
- } : null}
- simpleProductTitleLine
- bannerMode
- />
- </div>
- )) }
+ <LazyLoadComponent>
+ <ProductCategories />
+ </LazyLoadComponent>
<div className="px-4">
<h5 className="h2 mb-2">Platform Belanja B2B Alat Teknik & Industri di Indonesia</h5>
diff --git a/src/pages/my/invoice/[id].js b/src/pages/my/invoice/[id].js
index 05247210..10f625a9 100644
--- a/src/pages/my/invoice/[id].js
+++ b/src/pages/my/invoice/[id].js
@@ -93,7 +93,7 @@ export default function DetailInvoice() {
<p className="text-gray_r-11 leading-none">Faktur Pembelian</p>
<button
type="button"
- className="btn-solid-red py-1 px-2 ml-auto"
+ className="btn-light py-1.5 px-3 ml-auto"
onClick={downloadInvoice}
>
Download
@@ -103,7 +103,7 @@ export default function DetailInvoice() {
<p className="text-gray_r-11 leading-none">Faktur Pajak</p>
<button
type="button"
- className="btn-solid-red py-1 px-2 ml-auto"
+ className="btn-light py-1.5 px-3 ml-auto"
onClick={downloadTaxInvoice}
disabled={invoice.efaktur ? false : true}
>
@@ -131,6 +131,7 @@ export default function DetailInvoice() {
<VariantCard
key={index}
data={product}
+ buyMore
/>
)) }
<div className="flex justify-between mt-3 font-medium">
diff --git a/src/pages/my/invoices.js b/src/pages/my/invoices.js
index d54f9487..a86ddffc 100644
--- a/src/pages/my/invoices.js
+++ b/src/pages/my/invoices.js
@@ -115,7 +115,7 @@ export default function Invoices() {
</div>
</div>
</Link>
- { invoice.efaktur_token ? (
+ { invoice.efaktur ? (
<div className="badge-green h-fit mt-3 ml-auto flex items-center gap-x-0.5">
<CheckIcon className="w-4 stroke-2" />
Faktur Pajak
diff --git a/src/pages/my/transaction/[id].js b/src/pages/my/transaction/[id].js
index a508ef77..428d71fb 100644
--- a/src/pages/my/transaction/[id].js
+++ b/src/pages/my/transaction/[id].js
@@ -72,6 +72,7 @@ export default function DetailTransaction() {
<VariantCard
key={index}
data={product}
+ buyMore
/>
)) }
<div className="flex justify-between mt-3 font-medium">
diff --git a/src/pages/shop/checkout.js b/src/pages/shop/checkout.js
index 875cf0f1..8a540bcd 100644
--- a/src/pages/shop/checkout.js
+++ b/src/pages/shop/checkout.js
@@ -195,6 +195,7 @@ export default function Checkout() {
{ selectedAddress.shipping && (
<div className="mt-4 text-caption-1">
+ <div className="badge-red mb-2">{ selectedAddress.invoicing.type.charAt(0).toUpperCase() + selectedAddress.invoicing.type.slice(1) + ' Address' }</div>
<p className="font-medium">{ selectedAddress.shipping.name }</p>
<p className="mt-2 text-gray_r-11">{ selectedAddress.shipping.mobile }</p>
<p className="mt-1 text-gray_r-11">{ selectedAddress.shipping.street }, { selectedAddress.shipping?.city?.name }</p>
@@ -261,6 +262,7 @@ export default function Checkout() {
{ selectedAddress.invoicing && (
<div className="mt-4 text-caption-1">
+ <div className="badge-red mb-2">{ selectedAddress.invoicing.type.charAt(0).toUpperCase() + selectedAddress.invoicing.type.slice(1) + ' Address' }</div>
<p className="font-medium">{ selectedAddress.invoicing.name }</p>
<p className="mt-2 text-gray_r-11">{ selectedAddress.invoicing.mobile }</p>
<p className="mt-1 text-gray_r-11">{ selectedAddress.invoicing.street } { selectedAddress.invoicing.street2 }</p>
diff --git a/src/pages/shop/product/[slug].js b/src/pages/shop/product/[slug].js
index 03fac0be..c3d34806 100644
--- a/src/pages/shop/product/[slug].js
+++ b/src/pages/shop/product/[slug].js
@@ -15,6 +15,8 @@ import LineDivider from "@/components/elements/LineDivider";
import { HeartIcon as HeartIconSolid } from "@heroicons/react/24/solid";
import { useAuth } from "@/core/utils/auth";
import { HeartIcon } from "@heroicons/react/24/outline";
+import { LazyLoadComponent } from "react-lazy-load-image-component";
+import ProductSimilar from "@/components/products/ProductSimilar";
export async function getServerSideProps( context ) {
const { slug } = context.query;
@@ -37,7 +39,6 @@ export default function ProductDetail({ product }) {
const { slug } = router.query;
const [selectedVariant, setSelectedVariant] = useState("");
const [quantity, setQuantity] = useState("1");
- const [similarProducts, setSimilarProducts] = useState(null);
const [activeVariant, setActiveVariant] = useState({
id: product.id,
code: product.code,
@@ -83,15 +84,6 @@ export default function ProductDetail({ product }) {
}, [ product ]);
useEffect(() => {
- setSimilarProducts(null);
- const getSimilarProducts = async () => {
- const dataSimilarProducts = await apiOdoo('GET', `/api/v1/product/${getIdFromSlug(slug)}/similar?limit=20`);
- setSimilarProducts(dataSimilarProducts);
- }
- if (slug) getSimilarProducts();
- }, [slug]);
-
- useEffect(() => {
if (selectedVariant != '') {
let newActiveVariant = product.variants.filter((variant) => {
return variant.id == selectedVariant;
@@ -281,11 +273,10 @@ export default function ProductDetail({ product }) {
</div>
<LineDivider />
-
- <div className="p-4">
- <h2 className="font-bold mb-4">Kamu Mungkin Juga Suka</h2>
- <ProductSlider products={similarProducts}/>
- </div>
+
+ <LazyLoadComponent>
+ <ProductSimilar productId={getIdFromSlug(slug || '')} />
+ </LazyLoadComponent>
<Footer />
</Layout>
diff --git a/src/pages/shop/quotation/index.js b/src/pages/shop/quotation/index.js
index cf2b956d..e1c196db 100644
--- a/src/pages/shop/quotation/index.js
+++ b/src/pages/shop/quotation/index.js
@@ -16,8 +16,7 @@ export default function Quotation() {
const router = useRouter();
const [ auth ] = useAuth();
const [ products, setProducts ] = useState([]);
- const [ totalPriceBeforeTax, setTotalPriceBeforeTax ] = useState(0);
- const [ totalTaxAmount, setTotalTaxAmount ] = useState(0);
+ const [ totalAmount, setTotalAmount ] = useState(0);
const [ totalDiscountAmount, setTotalDiscountAmount ] = useState(0);
useEffect(() => {
@@ -43,18 +42,13 @@ export default function Quotation() {
useEffect(() => {
if (products) {
- const productsSelected = products.filter((product) => product.selected == true);
- let calculateTotalPriceBeforeTax = 0;
- let calculateTotalTaxAmount = 0;
+ let calculateTotalAmount = 0;
let calculateTotalDiscountAmount = 0;
- productsSelected.forEach(product => {
- let priceBeforeTax = product.price.price / 1.11;
- calculateTotalPriceBeforeTax += priceBeforeTax * product.quantity;
- calculateTotalTaxAmount += (product.price.price - priceBeforeTax) * product.quantity;
+ products.forEach(product => {
+ calculateTotalAmount += product.price.price * product.quantity;
calculateTotalDiscountAmount += (product.price.price - product.price.price_discount) * product.quantity;
});
- setTotalPriceBeforeTax(calculateTotalPriceBeforeTax);
- setTotalTaxAmount(calculateTotalTaxAmount);
+ setTotalAmount(calculateTotalAmount);
setTotalDiscountAmount(calculateTotalDiscountAmount);
}
}, [products]);
@@ -102,22 +96,26 @@ export default function Quotation() {
<hr className="my-4 border-gray_r-6"/>
<div className="flex flex-col gap-y-4">
<div className="flex gap-x-2 justify-between">
- <p>Subtotal</p>
- <p className="font-medium">{currencyFormat(totalPriceBeforeTax)}</p>
+ <p>Total Belanja</p>
+ <p className="font-medium">{currencyFormat(totalAmount)}</p>
</div>
<div className="flex gap-x-2 justify-between">
- <p>PPN 11%</p>
- <p className="font-medium">{currencyFormat(totalTaxAmount)}</p>
+ <p>Total Diskon</p>
+ <p className="font-medium text-red_r-11">{'- ' + currencyFormat(totalDiscountAmount)}</p>
</div>
<div className="flex gap-x-2 justify-between">
- <p>Total Diskon</p>
- <p className="font-medium text-red_r-11">- {currencyFormat(totalDiscountAmount)}</p>
+ <p>Subtotal</p>
+ <p className="font-medium">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
+ </div>
+ <div className="flex gap-x-2 justify-between">
+ <p>PPN 11% (Incl.)</p>
+ <p className="font-medium">{currencyFormat((totalAmount - totalDiscountAmount) * 0.11)}</p>
</div>
</div>
<hr className="my-4 border-gray_r-6"/>
<div className="flex gap-x-2 justify-between mb-4">
<p>Grand Total</p>
- <p className="font-medium text-yellow_r-11">{currencyFormat(totalPriceBeforeTax + totalTaxAmount - totalDiscountAmount)}</p>
+ <p className="font-medium text-yellow_r-11">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
</div>
<p className="text-caption-2 text-gray_r-10 mb-2">*) Belum termasuk biaya pengiriman</p>
<p className="text-caption-2 text-gray_r-10 leading-5">