summaryrefslogtreecommitdiff
path: root/src-migrate
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2024-01-15 13:54:30 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2024-01-15 13:54:30 +0700
commitc42f03768e4c009a247d5cacbecaf4ac952752c9 (patch)
tree9199f9b7fae77e1988724159380567b8046c94a9 /src-migrate
parentf62b2345f463695ef0f8f79830cd76b6e0332821 (diff)
Improve product detail performance
Diffstat (limited to 'src-migrate')
-rw-r--r--src-migrate/libs/whatsappUrl.ts46
-rw-r--r--src-migrate/modules/product-detail/components/PriceAction.tsx42
-rw-r--r--src-migrate/modules/product-detail/components/ProductDetail.tsx32
-rw-r--r--src-migrate/modules/product-detail/components/VariantList.tsx12
-rw-r--r--src-migrate/modules/product-detail/stores/useProductDetail.ts6
-rw-r--r--src-migrate/modules/product-detail/styles/price-action.module.css6
-rw-r--r--src-migrate/modules/product-promo/components/Section.tsx9
-rw-r--r--src-migrate/types/auth.ts6
8 files changed, 135 insertions, 24 deletions
diff --git a/src-migrate/libs/whatsappUrl.ts b/src-migrate/libs/whatsappUrl.ts
new file mode 100644
index 00000000..02c36cef
--- /dev/null
+++ b/src-migrate/libs/whatsappUrl.ts
@@ -0,0 +1,46 @@
+import { getAuth } from './auth';
+
+const TEMPLATES = {
+ default: 'Bisa tolong bantu kebutuhan saya?',
+ product:
+ 'Saya mencari barang berikut:\n\n{{url}}\n\n```Brand: {{manufacture}}\nName: {{productName}}```',
+};
+
+interface WhatsappUrlProps {
+ template: keyof typeof TEMPLATES;
+ payload: any;
+ greeting?: boolean;
+ needLogin?: boolean;
+ fallbackUrl?: string;
+}
+
+export const whatsappUrl = ({
+ template,
+ payload,
+ greeting = true,
+ needLogin = true,
+ fallbackUrl,
+}: WhatsappUrlProps) => {
+ const auth = getAuth();
+
+ let greetingText = '';
+
+ if (needLogin && !auth) {
+ return fallbackUrl ? `/login=next?${fallbackUrl}` : '/login';
+ }
+
+ let result = TEMPLATES[template].replace(
+ /{{(.*?)}}/g,
+ (match, key) => payload[key] || ''
+ );
+
+ if (greeting && typeof auth === 'object') {
+ greetingText = `Halo Indoteknik.com, Saya ${auth.name} `;
+ if (auth.parentName) greetingText += `dari ${auth.parentName}`;
+ greetingText += '.\n\n';
+
+ result = greetingText + result;
+ }
+
+ return `https://wa.me/628128080622?text=${encodeURIComponent(result)}`;
+};
diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx
index 8189e5bd..cfb596fa 100644
--- a/src-migrate/modules/product-detail/components/PriceAction.tsx
+++ b/src-migrate/modules/product-detail/components/PriceAction.tsx
@@ -6,13 +6,21 @@ import { formatToShortText } from '~/libs/formatNumber'
import { IProductDetail } from '~/types/product'
import { useProductDetail } from '../stores/useProductDetail'
import AddToCart from './AddToCart'
+import Link from 'next/link'
type Props = {
product: IProductDetail
}
const PriceAction = ({ product }: Props) => {
- const { activePrice, setActive, activeVariantId, quantityInput, setQuantityInput } = useProductDetail()
+ const {
+ activePrice,
+ setActive,
+ activeVariantId,
+ quantityInput,
+ setQuantityInput,
+ askAdminUrl
+ } = useProductDetail()
useEffect(() => {
setActive(product.variants[0])
@@ -26,18 +34,28 @@ const PriceAction = ({ product }: Props) => {
</div>
)}
<div className='h-2' />
- <div className={style['main-price']}>
- Rp {formatCurrency(activePrice?.price || 0)}
- </div>
- <div className='h-1' />
- <div className={style['secondary-text']}>
- {!!activePrice && (
- <>
+
+ {!!activePrice && activePrice.price > 0 && (
+ <>
+ <div className={style['main-price']}>
+ Rp {formatCurrency(activePrice.price || 0)}
+ </div>
+ <div className='h-1' />
+ <div className={style['secondary-text']}>
Termasuk PPN: {' '}
- Rp {formatCurrency(Math.round(activePrice?.price * 1.11))}
- </>
- )}
- </div>
+ Rp {formatCurrency(Math.round(activePrice.price * 1.11))}
+ </div>
+ </>
+ )}
+
+ {!!activePrice && activePrice.price === 0 && (
+ <span>
+ Hubungi kami untuk dapatkan harga terbaik,{' '}
+ <Link href={askAdminUrl} target='_blank' className={style['contact-us']}>
+ klik disini
+ </Link>
+ </span>
+ )}
<div className='h-4' />
diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index b752a138..d38e0686 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -1,6 +1,6 @@
import style from '../styles/product-detail.module.css'
-import React from 'react'
+import React, { useEffect } from 'react'
import Link from 'next/link'
import { MessageCircleIcon } from 'lucide-react'
import { Button } from '@chakra-ui/react'
@@ -15,6 +15,10 @@ import SimilarSide from './SimilarSide'
import SimilarBottom from './SimilarBottom'
import useDevice from '@/core/hooks/useDevice'
import PriceAction from './PriceAction'
+import { whatsappUrl } from '~/libs/whatsappUrl'
+import { useRouter } from 'next/router'
+import { useProductDetail } from '../stores/useProductDetail'
+import ProductPromoSection from '~/modules/product-promo/components/Section'
type Props = {
product: IProductDetail
@@ -22,6 +26,22 @@ type Props = {
const ProductDetail = ({ product }: Props) => {
const { isDesktop, isMobile } = useDevice()
+ const router = useRouter()
+ const { setAskAdminUrl, askAdminUrl, activeVariantId } = useProductDetail()
+
+ useEffect(() => {
+ const createdAskUrl = whatsappUrl({
+ template: 'product',
+ payload: {
+ manufacture: product.manufacture.name,
+ productName: product.name,
+ url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath
+ },
+ fallbackUrl: router.asPath
+ })
+
+ setAskAdminUrl(createdAskUrl)
+ }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl])
return (
<>
@@ -47,8 +67,9 @@ const ProductDetail = ({ product }: Props) => {
<Button
as={Link}
- href=''
+ href={askAdminUrl}
variant='link'
+ target='_blank'
colorScheme='red'
leftIcon={<MessageCircleIcon size={18} />}
>
@@ -64,7 +85,10 @@ const ProductDetail = ({ product }: Props) => {
</div>
)}
- <div className='h-4 md:h-10'></div>
+ <div className='h-4 md:h-10' />
+ {activeVariantId && (
+ <ProductPromoSection productId={activeVariantId} />
+ )}
<div className={style['section-card']}>
<h2 className={style['heading']}>
@@ -74,7 +98,7 @@ const ProductDetail = ({ product }: Props) => {
<VariantList variants={product.variants} />
</div>
- <div className='h-0 md:h-6'></div>
+ <div className='h-0 md:h-6' />
<div className={style['section-card']}>
<h2 className={style['heading']}>
diff --git a/src-migrate/modules/product-detail/components/VariantList.tsx b/src-migrate/modules/product-detail/components/VariantList.tsx
index d07e6b23..f8aa5565 100644
--- a/src-migrate/modules/product-detail/components/VariantList.tsx
+++ b/src-migrate/modules/product-detail/components/VariantList.tsx
@@ -48,11 +48,16 @@ const Row = ({ variant }: { variant: IProductVariantDetail }) => {
return (
<div className={style['row']}>
- <div className='w-2/12 sticky left-0 bg-white'>{variant.code}</div>
+ <div className='w-2/12 sticky left-0 bg-white md:bg-transparent'>{variant.code}</div>
<div className='w-2/12'>{variant.attributes.join(', ')}</div>
<div className='w-1/12'>
<Skeleton isLoaded={querySLA.isSuccess} h='21px' w={16}>
- {sla?.qty}
+ {sla?.qty !== undefined && (
+ <>
+ {sla.qty > 0 && sla.qty}
+ {sla.qty == 0 && '-'}
+ </>
+ )}
</Skeleton>
</div>
<div className='w-2/12'>
@@ -64,7 +69,8 @@ const Row = ({ variant }: { variant: IProductVariantDetail }) => {
{variant.weight > 0 ? `${variant.weight} Kg` : '-'}
</div>
<div className='w-2/12'>
- Rp {formatCurrency(variant.price.price)}
+ {variant.price.price > 0 && `Rp ${formatCurrency(variant.price.price)}`}
+ {variant.price.price === 0 && '-'}
</div>
<div className='w-2/12'>
<Button
diff --git a/src-migrate/modules/product-detail/stores/useProductDetail.ts b/src-migrate/modules/product-detail/stores/useProductDetail.ts
index 984d7948..794f0346 100644
--- a/src-migrate/modules/product-detail/stores/useProductDetail.ts
+++ b/src-migrate/modules/product-detail/stores/useProductDetail.ts
@@ -5,21 +5,27 @@ type State = {
activeVariantId: number | null;
activePrice: IProductVariantDetail['price'] | null;
quantityInput: string;
+ askAdminUrl: string;
};
type Action = {
setActive: (variant: IProductVariantDetail) => void;
setQuantityInput: (value: string) => void;
+ setAskAdminUrl: (url: string) => void;
};
export const useProductDetail = create<State & Action>((set, get) => ({
activeVariantId: null,
activePrice: null,
quantityInput: '1',
+ askAdminUrl: '',
setActive: (variant) => {
set({ activeVariantId: variant.id, activePrice: variant.price });
},
setQuantityInput: (value: string) => {
set({ quantityInput: value });
},
+ setAskAdminUrl: (url: string) => {
+ set({ askAdminUrl: url });
+ },
}));
diff --git a/src-migrate/modules/product-detail/styles/price-action.module.css b/src-migrate/modules/product-detail/styles/price-action.module.css
index 594167af..a8ec0ed3 100644
--- a/src-migrate/modules/product-detail/styles/price-action.module.css
+++ b/src-migrate/modules/product-detail/styles/price-action.module.css
@@ -9,4 +9,8 @@
}
.quantity-input {
@apply px-2 rounded text-center border border-gray-300 w-14 h-10 focus:outline-none;
-} \ No newline at end of file
+}
+
+.contact-us {
+ @apply text-danger-500 font-medium underline;
+}
diff --git a/src-migrate/modules/product-promo/components/Section.tsx b/src-migrate/modules/product-promo/components/Section.tsx
index 04cf1363..b6753be7 100644
--- a/src-migrate/modules/product-promo/components/Section.tsx
+++ b/src-migrate/modules/product-promo/components/Section.tsx
@@ -8,6 +8,7 @@ import ProductPromoCard from './Card'
import { IPromotion } from '~/types/promotion'
import ProductPromoModal from "./Modal"
import { useModalStore } from "../stores/useModalStore"
+import clsxm from "~/libs/clsxm"
type Props = {
productId: number
@@ -36,7 +37,13 @@ const ProductPromoSection = ({ productId }: Props) => {
</div>
)}
- <Skeleton isLoaded={promotionsQuery.isSuccess} className="flex gap-x-4 overflow-x-auto min-h-[340px] px-4 md:px-0">
+ <Skeleton
+ isLoaded={promotionsQuery.isSuccess}
+ className={clsxm(
+ "flex gap-x-4 overflow-x-auto px-4 md:px-0", {
+ "min-h-[340px]": promotions?.data && promotions?.data.length > 0
+ })}
+ >
{promotions?.data.map((promotion) => (
<div key={promotion.id} className="min-w-[400px] max-w-[400px]">
<ProductPromoCard promotion={promotion} />
diff --git a/src-migrate/types/auth.ts b/src-migrate/types/auth.ts
index 464bc12a..4f69bb96 100644
--- a/src-migrate/types/auth.ts
+++ b/src-migrate/types/auth.ts
@@ -4,9 +4,9 @@ import { z } from 'zod';
export type AuthProps = {
id: number;
- parent_id: number;
- parent_name: string;
- partner_id: number;
+ parentId: number;
+ parentName: string;
+ partnerId: number;
name: string;
email: string;
phone: string;