diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-11-28 10:47:43 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-11-28 10:47:43 +0700 |
| commit | 5bc7a6807847610b190ea9d5046021d2db15afc5 (patch) | |
| tree | e895b02c65bf97e3c6c970bb8d777922120f4570 /src/pages | |
| parent | 7ed3fd96322d08bd91434b8ec4dcbc542a610998 (diff) | |
| parent | 952421c810b53ec4d25ad5ef605bae1bd1d5d616 (diff) | |
Merge branch 'new-release' into Feature/switch-account
Diffstat (limited to 'src/pages')
23 files changed, 783 insertions, 187 deletions
diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index bcb41dd6..f52aa5f7 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -85,7 +85,7 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }) { return ( <SessionProvider session={session}> <ScrollToTop /> - + <AnimatePresence> {animateLoader && ( <motion.div diff --git a/src/pages/_document.jsx b/src/pages/_document.jsx index 6af6294f..4b67c3f9 100644 --- a/src/pages/_document.jsx +++ b/src/pages/_document.jsx @@ -115,6 +115,19 @@ export default function MyDocument() { }} /> + <Script + async + id='gtag-config' + strategy='afterInteractive' + dangerouslySetInnerHTML={{ + __html: ` + gtag('config', 'AW-954540379/fCU8CI3Y8OoZENvClMcD', { + 'phone_conversion_number': '(021) 29338828' + }); + `, + }} + /> + {/* <Script id='tawk-script-tag' strategy='afterInteractive' diff --git a/src/pages/api/banner-section.js b/src/pages/api/banner-section.js new file mode 100644 index 00000000..7d7040c0 --- /dev/null +++ b/src/pages/api/banner-section.js @@ -0,0 +1,44 @@ +import odooApi from '@/core/api/odooApi'; +import { createClient } from 'redis'; + +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + try { + await connectRedis(); + const cacheKey = 'hero-banner'; + // await client.del(cacheKey); + let cachedData = await client.get(cacheKey); + + if (cachedData) { + const data = JSON.parse(cachedData); + return res.status(200).json({ data }); + } else { + const dataBannerSections = await odooApi( + 'GET', + '/api/v1/banner?type=home-banner' + ); + + // Simpan hasil fetch ke Redis dengan masa kadaluarsa 3 hari (259200 detik) + await client.set( + cacheKey, + JSON.stringify(dataBannerSections), + 'EX', + 259200 + ); + + return res.status(200).json({ data: dataBannerSections }); + } + } catch (error) { + console.error('Error interacting with Redis or fetching data:', error); + return res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/api/category-management.js b/src/pages/api/category-management.js new file mode 100644 index 00000000..f05d8644 --- /dev/null +++ b/src/pages/api/category-management.js @@ -0,0 +1,85 @@ +import { createClient } from 'redis'; +// import { fetchCategoryManagementSolr } from '../../lib/home/api/categoryManagementApi'; +const client = createClient(); +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + try { + await connectRedis(); + // await client.del('homepage_categoryDynamic'); + + let cachedData; + if (req.method === 'GET') { + cachedData = await client.get('homepage_categoryDynamic'); + + if (!cachedData) { + const items = await fetchCategoryManagementSolr(); + await client.set( + 'homepage_categoryDynamic', + JSON.stringify(items), + 'EX', + 259200 // Expiry 3 hari + ); + cachedData = await client.get('homepage_categoryDynamic'); + } + const data = cachedData ? JSON.parse(cachedData) : null; + res.status(200).json({ data }); + } else { + res.setHeader('Allow', ['GET']); + res.status(405).end(`Method ${req.method} Not Allowed`); + } + } catch (error) { + console.error('Error interacting with Redis:', error); + res.status(500).json({ error: 'Error interacting with Redis' }); + } +} + +const fetchCategoryManagementSolr = async () => { + let sort = 'sort=sequence_i asc'; + try { + const response = await fetch( + `http://34.101.189.218:8983/solr/category_management/query?q=*:*&q.op=OR&indent=true&${sort}&&rows=20` + ); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + const promotions = await map(data.response.docs); + return promotions; + } catch (error) { + console.error('Error fetching promotion data:', error); + return []; + } +}; +const map = async (promotions) => { + return promotions.map((promotion) => { + let parsedCategories = promotion.categories.map((category) => { + // Parse string JSON utama + let parsedCategory = JSON.parse(category); + + // Parse setiap elemen di child_frontend_id_i jika ada + if (parsedCategory.child_frontend_id_i) { + parsedCategory.child_frontend_id_i = + parsedCategory.child_frontend_id_i.map((child) => JSON.parse(child)); + } + + return parsedCategory; + }); + let productMapped = { + id: promotion.id, + name: promotion.name_s, + image: promotion.image_s, + sequence: promotion.sequence_i, + numFound: promotion.numFound_i, + categories: parsedCategories, + category_id: promotion.category_id_i, + }; + return productMapped; + }); +}; diff --git a/src/pages/api/flashsale-header.js b/src/pages/api/flashsale-header.js new file mode 100644 index 00000000..31f8efdd --- /dev/null +++ b/src/pages/api/flashsale-header.js @@ -0,0 +1,40 @@ +import odooApi from '@/core/api/odooApi'; +import { createClient } from 'redis'; + +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + try { + await connectRedis(); + const cacheKey = `flashsale_header`; + // await client.del(cacheKey); + let cachedData = await client.get(cacheKey); + + if (cachedData) { + const data = JSON.parse(cachedData); + return res.status(200).json({ data }); + } else { + const flashSale = await odooApi('GET', `/api/v1/flashsale/header`); + + await client.set( + cacheKey, + JSON.stringify(flashSale), + 'EX', + flashSale.duration + ); + cachedData = await client.get(cacheKey); + return res.status(200).json({ data: cachedData }); + } + } catch (error) { + console.error('Error interacting with Redis or fetching data:', error); + return res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/api/hero-banner.js b/src/pages/api/hero-banner.js new file mode 100644 index 00000000..7a348cfa --- /dev/null +++ b/src/pages/api/hero-banner.js @@ -0,0 +1,45 @@ +import odooApi from '@/core/api/odooApi'; +import { createClient } from 'redis'; + +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + const { type } = req.query; + try { + await connectRedis(); + const cacheKey = `homepage_bannerSection_${type}`; + // await client.del(cacheKey); + let cachedData = await client.get(cacheKey); + + if (cachedData) { + const data = JSON.parse(cachedData); + return res.status(200).json({ data }); + } else { + const dataBannerSections = await odooApi( + 'GET', + `/api/v1/banner?type=${type}` + ); + + // Simpan hasil fetch ke Redis dengan masa kadaluarsa 3 hari (259200 detik) + await client.set( + cacheKey, + JSON.stringify(dataBannerSections), + 'EX', + 259200 + ); + cachedData = await client.get(cacheKey); + return res.status(200).json({ data: cachedData }); + } + } catch (error) { + console.error('Error interacting with Redis or fetching data:', error); + return res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/api/page-content.js b/src/pages/api/page-content.js new file mode 100644 index 00000000..a6514505 --- /dev/null +++ b/src/pages/api/page-content.js @@ -0,0 +1,43 @@ +import { createClient } from 'redis'; +import { getPageContent } from '~/services/pageContent'; +// import { fetchCategoryManagementSolr } from '../../lib/home/api/categoryManagementApi'; +const client = createClient(); +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + const { path } = req.query; + try { + await connectRedis(); + // await client.del('onbording-popup'); + + let cachedData; + if (req.method === 'GET') { + cachedData = await client.get(`page-content:${path}`); + + if (!cachedData) { + const items = await getPageContent({ path }); + await client.set( + `page-content:${path}`, + JSON.stringify(items), + 'EX', + 604800 // Expiry 1 minggu + ); + cachedData = await client.get(`page-content:${path}`); + } + const data = cachedData ? JSON.parse(cachedData) : null; + res.status(200).json({ data }); + } else { + res.setHeader('Allow', ['GET']); + res.status(405).end(`Method ${req.method} Not Allowed`); + } + } catch (error) { + console.error('Error interacting with Redis:', error); + res.status(500).json({ error: 'Error interacting with Redis' }); + } +} diff --git a/src/pages/api/search-flashsale.js b/src/pages/api/search-flashsale.js new file mode 100644 index 00000000..d9e56c83 --- /dev/null +++ b/src/pages/api/search-flashsale.js @@ -0,0 +1,45 @@ +import odooApi from '@/core/api/odooApi'; +import { createClient } from 'redis'; +import _ from 'lodash-contrib'; +import axios from 'axios'; + +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + const { query, operation, duration } = req.query; + try { + await connectRedis(); + const cacheKey = `flashsale_product`; + // await client.del(cacheKey); + let cachedData = await client.get(cacheKey); + + if (cachedData) { + const data = JSON.parse(cachedData); + return res.status(200).json({ data }); + } else { + const dataProductSearch = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}]` + ); + + await client.set( + cacheKey, + JSON.stringify(dataProductSearch.data), + 'EX', + duration + ); + cachedData = await client.get(cacheKey); + return res.status(200).json({ data: cachedData }); + } + } catch (error) { + console.error('Error interacting with Redis or fetching data:', error); + return res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/api/shop/brands.js b/src/pages/api/shop/brands.js index 9c2824b3..d56e4b13 100644 --- a/src/pages/api/shop/brands.js +++ b/src/pages/api/shop/brands.js @@ -1,8 +1,20 @@ import axios from 'axios'; +import { createClient } from 'redis'; const SOLR_HOST = process.env.SOLR_HOST; +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; export default async function handler(req, res) { + await connectRedis(); + try { let params = '*:*'; let sort = @@ -11,12 +23,12 @@ export default async function handler(req, res) { if (req.query.params) { rows = 100; - switch (req?.query?.params) { + switch (req.query.params) { case 'level_s': params = 'level_s:prioritas'; break; case 'search': - params = `name_s:"${req?.query?.q.toLowerCase()}"`; + params = `name_s:"${req.query.q.toLowerCase()}"`; sort = ''; rows = 1; break; @@ -24,11 +36,11 @@ export default async function handler(req, res) { params = `name_s:${req.query.params}`.toLowerCase(); } } - if(req.query.rows) rows = req.query.rows; - + if (req.query.rows) rows = req.query.rows; + const url = `${SOLR_HOST}/solr/brands/select?q=${params}&q.op=OR&indent=true&rows=${rows}&${sort}`; - let brands = await axios(url); - let dataBrands = responseMap(brands.data.response.docs); + const brands = await axios(url); + const dataBrands = responseMap(brands.data.response.docs); res.status(200).json(dataBrands); } catch (error) { @@ -39,13 +51,11 @@ export default async function handler(req, res) { const responseMap = (brands) => { return brands.map((brand) => { - let brandMapping = { + return { id: brand.id, name: brand.display_name_s, logo: brand.image_s || '', - sequance: brand.sequence_i || '', + sequence: brand.sequence_i || '', }; - - return brandMapping; }); }; diff --git a/src/pages/api/shop/preferredBrand.js b/src/pages/api/shop/preferredBrand.js new file mode 100644 index 00000000..4cb35c84 --- /dev/null +++ b/src/pages/api/shop/preferredBrand.js @@ -0,0 +1,61 @@ +import axios from 'axios'; +import { createClient } from 'redis'; + +const SOLR_HOST = process.env.SOLR_HOST; +const client = createClient(); + +client.on('error', (err) => console.error('Redis Client Error', err)); + +const connectRedis = async () => { + if (!client.isOpen) { + await client.connect(); + } +}; + +export default async function handler(req, res) { + await connectRedis(); + + try { + let params = '*:*'; + let sort = + 'sort=if(exists(sequence_i),0,1) asc,sequence_i asc, if(exists(image_s),0,1) asc '; + let rows = 20; + + if (req.query.params) { + rows = 20; + switch (req.query.params) { + case 'level_s': + params = 'level_s:prioritas'; + break; + case 'search': + params = `name_s:"${req.query.q.toLowerCase()}"`; + sort = ''; + rows = 1; + break; + default: + params = `name_s:${req.query.params}`.toLowerCase(); + } + } + if (req.query.rows) rows = req.query.rows; + + const url = `${SOLR_HOST}/solr/brands/select?q=${params}&q.op=OR&indent=true&rows=${rows}&${sort}`; + const brands = await axios(url); + const dataBrands = responseMap(brands.data.response.docs); + + res.status(200).json(dataBrands); + } catch (error) { + console.error('Error fetching data from Solr:', error); + res.status(500).json({ error: 'Internal Server Error' }); + } +} + +const responseMap = (brands) => { + return brands.map((brand) => { + return { + id: brand.id, + name: brand.display_name_s, + logo: brand.image_s || '', + sequence: brand.sequence_i || '', + }; + }); +}; diff --git a/src/pages/api/shop/product-detail.js b/src/pages/api/shop/product-detail.js index 247f2a04..faa96028 100644 --- a/src/pages/api/shop/product-detail.js +++ b/src/pages/api/shop/product-detail.js @@ -8,7 +8,7 @@ export default async function handler(req, res) { ) let productVariants = await axios( process.env.SOLR_HOST + - `/solr/variants/select?q=template_id_i:${req.query.id}&q.op=OR&indent=true&rows=100&fq=-publish_b:false` + `/solr/variants/select?q=template_id_i:${req.query.id}&q.op=OR&indent=true&rows=100&fq=-publish_b:false AND price_tier1_v2_f:[1 TO *]` ) let auth = req.query.auth === 'false' ? JSON.parse(req.query.auth) : req.query.auth let result = productMappingSolr(productTemplate.data.response.docs, auth || false) diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 6269d3ed..63ec7ca0 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -20,9 +20,11 @@ export default async function handler(req, res) { } = req.query; let { stock = '' } = req.query; - let paramOrderBy = ''; switch (orderBy) { + case 'flashsale-discount-desc': + paramOrderBy += 'flashsale_discount_f DESC'; + break; case 'price-asc': paramOrderBy += 'price_tier1_v2_f ASC'; break; @@ -68,16 +70,40 @@ export default async function handler(req, res) { let checkQ = q.trim().split(/[\s\+\-\!\(\)\{\}\[\]\^"~\*\?:\\\/]+/); let newQ = escapeSolrQuery(q); - const formattedQuery = `(${newQ.split(' ').map(term => `${term}*`).join(' ') })`; - const mm = checkQ.length > 2 ? checkQ.length > 5 ? '55%' : '85%' : `${checkQ.length}`; + const formattedQuery = `(${newQ + .split(' ') + .map((term) => (term.length < 2 ? term : `${term}*`)) // Tambahkan '*' hanya jika panjang kata >= 2 + .join(' ')})`; + + const mm = + checkQ.length > 2 + ? checkQ.length > 5 + ? '55%' + : '85%' + : `${checkQ.length}`; const filterQueries = [ '-publish_b:false', 'product_rating_f:[8 TO *]', - 'price_tier1_v2_f:[1 TO *]' + 'price_tier1_v2_f:[1 TO *]', ]; - - const fq_ = filterQueries.join('AND '); + + if (fq && source != 'similar' && typeof fq != 'string') { + // filterQueries.push(fq); + fq.push(...filterQueries); + } + const fq_ = filterQueries.join(' AND '); + + let keywords = newQ; + if (source === 'similar' || checkQ.length < 3) { + if (checkQ.length < 2 || checkQ[1].length < 2) { + keywords = newQ; + } else { + keywords = newQ + '*'; + } + } else { + keywords = formattedQuery; + } let offset = (page - 1) * limit; let parameter = [ @@ -87,9 +113,9 @@ export default async function handler(req, res) { 'indent=true', `facet.query=${escapeSolrQuery(q)}`, `q.op=OR`, - `q=${source == 'similar' || checkQ.length < 3 ? checkQ.length < 2 ? newQ : newQ + '*' : formattedQuery }`, + `q=${keywords}`, `defType=edismax`, - 'qf=name_s description_clean_t category_name manufacture_name_s variants_code_t variants_name_t category_id_ids default_code_s', + 'qf=name_s description_clean_t category_name manufacture_name_s variants_code_t variants_name_t category_id_ids default_code_s manufacture_id_i category_id_i ', `start=${parseInt(offset)}`, `rows=${limit}`, `sort=${paramOrderBy}`, @@ -135,12 +161,13 @@ export default async function handler(req, res) { if (typeof fq === 'string') parameter.push(`fq=${encodeURIComponent(fq)}`); // Multi fq in url params if (Array.isArray(fq)) - parameter = parameter.concat(fq.map((val) => `fq=${encodeURIComponent(val)}`)); - + parameter = parameter.concat( + fq.map((val) => `fq=${encodeURIComponent(val)}`) + ); let result = await axios( process.env.SOLR_HOST + '/solr/product/select?' + parameter.join('&') ); - + try { result.data.response.products = productMappingSolr( result.data.response.docs, diff --git a/src/pages/api/shop/url-category_brand.js b/src/pages/api/shop/url-category_brand.js new file mode 100644 index 00000000..160aa166 --- /dev/null +++ b/src/pages/api/shop/url-category_brand.js @@ -0,0 +1,20 @@ +import axios from 'axios'; + +export default async function handler(req, res) { + const { url = '', page = 1, limit = 30 } = req.query; + + let offset = (page - 1) * limit; + + const params = [`q.op=AND`, `q=${url ? `"${url}"` : '*'}`, `indent=true`, `rows=${limit}`, `start=${offset}`]; + + try { + let result = await axios( + process.env.SOLR_HOST + + `/solr/url_category_brand/select?` + + params.join('&') + ); + res.status(200).json(result.data); + } catch (error) { + res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/api/shop/variant-detail.js b/src/pages/api/shop/variant-detail.js index 08ce75b8..af3525b3 100644 --- a/src/pages/api/shop/variant-detail.js +++ b/src/pages/api/shop/variant-detail.js @@ -1,21 +1,28 @@ -import { productMappingSolr, variantsMappingSolr } from '@/utils/solrMapping' -import axios from 'axios' +import { productMappingSolr, variantsMappingSolr } from '@/utils/solrMapping'; +import axios from 'axios'; export default async function handler(req, res) { try { let productVariants = await axios( process.env.SOLR_HOST + `/solr/variants/select?q=id:${req.query.id}&q.op=OR&indent=true` - ) - let auth = req.query.auth === 'false' ? JSON.parse(req.query.auth) : req.query.auth + ); + let template_id = productVariants.data.response.docs[0].template_id_i; + let auth = + req.query.auth === 'false' ? JSON.parse(req.query.auth) : req.query.auth; let productTemplate = await axios( - process.env.SOLR_HOST + `/solr/product/select?q=id:${req.query.id}&q.op=OR&indent=true` - ) - let result = variantsMappingSolr(productTemplate.data.response.docs, productVariants.data.response.docs, auth || false) - - res.status(200).json(result) + process.env.SOLR_HOST + + `/solr/product/select?q=id:${template_id}&q.op=OR&indent=true` + ); + let result = variantsMappingSolr( + productTemplate.data.response.docs, + productVariants.data.response.docs, + auth || false + ); + + res.status(200).json(result); } catch (error) { - console.error('Error fetching data from Solr:', error) - res.status(500).json({ error: 'Internal Server Error' }) + console.error('Error fetching data from Solr:', error); + res.status(500).json({ error: 'Internal Server Error' }); } -}
\ No newline at end of file +} diff --git a/src/pages/garansi-resmi.jsx b/src/pages/garansi-resmi.jsx new file mode 100644 index 00000000..7384a89d --- /dev/null +++ b/src/pages/garansi-resmi.jsx @@ -0,0 +1,13 @@ +import Seo from '@/core/components/Seo' +import BasicLayout from '@/core/components/layouts/BasicLayout' +import IframeContent from '@/lib/iframe/components/IframeContent' + +export default function GaransiResmi() { + return ( + <BasicLayout> + <Seo title='Garansi Resmi - Indoteknik.com' /> + + <IframeContent url={`${process.env.NEXT_PUBLIC_ODOO_HOST}/content?url=garansi-resmi`} /> + </BasicLayout> + ) +} diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 6077c192..2ec1231a 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -1,21 +1,19 @@ -import dynamic from 'next/dynamic'; -import { useEffect, useRef, useState } from 'react'; import { HeroBannerSkeleton } from '@/components/skeleton/BannerSkeleton'; import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton'; +import odooApi from '@/core/api/odooApi'; import Seo from '@/core/components/Seo'; import DelayRender from '@/core/components/elements/DelayRender/DelayRender'; import DesktopView from '@/core/components/views/DesktopView'; import MobileView from '@/core/components/views/MobileView'; import { FlashSaleSkeleton } from '@/lib/flashSale/skeleton/FlashSaleSkeleton'; -import PreferredBrandSkeleton from '@/lib/home/components/Skeleton/PreferredBrandSkeleton'; import BannerPromoSkeleton from '@/lib/home/components/Skeleton/BannerPromoSkeleton'; -import PromotinProgram from '@/lib/promotinProgram/components/HomePage'; +import PreferredBrandSkeleton from '@/lib/home/components/Skeleton/PreferredBrandSkeleton'; +import dynamic from 'next/dynamic'; +import { useEffect, useRef, useState } from 'react'; +import { getAuth } from '~/libs/auth'; import PagePopupIformation from '~/modules/popup-information'; // need change to dynamic and ssr : false import CategoryPilihan from '../lib/home/components/CategoryPilihan'; -import odooApi from '@/core/api/odooApi'; -import { getAuth } from '~/libs/auth'; // import { getAuth } from '~/libs/auth'; -import useProductDetail from '~/modules/product-detail/stores/useProductDetail'; const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout'),{ssr: false} @@ -47,36 +45,38 @@ const FlashSale = dynamic( } ); -const ProgramPromotion = dynamic(() => - import('@/lib/home/components/PromotionProgram'), -{ - loading: () => <BannerPromoSkeleton />, -} +const ProgramPromotion = dynamic( + () => import('@/lib/home/components/PromotionProgram'), + { + loading: () => <BannerPromoSkeleton />, + } ); const BannerSection = dynamic(() => - import('@/lib/home/components/BannerSection'), {ssr: false} -); -const CategoryHomeId = dynamic(() => - import('@/lib/home/components/CategoryHomeId'), {ssr: false} + import('@/lib/home/components/BannerSection') +); +const CategoryHomeId = dynamic( + () => import('@/lib/home/components/CategoryHomeId'), + { ssr: false } ); const CategoryDynamic = dynamic(() => - import('@/lib/home/components/CategoryDynamic'), {ssr: false} + import('@/lib/home/components/CategoryDynamic') ); const CategoryDynamicMobile = dynamic(() => -import('@/lib/home/components/CategoryDynamicMobile'), {ssr: false} + import('@/lib/home/components/CategoryDynamicMobile') ); -const CustomerReviews = dynamic(() => - import('@/lib/review/components/CustomerReviews'), {ssr: false} +const CustomerReviews = dynamic( + () => import('@/lib/review/components/CustomerReviews'), + { ssr: false } ); // need to ssr:false -const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList'), {ssr: false}); // need to ssr: false +const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList'), { + ssr: false, +}); // need to ssr: false - - -export default function Home({categoryId}) { +export default function Home({ categoryId }) { const bannerRef = useRef(null); const wrapperRef = useRef(null); @@ -87,123 +87,110 @@ export default function Home({categoryId}) { bannerRef.current?.querySelector(':first-child')?.clientHeight + 'px'; }; - useEffect(() => { - const loadCategories = async () => { - const getCategories = await odooApi('GET', '/api/v1/category/child?partner_id='+{categoryId}) - if(getCategories){ - setDataCategories(getCategories) - } - } - loadCategories() - }, []) - - const [dataCategories, setDataCategories] = useState([]) return ( <> - <BasicLayout> - <Seo - title='Indoteknik.com: B2B Industrial Supply & Solution' - description='Temukan pilihan produk B2B Industri & Alat Teknik untuk Perusahaan, UMKM & Pemerintah dengan lengkap, mudah dan transparan.' - additionalMetaTags={[ - { - name: 'keywords', - content: 'indoteknik, indoteknik.com, toko teknik, toko perkakas, jual genset, jual fogging, jual krisbow, harga krisbow, harga alat safety, harga pompa air', - }, - ]} /> - - <PagePopupIformation /> - - <DesktopView> - <div className='container mx-auto'> - <div - className='flex min-h-[400px] h-[460px]' - ref={wrapperRef} - onLoad={handleOnLoad} - > - <div className='w-2/12'> - <HeroBannerSecondary /> - </div> - <div className='w-7/12 px-1' ref={bannerRef}> - <HeroBanner /> - </div> - <div className='w-3/12'> - <DelayRender renderAfter={200}> - <PopularProduct /> - </DelayRender> + <BasicLayout> + <Seo + title='Indoteknik.com: B2B Industrial Supply & Solution' + description='Temukan pilihan produk B2B Industri & Alat Teknik untuk Perusahaan, UMKM & Pemerintah dengan lengkap, mudah dan transparan.' + additionalMetaTags={[ + { + name: 'keywords', + content: + 'indoteknik, indoteknik.com, toko teknik, toko perkakas, jual genset, jual fogging, jual krisbow, harga krisbow, harga alat safety, harga pompa air', + }, + ]} + /> + + <PagePopupIformation /> + + <DesktopView> + <div className='container mx-auto'> + <div + className='flex min-h-[400px] h-[460px]' + ref={wrapperRef} + onLoad={handleOnLoad} + > + <div className='w-2/12'> + <HeroBannerSecondary /> + </div> + <div className='w-7/12 px-1' ref={bannerRef}> + <HeroBanner /> + </div> + <div className='w-3/12'> + <DelayRender renderAfter={200}> + <PopularProduct /> + </DelayRender> + </div> </div> - </div> - <div className='my-16 flex flex-col gap-y-8'> - <ServiceList /> - <div id='flashsale'> - <PreferredBrand /> + <div className='my-16 flex flex-col gap-y-8'> + <ServiceList /> + <div id='flashsale'> + <PreferredBrand /> + </div> + {!auth?.feature?.soApproval && ( + <> + <DelayRender renderAfter={200}> + <ProgramPromotion /> + </DelayRender> + <DelayRender renderAfter={200}> + <FlashSale /> + </DelayRender> + </> + )} + {/* <PromotinProgram /> */} + <CategoryPilihan /> + <CategoryDynamic /> + <CategoryHomeId /> + <BannerSection /> + <CustomerReviews /> </div> + </div> + </DesktopView> + <MobileView> + <DelayRender renderAfter={200}> + <HeroBanner /> + </DelayRender> + <div className='flex flex-col gap-y-4 my-6'> + <DelayRender renderAfter={400}> + <ServiceList /> + </DelayRender> + <DelayRender renderAfter={400}> + <div id='flashsale'> + <PreferredBrand /> + </div> + </DelayRender> {!auth?.feature?.soApproval && ( <> - <DelayRender renderAfter={200}> - <ProgramPromotion /> - </DelayRender> - <DelayRender renderAfter={200}> - <FlashSale /> - </DelayRender> + <DelayRender renderAfter={400}> + <ProgramPromotion /> + </DelayRender> + <DelayRender renderAfter={600}> + <FlashSale /> + </DelayRender> </> )} - {/* <PromotinProgram /> */} - {dataCategories &&( - <CategoryPilihan categories={dataCategories} /> - )} - <CategoryDynamic /> - <CategoryHomeId /> - <BannerSection /> - <CustomerReviews /> + <DelayRender renderAfter={600}> + {/* <PromotinProgram /> */} + </DelayRender> + <DelayRender renderAfter={600}> + <CategoryPilihan /> + <CategoryDynamicMobile /> + </DelayRender> + <DelayRender renderAfter={800}> + <PopularProduct /> + </DelayRender> + <DelayRender renderAfter={1000}> + <CategoryHomeId /> + <BannerSection /> + </DelayRender> + <DelayRender renderAfter={1200}> + <CustomerReviews /> + </DelayRender> </div> - </div> - </DesktopView> - <MobileView> - <DelayRender renderAfter={200}> - <HeroBanner /> - </DelayRender> - <div className='flex flex-col gap-y-4 my-6'> - <DelayRender renderAfter={400}> - <ServiceList /> - </DelayRender> - <DelayRender renderAfter={400}> - <div id='flashsale'> - <PreferredBrand /> - </div> - </DelayRender> - {!auth?.feature?.soApproval && ( - <> - <DelayRender renderAfter={400}> - <ProgramPromotion /> - </DelayRender> - <DelayRender renderAfter={600}> - <FlashSale /> - </DelayRender> - </> - )} - <DelayRender renderAfter={600}> - {/* <PromotinProgram /> */} - </DelayRender> - <DelayRender renderAfter={600}> - {dataCategories &&( - <CategoryPilihan categories={dataCategories} /> - )} - <CategoryDynamicMobile /> - </DelayRender> - <DelayRender renderAfter={800}> - <PopularProduct /> - </DelayRender> - <DelayRender renderAfter={1000}> - <CategoryHomeId /> - <BannerSection /> - </DelayRender> - <DelayRender renderAfter={1200}> - <CustomerReviews /> - </DelayRender> - </div> - </MobileView> - </BasicLayout> - </> + </MobileView> + </BasicLayout> + </> ); -}
\ No newline at end of file +} diff --git a/src/pages/my/address/[id]/edit.jsx b/src/pages/my/address/[id]/edit.jsx index c552659b..19d7af41 100644 --- a/src/pages/my/address/[id]/edit.jsx +++ b/src/pages/my/address/[id]/edit.jsx @@ -37,12 +37,15 @@ export async function getServerSideProps(context) { mobile: address.mobile, street: address.street, zip: address.zip, - city: address.city?.id || '', + state: address.stateId?.id || '', + oldCity: address.city?.id || '', + city: '', oldDistrict: address.district?.id || '', district: '', oldSubDistrict: address.subDistrict?.id || '', subDistrict: '', business_name: '', }; + // console.log('ini default',defaultValues); return { props: { id, defaultValues } }; } diff --git a/src/pages/pembayaran-tempo.jsx b/src/pages/pembayaran-tempo.jsx new file mode 100644 index 00000000..363e3099 --- /dev/null +++ b/src/pages/pembayaran-tempo.jsx @@ -0,0 +1,13 @@ +import Seo from '@/core/components/Seo' +import BasicLayout from '@/core/components/layouts/BasicLayout' +import IframeContent from '@/lib/iframe/components/IframeContent' + +export default function PembnayaranTempo() { + return ( + <BasicLayout> + <Seo title='Pambayaran Tempo - Indoteknik.com' /> + + <IframeContent url={`${process.env.NEXT_PUBLIC_ODOO_HOST}/content?url=pembayaran-tempo`} /> + </BasicLayout> + ) +} diff --git a/src/pages/shop/checkout/[status].jsx b/src/pages/shop/checkout/[status].jsx index 2c3bebcf..0d5cffe8 100644 --- a/src/pages/shop/checkout/[status].jsx +++ b/src/pages/shop/checkout/[status].jsx @@ -1,22 +1,22 @@ -import BasicLayout from '@/core/components/layouts/BasicLayout' -import IsAuth from '@/lib/auth/components/IsAuth' -import FinishCheckoutComponent from '@/lib/checkout/components/FinishCheckout' -import { useRouter } from 'next/router' -import axios from 'axios' -import Seo from '@/core/components/Seo' +import BasicLayout from '@/core/components/layouts/BasicLayout'; +import IsAuth from '@/lib/auth/components/IsAuth'; +import FinishCheckoutComponent from '@/lib/checkout/components/FinishCheckout'; +import { useRouter } from 'next/router'; +import axios from 'axios'; +import Seo from '@/core/components/Seo'; export async function getServerSideProps(context) { - const { order_id } = context.query + const { order_id } = context.query; await axios.post( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/finish-checkout?orderName=${order_id}`, {}, { headers: context.req.headers } - ) - return { props: {} } + ); + return { props: {} }; } export default function Finish() { - const router = useRouter() + const router = useRouter(); return ( <> @@ -28,5 +28,5 @@ export default function Finish() { </BasicLayout> </IsAuth> </> - ) + ); } diff --git a/src/pages/shop/find/[slug].jsx b/src/pages/shop/find/[slug].jsx new file mode 100644 index 00000000..268b1e56 --- /dev/null +++ b/src/pages/shop/find/[slug].jsx @@ -0,0 +1,69 @@ +import axios from 'axios'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import Seo from '@/core/components/Seo'; +import dynamic from 'next/dynamic'; +import { get } from 'lodash-contrib'; +import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug'; +import { capitalizeEachWord } from '../../../utils/capializeFIrstWord'; + +const BasicLayout = dynamic(() => + import('@/core/components/layouts/BasicLayout') +); +const ProductSearch = dynamic(() => + import('@/lib/product/components/ProductSearch') +); + +const BASE_URL = 'https://indoteknik.com'; +export default function FindPage() { + const route = useRouter(); + const qSlug = route?.query?.slug || null; + const url = BASE_URL + route.asPath.split('?')[0]; + const [result, setResult] = useState(null); + const [query, setQuery] = useState(null); + + const __slug = qSlug ? getNameFromSlug(route?.query?.slug) +' '+ getIdFromSlug(route?.query?.slug) : ''; + const slug = capitalizeEachWord(__slug); + + const getUrls = async (url) => { + try { + let response = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/url-category_brand?url=${url}` + ); + let result = response?.data?.response?.docs[0] || null; + setResult(result); + } catch (error) { + console.error('Error fetching data:', error); + } + }; + + useEffect(() => { + getUrls(url); + }, []); + + useEffect(() => { + if (result) { + let fq = `category_parent_ids:${result.category_id_i} AND manufacture_id_i:${result.brand_id_i}`; + setQuery({ + fq: fq, + }); + } + }, [result]); + + return ( + <BasicLayout> + <Seo + title={`Beli ${slug} Original & Harga Terjangkau - indoteknik.com`} + description={`Beli ${slug} Kirim Jakarta Surabaya Semarang Makassar Manado Denpasar Balikpapan Medan Palembang Lampung Bali Bandung Makassar Manado.`} + additionalMetaTags={[ + { + property: 'keywords', + content: `Beli ${slug}, harga ${slug}, ${slug} murah, toko ${slug}, ${slug} jakarta, ${slug} surabaya`, + + }, + ]} + /> + {query && <ProductSearch query={query} prefixUrl={`${route.asPath}`} />} + </BasicLayout> + ); +} diff --git a/src/pages/shop/product/variant/[slug].jsx b/src/pages/shop/product/variant/[slug].jsx index 42f38774..2c0dd64b 100644 --- a/src/pages/shop/product/variant/[slug].jsx +++ b/src/pages/shop/product/variant/[slug].jsx @@ -32,16 +32,9 @@ export async function getServerSideProps(context) { tier ); let product = response.data; - // let product = await variantApi({ id: getIdFromSlug(slug), headers: { Token: authToken } }) if (product?.length == 1) { product = product[0]; - /* const regexHtmlTags = /(<([^>]+)>)/gi - const regexHtmlTagsExceptP = /<\/?(?!p\b)[^>]*>/g - product.description = product.description - .replace(regexHtmlTagsExceptP, ' ') - .replace(regexHtmlTags, ' ') - .trim()*/ } else { product = null; } diff --git a/src/pages/sitemap/categories-brand.xml.js b/src/pages/sitemap/categories-brand.xml.js new file mode 100644 index 00000000..b23363e9 --- /dev/null +++ b/src/pages/sitemap/categories-brand.xml.js @@ -0,0 +1,35 @@ +import productSearchApi from '@/lib/product/api/productSearchApi' +import { create } from 'xmlbuilder' +import _ from 'lodash-contrib' +import axios from 'axios' + +export async function getServerSideProps({ res }) { + const baseUrl = process.env.SELF_HOST + '/sitemap/categories-brand' + const limit = 500 + const categories = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/url-category_brand?limit=${limit}` + ) + const pageCount = Math.ceil(categories.data.response.numFound / limit) + const pages = Array.from({ length: pageCount }, (_, i) => i + 1) + const sitemapIndex = create('sitemapindex', { encoding: 'UTF-8' }).att( + 'xmlns', + 'http://www.sitemaps.org/schemas/sitemap/0.9' + ) + + const date = new Date() + pages.forEach((page) => { + const sitemap = sitemapIndex.ele('sitemap') + sitemap.ele('loc', `${baseUrl}/${page}.xml`) + sitemap.ele('lastmod', date.toISOString().slice(0, 10)) + }) + + res.setHeader('Content-Type', 'text/xml') + res.write(sitemapIndex.end()) + res.end() + + return { props: {} } +} + +export default function SitemapProducts() { + return null +} diff --git a/src/pages/sitemap/categories-brand/[page].js b/src/pages/sitemap/categories-brand/[page].js new file mode 100644 index 00000000..6b55e426 --- /dev/null +++ b/src/pages/sitemap/categories-brand/[page].js @@ -0,0 +1,43 @@ + +import productSearchApi from '@/lib/product/api/productSearchApi' +import { create } from 'xmlbuilder' +import _ from 'lodash-contrib' +import { createSlug } from '@/core/utils/slug' +import axios from 'axios' + +export async function getServerSideProps({ query, res }) { + const baseUrl = process.env.SELF_HOST + '/shop/product/' + const { page } = query + const limit = 500 + const categories = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/url-category_brand?limit=${limit}&page=${page.replace( + '.xml', + '' + )}` + ) + + const sitemap = create('urlset', { encoding: 'utf-8' }).att( + 'xmlns', + 'http://www.sitemaps.org/schemas/sitemap/0.9' + ) + + const date = new Date() + categories.data.response.docs.forEach((product) => { + const url = sitemap.ele('url') + const loc = product.url_s; + url.ele('loc', loc) + url.ele('lastmod', date.toISOString().slice(0, 10)) + url.ele('changefreq', 'daily') + url.ele('priority', '0.8') + }) + + res.setHeader('Content-Type', 'text/xml') + res.write(sitemap.end()) + res.end() + + return { props: {} } +} + +export default function SitemapProducts() { + return null +} |
