summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/product/api/productSearchApi.js2
-rw-r--r--src/lib/product/components/ProductSearch.jsx2
-rw-r--r--src/pages/api/shop/promo.js205
-rw-r--r--src/pages/shop/promo/[slug].tsx67
-rw-r--r--src/utils/solrMapping.js29
5 files changed, 285 insertions, 20 deletions
diff --git a/src/lib/product/api/productSearchApi.js b/src/lib/product/api/productSearchApi.js
index 1626b7b7..2f792fd4 100644
--- a/src/lib/product/api/productSearchApi.js
+++ b/src/lib/product/api/productSearchApi.js
@@ -3,7 +3,7 @@ import axios from 'axios'
const productSearchApi = async ({ query, operation = 'AND' }) => {
const dataProductSearch = await axios(
- `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}`
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}`
)
return dataProductSearch.data
}
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index eaeac71a..1f083722 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -87,7 +87,7 @@ const ProductSearch = ({
recurse(category);
return ids;
};
-
+ console.log("queryFinal",queryFinal)
useEffect(() => {
if(prefixUrl.includes('category')){
const ids = collectIds(dataCategoriesProduct);
diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js
new file mode 100644
index 00000000..4b4c09b7
--- /dev/null
+++ b/src/pages/api/shop/promo.js
@@ -0,0 +1,205 @@
+import { map } from '@/utils/solrMapping';
+import axios from 'axios';
+import camelcaseObjectDeep from 'camelcase-object-deep';
+
+export default async function handler(req, res) {
+ console.log("req_iman",req)
+ const {
+ q = '*',
+ page = 1,
+ brand = '',
+ category = '',
+ priceFrom = 0,
+ priceTo = 0,
+ orderBy = '',
+ operation = 'AND',
+ fq = '',
+ limit = 30,
+ } = req.query;
+
+ let { stock = '' } = req.query;
+
+ let paramOrderBy = '';
+ switch (orderBy) {
+ case 'price-asc':
+ paramOrderBy += 'price_tier1_v2_f ASC';
+ break;
+ case 'price-desc':
+ paramOrderBy += 'price_tier1_v2_f DESC';
+ break;
+ case 'popular':
+ paramOrderBy += 'product_rating_f DESC, search_rank_i DESC,';
+ break;
+ case 'popular-weekly':
+ paramOrderBy += 'search_rank_weekly_i DESC';
+ break;
+ case 'stock':
+ paramOrderBy += 'product_rating_f DESC, stock_total_f DESC';
+ break;
+ case 'flashsale-price-asc':
+ paramOrderBy += 'flashsale_price_f ASC';
+ break;
+ default:
+ paramOrderBy += '';
+ break;
+ }
+
+ let checkQ = q.trim().split(/[\s\+\-\!\(\)\{\}\[\]\^"~\*\?:\\\/]+/);
+ let newQ = checkQ.length > 1 ? escapeSolrQuery(q) + '*' : escapeSolrQuery(q);
+
+ let offset = (page - 1) * limit;
+ let parameter = [
+ // 'facet.field=manufacture_name_s',
+ // 'facet.field=category_name',
+ 'facet=true',
+ 'indent=true',
+ // `facet.query=${escapeSolrQuery(q)}`,
+ `q.op=${operation}`,
+ `q=${newQ}`,
+ // 'qf=name_s',
+ `start=${parseInt(offset)}`,
+ `rows=${limit}`,
+ `sort=${paramOrderBy}`,
+ // `fq=-publish_b:false, product_rating_f:[8 TO *], price_tier1_v2_f:[1 TO *]`,
+ ];
+
+ if (priceFrom > 0 || priceTo > 0) {
+ parameter.push(
+ `fq=price_tier1_v2_f:[${priceFrom == '' ? '*' : priceFrom} TO ${
+ priceTo == '' ? '*' : priceTo
+ }]`
+ );
+ }
+
+ let { auth } = req.cookies;
+ if (auth) {
+ auth = JSON.parse(auth);
+ if (auth.feature.onlyReadyStock) stock = true;
+ }
+
+ if (brand)
+ parameter.push(
+ `fq=${brand
+ .split(',')
+ .map(
+ (manufacturer) =>
+ `manufacture_name:"${encodeURIComponent(manufacturer)}"`
+ )
+ .join(' OR ')}`
+ );
+ if (category)
+ parameter.push(
+ `fq=${category
+ .split(',')
+ .map((cat) => `category_name:"${encodeURIComponent(cat)}"`)
+ .join(' OR ')}`
+ );
+ // if (category) parameter.push(`fq=category_name:${capitalizeFirstLetter(category.replace(/,/g, ' OR '))}`)
+ if (stock) parameter.push(`fq=stock_total_f:{1 TO *}`);
+
+ // Single fq in url params
+ if (typeof fq === 'string') parameter.push(`fq=${fq}`);
+ // Multi fq in url params
+ if (Array.isArray(fq))
+ parameter = parameter.concat(fq.map((val) => `fq=${val}`));
+
+ console.log("parameter",parameter)
+
+ let result = await axios(
+ process.env.SOLR_HOST + '/solr/promotion_program_lines/select?' + parameter.join('&')
+ );
+ console.log("result",result)
+ try {
+ result.data.response.products = map(
+ result.data.response.docs,
+ auth?.pricelist || false
+ );
+ result.data.responseHeader.params.start = parseInt(
+ result.data.responseHeader.params.start
+ );
+ result.data.responseHeader.params.rows = parseInt(
+ result.data.responseHeader.params.rows
+ );
+ delete result.data.response.docs;
+ result.data = camelcaseObjectDeep(result.data);
+ res.status(200).json(result.data);
+ } catch (error) {
+ res.status(400).json({ error: error.message });
+ }
+}
+
+const escapeSolrQuery = (query) => {
+ if (query == '*') return query;
+
+ query = query.replace(/-/g, ' ');
+
+ const specialChars = /([\+\!\(\)\{\}\[\]\^"~\*\?:\\\/])/g;
+ const words = query.split(/\s+/);
+ const escapedWords = words.map((word) => {
+ if (specialChars.test(word)) {
+ return word.replace(specialChars, '\\$1');
+ }
+ return word;
+ });
+
+ return escapedWords.join(' ');
+};
+
+
+/*const productResponseMap = (products, pricelist) => {
+ return products.map((product) => {
+ let price = product.price_tier1_v2_f || 0
+ let priceDiscount = product.price_discount_f || 0
+ let discountPercentage = product.discount_f || 0
+
+ if (pricelist) {
+ // const pricelistDiscount = product?.[`price_${pricelist}_f`] || false
+ // const pricelistDiscountPerc = product?.[`discount_${pricelist}_f`] || false
+
+ // if (pricelistDiscount && pricelistDiscount > 0) priceDiscount = pricelistDiscount
+ // if (pricelistDiscountPerc && pricelistDiscountPerc > 0)
+ // discountPercentage = pricelistDiscountPerc
+
+ price = product?.[`price_${pricelist}_f`] || 0
+ }
+
+ if (product?.flashsale_id_i > 0) {
+ price = product?.flashsale_base_price_f || 0
+ priceDiscount = product?.flashsale_price_f || 0
+ discountPercentage = product?.flashsale_discount_f || 0
+ }
+
+ let productMapped = {
+ id: product.product_id_i || '',
+ image: product.image_s || '',
+ code: product.default_code_s || '',
+ name: product.name_s || '',
+ lowestPrice: { price, priceDiscount, discountPercentage },
+ variantTotal: product.variant_total_i || 0,
+ stockTotal: product.stock_total_f || 0,
+ weight: product.weight_f || 0,
+ manufacture: {},
+ categories: [],
+ flashSale: {
+ id: product?.flashsale_id_i,
+ name: product?.product?.flashsale_name_s,
+ tag : product?.flashsale_tag_s || 'FLASH SALE'
+ }
+ }
+
+ if (product.manufacture_id_i && product.manufacture_name_s) {
+ productMapped.manufacture = {
+ id: product.manufacture_id_i || '',
+ name: product.manufacture_name_s || ''
+ }
+ }
+
+ productMapped.categories = [
+ {
+ id: product.category_id_i || '',
+ name: product.category_name_s || ''
+ }
+ ]
+ return productMapped
+ })
+}*/
diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx
index aaee1249..92f5b7f8 100644
--- a/src/pages/shop/promo/[slug].tsx
+++ b/src/pages/shop/promo/[slug].tsx
@@ -2,30 +2,31 @@ import dynamic from 'next/dynamic'
import NextImage from 'next/image';
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
-import Seo from '../../../core/components/Seo'
-import Promocrumb from '../../../lib/promo/components/Promocrumb'
-import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi'
+import Seo from '../../../core/components/Seo.jsx'
+import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx'
+import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi.js'
import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx'
-import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card'
-import { IPromotion } from '../../../../src-migrate/types/promotion'
+import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx'
+import { IPromotion } from '../../../../src-migrate/types/promotion.ts'
import React from 'react'
import { SolrResponse } from "../../../../src-migrate/types/solr.ts";
-import DesktopView from '../../../core/components/views/DesktopView';
-import MobileView from '../../../core/components/views/MobileView';
+import DesktopView from '../../../core/components/views/DesktopView.jsx';
+import MobileView from '../../../core/components/views/MobileView.jsx';
import 'swiper/swiper-bundle.css';
-import useDevice from '../../../core/hooks/useDevice'
-import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion';
-import ProductFilter from '../../../lib/product/components/ProductFilter';
+import useDevice from '../../../core/hooks/useDevice.js'
+import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion.jsx';
+import ProductFilter from '../../../lib/product/components/ProductFilter.jsx';
import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react';
-import { formatCurrency } from '../../../core/utils/formatValue';
-import Pagination from '../../../core/components/elements/Pagination/Pagination';
-import SideBanner from '../../../../src-migrate/modules/side-banner';
-import whatsappUrl from '../../../core/utils/whatsappUrl';
+import { formatCurrency } from '../../../core/utils/formatValue.js';
+import Pagination from '../../../core/components/elements/Pagination/Pagination.js';
+import SideBanner from '../../../../src-migrate/modules/side-banner/index.tsx';
+import whatsappUrl from '../../../core/utils/whatsappUrl.js';
import { cons, toQuery } from 'lodash-contrib';
import _ from 'lodash';
-import useActive from '../../../core/hooks/useActive';
+import useActive from '../../../core/hooks/useActive.js';
+import useProductSearch from '../../../lib/product/hooks/useProductSearch.js';
-const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout'))
+const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx'))
export default function PromoDetail() {
const router = useRouter()
@@ -40,9 +41,39 @@ export default function PromoDetail() {
const [categories, setCategories] = useState<Category[]>([]);
const [brandValues, setBrandValues] = useState<string[]>([]);
const [categoryValues, setCategoryValues] = useState<string[]>([]);
- const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular');
+ const [orderBy, setOrderBy] = useState(router.query?.orderBy);
const popup = useActive();
const prefixUrl = `/shop/promo/${slug}`
+ const [queryFinal, setQueryFinal] = useState({});
+ const [limit, setLimit] = useState<number>(30);
+ const [q, setQ] = useState('**');
+ const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`});
+ const [products, setProducts] = useState(null);
+ useEffect(() => {
+ setQueryFinal({ ...finalQuery, q, limit, orderBy });
+}, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]);
+ useEffect(() => {
+ setQueryFinal({ ...finalQuery, q, limit, orderBy });
+ }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]);
+
+ const { productSearch } = useProductSearch({
+ query: queryFinal,
+ operation: 'OR',
+ });
+
+ console.log("productSearch",productSearch)
+ console.log("queryFinal",queryFinal)
+
+ const pageCount = Math.ceil(productSearch.data?.response.numFound / limit);
+ const productStart = productSearch.data?.responseHeader.params.start;
+ const productRows = limit;
+ const productFound = productSearch.data?.response.numFound;
+
+ useEffect(() => {
+ setProducts(productSearch.data?.response?.products);
+ }, [productSearch]);
+
+ console.log("products",products)
useEffect(() => {
if (router.query.brand) {
@@ -91,7 +122,7 @@ export default function PromoDetail() {
setCurrentPage(pageNumber)
try {
- const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`,0,100);
+ const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`,0,10);
setPromoItems(items);
if (items.length === 0) {
diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js
index fee474be..e93b0b54 100644
--- a/src/utils/solrMapping.js
+++ b/src/utils/solrMapping.js
@@ -1,3 +1,31 @@
+const map = (promotions) => {
+ const result = [];
+ for (const promotion of promotions) {
+ const data = {
+ id: promotion.id,
+ program_id: promotion.program_id_i,
+ name: promotion.name_s,
+ type: {
+ value: promotion.type_value_s,
+ label: promotion.type_label_s,
+ },
+ limit: promotion.package_limit_i,
+ limit_user: promotion.package_limit_user_i,
+ limit_trx: promotion.package_limit_trx_i,
+ price: promotion.price_f,
+ sequence: promotion.sequence_i,
+ total_qty: promotion.total_qty_i,
+ products: JSON.parse(promotion.products_s),
+ product_id: promotion.product_ids[0],
+ qty_sold_f:promotion.total_qty_sold_f,
+ free_products: JSON.parse(promotion.free_products_s),
+ };
+ result.push(data);
+ }
+ return result;
+};
+
+
export const productMappingSolr = (products, pricelist) => {
return products.map((product) => {
let price = product.price_tier1_v2_f || 0;
@@ -123,3 +151,4 @@ const flashsaleTime = (endDate) => {
isFlashSale: flashsaleEndDate > currentTime,
};
};
+