summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-10-21 10:06:54 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-10-21 10:06:54 +0700
commita001da95b9c03167656aec8a573cf60c12164b3f (patch)
tree54c8432bf9b1ec21648c6fae9faf94066c96987f
parent5c1f114b9e9feb256a49bfd60ed60c72823bca7c (diff)
parentbf33b9a9493aeab84e72647fad384bed43feabd5 (diff)
Merge branch 'master' into refactor/all
-rw-r--r--src/core/utils/formatValue.js10
-rw-r--r--src/lib/checkout/components/Checkout.jsx14
-rw-r--r--src/lib/checkout/components/CheckoutOld.jsx4
-rw-r--r--src/lib/flashSale/components/FlashSale.jsx2
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx27
-rw-r--r--src/lib/product/components/Product/ProductMobile.jsx11
-rw-r--r--src/lib/product/components/ProductCard.jsx39
-rw-r--r--src/lib/product/components/ProductFilter.jsx6
-rw-r--r--src/lib/product/components/ProductSearch.jsx12
-rw-r--r--src/lib/variant/components/VariantCard.jsx2
-rw-r--r--src/pages/api/shop/search.js15
-rw-r--r--src/pages/google_merchant/products/[page].js45
-rw-r--r--src/utils/solrMapping.js6
13 files changed, 125 insertions, 68 deletions
diff --git a/src/core/utils/formatValue.js b/src/core/utils/formatValue.js
new file mode 100644
index 00000000..f2c17769
--- /dev/null
+++ b/src/core/utils/formatValue.js
@@ -0,0 +1,10 @@
+const sellingProductFormat = (value) => {
+ if (value > 1000) {
+ const formattedValue = (value / 1000).toFixed(0).replace('.', ',')
+ return formattedValue + 'rb+';
+ } else {
+ return value.toString()
+ }
+}
+
+export { sellingProductFormat }
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index 511fcdba..9a799010 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -168,6 +168,16 @@ const Checkout = () => {
setExpedisi(dataExpedisi)
}
loadExpedisi()
+
+ const handlePopState = () => {
+ router.push('/shop/cart')
+ }
+
+ window.onpopstate = handlePopState
+
+ return () => {
+ window.onpopstate = null
+ }
// voucher()
}, [])
@@ -1071,7 +1081,7 @@ const Checkout = () => {
<div className='font-normal mt-1'>
{product.price.priceDiscount > 0
? currencyFormat(product?.price?.priceDiscount)
- : 'Call For Price'}
+ : 'Call for Inquiry'}
</div>
)}
</td>
@@ -1092,7 +1102,7 @@ const Checkout = () => {
})}
className='underline'
>
- Call For Price{' '}
+ Call for Inquiry{' '}
</a>
)}
</div>
diff --git a/src/lib/checkout/components/CheckoutOld.jsx b/src/lib/checkout/components/CheckoutOld.jsx
index 6852059e..d57fbd66 100644
--- a/src/lib/checkout/components/CheckoutOld.jsx
+++ b/src/lib/checkout/components/CheckoutOld.jsx
@@ -486,7 +486,7 @@ const Checkout = () => {
<div className='font-normal mt-1'>
{product.price.priceDiscount > 0
? currencyFormat(product?.price?.priceDiscount)
- : 'Call For Price'}
+ : 'Call for Inquiry'}
</div>
</td>
<td>
@@ -501,7 +501,7 @@ const Checkout = () => {
})}
className='underline'
>
- Call For Price{' '}
+ Call for Inquiry{' '}
</a>
)}
</div>
diff --git a/src/lib/flashSale/components/FlashSale.jsx b/src/lib/flashSale/components/FlashSale.jsx
index 87545d8d..3d5c4e0e 100644
--- a/src/lib/flashSale/components/FlashSale.jsx
+++ b/src/lib/flashSale/components/FlashSale.jsx
@@ -63,7 +63,7 @@ const FlashSaleProduct = ({ flashSaleId }) => {
useEffect(() => {
const loadProducts = async () => {
const dataProducts = await productSearchApi({
- query: `fq=flashsale_id_i:${flashSaleId}&fq=flashsale_price_f:[1 TO *]&limit=500`,
+ query: `fq=flashsale_id_i:${flashSaleId}&fq=flashsale_price_f:[1 TO *]&limit=500&orderBy=flashsale-price-asc`,
operation: 'AND'
})
setProducts(dataProducts.response)
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index 701750b2..a8cca416 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -25,6 +25,7 @@ import { useProductCartContext } from '@/contexts/ProductCartContext'
import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
import { Info } from 'lucide-react'
import Breadcrumb from './Breadcrumb'
+import { sellingProductFormat } from '@/core/utils/formatValue'
const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -44,21 +45,9 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
const { setRefreshCart, refreshCart } = useProductCartContext()
- const getLowestPrice = useCallback(() => {
- const prices = product.variants.map((variant) => ({
- price: variant.price,
- isFlashsale: variant.isFlashsale
- }))
- const lowest = prices.reduce((lowest, price) => {
- return price.price < lowest.price ? price : lowest
- }, prices[0])
- return lowest
- }, [product])
-
useEffect(() => {
- const lowest = getLowestPrice()
- setLowestPrice(lowest)
- }, [getLowestPrice])
+ setLowestPrice({ price: product?.lowestPrice })
+ }, [product])
useEffect(() => {
const getBackgound = async () => {
@@ -418,7 +407,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
</div>
- <div className='w-[25%]'>
+ <div className='w-[30%]'>
{product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && (
<div className='text-gray_r-12/80'>Harga mulai dari: </div>
)}
@@ -447,7 +436,11 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
)}
</div>
)} */}
-
+ {product?.qtySold > 0 && (
+ <div className='text-gray_r-9'>
+ {sellingProductFormat(product?.qtySold) + ' Terjual'}
+ </div>
+ )}
{lowestPrice?.isFlashsale && lowestPrice?.price.discountPercentage > 0 ? (
<>
<div className='flex gap-x-1 items-center mt-2'>
@@ -632,7 +625,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
rel='noopener noreferrer'
target='_blank'
>
- Call for price
+ Call for Inquiry
</a>
)}
</div>
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx
index 70ac1cbc..ef2c0002 100644
--- a/src/lib/product/components/Product/ProductMobile.jsx
+++ b/src/lib/product/components/Product/ProductMobile.jsx
@@ -21,6 +21,7 @@ import ImageNext from 'next/image'
import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
import Breadcrumb from './Breadcrumb'
import useAuth from '@/core/hooks/useAuth'
+import { sellingProductFormat } from '@/core/utils/formatValue'
const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -62,7 +63,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
price: getLowestPrice(),
stock: product.stockTotal,
weight: product.weight,
- hasProgram: false
+ hasProgram: false,
+ qtySold: product.qtySold
})
const variantOptions = product.variants?.map((variant) => {
@@ -105,7 +107,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
stock: variant.stock,
weight: variant.weight,
hasProgram: variant.hasProgram,
- isFlashsale: variant.isFlashsale
+ isFlashsale: variant.isFlashsale,
+ qtySold: variant.qtySold
}
setActiveVariant(newActiveVariant)
@@ -245,7 +248,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
</button>
</div>
<h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1>
-
+ {product?.qtySold > 0 && (
+ <div className='text-gray_r-9'>{sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}</div>
+ )}
{product.variants.length > 1 &&
activeVariant.price.priceDiscount > 0 &&
!selectedVariant && (
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index 3b96ac32..9500a3fd 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -1,6 +1,7 @@
import Image from '@/core/components/elements/Image/Image'
import Link from '@/core/components/elements/Link/Link'
import currencyFormat from '@/core/utils/currencyFormat'
+import { sellingProductFormat } from '@/core/utils/formatValue'
import { createSlug } from '@/core/utils/slug'
import whatsappUrl from '@/core/utils/whatsappUrl'
import ImageNext from 'next/image'
@@ -82,9 +83,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
<Link
href={createSlug('/shop/product/', product?.name, product?.id)}
- className={`mb-3 !text-gray_r-12 leading-6 block ${
- simpleTitle ? 'line-clamp-2 h-12' : 'line-clamp-3 h-[64px]'
- }`}
+ className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`}
title={product?.name}
>
{product?.name}
@@ -103,7 +102,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
{product?.lowestPrice.priceDiscount > 0 ? (
currencyFormat(product?.lowestPrice.priceDiscount)
) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
+ <a href={callForPriceWhatsapp}>Call for Inquiry</a>
)}
</div>
</>
@@ -118,17 +117,16 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
</div>
</>
) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
+ <a href={callForPriceWhatsapp}>Call for Inquiry</a>
)}
</div>
)}
- {product?.stockTotal > 0 && (
- <div className='flex gap-x-1'>
- <div className='badge-solid-red'>Ready Stock</div>
- <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div>
- </div>
- )}
+ <div className='flex w-full items-center gap-x-1 '>
+ {product?.stockTotal > 0 && <div className='badge-solid-red'>Ready Stock</div>}
+ {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */}
+ {product?.qtySold > 0 && <div className='text-gray_r-9 text-[11px]'>{sellingProductFormat(product?.qtySold) + ' Terjual'}</div>}
+ </div>
</div>
</div>
)
@@ -186,9 +184,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
<Link
href={createSlug('/shop/product/', product?.name, product?.id)}
- className={`mb-3 !text-gray_r-12 leading-6 ${
- simpleTitle ? 'line-clamp-2' : 'line-clamp-3'
- }`}
+ className={`mb-3 !text-gray_r-12 leading-6 line-clamp-3`}
>
{product?.name}
</Link>
@@ -209,7 +205,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
{product?.lowestPrice?.priceDiscount > 0 ? (
currencyFormat(product?.lowestPrice?.priceDiscount)
) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
+ <a href={callForPriceWhatsapp}>Call for Inquiry</a>
)}
</div>
</>
@@ -224,17 +220,16 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
</div>
</>
) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
+ <a href={callForPriceWhatsapp}>Call for Inquiry</a>
)}
</div>
)}
- {product?.stockTotal > 0 && (
- <div className='flex gap-x-1'>
- <div className='badge-solid-red'>Ready Stock</div>
- <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div>
- </div>
- )}
+ <div className='flex w-full items-center gap-x-1 '>
+ {product?.stockTotal > 0 && <div className='badge-solid-red'>Ready Stock</div>}
+ {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */}
+ {product?.qtySold > 0 && <div className='text-gray_r-9 text-[11px]'>{sellingProductFormat(product?.qtySold) + ' Terjual'}</div>}
+ </div>
</div>
</div>
)
diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx
index 14eef0ba..d52fcb90 100644
--- a/src/lib/product/components/ProductFilter.jsx
+++ b/src/lib/product/components/ProductFilter.jsx
@@ -15,7 +15,7 @@ const orderOptions = [
const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBrand = null }) => {
const router = useRouter()
const { query } = router
- const [order, setOrder] = useState(query?.orderBy)
+ const [order, setOrder] = useState(query?.orderBy || 'popular')
const [brand, setBrand] = useState(query?.brand)
const [category, setCategory] = useState(query?.category)
const [priceFrom, setPriceFrom] = useState(query?.priceFrom)
@@ -184,7 +184,7 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr
))}
</div>
</div>
- <div>
+ {/* <div>
<label>Ketersedian Stok</label>
<div className='mt-2'>
<Checkbox
@@ -196,7 +196,7 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr
Ketersedian Stok
</Checkbox>
</div>
- </div>
+ </div> */}
<button type='button' className='btn-solid-red w-full mt-2' onClick={handleSubmit}>
Terapkan Filter
</button>
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index fd75d587..9d59b305 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -23,8 +23,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
const { page = 1 } = query
const [q, setQ] = useState(query?.q || '*')
const [limit, setLimit] = useState(query?.limit || 30)
+ const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular')
if (defaultBrand) query.brand = defaultBrand.toLowerCase()
- const { productSearch } = useProductSearch({ query: { ...query, q, limit } })
+ const { productSearch } = useProductSearch({ query: { ...query, q, limit, orderBy } })
const [products, setProducts] = useState(null)
const [spellings, setSpellings] = useState(null)
const [bannerPromotionHeader, setBannerPromotionHeader] = useState(null)
@@ -70,11 +71,11 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
const brands = []
for (
let i = 0;
- i < productSearch.data?.facetCounts?.facetFields?.manufactureName.length;
+ i < productSearch.data?.facetCounts?.facetFields?.manufactureNameS.length;
i += 2
) {
- const brand = productSearch.data?.facetCounts?.facetFields?.manufactureName[i]
- const qty = productSearch.data?.facetCounts?.facetFields?.manufactureName[i + 1]
+ const brand = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i]
+ const qty = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1]
if (qty > 0) {
brands.push({ brand, qty })
}
@@ -303,10 +304,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
<select
name='urutan'
className='form-input mt-2'
- value={router.query?.orderBy || ''}
+ value={orderBy}
onChange={(e) => handleOrderBy(e)}
>
- <option value=''>Urutkan</option>
{orderOptions.map((option, index) => (
<option key={index} value={option.value}>
{' '}
diff --git a/src/lib/variant/components/VariantCard.jsx b/src/lib/variant/components/VariantCard.jsx
index 6c0ab974..9f1b5733 100644
--- a/src/lib/variant/components/VariantCard.jsx
+++ b/src/lib/variant/components/VariantCard.jsx
@@ -68,7 +68,7 @@ const VariantCard = ({ product, openOnClick = true, buyMore = false }) => {
})}
className='underline text-danger-500'
>
- Call For Price{' '}
+ Call for Inquiry{' '}
</a>
)}
</p>
diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js
index fd7a215a..b4d67c5d 100644
--- a/src/pages/api/shop/search.js
+++ b/src/pages/api/shop/search.js
@@ -13,20 +13,20 @@ export default async function handler(req, res) {
orderBy = '',
operation = 'AND',
fq = '',
- limit = 0,
+ limit = 30,
stock = ''
} = req.query
let paramOrderBy = ''
switch (orderBy) {
case 'price-asc':
- paramOrderBy += 'price_discount_f ASC'
+ paramOrderBy += 'price_tier1_v2_f ASC'
break
case 'price-desc':
- paramOrderBy += 'price_discount_f DESC'
+ paramOrderBy += 'price_tier1_v2_f DESC'
break
case 'popular':
- paramOrderBy += 'search_rank_i DESC'
+ paramOrderBy += 'product_rating_f DESC, search_rank_i DESC,'
break
case 'popular-weekly':
paramOrderBy += 'search_rank_weekly_i DESC'
@@ -34,6 +34,9 @@ export default async function handler(req, res) {
case 'stock':
paramOrderBy += 'stock_total_f DESC'
break
+ case 'flashsale-price-asc':
+ paramOrderBy += 'flashsale_price_f ASC'
+ break
default:
paramOrderBy += 'product_rating_f DESC, price_discount_f DESC'
break
@@ -41,7 +44,7 @@ export default async function handler(req, res) {
let offset = (page - 1) * limit
let parameter = [
- 'facet.field=manufacture_name',
+ 'facet.field=manufacture_name_s',
'facet.field=category_name',
'facet=true',
'indent=true',
@@ -49,7 +52,7 @@ export default async function handler(req, res) {
`q.op=${operation}`,
`q=${escapeSolrQuery(q)}`,
'qf=name_s',
- `start=${offset}`,
+ `start=${parseInt(offset)}`,
`rows=${limit}`,
`sort=${paramOrderBy}`,
`fq=-publish_b:false`
diff --git a/src/pages/google_merchant/products/[page].js b/src/pages/google_merchant/products/[page].js
index d6309090..c8b4079b 100644
--- a/src/pages/google_merchant/products/[page].js
+++ b/src/pages/google_merchant/products/[page].js
@@ -2,6 +2,7 @@ import { createSlug } from '@/core/utils/slug'
import toTitleCase from '@/core/utils/toTitleCase'
import productSearchApi from '@/lib/product/api/productSearchApi'
import variantSearchApi from '@/lib/product/api/variantSearchApi'
+import axios from 'axios'
import _ from 'lodash-contrib'
import { create } from 'xmlbuilder'
@@ -21,8 +22,11 @@ export async function getServerSideProps({ res, query }) {
}
const products = await variantSearchApi({ query: _.toQuery(queries) })
+ const brandsData = {}
+ const categoriesData = {}
+
const productItems = []
- products.response.products.forEach((product) => {
+ for (const product of products.response.products) {
const productUrl = createSlug('/shop/product/variant/', product.name, product.id, true)
const productId = product.code != '' ? product.code : product.id
const regexHtmlTags = /(<([^>]+)>)/gi
@@ -34,6 +38,27 @@ export async function getServerSideProps({ res, query }) {
product.description = defaultProductDescription
}
+ let categoryName = null
+
+ let brandId = product.manufacture?.id ?? null
+ let categoryId = null
+
+ if (brandId && brandId in brandsData) {
+ categoryId = brandsData[brandId].category_ids?.[0] ?? null
+ } else {
+ const solrBrand = await getBrandById(brandId)
+ brandsData[brandId] = solrBrand
+ categoryId = solrBrand?.category_ids?.[0] ?? null
+ }
+
+ if (categoryId && categoryId in categoriesData) {
+ categoryName = categoriesData[categoryId].name_s ?? null
+ } else {
+ const solrCategory = await getCategoryById(categoryId)
+ categoriesData[categoryId] = solrCategory
+ categoryName = solrCategory?.name_s ?? null
+ }
+
const availability = 'in_stock'
const item = {
@@ -47,20 +72,24 @@ export async function getServerSideProps({ res, query }) {
'g:brand': { '#text': product.manufacture?.name || '' },
'g:price': { '#text': `${Math.round(product.lowestPrice.price * 1.11)} IDR` }
}
-
+
if (product.stockTotal == 0) {
item['g:custom_label_0'] = { '#text': 'Stok Tidak Tersedia' }
} else {
item['g:custom_label_1'] = { '#text': 'Stok Tersedia' }
}
+ if (categoryName) {
+ item['g:custom_label_2'] = { '#text': categoryName }
+ }
+
if (product.lowestPrice.discountPercentage > 0) {
item['g:sale_price'] = {
'#text': `${Math.round(product.lowestPrice.priceDiscount * 1.11)} IDR`
}
}
productItems.push(item)
- })
+ }
const googleMerchant = {
rss: {
@@ -82,6 +111,16 @@ export async function getServerSideProps({ res, query }) {
return { props: {} }
}
+const getBrandById = async (id) => {
+ const brand = await axios(`${process.env.SOLR_HOST}/solr/brands/select?q=id:${id}`)
+ return brand.data.response.docs[0] ?? null
+}
+
+const getCategoryById = async (id) => {
+ const category = await axios(`${process.env.SOLR_HOST}/solr/categories/select?q=id:${id}`)
+ return category.data.response.docs[0] ?? null
+}
+
export default function GoogleMerchantPage() {
return null
}
diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js
index 61816cf8..41d24b53 100644
--- a/src/utils/solrMapping.js
+++ b/src/utils/solrMapping.js
@@ -32,7 +32,8 @@ export const productMappingSolr = (products, pricelist) => {
remainingTime: flashsaleTime(product?.flashsale_end_date_s)?.remainingTime,
name: product?.product?.flashsale_name_s,
tag: product?.flashsale_tag_s || 'FLASH SALE'
- }
+ },
+ qtySold : product?.qty_sold_f || 0
}
if (product.manufacture_id_i && product.manufacture_name_s) {
@@ -85,7 +86,8 @@ export const variantsMappingSolr = (parent, products, pricelist) => {
stockTotal: product.stock_total_f || 0,
weight: product.weight_f || 0,
manufacture: {},
- parent: {}
+ parent: {},
+ qtySold : product?.qty_sold_f || 0
}
if (product.manufacture_id_i && product.manufacture_name_s) {