From 3f849355048e5c280a35a5747577e5296b90e9fd Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Thu, 25 Jan 2024 15:27:27 +0700 Subject: Add all promo page --- .../components/elements/Navbar/NavbarDesktop.jsx | 18 +++++----- src/pages/shop/promo/index.jsx | 38 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 src/pages/shop/promo/index.jsx (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 9bcd4df2..2605acbb 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -167,6 +167,14 @@ const NavbarDesktop = () => {
+ + Semua Promo + { target='_blank' rel='noreferrer noopener' > - Blog Indoteknik - - - Indoteknik TV + Blog
diff --git a/src/pages/shop/promo/index.jsx b/src/pages/shop/promo/index.jsx new file mode 100644 index 00000000..0d831c21 --- /dev/null +++ b/src/pages/shop/promo/index.jsx @@ -0,0 +1,38 @@ +import BasicLayout from '@/core/components/layouts/BasicLayout'; +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react'; +import Link from 'next/link'; +import Promo from '~/pages/shop/promo'; + +import React from 'react'; + +const PromoPage = () => { + return ( + +
+ + + + Home + + + + + + Semua Promo + + + + +
+ + +
+ + ); +}; + +export default PromoPage; -- cgit v1.2.3 From 65377952fbd0721ce1550c42384d723ccd7b9b1a Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Fri, 1 Mar 2024 09:20:11 +0700 Subject: generate recomendation --- .../elements/Navbar/NavbarUserDropdown.jsx | 5 ++ src/pages/my/recomendation/api/recomendation.js | 8 +++ .../components/products-recomendatison.jsx | 65 ++++++++++++++++++++++ src/pages/my/recomendation/index.jsx | 26 +++++++++ 4 files changed, 104 insertions(+) create mode 100644 src/pages/my/recomendation/api/recomendation.js create mode 100644 src/pages/my/recomendation/components/products-recomendatison.jsx create mode 100644 src/pages/my/recomendation/index.jsx (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx index 1851ce84..42bdc12a 100644 --- a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx +++ b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx @@ -2,9 +2,11 @@ import { deleteAuth } from '@/core/utils/auth' import Link from '../Link/Link' import { useRouter } from 'next/router' import { signOut, useSession } from 'next-auth/react' +import useAuth from '@/core/hooks/useAuth' const NavbarUserDropdown = () => { const router = useRouter() + const atuh = useAuth() const logout = async () => { deleteAuth().then(() => { @@ -21,6 +23,9 @@ const NavbarUserDropdown = () => { Invoice & Faktur Pajak Wishlist Daftar Alamat + {!atuh?.external && + Dashboard Recomendation + } diff --git a/src/pages/my/recomendation/api/recomendation.js b/src/pages/my/recomendation/api/recomendation.js new file mode 100644 index 00000000..47ed743a --- /dev/null +++ b/src/pages/my/recomendation/api/recomendation.js @@ -0,0 +1,8 @@ +import axios from "axios" + +const GenerateRecomendations = async ({query}) => { + const GenerateRecomendationProducts = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/recomendation?${query}`) + + return GenerateRecomendationProducts +} +export default GenerateRecomendations \ No newline at end of file diff --git a/src/pages/my/recomendation/components/products-recomendatison.jsx b/src/pages/my/recomendation/components/products-recomendatison.jsx new file mode 100644 index 00000000..9438eb46 --- /dev/null +++ b/src/pages/my/recomendation/components/products-recomendatison.jsx @@ -0,0 +1,65 @@ +import Menu from '@/lib/auth/components/Menu'; +import { cons } from 'lodash-contrib'; + +const ProductsRecomendation = ({ id }) => { + const handleSubmit = () => {} + const handleFileChange = () => {} + return ( +
+
+ +
+
+
+

+ Generate Recomendation +

+
+
+

Contoh Excel

+ + + + + + + + + + + + + +
ProductQty
Tekiro Long Nose Pliers Tang Lancip10
+
+
+
+
+ + +
+ +
+
+
+
+ ); +}; + +export default ProductsRecomendation; diff --git a/src/pages/my/recomendation/index.jsx b/src/pages/my/recomendation/index.jsx new file mode 100644 index 00000000..684b30c2 --- /dev/null +++ b/src/pages/my/recomendation/index.jsx @@ -0,0 +1,26 @@ +import DesktopView from '@/core/components/views/DesktopView'; +import MobileView from '@/core/components/views/MobileView'; +import IsAuth from '../../../lib/auth/components/IsAuth'; +import AppLayout from '@/core/components/layouts/AppLayout'; +import BasicLayout from '@/core/components/layouts/BasicLayout'; +import dynamic from 'next/dynamic'; +import Seo from '@/core/components/Seo' + +const ProductsRecomendation = dynamic(() => import('./components/products-recomendatison')) +export default function MyRecomendation() { + return ( + + + + + + + + + + + + + + ); +} -- cgit v1.2.3 From d0d38a82bb3d368632243ffb1cd317bb41cb13a3 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 6 Mar 2024 11:01:09 +0700 Subject: import excel --- .../components/products-recomendatison.jsx | 36 +++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pages/my/recomendation/components/products-recomendatison.jsx b/src/pages/my/recomendation/components/products-recomendatison.jsx index 9438eb46..c20aaa5b 100644 --- a/src/pages/my/recomendation/components/products-recomendatison.jsx +++ b/src/pages/my/recomendation/components/products-recomendatison.jsx @@ -1,9 +1,32 @@ import Menu from '@/lib/auth/components/Menu'; -import { cons } from 'lodash-contrib'; +import { useState } from 'react'; +import * as XLSX from 'xlsx'; const ProductsRecomendation = ({ id }) => { - const handleSubmit = () => {} - const handleFileChange = () => {} + const [excelData, setExcelData] = useState(null); + + const handleSubmit = (e) => { + e.preventDefault(); + if (excelData) { + // Lakukan operasi pencarian atau operasi lainnya di sini + console.log('ini data excel',excelData); // Contoh: Menampilkan data excel ke konsol + } else { + console.log('No excel data available'); + } + }; + const handleFileChange = (e) => { + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (event) => { + const data = new Uint8Array(event.target.result); + const workbook = XLSX.read(data, { type: 'array' }); + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1, range: 1 }); + setExcelData(jsonData); + }; + reader.readAsArrayBuffer(file); + }; return (
@@ -33,12 +56,9 @@ const ProductsRecomendation = ({ id }) => {
-
+
-
+ setOtherRec(false)} + className='w-full md:!w-[60%]' + title='Other Recomendations' + > +
+ + + + + + + + + + + + + {variantsOpen?.map((variant, index) => ( + + + + + + + ))} + +
ProductItem Code DescriptionBrandPriceImage
{variant.code}{variant.attributes.join(', ') || '-'} + {variant.price.discountPercentage > 0 && ( +
+
+ {Math.floor(variant.price.discountPercentage)}% +
+
+ Rp {formatCurrency(variant.price.price)} +
+
+ )} + {variant.price.priceDiscount > 0 && + `Rp ${formatCurrency(variant.price.priceDiscount)}`} + {variant.price.priceDiscount === 0 && '-'} +
+ +
+
+
@@ -216,10 +309,10 @@ const ProductsRecomendation = ({ id }) => { Product - Item code - Keterangan + Item Code + Description Brand - Harga + Price Image lainnya @@ -284,7 +377,19 @@ const ProductsRecomendation = ({ id }) => { '-' )} - + + {' '} + + ))} -- cgit v1.2.3 From 463a051646fe1dc70bebd05359381c393b951fff Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Thu, 2 May 2024 09:30:54 +0700 Subject: hotfix - validate stepapproval on mobile version --- src/lib/transaction/components/Transaction.jsx | 124 +++++++++++++++---------- 1 file changed, 77 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx index 8f4b2038..b68bb4cd 100644 --- a/src/lib/transaction/components/Transaction.jsx +++ b/src/lib/transaction/components/Transaction.jsx @@ -37,8 +37,8 @@ import rejectApi from '../api/rejectApi'; const Transaction = ({ id }) => { const auth = useAuth(); const { transaction } = useTransaction({ id }); - - const statusApprovalWeb = transaction.data?.approvalStep + + const statusApprovalWeb = transaction.data?.approvalStep; const { queryAirwayBill } = useAirwayBill({ orderId: id }); const [airwayBillPopup, setAirwayBillPopup] = useState(null); @@ -78,7 +78,7 @@ const Transaction = ({ id }) => { const closeCancelTransaction = () => setCancelTransaction(false); const [rejectTransaction, setRejectTransaction] = useState(false); - + const openRejectTransaction = () => setRejectTransaction(true); const closeRejectTransaction = () => setRejectTransaction(false); const submitCancelTransaction = async () => { @@ -106,13 +106,13 @@ const Transaction = ({ id }) => { await aprpoveApi({ id }); toast.success('Berhasil melanjutkan approval'); transaction.refetch(); - } + }; const handleReject = async () => { - await rejectApi({ id }); - closeRejectTransaction() - transaction.refetch(); - } + await rejectApi({ id }); + closeRejectTransaction(); + transaction.refetch(); + }; const memoizeVariantGroupCard = useMemo( () => ( @@ -238,7 +238,13 @@ const Transaction = ({ id }) => {
- + {auth?.feature?.soApproval && ( + + )}
@@ -359,33 +365,43 @@ const Transaction = ({ id }) => {
- {transaction.data?.status == 'draft' && auth?.feature.soApproval && ( -
- - + +
+ )} + {transaction.data?.status == 'draft' && + !auth?.feature?.soApproval && ( + -
- )} - {transaction.data?.status == 'draft' && !auth?.feature?.soApproval && ( - - )} + )} {transaction.data?.status == 'draft' && - auth?.feature?.soApproval && auth?.webRole && ( + auth?.feature?.soApproval && + auth?.webRole && (
)} - {transaction.data?.status != 'draft' && !auth?.feature.soApproval && ( - - )} + {transaction.data?.status != 'draft' && + !auth?.feature.soApproval && ( + + )}
-- cgit v1.2.3 From 1bb3f91f27db4db6a16a1ed3fe59016268ba3d44 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 8 May 2024 13:23:10 +0700 Subject: change wa number --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 2 +- src/core/utils/whatsappUrl.js | 2 +- src/lib/checkout/components/Checkout.jsx | 2 +- src/lib/checkout/components/CheckoutOld.jsx | 2 +- src/lib/checkout/components/CheckoutSection.jsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index d2f73d2d..308f2623 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -142,7 +142,7 @@ const NavbarDesktop = () => { />
Whatsapp
- 0812 8080 622 (Chat) + 0817 1718 1922 (Chat)
diff --git a/src/core/utils/whatsappUrl.js b/src/core/utils/whatsappUrl.js index 9a92f424..7a129aa6 100644 --- a/src/core/utils/whatsappUrl.js +++ b/src/core/utils/whatsappUrl.js @@ -7,7 +7,7 @@ const whatsappUrl = (template = 'default', payload, urlPath = null) => { if(!urlPath) return '/login' } let parentName = user.parentName || '-' - let url = 'https://wa.me/628128080622' + let url = 'https://wa.me/6281717181922' let text = 'Hallo Indoteknik.com,' switch (template) { case 'product': diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 7a456d70..0090acee 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1454,7 +1454,7 @@ const SectionExpedisi = ({ dengan menghubungi admin melalui{' '} tautan ini diff --git a/src/lib/checkout/components/CheckoutOld.jsx b/src/lib/checkout/components/CheckoutOld.jsx index d57fbd66..e2c45ce6 100644 --- a/src/lib/checkout/components/CheckoutOld.jsx +++ b/src/lib/checkout/components/CheckoutOld.jsx @@ -696,7 +696,7 @@ const SectionExpedisi = ({ address, listExpedisi, setSelectedExpedisi, checkWeig diatur beratnya. Mohon atur berat barang dengan menghubungi admin melalui{' '} tautan ini diff --git a/src/lib/checkout/components/CheckoutSection.jsx b/src/lib/checkout/components/CheckoutSection.jsx index 7f9ea08a..affe6138 100644 --- a/src/lib/checkout/components/CheckoutSection.jsx +++ b/src/lib/checkout/components/CheckoutSection.jsx @@ -120,7 +120,7 @@ export const SectionExpedisi = ({ dengan menghubungi admin melalui{' '} tautan ini -- cgit v1.2.3 From cb2ebbb43a7d4b475ab9838a9b9773df21c1db3f Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 8 May 2024 14:29:55 +0700 Subject: change phone number footer --- src/core/components/elements/Footer/BasicFooter.jsx | 2 +- src/core/components/elements/Footer/SimpleFooter.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 314d70ea..10ca732d 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -271,7 +271,7 @@ const InformationCenter = () => (
  • - 0812-8080-622 + 0817-1718-1922
  • diff --git a/src/core/components/elements/Footer/SimpleFooter.jsx b/src/core/components/elements/Footer/SimpleFooter.jsx index 26f7f786..371b1652 100644 --- a/src/core/components/elements/Footer/SimpleFooter.jsx +++ b/src/core/components/elements/Footer/SimpleFooter.jsx @@ -22,7 +22,7 @@ const SimpleFooter = () => (
  • - 0812-8080-622 + 081717181922
  • -- cgit v1.2.3 From 0e364afc10b7a4b590e21ec71e9b30134a80e090 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Mon, 20 May 2024 11:13:44 +0700 Subject: change image payment method on footer --- src/core/components/elements/Footer/BasicFooter.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 10ca732d..6129143d 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -386,7 +386,7 @@ const Payments = () => (
    Metode Pembayaran
    Date: Tue, 21 May 2024 14:10:36 +0700 Subject: filter site dan export --- src/lib/transaction/components/Transactions.jsx | 299 +++++++++++++++++------- 1 file changed, 219 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx index be63effd..9485449d 100644 --- a/src/lib/transaction/components/Transactions.jsx +++ b/src/lib/transaction/components/Transactions.jsx @@ -1,63 +1,139 @@ -import { useRouter } from 'next/router' -import { useState } from 'react' -import { toast } from 'react-hot-toast' -import { EllipsisVerticalIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline' +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-hot-toast'; +import { + EllipsisVerticalIcon, + MagnifyingGlassIcon, +} from '@heroicons/react/24/outline'; +import useAuth from '@/core/hooks/useAuth'; -import { downloadPurchaseOrder, downloadQuotation } from '../utils/transactions' -import useTransactions from '../hooks/useTransactions' -import currencyFormat from '@/core/utils/currencyFormat' -import cancelTransactionApi from '../api/cancelTransactionApi' -import TransactionStatusBadge from './TransactionStatusBadge' -import Spinner from '@/core/components/elements/Spinner/Spinner' -import Link from '@/core/components/elements/Link/Link' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import Pagination from '@/core/components/elements/Pagination/Pagination' -import { toQuery } from 'lodash-contrib' -import _ from 'lodash' -import Alert from '@/core/components/elements/Alert/Alert' -import MobileView from '@/core/components/views/MobileView' -import DesktopView from '@/core/components/views/DesktopView' -import Menu from '@/lib/auth/components/Menu' +import { + downloadPurchaseOrder, + downloadQuotation, +} from '../utils/transactions'; +import useTransactions from '../hooks/useTransactions'; +import currencyFormat from '@/core/utils/currencyFormat'; +import cancelTransactionApi from '../api/cancelTransactionApi'; +import TransactionStatusBadge from './TransactionStatusBadge'; +import Spinner from '@/core/components/elements/Spinner/Spinner'; +import Link from '@/core/components/elements/Link/Link'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Pagination from '@/core/components/elements/Pagination/Pagination'; +import { toQuery } from 'lodash-contrib'; +import _ from 'lodash'; +import Alert from '@/core/components/elements/Alert/Alert'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import Menu from '@/lib/auth/components/Menu'; +import * as XLSX from 'xlsx'; const Transactions = ({ context = '' }) => { - const router = useRouter() - const { q = '', page = 1 } = router.query + const auth = useAuth(); + const router = useRouter(); + const { q = '', page = 1, site = null } = router.query; - const limit = 15 + const limit = 15; + + const [inputQuery, setInputQuery] = useState(q); + const [toOthers, setToOthers] = useState(null); + const [toCancel, setToCancel] = useState(null); + + const [siteFilter, setSiteFilter] = useState(site); const query = { name: q, offset: (page - 1) * limit, context, - limit - } - const { transactions } = useTransactions({ query }) + limit, + site: + siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null), + }; - const [inputQuery, setInputQuery] = useState(q) - const [toOthers, setToOthers] = useState(null) - const [toCancel, setToCancel] = useState(null) + const { transactions } = useTransactions({ query }); const submitCancelTransaction = async () => { const isCancelled = await cancelTransactionApi({ - transaction: toCancel - }) + transaction: toCancel, + }); if (isCancelled) { - toast.success('Berhasil batalkan transaksi') - transactions.refetch() + toast.success('Berhasil batalkan transaksi'); + transactions.refetch(); } - setToCancel(null) - } + setToCancel(null); + }; - const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limit) - let pageQuery = _.omit(query, ['limit', 'offset', 'context']) - pageQuery = _.pickBy(pageQuery, _.identity) - pageQuery = toQuery(pageQuery) + const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limit); + let pageQuery = _.omit(query, ['limit', 'offset', 'context']); + pageQuery = _.pickBy( + pageQuery, + (value, key) => value !== '' && !(key === 'page' && value === '1') + ); + pageQuery = toQuery(pageQuery); const handleSubmit = (e) => { - e.preventDefault() - router.push(`${router.pathname}?q=${inputQuery}`) - } + e.preventDefault(); + const queryParams = {}; + if (inputQuery) queryParams.q = inputQuery; + if (siteFilter) queryParams.site = siteFilter; + router.push({ + pathname: router.pathname, + query: queryParams, + }); + }; + + const handleSiteFilterChange = (e) => { + setSiteFilter(e.target.value); + const queryParams = {}; + if (inputQuery) queryParams.q = inputQuery; + if (e.target.value) queryParams.site = e.target.value; + router.push({ + pathname: router.pathname, + query: queryParams, + }); + }; + + const exportToExcel = (data, siteFilter) => { + const fieldsToExport = [ + 'No. Transaksi', + 'No. PO', + 'Tanggal', + 'Created By', + 'Salesperson', + 'Total', + 'Status', + ]; + const rowsToExport = []; + + data.forEach((saleOrder) => { + const row = { + 'No. Transaksi': saleOrder.name, + 'No. PO': saleOrder.purchaseOrderName || '-', + 'Tanggal': saleOrder.dateOrder || '-', + 'Created By': saleOrder.address.customer?.name || '-', + 'Salesperson': saleOrder.sales, + 'Total': currencyFormat(saleOrder.amountTotal), + 'Status': saleOrder.status, + }; + if(siteFilter){ + row['Site'] = siteFilter; + } + rowsToExport.push(row); + }); + const worksheet = XLSX.utils.json_to_sheet(rowsToExport, { + header: fieldsToExport, + }); + + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + XLSX.writeFile(workbook, 'transactions.xlsx'); + }; + + const handleExportExcel = () => { + const dataToExport = transactions.data.saleOrders; + + exportToExcel(dataToExport, siteFilter); + }; return ( <> @@ -81,17 +157,23 @@ const Transactions = ({ context = '' }) => {
    )} - {!transactions.isLoading && transactions.data?.saleOrders?.length === 0 && ( - - Tidak ada transaksi - - )} + {!transactions.isLoading && + transactions.data?.saleOrders?.length === 0 && ( + + Tidak ada transaksi + + )} {transactions.data?.saleOrders?.map((saleOrder, index) => ( -
    +
    - No. Transaksi + + No. Transaksi +

    {saleOrder.name}

    @@ -105,13 +187,17 @@ const Transactions = ({ context = '' }) => {
    - No. Purchase Order + + No. Purchase Order +

    {saleOrder.purchaseOrderName || '-'}

    - Total Invoice + + Total Invoice +

    {saleOrder.invoiceCount} Invoice

    @@ -120,10 +206,14 @@ const Transactions = ({ context = '' }) => {
    Sales -

    {saleOrder.sales}

    +

    + {saleOrder.sales} +

    - Total Harga + + Total Harga +

    {currencyFormat(saleOrder.amountTotal)}

    @@ -140,14 +230,18 @@ const Transactions = ({ context = '' }) => { className='mt-2 mb-2' /> - setToOthers(null)}> + setToOthers(null)} + >
    - setToCancel(null)} title='Batalkan Transaksi'> + setToCancel(null)} + title='Batalkan Transaksi' + >
    Apakah anda yakin membatalkan transaksi{' '} {toCancel?.name}? @@ -188,7 +286,11 @@ const Transactions = ({ context = '' }) => { > Ya, Batalkan -
    @@ -202,24 +304,54 @@ const Transactions = ({ context = '' }) => {
    -
    +

    Daftar Transaksi{' '} - {transactions?.data?.saleOrders ? `(${transactions?.data?.saleOrders.length})` : ''} + {transactions?.data?.saleOrders + ? `(${transactions?.data?.saleOrders.length})` + : ''}

    -
    - + + + setInputQuery(e.target.value)} + /> + +
    +
    + @@ -252,13 +384,20 @@ const Transactions = ({ context = '' }) => { {transactions.data?.saleOrders?.map((saleOrder) => ( - + - + {/* */} @@ -605,18 +605,18 @@ const Transaction = ({ id }) => { - + */} -- cgit v1.2.3 From ebf4faee910b591254b27b99be68e2e0cb6d31ae Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 22 May 2024 10:34:58 +0700 Subject: list site & button download --- src/lib/transaction/components/Transactions.jsx | 60 ++++++++++++++----------- 1 file changed, 35 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx index 9485449d..1a57a976 100644 --- a/src/lib/transaction/components/Transactions.jsx +++ b/src/lib/transaction/components/Transactions.jsx @@ -26,6 +26,7 @@ import MobileView from '@/core/components/views/MobileView'; import DesktopView from '@/core/components/views/DesktopView'; import Menu from '@/lib/auth/components/Menu'; import * as XLSX from 'xlsx'; +import getSite from '../api/listSiteApi'; const Transactions = ({ context = '' }) => { const auth = useAuth(); @@ -37,6 +38,7 @@ const Transactions = ({ context = '' }) => { const [inputQuery, setInputQuery] = useState(q); const [toOthers, setToOthers] = useState(null); const [toCancel, setToCancel] = useState(null); + const [listSites, setListSites] = useState([]); const [siteFilter, setSiteFilter] = useState(site); @@ -51,6 +53,11 @@ const Transactions = ({ context = '' }) => { const { transactions } = useTransactions({ query }); + const fetchSite = async () => { + const site = await getSite(); + setListSites(site.sites); + }; + const submitCancelTransaction = async () => { const isCancelled = await cancelTransactionApi({ transaction: toCancel, @@ -108,13 +115,13 @@ const Transactions = ({ context = '' }) => { const row = { 'No. Transaksi': saleOrder.name, 'No. PO': saleOrder.purchaseOrderName || '-', - 'Tanggal': saleOrder.dateOrder || '-', + Tanggal: saleOrder.dateOrder || '-', 'Created By': saleOrder.address.customer?.name || '-', - 'Salesperson': saleOrder.sales, - 'Total': currencyFormat(saleOrder.amountTotal), - 'Status': saleOrder.status, + Salesperson: saleOrder.sales, + Total: currencyFormat(saleOrder.amountTotal), + Status: saleOrder.status, }; - if(siteFilter){ + if (siteFilter) { row['Site'] = siteFilter; } rowsToExport.push(row); @@ -134,6 +141,10 @@ const Transactions = ({ context = '' }) => { exportToExcel(dataToExport, siteFilter); }; + + useEffect(() => { + fetchSite(); + }, []); return ( <> @@ -304,7 +315,7 @@ const Transactions = ({ context = '' }) => {
    -
    +

    Daftar Transaksi{' '} {transactions?.data?.saleOrders @@ -312,16 +323,21 @@ const Transactions = ({ context = '' }) => { : ''}

    - + {listSites.length > 0 && ( + + )} +
    {
    - {saleOrder.name} + + {saleOrder.name} + {saleOrder.purchaseOrderName || '-'} {saleOrder.dateOrder || '-'} {saleOrder.address.customer?.name || '-'} {saleOrder.sales}{currencyFormat(saleOrder.amountTotal)} + {currencyFormat(saleOrder.amountTotal)} +
    @@ -272,14 +411,14 @@ const Transactions = ({ context = '' }) => {
    - ) -} + ); +}; -export default Transactions +export default Transactions; -- cgit v1.2.3 From 21d3c9cdc25477f5d07ff395a65f89430b7c9924 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 21 May 2024 14:54:08 +0700 Subject: delete discount field --- src/lib/transaction/components/Transaction.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx index 8f4b2038..9b11f5bb 100644 --- a/src/lib/transaction/components/Transaction.jsx +++ b/src/lib/transaction/components/Transaction.jsx @@ -562,7 +562,7 @@ const Transaction = ({ id }) => {
    Nama ProdukDiskonDiskonJumlah Harga Subtotal + {/* {product.price.discountPercentage > 0 ? `${product.price.discountPercentage}%` : ''} - {product.quantity} - {product.price.discountPercentage > 0 && ( + {/* {product.price.discountPercentage > 0 && (
    {currencyFormat(product.price.price)}
    - )} + )} */}
    {currencyFormat(product.price.priceDiscount)}
    {currencyFormat(product.price.subtotal)}
    -- cgit v1.2.3 From 6d57f1f7449ace08f56a80f5f03b43f5da05a995 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 22 May 2024 10:39:19 +0700 Subject: modul list site --- src/lib/transaction/api/listSiteApi.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/lib/transaction/api/listSiteApi.js (limited to 'src') diff --git a/src/lib/transaction/api/listSiteApi.js b/src/lib/transaction/api/listSiteApi.js new file mode 100644 index 00000000..8b7740c5 --- /dev/null +++ b/src/lib/transaction/api/listSiteApi.js @@ -0,0 +1,10 @@ +import odooApi from '@/core/api/odooApi' +import { getAuth } from '@/core/utils/auth' + +const getSite = async () => { + const auth = getAuth() + const dataSite = await odooApi('GET', `/api/v1/partner/${auth?.partnerId}/list/site`) + return dataSite +} + +export default getSite \ No newline at end of file -- cgit v1.2.3 From d1f70e37fdea0d677cedccec9effdbeeb91656aa Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 22 May 2024 15:18:49 +0700 Subject: feedback testing renca --- src/lib/transaction/components/Transactions.jsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx index 1a57a976..5a6dfb01 100644 --- a/src/lib/transaction/components/Transactions.jsx +++ b/src/lib/transaction/components/Transactions.jsx @@ -27,6 +27,7 @@ import DesktopView from '@/core/components/views/DesktopView'; import Menu from '@/lib/auth/components/Menu'; import * as XLSX from 'xlsx'; import getSite from '../api/listSiteApi'; +import transactionsApi from '../api/transactionsApi'; const Transactions = ({ context = '' }) => { const auth = useAuth(); @@ -136,10 +137,22 @@ const Transactions = ({ context = '' }) => { XLSX.writeFile(workbook, 'transactions.xlsx'); }; - const handleExportExcel = () => { - const dataToExport = transactions.data.saleOrders; + const getAllData = async () => { + const query = { + name: q, + context, + site: + siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null), + }; + const queryString = toQuery(query) + const data = await transactionsApi({ query : queryString }); + return data; + }; + + const handleExportExcel = async () => { + const dataToExport = await getAllData(); - exportToExcel(dataToExport, siteFilter); + exportToExcel(dataToExport?.saleOrders, siteFilter); }; useEffect(() => { @@ -323,7 +336,7 @@ const Transactions = ({ context = '' }) => { : ''}
    - {listSites.length > 0 && ( + {listSites?.length > 0 ? ( - )} + ):(
    ) } Date: Wed, 5 Jun 2024 13:02:27 +0700 Subject: add Informasi SNI & TKDN --- src/lib/product/components/ProductCard.jsx | 109 +++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 38ed35f8..8dde4dbe 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import ImageNext from 'next/image'; import { useRouter } from 'next/router'; -import { useMemo } from 'react'; +import { useMemo, useEffect, useState } from 'react'; import Image from '@/core/components/elements/Image/Image'; import Link from '@/core/components/elements/Link/Link'; @@ -15,6 +15,47 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const router = useRouter(); const utmSource = useUtmSource(); + const [isSni, setIsSni] = useState(false); + const [isTkdn, setTkdn] = useState(false); + + useEffect(() => { + // Lakukan pemanggilan API untuk memeriksa isSni + const fetchSniData = async () => { + try { + const response = await fetch('URL_API_SNI'); + const data = await response.json(); + if (data && data.sni) { + setIsSni(true); + } else { + setIsSni(false); + } + } catch (error) { + console.error('Error fetching SNI data:', error); + setIsSni(false); + } + }; + + // Lakukan pemanggilan API untuk memeriksa isTkdn + const fetchTkdnData = async () => { + try { + const response = await fetch('URL_API_TKDN'); + const data = await response.json(); + if (data && data.tkdn) { + setTkdn(true); + } else { + setTkdn(false); + } + } catch (error) { + console.error('Error fetching TKDN data:', error); + setTkdn(false); + } + }; + fetchSniData(); + fetchTkdnData(); + return () => { + }; + }, []); + const callForPriceWhatsapp = whatsappUrl('product', { name: product.name, manufacture: product.manufacture?.name, @@ -41,11 +82,39 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { return (
    +
    +
    +
    + {!isSni && ( + + )} +
    +
    + {!isTkdn && ( + + )} +
    +
    +
    + + {router.pathname != '/' && product?.flashSale?.id > 0 && (
    @@ -171,11 +240,37 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
    - +
    + +
    +
    + {!isSni && ( + + )} +
    +
    + {!isTkdn && ( + + )} +
    +
    +
    {product.variantTotal > 1 && (
    {product.variantTotal} Varian -- cgit v1.2.3 From 87432c8627896711167813654dce2969ce45e643 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 5 Jun 2024 13:11:26 +0700 Subject: add Informasi SNI & TKDN --- src/lib/product/components/ProductCard.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 8dde4dbe..00edc29d 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -90,7 +90,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { />
    - {!isSni && ( + {isSni && ( { )}
    - {!isTkdn && ( + {isTkdn && ( Date: Wed, 5 Jun 2024 15:01:12 +0700 Subject: fixing shipping address and invoice address --- src/lib/checkout/components/Checkout.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 0090acee..5ca3611f 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -333,8 +333,10 @@ const Checkout = () => { quantity: product.quantity, })); let data = { - partner_shipping_id: auth.partnerId, - partner_invoice_id: auth.partnerId, + // partner_shipping_id: auth.partnerId, + // partner_invoice_id: auth.partnerId, + partner_shipping_id: selectedAddress?.shipping?.id || auth.partnerId, + partner_invoice_id: selectedAddress?.invoicing?.id || auth.partnerId, user_id: auth.id, order_line: JSON.stringify(productOrder), delivery_amount: biayaKirim, -- cgit v1.2.3 From f9f1fdf83c2b6ed5c1d85d7418d45aeed9b05c77 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 5 Jun 2024 15:24:42 +0700 Subject: add feature SNI-TKDR --- src/lib/product/components/ProductCard.jsx | 4 +- src/lib/transaction/components/Transaction.jsx | 71 ++++++++++++++++++++++++- src/lib/variant/components/VariantCard.jsx | 72 +++++++++++++++++++++++++- 3 files changed, 142 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 00edc29d..8dde4dbe 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -90,7 +90,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { />
    - {isSni && ( + {!isSni && ( { )}
    - {isTkdn && ( + {!isTkdn && ( { const [idAWB, setIdAWB] = useState(null); const openUploadPo = () => setUploadPo(true); const closeUploadPo = () => setUploadPo(false); + const [isSni, setIsSni] = useState(false); + const [isTkdn, setTkdn] = useState(false); + + useEffect(() => { + const fetchSniData = async () => { + try { + const response = await fetch('URL_API_SNI'); + const data = await response.json(); + if (data && data.sni) { + setIsSni(true); + } else { + setIsSni(false); + } + } catch (error) { + console.error('Error fetching SNI data:', error); + setIsSni(false); + } + }; + const fetchTkdnData = async () => { + try { + const response = await fetch('URL_API_TKDN'); + const data = await response.json(); + if (data && data.tkdn) { + setTkdn(true); + } else { + setTkdn(false); + } + } catch (error) { + console.error('Error fetching TKDN data:', error); + setTkdn(false); + } + }; + fetchSniData(); + fetchTkdnData(); + return () => { + }; + }, []); + const submitUploadPo = async () => { const file = poFile.current.files[0]; const name = poNumber.current.value; @@ -610,11 +649,39 @@ const Transaction = ({ id }) => { )} className='w-[20%] flex-shrink-0' > - + +
    +
    + {!isSni && ( + + )} +
    +
    + {!isTkdn && ( + + )} +
    +
    +
    +
    { const router = useRouter() + const [isSni, setIsSni] = useState(false); + const [isTkdn, setTkdn] = useState(false); + + useEffect(() => { + // Lakukan pemanggilan API untuk memeriksa isSni + const fetchSniData = async () => { + try { + const response = await fetch('URL_API_SNI'); + const data = await response.json(); + if (data && data.sni) { + setIsSni(true); + } else { + setIsSni(false); + } + } catch (error) { + console.error('Error fetching SNI data:', error); + setIsSni(false); + } + }; + + // Lakukan pemanggilan API untuk memeriksa isTkdn + const fetchTkdnData = async () => { + try { + const response = await fetch('URL_API_TKDN'); + const data = await response.json(); + if (data && data.tkdn) { + setTkdn(true); + } else { + setTkdn(false); + } + } catch (error) { + console.error('Error fetching TKDN data:', error); + setTkdn(false); + } + }; + fetchSniData(); + fetchTkdnData(); + return () => { + }; + }, []); const addItemToCart = () => { toast.success('Berhasil menambahkan ke keranjang', { duration: 1500 }) @@ -27,11 +69,39 @@ const VariantCard = ({ product, openOnClick = true, buyMore = false }) => { const Card = () => (
    - + +
    +
    + {!isSni && ( + + )} +
    +
    + {!isTkdn && ( + + )} +
    +
    +
    +

    {product.parent.name}

    -- cgit v1.2.3 From 755b61a8a7a082cc13f7ecb4a79807f90e60b3d6 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 5 Jun 2024 16:50:38 +0700 Subject: add feature SNI-TKDN --- src/lib/product/components/ProductCard.jsx | 103 ++++++++----------------- src/lib/transaction/components/Transaction.jsx | 4 +- src/lib/variant/components/VariantCard.jsx | 4 +- src/utils/solrMapping.js | 2 + 4 files changed, 38 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 8dde4dbe..48a30b51 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import ImageNext from 'next/image'; import { useRouter } from 'next/router'; -import { useMemo, useEffect, useState } from 'react'; +import { useMemo} from 'react'; import Image from '@/core/components/elements/Image/Image'; import Link from '@/core/components/elements/Link/Link'; @@ -15,46 +15,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const router = useRouter(); const utmSource = useUtmSource(); - const [isSni, setIsSni] = useState(false); - const [isTkdn, setTkdn] = useState(false); - - useEffect(() => { - // Lakukan pemanggilan API untuk memeriksa isSni - const fetchSniData = async () => { - try { - const response = await fetch('URL_API_SNI'); - const data = await response.json(); - if (data && data.sni) { - setIsSni(true); - } else { - setIsSni(false); - } - } catch (error) { - console.error('Error fetching SNI data:', error); - setIsSni(false); - } - }; - - // Lakukan pemanggilan API untuk memeriksa isTkdn - const fetchTkdnData = async () => { - try { - const response = await fetch('URL_API_TKDN'); - const data = await response.json(); - if (data && data.tkdn) { - setTkdn(true); - } else { - setTkdn(false); - } - } catch (error) { - console.error('Error fetching TKDN data:', error); - setTkdn(false); - } - }; - fetchSniData(); - fetchTkdnData(); - return () => { - }; - }, []); + const callForPriceWhatsapp = whatsappUrl('product', { name: product.name, @@ -90,7 +51,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { />
    - {!isSni && ( + {product.isSni && ( { )}
    - {!isTkdn && ( + {product.isTkdn && ( {
    - -
    -
    - {!isSni && ( - - )} -
    -
    - {!isTkdn && ( - - )} + +
    +
    + {product.isSni && ( + + )} +
    +
    + {product.isTkdn && ( + + )} +
    -
    {product.variantTotal > 1 && (
    diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx index fb5fd0dd..f3e2afb9 100644 --- a/src/lib/transaction/components/Transaction.jsx +++ b/src/lib/transaction/components/Transaction.jsx @@ -658,7 +658,7 @@ const Transaction = ({ id }) => { />
    - {!isSni && ( + {product.isSni && ( { )}
    - {!isTkdn && ( + {product.isTkdn && ( { />
    - {!isSni && ( + {product.isSni && ( { )}
    - {!isTkdn && ( + {product.isTkdn && ( { tag: product?.flashsale_tag_s || 'FLASH SALE', }, qtySold: product?.qty_sold_f || 0, + isTkdn:product?.tkdn_b || false, + isSni:product?.sni_b || false, }; if (product.manufacture_id_i && product.manufacture_name_s) { -- cgit v1.2.3 From f39f03f4d4e59597ffcc73ddb1b108c233842bf8 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 5 Jun 2024 17:01:12 +0700 Subject: add feature SNI-TKDN --- src/lib/product/components/ProductCard.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 48a30b51..357f3fd9 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import ImageNext from 'next/image'; import { useRouter } from 'next/router'; -import { useMemo} from 'react'; +import { useMemo, useEffect, useState } from 'react'; import Image from '@/core/components/elements/Image/Image'; import Link from '@/core/components/elements/Link/Link'; @@ -15,7 +15,6 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const router = useRouter(); const utmSource = useUtmSource(); - const callForPriceWhatsapp = whatsappUrl('product', { name: product.name, -- cgit v1.2.3 From 68a3c897edef3f42a339d92ed8d663039f3ddfc7 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 6 Jun 2024 09:39:01 +0700 Subject: add feature SNI-TKDN --- src/lib/transaction/components/Transaction.jsx | 40 ++----------------------- src/lib/variant/components/VariantCard.jsx | 41 ++------------------------ 2 files changed, 5 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx index f3e2afb9..9962b46e 100644 --- a/src/lib/transaction/components/Transaction.jsx +++ b/src/lib/transaction/components/Transaction.jsx @@ -50,43 +50,9 @@ const Transaction = ({ id }) => { const [idAWB, setIdAWB] = useState(null); const openUploadPo = () => setUploadPo(true); const closeUploadPo = () => setUploadPo(false); - const [isSni, setIsSni] = useState(false); - const [isTkdn, setTkdn] = useState(false); - - useEffect(() => { - const fetchSniData = async () => { - try { - const response = await fetch('URL_API_SNI'); - const data = await response.json(); - if (data && data.sni) { - setIsSni(true); - } else { - setIsSni(false); - } - } catch (error) { - console.error('Error fetching SNI data:', error); - setIsSni(false); - } - }; - const fetchTkdnData = async () => { - try { - const response = await fetch('URL_API_TKDN'); - const data = await response.json(); - if (data && data.tkdn) { - setTkdn(true); - } else { - setTkdn(false); - } - } catch (error) { - console.error('Error fetching TKDN data:', error); - setTkdn(false); - } - }; - fetchSniData(); - fetchTkdnData(); - return () => { - }; - }, []); + + + const submitUploadPo = async () => { const file = poFile.current.files[0]; diff --git a/src/lib/variant/components/VariantCard.jsx b/src/lib/variant/components/VariantCard.jsx index f5ae4478..9f65fc3c 100644 --- a/src/lib/variant/components/VariantCard.jsx +++ b/src/lib/variant/components/VariantCard.jsx @@ -12,46 +12,9 @@ import { useMemo, useEffect, useState } from 'react'; const VariantCard = ({ product, openOnClick = true, buyMore = false }) => { const router = useRouter() - const [isSni, setIsSni] = useState(false); - const [isTkdn, setTkdn] = useState(false); + - useEffect(() => { - // Lakukan pemanggilan API untuk memeriksa isSni - const fetchSniData = async () => { - try { - const response = await fetch('URL_API_SNI'); - const data = await response.json(); - if (data && data.sni) { - setIsSni(true); - } else { - setIsSni(false); - } - } catch (error) { - console.error('Error fetching SNI data:', error); - setIsSni(false); - } - }; - - // Lakukan pemanggilan API untuk memeriksa isTkdn - const fetchTkdnData = async () => { - try { - const response = await fetch('URL_API_TKDN'); - const data = await response.json(); - if (data && data.tkdn) { - setTkdn(true); - } else { - setTkdn(false); - } - } catch (error) { - console.error('Error fetching TKDN data:', error); - setTkdn(false); - } - }; - fetchSniData(); - fetchTkdnData(); - return () => { - }; - }, []); + const addItemToCart = () => { toast.success('Berhasil menambahkan ke keranjang', { duration: 1500 }) -- cgit v1.2.3 From e7ff25b6c0763149981df738ff50871b851bf4a6 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 6 Jun 2024 10:07:51 +0700 Subject: add feature SNI-TKDN --- src/lib/product/components/ProductCard.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 357f3fd9..98732407 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -50,7 +50,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { />
    - {product.isSni && ( + {product?.isSni && ( { )}
    - {product.isTkdn && ( + {product?.isTkdn && ( { />
    - {product.isSni && ( + {product?.isSni && ( { )}
    - {product.isTkdn && ( + {product?.isTkdn && ( Date: Fri, 7 Jun 2024 17:08:09 +0700 Subject: add promotion program --- src/api/promoApi.js | 12 ++++++++ src/lib/home/components/PromotionProgram.jsx | 31 +++++++++++++++++++ src/lib/promo/components/Promocrumb.jsx | 40 ++++++++++++++++++++++++ src/pages/index.jsx | 7 +++++ src/pages/shop/promo/[slug].jsx | 46 ++++++++++++++++++++++++++++ src/pages/shop/promo/index.jsx | 0 6 files changed, 136 insertions(+) create mode 100644 src/api/promoApi.js create mode 100644 src/lib/home/components/PromotionProgram.jsx create mode 100644 src/lib/promo/components/Promocrumb.jsx create mode 100644 src/pages/shop/promo/[slug].jsx create mode 100644 src/pages/shop/promo/index.jsx (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js new file mode 100644 index 00000000..a4acc768 --- /dev/null +++ b/src/api/promoApi.js @@ -0,0 +1,12 @@ +// src/api/promoApi.js +import odooApi from '@/core/api/odooApi'; + +export const fetchPromoItems = async (type) => { + try { + const response = await odooApi('GET', `/api/v1/program-line?type=${type}&limit=3`); + return response.map((item) => ({ value: item.id, label: item.name, product: item.products ,price:item.price})); + } catch (error) { + console.error('Error fetching promo items:', error); + return []; + } +}; diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx new file mode 100644 index 00000000..461383a1 --- /dev/null +++ b/src/lib/home/components/PromotionProgram.jsx @@ -0,0 +1,31 @@ +import Link from '@/core/components/elements/Link/Link' +import Image from 'next/image' +import { bannerApi } from '@/api/bannerApi'; + +const { useQuery } = require('react-query') + +const BannerSection = () => { + const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); + + return ( + promotionProgram.data && + promotionProgram.data?.length > 0 && ( +
    + {promotionProgram.data?.map((banner) => ( + + + + ))} +
    + ) + ) +} + +export default BannerSection diff --git a/src/lib/promo/components/Promocrumb.jsx b/src/lib/promo/components/Promocrumb.jsx new file mode 100644 index 00000000..a96ec6b4 --- /dev/null +++ b/src/lib/promo/components/Promocrumb.jsx @@ -0,0 +1,40 @@ +import { Breadcrumb as ChakraBreadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' + +/** + * Renders a breadcrumb component with links to navigate through different pages. + * + * @param {Object} props - The props object containing the brand name. + * @param {string} props.brandName - The name of the brand to display in the breadcrumb. + * @return {JSX.Element} The rendered breadcrumb component. + */ +const Breadcrumb = ({ brandName }) => { + return ( +
    + + + + Shop + + + + + + Promo + + + + + {brandName} + + +
    + ) +} + +export default Breadcrumb diff --git a/src/pages/index.jsx b/src/pages/index.jsx index c097530c..ddc41cbe 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -41,6 +41,11 @@ const FlashSale = dynamic( loading: () => , } ); + +const ProgramPromotion = dynamic(() => + import('@/lib/home/components/PromotionProgram') +); + const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection') ); @@ -103,6 +108,7 @@ export default function Home() {
    + @@ -126,6 +132,7 @@ export default function Home() { + diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx new file mode 100644 index 00000000..4211ceb8 --- /dev/null +++ b/src/pages/shop/promo/[slug].jsx @@ -0,0 +1,46 @@ +import dynamic from 'next/dynamic' +import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' +import { useRouter } from 'next/router' +import _ from 'lodash' +import Seo from '@/core/components/Seo' +import Promocrumb from '@/lib/promo/components/Promocrumb' +import useBrand from '@/lib/brand/hooks/useBrand' + +const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) +const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) +const Brand = dynamic(() => import('@/lib/brand/components/Brand')) + +export default function BrandDetail() { + const router = useRouter() + const { slug = '' } = router.query + console.log("apa itu slug",slug) + const brandName = getNameFromSlug(slug) + const id = getIdFromSlug(slug) + const {brand} = useBrand({id}) + return ( + + {/* seakarang arahkan web untuk menampilkan daftar promo sesuai slug */} + + + + + + harusnya disini menampilkan barang promosimya {slug} + + + {/* + {!_.isEmpty(router.query) && ( + + )} */} + + ) +} diff --git a/src/pages/shop/promo/index.jsx b/src/pages/shop/promo/index.jsx new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 5e5b67e5b98d3183044dc5149fe67a29feeb3c41 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 10 Jun 2024 16:53:28 +0700 Subject: update promotion-program --- src/api/promoApi.js | 43 +++++++ src/lib/home/components/PromotionProgram.jsx | 22 +++- src/pages/shop/promo/[slug].jsx | 46 -------- src/pages/shop/promo/[slug].tsx | 161 +++++++++++++++++++++++++++ src/pages/shop/promo/index.jsx | 0 5 files changed, 221 insertions(+), 51 deletions(-) delete mode 100644 src/pages/shop/promo/[slug].jsx create mode 100644 src/pages/shop/promo/[slug].tsx delete mode 100644 src/pages/shop/promo/index.jsx (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index a4acc768..535df021 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -1,5 +1,6 @@ // src/api/promoApi.js import odooApi from '@/core/api/odooApi'; +// import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; export const fetchPromoItems = async (type) => { try { @@ -10,3 +11,45 @@ export const fetchPromoItems = async (type) => { return []; } }; + +export const fetchPromoItemsSolr = async (type) => { + let start = 0 + let rows = 120 + try { + const queryParams = new URLSearchParams({ q: `type_value_s:${type}` }); + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + 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) => { + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + }; + result.push(data); + } + return result; +}; \ No newline at end of file diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index 461383a1..a3c09a9b 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -1,16 +1,25 @@ import Link from '@/core/components/elements/Link/Link' import Image from 'next/image' import { bannerApi } from '@/api/bannerApi'; - +import useDevice from '@/core/hooks/useDevice' const { useQuery } = require('react-query') - const BannerSection = () => { const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); + const { isMobile, isDesktop } = useDevice() return ( - promotionProgram.data && +
    +
    +
    Promo Tersedia
    + {isDesktop && ( + + Lihat Semua + + )} +
    + {promotionProgram.data && promotionProgram.data?.length > 0 && ( -
    +
    {promotionProgram.data?.map((banner) => ( { ))}
    - ) + + )} +
    + ) } diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx deleted file mode 100644 index 4211ceb8..00000000 --- a/src/pages/shop/promo/[slug].jsx +++ /dev/null @@ -1,46 +0,0 @@ -import dynamic from 'next/dynamic' -import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' -import { useRouter } from 'next/router' -import _ from 'lodash' -import Seo from '@/core/components/Seo' -import Promocrumb from '@/lib/promo/components/Promocrumb' -import useBrand from '@/lib/brand/hooks/useBrand' - -const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) -const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) -const Brand = dynamic(() => import('@/lib/brand/components/Brand')) - -export default function BrandDetail() { - const router = useRouter() - const { slug = '' } = router.query - console.log("apa itu slug",slug) - const brandName = getNameFromSlug(slug) - const id = getIdFromSlug(slug) - const {brand} = useBrand({id}) - return ( - - {/* seakarang arahkan web untuk menampilkan daftar promo sesuai slug */} - - - - - - harusnya disini menampilkan barang promosimya {slug} - - - {/* - {!_.isEmpty(router.query) && ( - - )} */} - - ) -} diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx new file mode 100644 index 00000000..cd3e93c4 --- /dev/null +++ b/src/pages/shop/promo/[slug].tsx @@ -0,0 +1,161 @@ +import dynamic from 'next/dynamic' +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 } from '../../../api/promoApi' +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 React from 'react' +import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; + + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) + +export default function PromoDetail() { + const router = useRouter() + const { slug = '' } = router.query + const [promoItems, setPromoItems] = useState([]) + const [promoData, setPromoData] = useState(null) + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); + const visiblePromotions = promoData?.slice(startIndex, endIndex); + const [loading, setLoading] = useState(true); // Menambahkan status loading + + + useEffect(() => { + const loadPromo = async () => { + try { + const items = await fetchPromoItemsSolr(Array.isArray(slug) ? slug[0] : slug) + console.log("slug sekarang ", slug) + + setPromoItems(items) + console.log("data dari promotion pakai SOLR", items) + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const promoDataPromises = items.map(async (item) => { + const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + + try { + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) + console.log("respon data ", response) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: SolrResponse = await response.json() + console.log("data promo IPromotion[]", data) + + const promotions = await map(data.response.docs) + return promotions; + } catch (fetchError) { + console.error("Error fetching promotion data:", fetchError) + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + } catch (loadError) { + console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + }, [slug]) + + useEffect(() => { + window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates + }, []); // Run only once when component mounts + + + const map = async (promotions: any[]): Promise => { + const result: IPromotion[] = [] + + for (const promotion of promotions) { + const data: IPromotion = { + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + } + + result.push(data) + } + + return result + } + + console.log("data yg dikirim ke ProductPromoCard", promoData) + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + const goToNextPage = () => { + setCurrentPage((prevPage) => prevPage + 1); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + const goToPreviousPage = () => { + setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + return ( + + + + + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {visiblePromotions?.map((promotion) => ( +
    + +
    + ))} +
    +
    + + +
    + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} +
    + ) +} \ No newline at end of file diff --git a/src/pages/shop/promo/index.jsx b/src/pages/shop/promo/index.jsx deleted file mode 100644 index e69de29b..00000000 -- cgit v1.2.3 From 9565ddf794165e297acf511a108f9a9643ee615d Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 11 Jun 2024 13:40:23 +0700 Subject: update promotion program --- src/api/promoApi.js | 4 +- src/lib/home/components/PromotionProgram.jsx | 14 +- src/pages/shop/promo/[slug].tsx | 77 ++++++++--- src/pages/shop/promo/index.tsx | 188 +++++++++++++++++++++++++++ 4 files changed, 259 insertions(+), 24 deletions(-) create mode 100644 src/pages/shop/promo/index.tsx (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index 535df021..ecae5080 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -13,11 +13,13 @@ export const fetchPromoItems = async (type) => { }; export const fetchPromoItemsSolr = async (type) => { + // let query = type ? `type_value_s:${type}` : '*:*'; let start = 0 let rows = 120 try { - const queryParams = new URLSearchParams({ q: `type_value_s:${type}` }); + const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + console.log("Constructed URL SLOR:", `/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index a3c09a9b..98bc7c7f 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -9,17 +9,19 @@ const BannerSection = () => { return (
    -
    +
    Promo Tersedia
    {isDesktop && ( - - Lihat Semua - + + Lihat Semua + )}
    {promotionProgram.data && promotionProgram.data?.length > 0 && ( -
    +
    {promotionProgram.data?.map((banner) => ( { quality={100} src={banner.image} alt={banner.name} - className='h-auto w-full rounded' + className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out' /> ))} diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index cd3e93c4..be5a715d 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -10,7 +10,6 @@ import { IPromotion } from '../../../../src-migrate/types/promotion' import React from 'react' import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; - const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { @@ -22,14 +21,15 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); - const visiblePromotions = promoData?.slice(startIndex, endIndex); + // const visiblePromotions = promoData?.slice(startIndex, endIndex); const [loading, setLoading] = useState(true); // Menambahkan status loading + const [fetchingData, setFetchingData] = useState(false) useEffect(() => { const loadPromo = async () => { try { - const items = await fetchPromoItemsSolr(Array.isArray(slug) ? slug[0] : slug) + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) console.log("slug sekarang ", slug) setPromoItems(items) @@ -112,18 +112,60 @@ export default function PromoDetail() { console.log("data yg dikirim ke ProductPromoCard", promoData) function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); + // Ganti semua tanda _ dengan spasi + string = string.replace(/_/g, ' '); + + // Kapitalisasi huruf pertama setelah spasi atau awal string + return string.replace(/(^\w|\s\w)/g, function(match) { + return match.toUpperCase(); + }); + + + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } } - const goToNextPage = () => { - setCurrentPage((prevPage) => prevPage + 1); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; + const visiblePromotions = promoData?.slice(0, currentPage * 12) + - const goToPreviousPage = () => { - setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; return ( @@ -142,14 +184,15 @@ export default function PromoDetail() {
    {visiblePromotions?.map((promotion) => (
    - +
    ))}
    -
    - - -
    + {fetchingData && ( +
    + +
    + )} ) : (
    diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx new file mode 100644 index 00000000..6f5134a3 --- /dev/null +++ b/src/pages/shop/promo/index.tsx @@ -0,0 +1,188 @@ +import dynamic from 'next/dynamic' +import { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import Seo from '../../../core/components/Seo.jsx' +import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx' +import { fetchPromoItemsSolr } from '../../../api/promoApi.js' +import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' +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"; + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) + +export default function Promo() { + const router = useRouter() + const { slug = '' } = router.query + const [promoItems, setPromoItems] = useState([]) + const [promoData, setPromoData] = useState(null) + const [loading, setLoading] = useState(true) + const [currentPage, setCurrentPage] = useState(1) + const [fetchingData, setFetchingData] = useState(false) + + useEffect(() => { + const loadPromo = async () => { + try { + const items = await fetchPromoItemsSolr(`*:*`) + console.log("slug sekarang ", slug) + + setPromoItems(items) + console.log("data dari promotion pakai SOLR", items) + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const promoDataPromises = items.map(async (item) => { + const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + + try { + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) + console.log("respon data ", response) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: SolrResponse = await response.json() + console.log("data promo IPromotion[]", data) + + const promotions = await map(data.response.docs) + return promotions; + } catch (fetchError) { + console.error("Error fetching promotion data:", fetchError) + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + } catch (loadError) { + console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + }, [slug]) + + const map = async (promotions: any[]): Promise => { + const result: IPromotion[] = [] + + for (const promotion of promotions) { + const data: IPromotion = { + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + } + + result.push(data) + } + + return result + } + + console.log("data yg dikirim ke ProductPromoCard", promoData) + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } + } + + const visiblePromotions = promoData?.slice(0, currentPage * 12) + + return ( + + + {/* */} +
    +
    +

    Semua Promo di Indoteknik

    +
    +
    + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {visiblePromotions?.map((promotion) => ( +
    + +
    + ))} +
    + {fetchingData && ( +
    + +
    + )} + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} +
    + ) +} -- cgit v1.2.3 From ce968fcd38e5c4bb69400862fe4da484934088d5 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 11 Jun 2024 16:14:07 +0700 Subject: import('../../../core/components/layouts/BasicLayout')) @@ -21,10 +24,9 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); - // const visiblePromotions = promoData?.slice(startIndex, endIndex); - const [loading, setLoading] = useState(true); // Menambahkan status loading + const [loading, setLoading] = useState(true); const [fetchingData, setFetchingData] = useState(false) - + const { isMobile, isDesktop } = useDevice() useEffect(() => { const loadPromo = async () => { @@ -66,7 +68,7 @@ export default function PromoDetail() { const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); setPromoData(mergedPromoData); - setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + setTimeout(() => setLoading(false), 120); // Menambahkan delay 120ms sebelum mengubah status loading } catch (loadError) { console.error("Error loading promo items:", loadError) setLoading(false); @@ -82,7 +84,6 @@ export default function PromoDetail() { window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates }, []); // Run only once when component mounts - const map = async (promotions: any[]): Promise => { const result: IPromotion[] = [] @@ -119,8 +120,6 @@ export default function PromoDetail() { return string.replace(/(^\w|\s\w)/g, function(match) { return match.toUpperCase(); }); - - } useEffect(() => { @@ -162,11 +161,10 @@ export default function PromoDetail() { } } - + + const visiblePromotions = promoData?.slice(0, currentPage * 12) - - return ( - -
    + +
    ) : promoData && promoItems.length >= 1 ? ( <> -
    + +
    {visiblePromotions?.map((promotion) => ( -
    - -
    + +
    + +
    +
    ))} +
    - {fetchingData && ( -
    - -
    - )} +
    ) : (
    -- cgit v1.2.3 From 0a87455727114468c216fbcd74266ea928eaec37 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 13 Jun 2024 09:34:24 +0700 Subject: update promotion-program --- .../product/components/ProductFilterDesktop.jsx | 10 +- src/pages/shop/promo/[slug].tsx | 243 +++++++++++++-------- 2 files changed, 162 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index e4a62abb..b4afebc2 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -21,6 +21,7 @@ import Image from '@/core/components/elements/Image/Image' import { formatCurrency } from '@/core/utils/formatValue' const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { + console.log("prefixUrl",prefixUrl) const router = useRouter() const { query } = router const [order, setOrder] = useState(query?.orderBy) @@ -102,7 +103,14 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu } params = _.pickBy(params, _.identity) params = toQuery(params) - router.push(`${prefixUrl}?${params}`) + + const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + + if (slug) { + router.push(`${prefixUrl}/${slug}?${params}`) + } else { + router.push(`${prefixUrl}?${params}`) + } } diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index a2b790ca..1935c61f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -3,21 +3,26 @@ 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 } from '../../../api/promoApi' +import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi' 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 React from 'react' import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; -import { Swiper, SwiperSlide } from 'swiper/react'; +import DesktopView from '../../../core/components/views/DesktopView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' +import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +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 { cons } from 'lodash-contrib' const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { const router = useRouter() - const { slug = '' } = router.query + const { slug = '', brand, category } = router.query const [promoItems, setPromoItems] = useState([]) const [promoData, setPromoData] = useState(null) const [currentPage, setCurrentPage] = useState(1); @@ -25,42 +30,95 @@ export default function PromoDetail() { const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); const [loading, setLoading] = useState(true); - const [fetchingData, setFetchingData] = useState(false) const { isMobile, isDesktop } = useDevice() + const [brands, setBrands] = useState([]); + const [categories, setCategories] = useState([]); + + interface Brand { + brand: string; + qty: number; + } + + interface Category { + name: string; + qty: number; + } useEffect(() => { const loadPromo = async () => { + setLoading(true); + const brandsData: Brand[] = []; + const categoriesData: Category[] = []; + + try { const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) - console.log("slug sekarang ", slug) - setPromoItems(items) - console.log("data dari promotion pakai SOLR", items) - + if (items.length === 0) { setPromoData([]) setLoading(false); return; - } - - const promoDataPromises = items.map(async (item) => { - const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + } + + const promoDataPromises = items.map(async (item) => { + // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("produk id",item.product_id) + + try { + if(brand && category){ + const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand} && category_name :${category}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + console.log("data response2 ",response2) + return response2; + }else if(brand){ // belum bisa menangani lebih dari 1 brand + const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + console.log("data response2 ",response2) + return response2; + }else if (category){ // belum bisa menangani lebih dari 1 category + const response = await fetchVariantSolr(`id:${item.product_id} && category_name :${category}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + return response2; + }else{ + const response = await fetchPromoItemsSolr( `id:${item.id}`) + console.log("data respon",response) + return response; + } + // if(brand || category){ + // let query = `id:${item.product_id}`; + // if (brand) query += ` OR manufacture_name_s:${brand}`; + // if (category) query += ` OR category_name:${category}`; + // const response = await fetchVariantSolr(query); + // const product = response.response.docs[0]; + // const product_id = product.id + // const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + // return response2; - try { - const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) - console.log("respon data ", response) - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } + // }else{ + // const response = await fetchPromoItemsSolr( `id:${item.id}`) + // console.log("data respon",response) + // return response; + // } - const data: SolrResponse = await response.json() - console.log("data promo IPromotion[]", data) - - const promotions = await map(data.response.docs) - return promotions; + } catch (fetchError) { - console.error("Error fetching promotion data:", fetchError) + // console.error("Error fetching promotion data:", fetchError) return []; } }); @@ -68,7 +126,61 @@ export default function PromoDetail() { const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); setPromoData(mergedPromoData); - setTimeout(() => setLoading(false), 120); // Menambahkan delay 120ms sebelum mengubah status loading + + const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { + if (promoData) { + const dataBrandCategory = promoData.map(async (item) => { + // const response = await fetch(`/solr/variants/select?${queryParams2.toString()}`); + let response; + if(category){ + // response = await fetchVariantSolr(`id:${item.products[0].product_id} && manufacture_name_s:${brand}`); + response = await fetchVariantSolr(`id:${item.products[0].product_id} && category_name:${category}`); + }else{ + response = await fetchVariantSolr(`id:${item.products[0].product_id}`) + } + + + if (response.response?.docs?.length > 0) { + const product = response.response.docs[0]; + const manufactureNameS = product.manufacture_name; + if (Array.isArray(manufactureNameS)) { + for (let i = 0; i < manufactureNameS.length; i += 2) { + const brand = manufactureNameS[i]; + const qty = 1; + const existingBrandIndex = brandsData.findIndex(b => b.brand === brand); + if (existingBrandIndex !== -1) { + brandsData[existingBrandIndex].qty += qty; + } else { + brandsData.push({ brand, qty }); + } + } + } + + const categoryNameS = product.category_name; + if (Array.isArray(categoryNameS)) { + for (let i = 0; i < categoryNameS.length; i += 2) { + const name = categoryNameS[i]; + const qty = 1; + const existingCategoryIndex = categoriesData.findIndex(c => c.name === name); + if (existingCategoryIndex !== -1) { + categoriesData[existingCategoryIndex].qty += qty; + } else { + categoriesData.push({ name, qty }); + } + } + } + } + }); + + return Promise.all(dataBrandCategory); + } + }); + + await Promise.all(dataBrandCategoryPromises); + setBrands(brandsData); + setCategories(categoriesData); + setLoading(false); + } catch (loadError) { console.error("Error loading promo items:", loadError) setLoading(false); @@ -80,13 +192,9 @@ export default function PromoDetail() { } }, [slug]) - useEffect(() => { - window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates - }, []); // Run only once when component mounts - const map = async (promotions: any[]): Promise => { const result: IPromotion[] = [] - + for (const promotion of promotions) { const data: IPromotion = { id: promotion.id, @@ -104,67 +212,22 @@ export default function PromoDetail() { products: JSON.parse(promotion.products_s), free_products: JSON.parse(promotion.free_products_s), } - + result.push(data) } - + return result } - console.log("data yg dikirim ke ProductPromoCard", promoData) function capitalizeFirstLetter(string) { - // Ganti semua tanda _ dengan spasi string = string.replace(/_/g, ' '); - - // Kapitalisasi huruf pertama setelah spasi atau awal string return string.replace(/(^\w|\s\w)/g, function(match) { return match.toUpperCase(); }); } - useEffect(() => { - const handleScroll = () => { - if ( - !fetchingData && - window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight - ) { - // User has scrolled to 95% of page height - - setTimeout(() => setFetchingData(true), 120); - setCurrentPage((prevPage) => prevPage + 1) - } - } - - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) - }, [fetchingData]) - - useEffect(() => { - if (fetchingData) { - // Fetch more data - // You may need to adjust this logic according to your API - fetchMoreData() - } - }, [fetchingData]) - - const fetchMoreData = async () => { - try { - // Add a delay of approximately 150ms - setTimeout(async () => { - // Fetch more data - // Update promoData state with the new data - }, 150) - } catch (error) { - console.error('Error fetching more data:', error) - } finally { - setTimeout(() => setFetchingData(false), 120); - - } - } - - const visiblePromotions = promoData?.slice(0, currentPage * 12) - + const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; return ( - + {loading ? (
    ) : promoData && promoItems.length >= 1 ? ( <> - -
    +
    {visiblePromotions?.map((promotion) => ( - -
    - -
    -
    +
    + +
    ))} -
    - ) : (
    @@ -199,4 +262,4 @@ export default function PromoDetail() { )} ) -} \ No newline at end of file +} -- cgit v1.2.3 From 9bf19afa1776f72d1cc930558ccce41ec855a30d Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Fri, 14 Jun 2024 09:15:00 +0700 Subject: google sign up --- src/lib/auth/components/LoginDesktop.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/auth/components/LoginDesktop.jsx b/src/lib/auth/components/LoginDesktop.jsx index 1333db14..9a68dc53 100644 --- a/src/lib/auth/components/LoginDesktop.jsx +++ b/src/lib/auth/components/LoginDesktop.jsx @@ -8,6 +8,7 @@ import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'; +import Image from 'next/image'; const LoginDesktop = () => { const { @@ -108,7 +109,7 @@ const LoginDesktop = () => { {!isLoading ? 'Masuk' : 'Loading...'} - {/*
    +

    ATAU


    @@ -127,7 +128,7 @@ const LoginDesktop = () => { height={10} />

    Masuk dengan Google

    - */} +
    Belum punya akun Indoteknik?{' '} -- cgit v1.2.3 From b7c98bf3586d31fa65eea048ed2c98db321ce28c Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Fri, 14 Jun 2024 10:39:54 +0700 Subject: login mobile --- src/lib/auth/components/LoginMobile.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/auth/components/LoginMobile.jsx b/src/lib/auth/components/LoginMobile.jsx index 40924fbe..d2bf704f 100644 --- a/src/lib/auth/components/LoginMobile.jsx +++ b/src/lib/auth/components/LoginMobile.jsx @@ -117,7 +117,7 @@ const LoginMobile = () => { {!isLoading ? 'Masuk' : 'Loading...'} - {/*
    +

    ATAU


    @@ -136,7 +136,7 @@ const LoginMobile = () => { height={10} />

    Masuk dengan Google

    - */} +
    Belum punya akun Indoteknik?{' '} -- cgit v1.2.3 From ef2d3ad6759db8535c04d986f4bc43f01da6ccd8 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:11:13 +0700 Subject: update promotion-program --- src/api/promoApi.js | 17 +- src/pages/shop/promo/[slug].tsx | 501 +++++++++++++++++++++++++++++++--------- 2 files changed, 404 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index ecae5080..4c386fba 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -1,5 +1,6 @@ // src/api/promoApi.js import odooApi from '@/core/api/odooApi'; +import { type } from 'os'; // import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; export const fetchPromoItems = async (type) => { @@ -15,11 +16,10 @@ export const fetchPromoItems = async (type) => { export const fetchPromoItemsSolr = async (type) => { // let query = type ? `type_value_s:${type}` : '*:*'; let start = 0 - let rows = 120 + let rows = 100 try { const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); - console.log("Constructed URL SLOR:", `/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } @@ -32,6 +32,18 @@ export const fetchPromoItemsSolr = async (type) => { } }; +export const fetchVariantSolr = async(data)=>{ + try { + const queryParams = new URLSearchParams({ q: data }); + const response = await fetch(`/solr/variants/select?${queryParams.toString()}`); + const responseData = await response.json(); + return responseData; + } catch (error) { + console.error("Error fetching promotion data:", error); + return []; + } +}; + const map = async (promotions) => { const result = []; for (const promotion of promotions) { @@ -49,6 +61,7 @@ const map = async (promotions) => { price: promotion.price_f, total_qty: promotion.total_qty_i, products: JSON.parse(promotion.products_s), + product_id: promotion.product_ids[0], free_products: JSON.parse(promotion.free_products_s), }; result.push(data); diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 1935c61f..70280d1f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -1,4 +1,5 @@ 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' @@ -10,6 +11,7 @@ import { IPromotion } from '../../../../src-migrate/types/promotion' 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 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; @@ -17,22 +19,47 @@ 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 { cons } from 'lodash-contrib' +// import SideBanner from '~/modules/side-banner'; +import SideBanner from '../../../../src-migrate/modules/side-banner'; +import whatsappUrl from '../../../core/utils/whatsappUrl'; +import { toQuery } from 'lodash-contrib'; +import _ from 'lodash'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { const router = useRouter() - const { slug = '', brand, category } = router.query + const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query const [promoItems, setPromoItems] = useState([]) const [promoData, setPromoData] = useState(null) - const [currentPage, setCurrentPage] = useState(1); + const [currentPage, setCurrentPage] = useState(parseInt(page as string, 10) || 1); const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman - const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); const [loading, setLoading] = useState(true); const { isMobile, isDesktop } = useDevice() const [brands, setBrands] = useState([]); const [categories, setCategories] = useState([]); + const [brandValues, setBrandValues] = useState([]); + const [categoryValues, setCategoryValues] = useState([]); + const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); + const [spellings, setSpellings] = useState(null); + + useEffect(() => { + // Initialize brandValues based on router.query.brand + if (router.query.brand) { + const brandsArray = Array.isArray(router.query.brand) ? router.query.brand : [router.query.brand]; + setBrandValues(brandsArray); + } else { + setBrandValues([]); + } + + // Initialize categoryValues based on router.query.category + if (router.query.category) { + const categoriesArray = Array.isArray(router.query.category) ? router.query.category : [router.query.category]; + setCategoryValues(categoriesArray); + } else { + setCategoryValues([]); + } + }, [router.query.brand, router.query.category]); interface Brand { brand: string; @@ -49,11 +76,15 @@ export default function PromoDetail() { setLoading(true); const brandsData: Brand[] = []; const categoriesData: Category[] = []; - + + const pageNumber = Array.isArray(page) ? parseInt(page[0], 10) : parseInt(page, 10); + setCurrentPage(pageNumber) try { - const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) - setPromoItems(items) + // const start = (pageNumber-1) * itemsPerPage; + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`); + setPromoItems(items); + console.log("promoItems lastIndexOf",promoItems.length) if (items.length === 0) { setPromoData([]) @@ -61,67 +92,76 @@ export default function PromoDetail() { return; } + const brandArray = Array.isArray(brand) ? brand : brand.split(','); + const categoryArray = Array.isArray(category) ? category : category.split(','); + console.log("brandArray",brandArray) + console.log("categoryArray",categoryArray) const promoDataPromises = items.map(async (item) => { // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) console.log("produk id",item.product_id) try { - if(brand && category){ - const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand} && category_name :${category}`); - const product = response.response.docs[0]; - const product_id = product.id - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - console.log("data response2 ",response2) - return response2; - }else if(brand){ // belum bisa menangani lebih dari 1 brand - const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand}`); + let brandQuery = ''; + if (brand) { + brandQuery = brandArray.map(b => `manufacture_name_s:${b}`).join(' OR '); + brandQuery = `(${brandQuery})`; + } + + let categoryQuery = ''; + if (category) { + categoryQuery = categoryArray.map(c => `category_name:${c}`).join(' OR '); + categoryQuery = `(${categoryQuery})`; + } + + let priceQuery = ''; + if (priceFrom && priceTo) { + priceQuery = `price_f:[${priceFrom} TO ${priceTo}]`; + } else if (priceFrom) { + priceQuery = `price_f:[${priceFrom} TO *]`; + } else if (priceTo) { + priceQuery = `price_f:[* TO ${priceTo}]`; + } + + let combinedQuery = ''; + let combinedQueryPrice = `${priceQuery}`; + if (brand && category && priceFrom || priceTo) { + combinedQuery = `${brandQuery} AND ${categoryQuery} `; + } else if (brand && category) { + combinedQuery = `${brandQuery} AND ${categoryQuery}`; + } else if (brand && priceFrom || priceTo) { + combinedQuery = `${brandQuery}`; + } else if (category && priceFrom || priceTo) { + combinedQuery = `${categoryQuery}`; + } else if (brand) { + combinedQuery = brandQuery; + } else if (category) { + combinedQuery = categoryQuery; + } else if (priceFrom || priceTo) { + } + console.log("combinedQuery",combinedQuery) + + if (combinedQuery && priceFrom || priceTo) { + const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; - const product_id = product.id - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - console.log("data response2 ",response2) + const product_id = product.id; + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`); + // const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - }else if (category){ // belum bisa menangani lebih dari 1 category - const response = await fetchVariantSolr(`id:${item.product_id} && category_name :${category}`); + }else if(combinedQuery){ + const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; - const product_id = product.id - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + const product_id = product.id; + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - }else{ - const response = await fetchPromoItemsSolr( `id:${item.id}`) - console.log("data respon",response) + } + else { + const response = await fetchPromoItemsSolr(`id:${item.id}`); return response; } - // if(brand || category){ - // let query = `id:${item.product_id}`; - // if (brand) query += ` OR manufacture_name_s:${brand}`; - // if (category) query += ` OR category_name:${category}`; - // const response = await fetchVariantSolr(query); - // const product = response.response.docs[0]; - // const product_id = product.id - // const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - // return response2; - - // }else{ - // const response = await fetchPromoItemsSolr( `id:${item.id}`) - // console.log("data respon",response) - // return response; - // } - - - } catch (fetchError) { - // console.error("Error fetching promotion data:", fetchError) - return []; - } - }); + } catch (fetchError) { + return []; + } + }); const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); @@ -130,11 +170,10 @@ export default function PromoDetail() { const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { if (promoData) { const dataBrandCategory = promoData.map(async (item) => { - // const response = await fetch(`/solr/variants/select?${queryParams2.toString()}`); let response; if(category){ - // response = await fetchVariantSolr(`id:${item.products[0].product_id} && manufacture_name_s:${brand}`); - response = await fetchVariantSolr(`id:${item.products[0].product_id} && category_name:${category}`); + const categoryQuery = categoryArray.map(c => `category_name:${c}`).join(' OR '); + response = await fetchVariantSolr(`id:${item.products[0].product_id} AND (${categoryQuery})`); }else{ response = await fetchVariantSolr(`id:${item.products[0].product_id}`) } @@ -190,34 +229,8 @@ export default function PromoDetail() { if (slug) { loadPromo() } - }, [slug]) - - const map = async (promotions: any[]): Promise => { - const result: IPromotion[] = [] - - for (const promotion of promotions) { - const data: IPromotion = { - 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, - total_qty: promotion.total_qty_i, - products: JSON.parse(promotion.products_s), - free_products: JSON.parse(promotion.free_products_s), - } - - result.push(data) - } + },[slug, brand, category, priceFrom, priceTo, currentPage]); - return result - } function capitalizeFirstLetter(string) { string = string.replace(/_/g, ' '); @@ -226,40 +239,304 @@ export default function PromoDetail() { }); } - const visiblePromotions = promoData?.slice(0, currentPage * 12) + const handleDeleteFilter = async (source, value) => { + let params = { + q: router.query.q, + orderBy: orderBy, + brand: brandValues.join(','), + category: categoryValues.join(','), + priceFrom: priceFrom || '', + priceTo: priceTo || '', + }; + + let brands = brandValues; + let catagories = categoryValues; + switch (source) { + case 'brands': + brands = brandValues.filter((item) => item !== value); + params.brand = brands.join(','); + await setBrandValues(brands); + break; + case 'category': + catagories = categoryValues.filter((item) => item !== value); + params.category = catagories.join(','); + await setCategoryValues(catagories); + break; + case 'price': + params.priceFrom = ''; // Setel ke string kosong jika ingin menghapus nilai + params.priceTo = ''; // Setel ke string kosong jika ingin menghapus nilai + break; + case 'delete': + params = { + q: router.query.q, + orderBy: orderBy, + brand: '', + category: '', + priceFrom: '', + priceTo: '', + }; + break; + } + + handleSubmitFilter(params); + }; + const handleSubmitFilter = (params) => { + params = _.pickBy(params, _.identity); + params = toQuery(params); + router.push(`${Array.isArray(slug) ? slug[0] : slug}?${params}`); + // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); + }; + const handlePageChange = (selectedPage: number) => { + setCurrentPage(selectedPage); + router.push(`/shop/promo/${slug}?page=${selectedPage}`); + }; + + const { search } = router.query; + const prefixUrl = `/promo/${slug}`; + + console.log("halaman sekarang", currentPage) + console.log("data yang di potong", (currentPage-1) * itemsPerPage, currentPage * 12) + + const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) + // const visiblePromotions = promoData?.slice( 0, 12) const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; + const whatPromo = capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug) return ( - - - {loading ? ( -
    - -
    - ) : promoData && promoItems.length >= 1 ? ( - <> -
    - {visiblePromotions?.map((promotion) => ( -
    - + + + +
    +
    + +
    + +
    +
    +

    Promo {whatPromo}

    + + {/*
    +
    + {!spellings ? ( + <> + Menampilkan  + {pageCount > 1 ? ( + <> + {productStart + 1}- + {parseInt(productStart) + parseInt(productRows) > + productFound + ? productFound + : parseInt(productStart) + parseInt(productRows)} +  dari  + + ) : ( + '' + )} + {productFound} +  produk{' '} + {query.q && ( + <> + untuk pencarian{' '} + {query.q} + + )} + + ) : ( + SpellingComponent + )} +
    +
    +
    + +
    +
    + +
    +
    +
    */} + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {visiblePromotions?.map((promotion) => ( +
    + +
    + ))} +
    + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} +
    +
    + +
    + + Barang yang anda cari tidak ada?{' '} + + Hubungi Kami + + +
    +
    + +
    - ))} +
    - - ) : ( -
    -

    Belum ada promo pada kategori ini

    - )} + {console.log("promoItems lastIndexOf",promoItems.length)} + ) -} + } + +const FilterChoicesComponent = ({ + brandValues, + categoryValues, + priceFrom, + priceTo, + handleDeleteFilter, + }) => ( +
    + + {brandValues?.map((value, index) => ( + + {value} + handleDeleteFilter('brands', value)} /> + + ))} + + {categoryValues?.map((value, index) => ( + + {value} + handleDeleteFilter('category', value)} + /> + + ))} + {priceFrom && priceTo && ( + + + {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)} + + handleDeleteFilter('price', priceFrom)} + /> + + )} + {brandValues?.length > 0 || + categoryValues?.length > 0 || + priceFrom || + priceTo ? ( + + + + ) : ( + '' + )} + +
    +); + +// {loading ? ( +//
    +// +//
    +// ) : promoData && promoItems.length >= 1 ? ( +// <> +//
    +// {visiblePromotions?.map((promotion) => ( +//
    +// +//
    +// ))} +//
    +// +// ) : ( +//
    +//

    Belum ada promo pada kategori ini

    +//
    +// )} \ No newline at end of file -- cgit v1.2.3 From e3e3fe8d87130fcd1872046de0160272b6ea9763 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:15:30 +0700 Subject: update promotion-program --- src/api/bannerApi.js | 3 +++ src/lib/product/components/ProductSearch.jsx | 2 ++ src/pages/shop/promo/index.tsx | 4 +--- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/api/bannerApi.js b/src/api/bannerApi.js index 8bae131d..431225a5 100644 --- a/src/api/bannerApi.js +++ b/src/api/bannerApi.js @@ -3,3 +3,6 @@ import odooApi from '@/core/api/odooApi' export const bannerApi = ({ type }) => { return async () => await odooApi('GET', `/api/v1/banner?type=${type}`) } + +// ubah ke SOLR + diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 08b64c13..ec0077c2 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -130,6 +130,7 @@ const ProductSearch = ({ brands.push({ brand, qty }); } } + console.log("daftar brand",brands) const categories = []; for ( @@ -144,6 +145,7 @@ const ProductSearch = ({ categories.push({ name, qty }); } } + console.log("daftar kategori",categories) const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx index 6f5134a3..89e88e29 100644 --- a/src/pages/shop/promo/index.tsx +++ b/src/pages/shop/promo/index.tsx @@ -101,9 +101,7 @@ export default function Promo() { } console.log("data yg dikirim ke ProductPromoCard", promoData) - function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); - } + useEffect(() => { const handleScroll = () => { -- cgit v1.2.3 From 7c45b1c564db183868b3b99011dd3a090818a285 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:46:41 +0700 Subject: update promotion program --- src/pages/shop/promo/[slug].tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 70280d1f..4f223aed 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -24,6 +24,7 @@ import SideBanner from '../../../../src-migrate/modules/side-banner'; import whatsappUrl from '../../../core/utils/whatsappUrl'; import { toQuery } from 'lodash-contrib'; import _ from 'lodash'; +import { Query } from 'react-query'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) @@ -283,13 +284,10 @@ export default function PromoDetail() { const handleSubmitFilter = (params) => { params = _.pickBy(params, _.identity); params = toQuery(params); - router.push(`${Array.isArray(slug) ? slug[0] : slug}?${params}`); + router.push(`${slug}?${params}`); // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); }; - const handlePageChange = (selectedPage: number) => { - setCurrentPage(selectedPage); - router.push(`/shop/promo/${slug}?page=${selectedPage}`); - }; + const { search } = router.query; const prefixUrl = `/promo/${slug}`; @@ -300,7 +298,7 @@ export default function PromoDetail() { const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) // const visiblePromotions = promoData?.slice( 0, 12) const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; - const whatPromo = capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug) + const whatPromo = capitalizeFirstLetter(slug) return ( + />
    -- cgit v1.2.3 From 518a2d89d91775ceffd06f8d7aca7050526310da Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 16:41:13 +0700 Subject: update add mobile view promotion-program --- src/pages/shop/promo/[slug].tsx | 182 ++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 4f223aed..c53bcf0e 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -15,16 +15,15 @@ import MobileView from '../../../core/components/views/MobileView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +import ProductFilter from '../../../lib/product/components/ProductFilter'; 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 { cons } from 'lodash-contrib' -// import SideBanner from '~/modules/side-banner'; import SideBanner from '../../../../src-migrate/modules/side-banner'; import whatsappUrl from '../../../core/utils/whatsappUrl'; import { toQuery } from 'lodash-contrib'; import _ from 'lodash'; -import { Query } from 'react-query'; +import useActive from '../../../core/hooks/useActive'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) @@ -43,6 +42,7 @@ export default function PromoDetail() { const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); const [spellings, setSpellings] = useState(null); + const popup = useActive(); useEffect(() => { // Initialize brandValues based on router.query.brand @@ -82,10 +82,8 @@ export default function PromoDetail() { setCurrentPage(pageNumber) try { - // const start = (pageNumber-1) * itemsPerPage; const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`); setPromoItems(items); - console.log("promoItems lastIndexOf",promoItems.length) if (items.length === 0) { setPromoData([]) @@ -95,11 +93,8 @@ export default function PromoDetail() { const brandArray = Array.isArray(brand) ? brand : brand.split(','); const categoryArray = Array.isArray(category) ? category : category.split(','); - console.log("brandArray",brandArray) - console.log("categoryArray",categoryArray) + const promoDataPromises = items.map(async (item) => { - // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("produk id",item.product_id) try { let brandQuery = ''; @@ -137,16 +132,13 @@ export default function PromoDetail() { combinedQuery = brandQuery; } else if (category) { combinedQuery = categoryQuery; - } else if (priceFrom || priceTo) { } - console.log("combinedQuery",combinedQuery) if (combinedQuery && priceFrom || priceTo) { const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; const product_id = product.id; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`); - // const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`); return response2; }else if(combinedQuery){ const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); @@ -154,8 +146,7 @@ export default function PromoDetail() { const product_id = product.id; const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - } - else { + } else { const response = await fetchPromoItemsSolr(`id:${item.id}`); return response; } @@ -222,7 +213,7 @@ export default function PromoDetail() { setLoading(false); } catch (loadError) { - console.error("Error loading promo items:", loadError) + // console.error("Error loading promo items:", loadError) setLoading(false); } } @@ -264,8 +255,8 @@ export default function PromoDetail() { await setCategoryValues(catagories); break; case 'price': - params.priceFrom = ''; // Setel ke string kosong jika ingin menghapus nilai - params.priceTo = ''; // Setel ke string kosong jika ingin menghapus nilai + params.priceFrom = ''; + params.priceTo = ''; break; case 'delete': params = { @@ -285,19 +276,10 @@ export default function PromoDetail() { params = _.pickBy(params, _.identity); params = toQuery(params); router.push(`${slug}?${params}`); - // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); }; - - const { search } = router.query; - const prefixUrl = `/promo/${slug}`; - - console.log("halaman sekarang", currentPage) - console.log("data yang di potong", (currentPage-1) * itemsPerPage, currentPage * 12) - const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) - // const visiblePromotions = promoData?.slice( 0, 12) - const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; + const whatPromo = capitalizeFirstLetter(slug) return ( @@ -306,7 +288,67 @@ export default function PromoDetail() { description='B2B Marketplace MRO & Industri dengan Layanan Pembayaran Tempo, Faktur Pajak, Online Quotation, Garansi Resmi & Harga Kompetitif' /> + +
    +

    Promo {whatPromo}

    + + + {promoItems.length >= 1 && ( +
    +
    + +
    +
    + )} + + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {visiblePromotions?.map((promotion) => ( +
    + +
    + ))} +
    + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} + + + +
    +
    @@ -328,69 +370,6 @@ export default function PromoDetail() { priceTo={priceTo} handleDeleteFilter={handleDeleteFilter} /> - {/*
    -
    - {!spellings ? ( - <> - Menampilkan  - {pageCount > 1 ? ( - <> - {productStart + 1}- - {parseInt(productStart) + parseInt(productRows) > - productFound - ? productFound - : parseInt(productStart) + parseInt(productRows)} -  dari  - - ) : ( - '' - )} - {productFound} -  produk{' '} - {query.q && ( - <> - untuk pencarian{' '} - {query.q} - - )} - - ) : ( - SpellingComponent - )} -
    -
    -
    - -
    -
    - -
    -
    -
    */} {loading ? (
    @@ -447,7 +426,6 @@ export default function PromoDetail() {
    - {console.log("promoItems lastIndexOf",promoItems.length)} ) @@ -517,23 +495,3 @@ const FilterChoicesComponent = ({
    ); - -// {loading ? ( -//
    -// -//
    -// ) : promoData && promoItems.length >= 1 ? ( -// <> -//
    -// {visiblePromotions?.map((promotion) => ( -//
    -// -//
    -// ))} -//
    -// -// ) : ( -//
    -//

    Belum ada promo pada kategori ini

    -//
    -// )} \ No newline at end of file -- cgit v1.2.3 From 55f4e2dc6e25dd425ad0a2b8763f8b8de0305e70 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 17:08:42 +0700 Subject: update promotion-program --- src/pages/shop/promo/[slug].tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index c53bcf0e..1248ba35 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -45,17 +45,26 @@ export default function PromoDetail() { const popup = useActive(); useEffect(() => { - // Initialize brandValues based on router.query.brand if (router.query.brand) { - const brandsArray = Array.isArray(router.query.brand) ? router.query.brand : [router.query.brand]; + let brandsArray: string[] = []; + if (Array.isArray(router.query.brand)) { + brandsArray = router.query.brand; + } else if (typeof router.query.brand === 'string') { + brandsArray = router.query.brand.split(',').map((brand) => brand.trim()); + } setBrandValues(brandsArray); } else { setBrandValues([]); } - // Initialize categoryValues based on router.query.category if (router.query.category) { - const categoriesArray = Array.isArray(router.query.category) ? router.query.category : [router.query.category]; + let categoriesArray: string[] = []; + + if (Array.isArray(router.query.category)) { + categoriesArray = router.query.category; + } else if (typeof router.query.category === 'string') { + categoriesArray = router.query.category.split(',').map((category) => category.trim()); + } setCategoryValues(categoriesArray); } else { setCategoryValues([]); @@ -467,6 +476,7 @@ const FilterChoicesComponent = ({ /> ))} + {console.log("categoryValues",categoryValues)} {priceFrom && priceTo && ( -- cgit v1.2.3 From e786215b1be4b88e1b43efb2beae15073d6f81db Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 08:32:37 +0700 Subject: update promotion program (handleSubmitFilter) --- src/pages/shop/promo/[slug].tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 1248ba35..da720b16 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -41,7 +41,6 @@ export default function PromoDetail() { const [brandValues, setBrandValues] = useState([]); const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); - const [spellings, setSpellings] = useState(null); const popup = useActive(); useEffect(() => { @@ -243,7 +242,7 @@ export default function PromoDetail() { const handleDeleteFilter = async (source, value) => { let params = { q: router.query.q, - orderBy: orderBy, + orderBy: '', brand: brandValues.join(','), category: categoryValues.join(','), priceFrom: priceFrom || '', @@ -270,7 +269,7 @@ export default function PromoDetail() { case 'delete': params = { q: router.query.q, - orderBy: orderBy, + orderBy: '', brand: '', category: '', priceFrom: '', @@ -353,6 +352,7 @@ export default function PromoDetail() { brands={brands || []} categories={categories || []} prefixUrl={router.asPath.includes('?') ? `${router.asPath}` : `${router.asPath}?`} + // prefixUrl={`${router.query}?`} defaultBrand={null} />
    -- cgit v1.2.3 From 4f4729440befed9899661a5c9a7bc9b57c16cc6e Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 10:20:30 +0700 Subject: update grid-cols promotion program --- src/pages/shop/promo/[slug].tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index da720b16..19592f6e 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -328,7 +328,7 @@ export default function PromoDetail() { <>
    {visiblePromotions?.map((promotion) => ( -
    +
    ))} @@ -385,7 +385,7 @@ export default function PromoDetail() {
    ) : promoData && promoItems.length >= 1 ? ( <> -
    +
    {visiblePromotions?.map((promotion) => (
    -- cgit v1.2.3 From 4d849f1ab72a0d0eb5851662f200ccef21b66457 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 18 Jun 2024 10:26:17 +0700 Subject: fixing error sign in and sign out google --- src/core/utils/auth.js | 2 +- src/pages/api/auth/[...nextauth].js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/utils/auth.js b/src/core/utils/auth.js index a7244747..03b20ae2 100644 --- a/src/core/utils/auth.js +++ b/src/core/utils/auth.js @@ -29,7 +29,7 @@ const setAuth = (user) => { * @returns {boolean} - Returns `true`. */ const deleteAuth = async() => { - // await signOut() + await signOut() deleteCookie('auth') return true } diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index 3c433167..c188aaa1 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -20,7 +20,11 @@ export default NextAuth({ session.accessToken = token.accessToken return session - } + }, + async redirect({ url, baseUrl }) { + // Redirect to dashboard after login + return url.startsWith(baseUrl) ? url : baseUrl; + }, }, secret: process.env.JWT_SECRET }) -- cgit v1.2.3 From 98109d3da0a88dfa1a513be68a0debe2e626d331 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 18 Jun 2024 11:50:51 +0700 Subject: fixing error refirect login --- src/lib/auth/hooks/useLogin.js | 2 +- src/pages/api/auth/[...nextauth].js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib/auth/hooks/useLogin.js b/src/lib/auth/hooks/useLogin.js index dc9580ea..dd5a4b03 100644 --- a/src/lib/auth/hooks/useLogin.js +++ b/src/lib/auth/hooks/useLogin.js @@ -74,7 +74,7 @@ const useLogin = () => { if (data.isAuth) { session.odooUser = data.user; setCookie('auth', JSON.stringify(session?.odooUser)); - router.push(decodeURIComponent(router?.query?.next) ?? '/'); + router.push(router?.query?.next || '/'); return; } }; diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index c188aaa1..3c433167 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -20,11 +20,7 @@ export default NextAuth({ session.accessToken = token.accessToken return session - }, - async redirect({ url, baseUrl }) { - // Redirect to dashboard after login - return url.startsWith(baseUrl) ? url : baseUrl; - }, + } }, secret: process.env.JWT_SECRET }) -- cgit v1.2.3 From 78575ef59454214f61f77b1a826af30497cfdc5f Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 14:23:16 +0700 Subject: update url page promotion program --- src/pages/shop/promo/[slug].tsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 19592f6e..667a26ce 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -21,7 +21,7 @@ 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 { toQuery } from 'lodash-contrib'; +import { cons, toQuery } from 'lodash-contrib'; import _ from 'lodash'; import useActive from '../../../core/hooks/useActive'; @@ -42,6 +42,7 @@ export default function PromoDetail() { const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); const popup = useActive(); + const prefixUrl = `/shop/promo/${slug}` useEffect(() => { if (router.query.brand) { @@ -287,8 +288,18 @@ export default function PromoDetail() { }; const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) + + const toQuery = (obj) => { + const str = Object.keys(obj) + .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`) + .join('&') + return str + } const whatPromo = capitalizeFirstLetter(slug) + const queryWithoutSlug = _.omit(router.query, ['slug']) + const queryString = toQuery(queryWithoutSlug) + return (
    {visiblePromotions?.map((promotion) => ( -
    +
    ))} @@ -343,7 +354,7 @@ export default function PromoDetail() {
    @@ -425,10 +435,12 @@ export default function PromoDetail() {
    + +
    -- cgit v1.2.3 From ba84659f27c84d0d2c0cc3275e211a865e416bf7 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 11:31:02 +0700 Subject: update responsive promotion program --- src/pages/shop/promo/[slug].tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 667a26ce..6e18101f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -339,7 +339,7 @@ export default function PromoDetail() { <>
    {visiblePromotions?.map((promotion) => ( -
    +
    ))} @@ -395,9 +395,9 @@ export default function PromoDetail() {
    ) : promoData && promoItems.length >= 1 ? ( <> -
    +
    {visiblePromotions?.map((promotion) => ( -
    +
    ))} -- cgit v1.2.3 From ced37d32aa345fc288483716771422e7b7c0913a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 17:10:24 +0700 Subject: update tampilan promotion program --- .../components/ProductFilterDesktopPromotion.jsx | 98 ++++++++++++++++++++++ src/pages/index.jsx | 4 +- src/pages/shop/promo/[slug].tsx | 29 +++---- 3 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 src/lib/product/components/ProductFilterDesktopPromotion.jsx (limited to 'src') diff --git a/src/lib/product/components/ProductFilterDesktopPromotion.jsx b/src/lib/product/components/ProductFilterDesktopPromotion.jsx new file mode 100644 index 00000000..332d2374 --- /dev/null +++ b/src/lib/product/components/ProductFilterDesktopPromotion.jsx @@ -0,0 +1,98 @@ +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import _ from 'lodash' +import { toQuery } from 'lodash-contrib' +import { Button } from '@chakra-ui/react' +import { MultiSelect } from 'primereact/multiselect'; + +const ProductFilterDesktop = ({ brands, categories, prefixUrl }) => { + const router = useRouter() + const { query } = router + + const [selectedBrand, setSelectedBrand] = useState(null); + const [selectedCategory, setSelectedCategory] = useState(null); + + const handleSubmit = () => { + let params = { + q: router.query.q, + orderBy: query?.orderBy, + brand: selectedBrand ? selectedBrand.map(b => b.code).join(',') : '', + category: query?.category, + priceFrom: query?.priceFrom, + priceTo: query?.priceTo, + stock: query?.stock + } + params = _.pickBy(params, _.identity) + params = toQuery(params) + + const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + + if (slug) { + router.push(`${prefixUrl}/${slug}?${params}`) + } else { + router.push(`${prefixUrl}?${params}`) + } + } + + const countryTemplate = (option) => { + return ( +
    +
    {option.name}
    +
    + ); + }; + + const brandOptions = brands.map(brand => ({ + name: `${brand.brand} (${brand.qty})`, + code: brand.brand + })); + + const categoryOptions = categories.map(category => ({ + name: `${category.name} (${category.qty})`, + code: category.name + })); + + const panelFooterTemplate = () => { + return ( + + ); + }; + + return ( +
    +
    + + setSelectedBrand(e.value)} + optionLabel="name" + placeholder="Pilih Brand" + itemTemplate={countryTemplate} + panelFooterTemplate={panelFooterTemplate} + className="w-full" + display="chip" + /> +
    + +
    + + setSelectedCategory(e.value)} + optionLabel="name" + placeholder="Pilih Kategori" + itemTemplate={countryTemplate} + panelFooterTemplate={panelFooterTemplate} + className="w-full" + display="chip" + /> +
    +
    + ) +} + +export default ProductFilterDesktop diff --git a/src/pages/index.jsx b/src/pages/index.jsx index ddc41cbe..80e9ef0e 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -102,13 +102,13 @@ export default function Home() {
    -
    +
    - + diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 6e18101f..7fea10ff 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -14,7 +14,7 @@ import DesktopView from '../../../core/components/views/DesktopView'; import MobileView from '../../../core/components/views/MobileView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' -import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion'; import ProductFilter from '../../../lib/product/components/ProductFilter'; import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react'; import { formatCurrency } from '../../../core/utils/formatValue'; @@ -369,19 +369,17 @@ export default function PromoDetail() { -
    -
    - -
    - -
    -
    +
    +

    Promo {whatPromo}

    +
    + +
    ) : promoData && promoItems.length >= 1 ? ( <> -
    +
    {visiblePromotions?.map((promotion) => ( -
    +
    ))} @@ -488,7 +486,6 @@ const FilterChoicesComponent = ({ /> ))} - {console.log("categoryValues",categoryValues)} {priceFrom && priceTo && ( -- cgit v1.2.3 From fd96f81bdf1ad6bfe8c7a60571eb9ea70f432ff8 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 20 Jun 2024 11:54:11 +0700 Subject: update filter promotion-program --- .../components/ProductFilterDesktopPromotion.jsx | 186 ++++++++++++--------- src/pages/shop/promo/[slug].tsx | 4 +- 2 files changed, 112 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilterDesktopPromotion.jsx b/src/lib/product/components/ProductFilterDesktopPromotion.jsx index 332d2374..0815b881 100644 --- a/src/lib/product/components/ProductFilterDesktopPromotion.jsx +++ b/src/lib/product/components/ProductFilterDesktopPromotion.jsx @@ -1,98 +1,132 @@ -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' -import { Button } from '@chakra-ui/react' -import { MultiSelect } from 'primereact/multiselect'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import _ from 'lodash'; +import { toQuery } from 'lodash-contrib'; +import { Button } from '@chakra-ui/react'; +import { MultiSelect } from 'react-multi-select-component'; const ProductFilterDesktop = ({ brands, categories, prefixUrl }) => { - const router = useRouter() - const { query } = router + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy); + const [brandValues, setBrand] = useState([]); + const [categoryValues, setCategory] = useState([]); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom); + const [priceTo, setPriceTo] = useState(query?.priceTo); + const [stock, setStock] = useState(query?.stock); + const [activeRange, setActiveRange] = useState(null); + const [isBrandDropdownClicked, setIsBrandDropdownClicked] = useState(false); + const [isCategoryDropdownClicked, setIsCategoryDropdownClicked] = useState(false); - const [selectedBrand, setSelectedBrand] = useState(null); - const [selectedCategory, setSelectedCategory] = useState(null); + // Effect to set brandValues from query parameter 'brand' + useEffect(() => { + const brandParam = query?.brand; + if (brandParam) { + const brandsArray = brandParam.split(',').map((b) => ({ + label: b, + value: b, + })); + setBrand(brandsArray); + } + + }, [query.brand]); // Trigger effect whenever query.brand changes + + useEffect(() => { + const categoryParam = query?.category; + if (categoryParam) { + const categoriesArray = categoryParam.split(',').map((c) => ({ + label: c, + value: c, + })); + setCategory(categoriesArray); + } + }, [query.category]); // Trigger effect whenever query.category changes const handleSubmit = () => { let params = { q: router.query.q, - orderBy: query?.orderBy, - brand: selectedBrand ? selectedBrand.map(b => b.code).join(',') : '', - category: query?.category, - priceFrom: query?.priceFrom, - priceTo: query?.priceTo, - stock: query?.stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) + orderBy: order, + brand: brandValues.map((b) => b.value).join(','), + category: categoryValues.map((c) => c.value).join(','), + priceFrom, + priceTo, + stock: stock, + }; + params = _.pickBy(params, _.identity); + params = toQuery(params); - const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + const slug = Array.isArray(router.query.slug) + ? router.query.slug[0] + : router.query.slug; if (slug) { - router.push(`${prefixUrl}/${slug}?${params}`) + router.push(`${prefixUrl}/${slug}?${params}`); } else { - router.push(`${prefixUrl}?${params}`) + router.push(`${prefixUrl}?${params}`); } - } - - const countryTemplate = (option) => { - return ( -
    -
    {option.name}
    -
    - ); }; - const brandOptions = brands.map(brand => ({ - name: `${brand.brand} (${brand.qty})`, - code: brand.brand - })); - const categoryOptions = categories.map(category => ({ - name: `${category.name} (${category.qty})`, - code: category.name + const brandOptions = brands.map((brand) => ({ + label: `${brand.brand} (${brand.qty})`, + value: brand.brand, })); - const panelFooterTemplate = () => { - return ( - - ); - }; + const categoryOptions = categories.map((category) => ({ + label: `${category.name} (${category.qty})`, + value: category.name, + })); return ( -
    -
    - - setSelectedBrand(e.value)} - optionLabel="name" - placeholder="Pilih Brand" - itemTemplate={countryTemplate} - panelFooterTemplate={panelFooterTemplate} - className="w-full" - display="chip" - /> -
    + <> +
    + {/* Brand MultiSelect */} +
    +
    + +
    + setIsBrandDropdownClicked(isOpen)} + hasSelectAll={false} + /> +
    +
    +
    + + {/* Category MultiSelect */} +
    +
    + +
    + + setIsCategoryDropdownClicked(!isCategoryDropdownClicked) + } + hasSelectAll={false} + /> +
    +
    +
    -
    - - setSelectedCategory(e.value)} - optionLabel="name" - placeholder="Pilih Kategori" - itemTemplate={countryTemplate} - panelFooterTemplate={panelFooterTemplate} - className="w-full" - display="chip" - /> + {/* Apply Button */} +
    +
    + +
    +
    -
    - ) -} + + ); +}; -export default ProductFilterDesktop +export default ProductFilterDesktop; diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 7fea10ff..dbf8d908 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -372,7 +372,7 @@ export default function PromoDetail() {

    Promo {whatPromo}

    -
    +
    ( -
    +
    {brandValues?.map((value, index) => ( Date: Thu, 20 Jun 2024 15:23:58 +0700 Subject: update filter promotion-program --- src/pages/shop/promo/[slug].tsx | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index dbf8d908..bd69c071 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -372,21 +372,28 @@ export default function PromoDetail() {

    Promo {whatPromo}

    -
    - +
    + +
    + + +
    +
    + + +
    - {loading ? (
    -- cgit v1.2.3 From 7b08c9358888148bf6f6c2c7145d75e466550298 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 21 Jun 2024 11:04:57 +0700 Subject: update after marge --- src/pages/shop/promo/index.tsx | 186 ----------------------------------------- 1 file changed, 186 deletions(-) delete mode 100644 src/pages/shop/promo/index.tsx (limited to 'src') diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx deleted file mode 100644 index 89e88e29..00000000 --- a/src/pages/shop/promo/index.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import dynamic from 'next/dynamic' -import { useEffect, useState } from 'react' -import { useRouter } from 'next/router' -import Seo from '../../../core/components/Seo.jsx' -import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx' -import { fetchPromoItemsSolr } from '../../../api/promoApi.js' -import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' -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"; - -const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) - -export default function Promo() { - const router = useRouter() - const { slug = '' } = router.query - const [promoItems, setPromoItems] = useState([]) - const [promoData, setPromoData] = useState(null) - const [loading, setLoading] = useState(true) - const [currentPage, setCurrentPage] = useState(1) - const [fetchingData, setFetchingData] = useState(false) - - useEffect(() => { - const loadPromo = async () => { - try { - const items = await fetchPromoItemsSolr(`*:*`) - console.log("slug sekarang ", slug) - - setPromoItems(items) - console.log("data dari promotion pakai SOLR", items) - - if (items.length === 0) { - setPromoData([]) - setLoading(false); - return; - } - - const promoDataPromises = items.map(async (item) => { - const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) - - try { - const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) - console.log("respon data ", response) - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const data: SolrResponse = await response.json() - console.log("data promo IPromotion[]", data) - - const promotions = await map(data.response.docs) - return promotions; - } catch (fetchError) { - console.error("Error fetching promotion data:", fetchError) - return []; - } - }); - - const promoDataArray = await Promise.all(promoDataPromises); - const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); - setPromoData(mergedPromoData); - setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading - } catch (loadError) { - console.error("Error loading promo items:", loadError) - setLoading(false); - } - } - - if (slug) { - loadPromo() - } - }, [slug]) - - const map = async (promotions: any[]): Promise => { - const result: IPromotion[] = [] - - for (const promotion of promotions) { - const data: IPromotion = { - 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, - total_qty: promotion.total_qty_i, - products: JSON.parse(promotion.products_s), - free_products: JSON.parse(promotion.free_products_s), - } - - result.push(data) - } - - return result - } - - console.log("data yg dikirim ke ProductPromoCard", promoData) - - - useEffect(() => { - const handleScroll = () => { - if ( - !fetchingData && - window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight - ) { - // User has scrolled to 95% of page height - - setTimeout(() => setFetchingData(true), 120); - setCurrentPage((prevPage) => prevPage + 1) - } - } - - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) - }, [fetchingData]) - - useEffect(() => { - if (fetchingData) { - // Fetch more data - // You may need to adjust this logic according to your API - fetchMoreData() - } - }, [fetchingData]) - - const fetchMoreData = async () => { - try { - // Add a delay of approximately 150ms - setTimeout(async () => { - // Fetch more data - // Update promoData state with the new data - }, 150) - } catch (error) { - console.error('Error fetching more data:', error) - } finally { - setTimeout(() => setFetchingData(false), 120); - - } - } - - const visiblePromotions = promoData?.slice(0, currentPage * 12) - - return ( - - - {/* */} -
    -
    -

    Semua Promo di Indoteknik

    -
    -
    - {loading ? ( -
    - -
    - ) : promoData && promoItems.length >= 1 ? ( - <> -
    - {visiblePromotions?.map((promotion) => ( -
    - -
    - ))} -
    - {fetchingData && ( -
    - -
    - )} - - ) : ( -
    -

    Belum ada promo pada kategori ini

    -
    - )} -
    - ) -} -- cgit v1.2.3 From f559326406175b18f75d2dd42c8bd2f0d901acbf Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Fri, 21 Jun 2024 15:09:57 +0700 Subject: recomendation product for sales --- src/pages/api/shop/generate-recomendation.js | 36 ++++--- .../components/products-recomendatison.jsx | 107 +++++++++++++++++---- 2 files changed, 109 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/pages/api/shop/generate-recomendation.js b/src/pages/api/shop/generate-recomendation.js index 11dd153e..aea39adf 100644 --- a/src/pages/api/shop/generate-recomendation.js +++ b/src/pages/api/shop/generate-recomendation.js @@ -9,7 +9,7 @@ export default async function handler(req, res) { return res.status(422).json({ error: 'parameter missing' }) } - let parameter = [ + /*let parameter = [ `q=${escapeSolrQuery(q)}`, `q.op=${op}`, `indent=true`, @@ -22,23 +22,27 @@ export default async function handler(req, res) { ]; let result = await axios( process.env.SOLR_HOST + '/solr/product/select?' + parameter.join('&') + );*/ + let parameter = [ + `q=${escapeSolrQuery(q)}`, + `q.op=${op}`, + `debugQuery=on`, + `defType=edismax`, + `df=display_name_s`, + `fq=-publish_b:false`, + `rows=5`, + ]; + if(op == 'AND'){ + parameter.push(`sort=product_rating_f DESC, price_discount_f DESC`); + parameter.push(`rows=1`); + } + + let result = await axios( + process.env.SOLR_HOST + '/solr/recommendation/select?' + parameter.join('&') ); try { - let { auth } = req.cookies; - if (auth) auth = JSON.parse(auth); - result.data.response.products = productMappingSolr( - 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); + result.data = camelcaseObjectDeep(result.data) + res.status(200).json(result.data) } catch (error) { res.status(400).json({ error: error.message }); } diff --git a/src/pages/my/recomendation/components/products-recomendatison.jsx b/src/pages/my/recomendation/components/products-recomendatison.jsx index bb5950c8..d39d2a99 100644 --- a/src/pages/my/recomendation/components/products-recomendatison.jsx +++ b/src/pages/my/recomendation/components/products-recomendatison.jsx @@ -8,6 +8,15 @@ import Image from 'next/image'; import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; import formatCurrency from '~/libs/formatCurrency'; +const exportToExcel = (data) => { + const worksheet = XLSX.utils.json_to_sheet(data); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'Results'); + + // Generate Excel file and trigger download in the browser + XLSX.writeFile(workbook, 'ProductRecommendations.xlsx'); +}; + const ProductsRecomendation = ({ id }) => { const [excelData, setExcelData] = useState(null); const [products, setProducts] = useState([]); @@ -22,13 +31,8 @@ const ProductsRecomendation = ({ id }) => { product: product, result: { id: result?.id || '-', - name: result?.displayName || '-', - code: result?.code || '-', - image: result?.image || '-', - price: result?.lowestPrice.priceDiscount || '-', - manufacture: result?.manufacture.name || '-', - variantTotal: result?.variantTotal || '-', - variants: variants || '-', + name: result?.nameS || '-', + code: result?.defaultCodeS || '-', }, }; @@ -76,9 +80,7 @@ const ProductsRecomendation = ({ id }) => { } }); - console.log('ini result', searchProduct.data.response); - - + console.log('ini result', searchProduct.data.response); } return resultMapping; @@ -91,26 +93,45 @@ const ProductsRecomendation = ({ id }) => { const results = await Promise.all( excelData.map(async (row, i) => { const index = i + 1; - const product = row[0]; - return await searchRecomendation({ product, index }); + const product = row['product']; + return await generateProductRecomendation({ product, index }); }) - ).then((results) => setProducts(results)); + ); + + const formattedResults = results.map((result) => { + const formattedResult = { product: result.product }; + for (let i = 0; i <= 5; i++) { + formattedResult[`recomendation product ${i + 1} - code`] = result.result[i] == null ? '-' : result.result[i]?.code; + formattedResult[`recomendation product ${i + 1} - name`] = result.result[i] == null ? '-' : result.result[i]?.name ; + } + return formattedResult; + }); + + exportToExcel(formattedResults); + setProducts(results); setIsLoading(false); } else { + setIsLoading(false); console.log('No excel data available'); } }; const handleFileChange = (e) => { + setIsLoading(true); const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const data = new Uint8Array(event.target.result); const workbook = XLSX.read(data, { type: 'array' }); - const sheetName = workbook.SheetNames[0]; - const sheet = workbook.Sheets[sheetName]; - const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1, range: 1 }); + + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + const jsonData = XLSX.utils.sheet_to_json(worksheet); + setExcelData(jsonData); + console.log('ini json data', jsonData); + + setIsLoading(false); }; reader.readAsArrayBuffer(file); }; @@ -137,6 +158,56 @@ const ProductsRecomendation = ({ id }) => { result(); }; + + const generateProductRecomendation = async ({ product, index }) => { + let variants = []; + let resultMapping = {}; + const searchProduct = await axios.post( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/generate-recomendation?q=${product}&op=AND` + ); + const searchProductOR = await axios.post( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/generate-recomendation?q=${product}&op=OR` + ); + const resultAND = + searchProduct.data.response.numFound > 0 + ? searchProduct.data.response.docs[0] + : null; // hasil satu + const resultOR = + searchProductOR.data.response.numFound > 0 + ? searchProductOR.data.response.docs + : []; // hasil 5 + + resultMapping = { + index: index, + product: product, + result: {}, + }; + + // Add resultAND to resultMapping if it exists + resultMapping.result[0] = resultAND + ? { + id: resultAND?.id || '-', + name: resultAND?.nameS || '-', + code: resultAND?.defaultCodeS || '-', + } + : null; + + // Add resultOR to resultMapping + if (resultOR.length > 0) { + resultOR.forEach((item, idx) => { + resultMapping.result[idx + 1] = { + id: item?.id || '-', + name: item?.nameS || '-', + code: item?.defaultCodeS || '-', + }; + }); + } else { + for (let i = 0; i <= 5; i++) { + resultMapping.result[i + 1] = null; + } + } + return resultMapping; + }; return ( <> { Generate
    -
    + {/*
    {products && products.length > 0 && (
    @@ -396,7 +467,7 @@ const ProductsRecomendation = ({ id }) => {
    )} -
    +
    */}
    -- cgit v1.2.3 From 3ada88f0faf901e05bd56ecff8c4bcb209c06787 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 21 Jun 2024 15:31:12 +0700 Subject: update all-promotion --- src/api/promoApi.js | 7 ++++--- src/pages/shop/promo/[slug].tsx | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index 4c386fba..95a27fd3 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -13,13 +13,14 @@ export const fetchPromoItems = async (type) => { } }; -export const fetchPromoItemsSolr = async (type) => { +export const fetchPromoItemsSolr = async (type, start, rows) => { // let query = type ? `type_value_s:${type}` : '*:*'; - let start = 0 - let rows = 100 + // let start = 0 + // let rows = 10 try { const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + console.log("URL",`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index bd69c071..aaee1249 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -91,7 +91,7 @@ export default function PromoDetail() { setCurrentPage(pageNumber) try { - const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`); + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`,0,100); setPromoItems(items); if (items.length === 0) { @@ -147,16 +147,16 @@ export default function PromoDetail() { const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; const product_id = product.id; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`); + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`,0,100); return response2; }else if(combinedQuery){ const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; const product_id = product.id; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `,0,100); return response2; } else { - const response = await fetchPromoItemsSolr(`id:${item.id}`); + const response = await fetchPromoItemsSolr(`id:${item.id}`,0,100); return response; } } catch (fetchError) { -- cgit v1.2.3 From 7afd73bde637528e9427124b6e9842a026f823f6 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 21 Jun 2024 16:46:24 +0700 Subject: remove console log --- src/api/promoApi.js | 1 - src/lib/product/components/ProductFilterDesktop.jsx | 1 - src/lib/product/components/ProductSearch.jsx | 2 -- 3 files changed, 4 deletions(-) (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index 95a27fd3..2c7f80a1 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -20,7 +20,6 @@ export const fetchPromoItemsSolr = async (type, start, rows) => { try { const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); - console.log("URL",`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index b4afebc2..b9be7c15 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -21,7 +21,6 @@ import Image from '@/core/components/elements/Image/Image' import { formatCurrency } from '@/core/utils/formatValue' const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { - console.log("prefixUrl",prefixUrl) const router = useRouter() const { query } = router const [order, setOrder] = useState(query?.orderBy) diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index ec0077c2..08b64c13 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -130,7 +130,6 @@ const ProductSearch = ({ brands.push({ brand, qty }); } } - console.log("daftar brand",brands) const categories = []; for ( @@ -145,7 +144,6 @@ const ProductSearch = ({ categories.push({ name, qty }); } } - console.log("daftar kategori",categories) const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, -- cgit v1.2.3 From 8456bd17207e349c717d062fcc6fe4d032da1334 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Sat, 22 Jun 2024 12:39:22 +0700 Subject: update bagian footer untuk penawaran(baru tampilan saja) all promotion --- .../components/elements/Footer/BasicFooter.jsx | 3 + src/core/components/elements/Footer/PromoOffer.tsx | 112 +++++++++++++++++++++ .../elements/Footer/style/promoOffer.module.css | 39 +++++++ 3 files changed, 154 insertions(+) create mode 100644 src/core/components/elements/Footer/PromoOffer.tsx create mode 100644 src/core/components/elements/Footer/style/promoOffer.module.css (limited to 'src') diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 6129143d..e1f95d6b 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -9,12 +9,14 @@ import Link from '../Link/Link'; import MobileView from '../../views/MobileView'; import DesktopView from '../../views/DesktopView'; import whatsappUrl from '@/core/utils/whatsappUrl'; +import PromoOffer from '../Footer/PromoOffer' const BasicFooter = () => { return ( <>