diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/pages/api/shop/search.js | 36 | ||||
| -rw-r--r-- | src/pages/api/shop/searchkey.js | 38 | ||||
| -rw-r--r-- | src/pages/searchkey/[slug].jsx | 75 | ||||
| -rw-r--r-- | src/pages/sitemap/searchkey.xml.js | 37 | ||||
| -rw-r--r-- | src/pages/sitemap/searchkey/[page].js | 42 |
5 files changed, 228 insertions, 0 deletions
diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 42d16100..d60b9a46 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -210,6 +210,42 @@ export default async function handler(req, res) { fq.map((val) => `fq=${encodeURIComponent(val)}`) ); + // Searchkey + if (req.query.from === 'searchkey') { + const ids = req.query.ids ? req.query.ids.split(',').filter(Boolean) : []; + + const q = ids.map((id) => `product_id_i:${id}`).join(' OR '); + + const strictQuery = [ + `q=${encodeURIComponent(q)}`, + `fq=-publish_b:false AND price_tier1_v2_f:[1 TO *] AND product_rating_f:[8 TO *]`, + // `qf=variants_code_t variants_name_t`, + `rows=${limit}`, + `start=${offset}`, + ]; + + const solrUrl = + process.env.SOLR_HOST + '/solr/product/select?' + strictQuery.join('&'); + + console.log('[SEARCHKEY FINAL QUERY]', solrUrl); + + const result = await axios(solrUrl); + + try { + result.data.response.products = productMappingSolr( + result.data.response.docs, + auth?.pricelist || false + ); + + delete result.data.response.docs; + result.data = camelcaseObjectDeep(result.data); + + return res.status(200).json(result.data); + } catch (e) { + return res.status(400).json({ error: e.message }); + } + } + const solrUrl = process.env.SOLR_HOST + '/solr/product/select?' + parameter.join('&'); diff --git a/src/pages/api/shop/searchkey.js b/src/pages/api/shop/searchkey.js new file mode 100644 index 00000000..2735e72c --- /dev/null +++ b/src/pages/api/shop/searchkey.js @@ -0,0 +1,38 @@ +import axios from 'axios'; + +export default async function handler(req, res) { + const { url = '', page = 1, limit = 30 } = req.query; + + let q = '*:*'; + + if (!req.query.all) { + const url = (req.query.q || '').trim(); + q = `keywords_s:"${url}"`; + } + let offset = (page - 1) * limit; + + const params = [ + `q.op=AND`, + // `q=keywords_s:"${url}"`, + `q=${q}`, + `indent=true`, + `rows=${limit}`, + `start=${offset}`, + ]; + + try { + // let result = await axios( + // process.env.SOLR_HOST + `/solr/searchkey/select?` + params.join('&') + // ); + let result = await axios.post( + process.env.SOLR_HOST + `/solr/searchkey/select`, + params.join('&'), + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } + ); + + console.log(result.data); + res.status(200).json(result.data); + } catch (error) { + res.status(500).json({ error: 'Internal Server Error' }); + } +} diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx new file mode 100644 index 00000000..3ebf6469 --- /dev/null +++ b/src/pages/searchkey/[slug].jsx @@ -0,0 +1,75 @@ +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 { 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') +); + +export default function FindPage() { + const route = useRouter(); + const [result, setResult] = useState(null); + const [query, setQuery] = useState(null); + + const slugRaw = route.query.slug || null; + console.log(slugRaw); + + // const cleanKey = slugRaw ? getNameFromSlug(slugRaw) : ''; + // console.log(cleanKey); + const readableSlug = capitalizeEachWord(slugRaw); + + const getSearchKeyData = async (clean) => { + try { + const res = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${clean}&from=searchkey` + ); + + setResult(res?.data?.response?.docs?.[0] || null); + } catch (e) { + console.error('Fetching searchkey failed:', e); + } + }; + + useEffect(() => { + if (!route.isReady) return; + if (!slugRaw) return; + + getSearchKeyData(slugRaw); + }, [route.isReady, slugRaw]); + + useEffect(() => { + if (result) { + const ids = result.product_ids_is || []; + + setQuery({ + ids: ids.join(','), + from: 'searchkey', + }); + } + }, [result]); + + return ( + <BasicLayout> + <Seo + title={`Beli ${readableSlug} Original & Harga Terjangkau - indoteknik.com`} + description={`Beli ${readableSlug} Kirim Jakarta Surabaya Semarang Makassar Manado Denpasar.`} + additionalMetaTags={[ + { + property: 'keywords', + content: `Beli ${readableSlug}, harga ${readableSlug}, ${readableSlug} murah`, + }, + ]} + canonical={`${process.env.NEXT_PUBLIC_SELF_HOST}${route.asPath}`} + /> + + {query && <ProductSearch query={query} prefixUrl={route.asPath} />} + </BasicLayout> + ); +} diff --git a/src/pages/sitemap/searchkey.xml.js b/src/pages/sitemap/searchkey.xml.js new file mode 100644 index 00000000..488337d3 --- /dev/null +++ b/src/pages/sitemap/searchkey.xml.js @@ -0,0 +1,37 @@ +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/searchkey'; + const limit = 500; + const keywords = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?limit=${limit}&all=1` + ); + // console.log(keywords); + const pageCount = Math.ceil(keywords.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(); + // const date = '2025-10-30'; + 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/searchkey/[page].js b/src/pages/sitemap/searchkey/[page].js new file mode 100644 index 00000000..cee53f5e --- /dev/null +++ b/src/pages/sitemap/searchkey/[page].js @@ -0,0 +1,42 @@ +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 keywords = await axios( + `${ + process.env.NEXT_PUBLIC_SELF_HOST + }/api/shop/searchkey?limit=${limit}&page=${page.replace('.xml', '')}&all=1` + ); + + const sitemap = create('urlset', { encoding: 'utf-8' }).att( + 'xmlns', + 'http://www.sitemaps.org/schemas/sitemap/0.9' + ); + + const date = new Date(); + // const date = '2025-10-30'; + keywords.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; +} |
