summaryrefslogtreecommitdiff
path: root/src2
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-03-02 16:51:05 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-03-02 16:51:05 +0700
commitd336735a91133cc3f1cf6f67ba2ac29f0985fd2e (patch)
treef64a5c6de6e0ea015952ae028dca115077cffa45 /src2
parent074edfe4e51efd3b4a44dc7fe6e1284c9c560501 (diff)
delete src2
Diffstat (limited to 'src2')
-rw-r--r--src2/components/auth/WithAuth.js20
-rw-r--r--src2/components/elements/Alert.js19
-rw-r--r--src2/components/elements/BottomPopup.js25
-rw-r--r--src2/components/elements/ConfirmAlert.js27
-rw-r--r--src2/components/elements/DescriptionRow.js10
-rw-r--r--src2/components/elements/Disclosure.js14
-rw-r--r--src2/components/elements/Fields.js21
-rw-r--r--src2/components/elements/Filter.js176
-rw-r--r--src2/components/elements/Image.js17
-rw-r--r--src2/components/elements/LineDivider.js7
-rw-r--r--src2/components/elements/Link.js13
-rw-r--r--src2/components/elements/Pagination.js58
-rw-r--r--src2/components/elements/ProgressBar.js25
-rw-r--r--src2/components/elements/Skeleton.js48
-rw-r--r--src2/components/elements/Spinner.js13
-rw-r--r--src2/components/layouts/AppBar.js47
-rw-r--r--src2/components/layouts/Footer.js91
-rw-r--r--src2/components/layouts/Header.js253
-rw-r--r--src2/components/layouts/Layout.js20
-rw-r--r--src2/components/manufactures/ManufactureCard.js18
-rw-r--r--src2/components/products/ProductCard.js69
-rw-r--r--src2/components/products/ProductCategories.js62
-rw-r--r--src2/components/products/ProductSimilar.js25
-rw-r--r--src2/components/products/ProductSlider.js39
-rw-r--r--src2/components/transactions/TransactionDetail.js67
-rw-r--r--src2/components/transactions/TransactionStatusBadge.js45
-rw-r--r--src2/components/variants/VariantCard.js92
-rw-r--r--src2/components/variants/VariantGroupCard.js31
-rw-r--r--src2/core/utils/address.js27
-rw-r--r--src2/core/utils/apiOdoo.js44
-rw-r--r--src2/core/utils/auth.js38
-rw-r--r--src2/core/utils/cart.js36
-rw-r--r--src2/core/utils/convertToOption.js11
-rw-r--r--src2/core/utils/currencyFormat.js8
-rw-r--r--src2/core/utils/formValidation.js107
-rw-r--r--src2/core/utils/getFileBase64.js11
-rw-r--r--src2/core/utils/greeting.js9
-rw-r--r--src2/core/utils/mailer.js12
-rw-r--r--src2/core/utils/slug.js25
-rw-r--r--src2/core/utils/toTitleCase.js8
-rw-r--r--src2/icons/chevron-left.svg3
-rw-r--r--src2/icons/chevron-right.svg3
-rw-r--r--src2/icons/close.svg1
-rw-r--r--src2/icons/filter.svg1
-rw-r--r--src2/icons/image-placeholder.svg1
-rw-r--r--src2/icons/instagram.svg5
-rw-r--r--src2/icons/linkedin.svg5
-rw-r--r--src2/icons/menu.svg1
-rw-r--r--src2/icons/minus.svg3
-rw-r--r--src2/icons/plus.svg4
-rw-r--r--src2/icons/search.svg4
-rw-r--r--src2/icons/shopping-cart.svg1
-rw-r--r--src2/icons/trash.svg4
-rw-r--r--src2/images/logo.pngbin49879 -> 0 bytes
-rw-r--r--src2/images/page-not-found.pngbin42280 -> 0 bytes
-rw-r--r--src2/lib/elements/hooks/useBottomPopup.js40
-rw-r--r--src2/lib/elements/hooks/useConfirmAlert.js49
-rw-r--r--src2/pages/404.js27
-rw-r--r--src2/pages/_app.js31
-rw-r--r--src2/pages/_error.js11
-rw-r--r--src2/pages/activate.js111
-rw-r--r--src2/pages/api/activation-request.js31
-rw-r--r--src2/pages/api/activation.js16
-rw-r--r--src2/pages/api/login.js15
-rw-r--r--src2/pages/api/register.js15
-rw-r--r--src2/pages/api/shop/search.js96
-rw-r--r--src2/pages/api/shop/suggest.js12
-rw-r--r--src2/pages/api/token.js10
-rw-r--r--src2/pages/faqs.js91
-rw-r--r--src2/pages/index.js106
-rw-r--r--src2/pages/login.js97
-rw-r--r--src2/pages/logout.js14
-rw-r--r--src2/pages/my/address/[id]/edit.js249
-rw-r--r--src2/pages/my/address/create.js234
-rw-r--r--src2/pages/my/address/index.js84
-rw-r--r--src2/pages/my/invoice/[id].js149
-rw-r--r--src2/pages/my/invoices.js180
-rw-r--r--src2/pages/my/menu.js82
-rw-r--r--src2/pages/my/profile.js134
-rw-r--r--src2/pages/my/transaction/[id].js265
-rw-r--r--src2/pages/my/transactions.js198
-rw-r--r--src2/pages/my/wishlist.js60
-rw-r--r--src2/pages/register.js100
-rw-r--r--src2/pages/shop/brands/[slug].js178
-rw-r--r--src2/pages/shop/brands/index.js79
-rw-r--r--src2/pages/shop/cart.js282
-rw-r--r--src2/pages/shop/checkout/finish.js47
-rw-r--r--src2/pages/shop/checkout/index.js325
-rw-r--r--src2/pages/shop/product/[slug].js305
-rw-r--r--src2/pages/shop/quotation/finish.js39
-rw-r--r--src2/pages/shop/quotation/index.js140
-rw-r--r--src2/pages/shop/search.js125
-rw-r--r--src2/styles/globals.css468
93 files changed, 0 insertions, 6219 deletions
diff --git a/src2/components/auth/WithAuth.js b/src2/components/auth/WithAuth.js
deleted file mode 100644
index ef975873..00000000
--- a/src2/components/auth/WithAuth.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { getAuth } from "@/core/utils/auth";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-
-const WithAuth = ({ children }) => {
- const router = useRouter();
- const [response, setResponse] = useState(<></>);
-
- useEffect(() => {
- if (!getAuth()) {
- router.replace('/login');
- } else {
- setResponse(children);
- }
- }, [children, router]);
-
- return response;
-}
-
-export default WithAuth; \ No newline at end of file
diff --git a/src2/components/elements/Alert.js b/src2/components/elements/Alert.js
deleted file mode 100644
index 914d1590..00000000
--- a/src2/components/elements/Alert.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const Alert = ({ children, className, type }) => {
- let typeClass = '';
- switch (type) {
- case 'info':
- typeClass = ' bg-blue-100 text-blue-900 border-blue-400 '
- break;
- case 'success':
- typeClass = ' bg-green-100 text-green-900 border-green-400 '
- break;
- case 'warning':
- typeClass = ' bg-yellow-100 text-yellow-900 border-yellow-400 '
- break;
- }
- return (
- <div className={"rounded-md w-full text-medium p-3 border" + typeClass + className}>{children}</div>
- );
-}
-
-export default Alert; \ No newline at end of file
diff --git a/src2/components/elements/BottomPopup.js b/src2/components/elements/BottomPopup.js
deleted file mode 100644
index c1a56e10..00000000
--- a/src2/components/elements/BottomPopup.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import CloseIcon from "@/icons/close.svg";
-
-const BottomPopup = ({
- active = false,
- title,
- children,
- closePopup = () => {}
-}) => {
- return (
- <>
- <div className={"menu-overlay " + (active ? 'block' : 'hidden')} onClick={closePopup} />
- <div className={`fixed w-full z-[60] py-6 px-4 bg-white rounded-t-3xl idt-transition bottom-0 ${active ? 'block' : 'hidden'}`}>
- <div className="flex justify-between items-center mb-5">
- <h2 className="text-xl font-semibold">{ title }</h2>
- <button onClick={closePopup}>
- <CloseIcon className="w-7" />
- </button>
- </div>
- { children }
- </div>
- </>
- );
-};
-
-export default BottomPopup; \ No newline at end of file
diff --git a/src2/components/elements/ConfirmAlert.js b/src2/components/elements/ConfirmAlert.js
deleted file mode 100644
index d33abb89..00000000
--- a/src2/components/elements/ConfirmAlert.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const ConfirmAlert = ({
- title,
- caption,
- show,
- onClose,
- onSubmit,
- closeText,
- submitText
-}) => {
- return (
- <>
- {show && (
- <div className="menu-overlay" onClick={onClose}></div>
- )}
- <div className={"p-4 rounded border bg-white border-gray_r-6 fixed top-[50%] left-[50%] translate-x-[-50%] z-[70] w-[90%] translate-y-[-50%] " + (show ? "block" : "hidden")}>
- <p className="h2 mb-2">{title}</p>
- <p className="text-gray_r-11 mb-6">{caption}</p>
- <div className="flex gap-x-2">
- <button className="flex-1 btn-yellow" onClick={onClose}>{closeText}</button>
- <button className="flex-1 btn-solid-red" onClick={onSubmit}>{submitText}</button>
- </div>
- </div>
- </>
- );
-};
-
-export default ConfirmAlert; \ No newline at end of file
diff --git a/src2/components/elements/DescriptionRow.js b/src2/components/elements/DescriptionRow.js
deleted file mode 100644
index 7fe9e3a1..00000000
--- a/src2/components/elements/DescriptionRow.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const DescriptionRow = ({ label, children }) => (
- <div className="grid grid-cols-2">
- <p className="leading-normal text-gray_r-11">{ label }</p>
- <div className="text-right leading-normal">
- { children }
- </div>
- </div>
-);
-
-export default DescriptionRow; \ No newline at end of file
diff --git a/src2/components/elements/Disclosure.js b/src2/components/elements/Disclosure.js
deleted file mode 100644
index 1f334be3..00000000
--- a/src2/components/elements/Disclosure.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const { ChevronUpIcon, ChevronDownIcon } = require("@heroicons/react/24/outline");
-
-const Disclosure = ({ label, active, onClick }) => (
- <div className={`flex justify-between p-4 ` + (active && 'bg-yellow_r-2')} onClick={onClick}>
- <p className="font-medium leading-normal">{ label }</p>
- { onClick && ( active ? (
- <ChevronUpIcon className="w-5 h-5 stroke-2" />
- ) : (
- <ChevronDownIcon className="w-5 h-5 stroke-2" />
- ) ) }
- </div>
-);
-
-export default Disclosure; \ No newline at end of file
diff --git a/src2/components/elements/Fields.js b/src2/components/elements/Fields.js
deleted file mode 100644
index 586a6a22..00000000
--- a/src2/components/elements/Fields.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import ReactSelect from "react-select";
-
-const Select = ({
- field,
- ...props
-}) => (
- <>
- <ReactSelect
- classNamePrefix="form-select"
- ref={field.ref}
- onChange={(option) => field.onChange(option.value)}
- value={field.value ? props.options.find(option => option.value === field.value) : ''}
- isDisabled={props.disabled}
- {...props}
- />
- </>
-);
-
-export {
- Select
-}; \ No newline at end of file
diff --git a/src2/components/elements/Filter.js b/src2/components/elements/Filter.js
deleted file mode 100644
index f2051ba8..00000000
--- a/src2/components/elements/Filter.js
+++ /dev/null
@@ -1,176 +0,0 @@
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-import BottomPopup from "./BottomPopup";
-
-const Filter = ({
- isActive,
- closeFilter,
- defaultRoute,
- defaultPriceFrom,
- defaultPriceTo,
- defaultCategory,
- defaultBrand,
- defaultOrderBy,
- searchResults,
- disableFilter = []
-}) => {
- const router = useRouter();
-
- const [priceFrom, setPriceFrom] = useState(defaultPriceFrom);
- const [priceTo, setPriceTo] = useState(defaultPriceTo);
- const [orderBy, setOrderBy] = useState(defaultOrderBy);
- const [selectedCategory, setSelectedCategory] = useState(defaultCategory);
- const [selectedBrand, setSelectedBrand] = useState(defaultBrand);
- const [categories, setCategories] = useState([]);
- const [brands, setBrands] = useState([]);
-
- const filterRoute = () => {
- let filterRoute = [];
- let filterRoutePrefix = '?';
- if (selectedBrand) filterRoute.push(`brand=${selectedBrand}`);
- if (selectedCategory) filterRoute.push(`category=${selectedCategory}`);
- if (priceFrom) filterRoute.push(`price_from=${priceFrom}`);
- if (priceTo) filterRoute.push(`price_to=${priceTo}`);
- if (orderBy) filterRoute.push(`order_by=${orderBy}`);
-
- if (defaultRoute.includes('?')) filterRoutePrefix = '&';
- if (filterRoute.length > 0) {
- filterRoute = filterRoutePrefix + filterRoute.join('&');
- } else {
- filterRoute = '';
- }
-
- return defaultRoute + filterRoute;
- }
-
- useEffect(() => {
- const filterCategory = searchResults.facet_counts.facet_fields.category_name_str.filter((category, index) => {
- if (index % 2 == 0) {
- const productCountInCategory = searchResults.facet_counts.facet_fields.category_name_str[index + 1];
- if (productCountInCategory > 0) return category;
- }
- });
- setCategories(filterCategory);
-
- const filterBrand = searchResults.facet_counts.facet_fields.brand_str.filter((brand, index) => {
- if (index % 2 == 0) {
- const productCountInBrand = searchResults.facet_counts.facet_fields.brand_str[index + 1];
- if (productCountInBrand > 0) return brand;
- }
- });
- setBrands(filterBrand);
- }, [searchResults]);
-
- const submit = (e) => {
- e.preventDefault();
- closeFilter();
- router.push(filterRoute(), undefined, { scroll: false });
- }
-
- const reset = () => {
- setSelectedBrand('');
- setSelectedCategory('');
- setPriceFrom('');
- setPriceTo('');
- setOrderBy('');
- }
-
- const changeOrderBy = (value) => {
- if (orderBy == value) {
- setOrderBy('');
- } else {
- setOrderBy(value);
- }
- }
-
- const sortOptions = [
- {
- name: 'Harga Terendah',
- value: 'price-asc',
- },
- {
- name: 'Harga Tertinggi',
- value: 'price-desc',
- },
- {
- name: 'Populer',
- value: 'popular',
- },
- {
- name: 'Ready Stock',
- value: 'stock',
- },
- ];
-
- return (
- <>
- <BottomPopup active={isActive} closePopup={closeFilter} title="Filter Produk">
- <form className="flex flex-col gap-y-4" onSubmit={submit}>
- {(selectedBrand || selectedCategory || priceFrom || priceTo || orderBy) && (
- <button type="button" className="text-yellow_r-11 font-semibold ml-auto" onClick={reset}>
- Reset Filter
- </button>
- )}
-
- {!disableFilter.includes('orderBy') && (
- <div>
- <label>Urutkan</label>
- <div className="flex gap-2 mt-2 overflow-x-auto w-full">
- {sortOptions.map((sortOption, index) => (
- <button
- key={index}
- type="button"
- className={"p-2 rounded border border-gray_r-6 flex-shrink-0" + (orderBy == sortOption.value ? ' border-yellow_r-10 bg-yellow_r-3 text-yellow_r-11' : '')}
- onClick={() => changeOrderBy(sortOption.value)}
- >
- {sortOption.name}
- </button>
- ))}
- </div>
- </div>
- )}
-
- {!disableFilter.includes('category') && (
- <div>
- <label>Kategori</label>
- <select className="form-input mt-2" value={selectedCategory} onChange={(e) => setSelectedCategory(e.target.value)}>
- <option value="">Pilih kategori...</option>
- {categories?.map((category, index) => (
- <option key={index} value={category}>{category}</option>
- ))}
- </select>
- </div>
- )}
-
- {!disableFilter.includes('brand') && (
- <div>
- <label>Brand</label>
- <select className="form-input mt-2" value={selectedBrand} onChange={(e) => setSelectedBrand(e.target.value)}>
- <option value="">Pilih brand...</option>
- {brands?.map((brand, index) => (
- <option key={index} value={brand}>{brand}</option>
- ))}
- </select>
- </div>
- )}
-
- {!disableFilter.includes('price') && (
- <div>
- <label>Harga</label>
- <div className="flex gap-x-4 mt-2 items-center">
- <input className="form-input" type="number" placeholder="Dari" value={priceFrom} onChange={(e) => setPriceFrom(e.target.value)}/>
- <span>&mdash;</span>
- <input className="form-input" type="number" placeholder="Sampai" value={priceTo} onChange={(e) => setPriceTo(e.target.value)}/>
- </div>
- </div>
- )}
- <button type="submit" className="btn-yellow font-semibold mt-2 w-full">
- Terapkan Filter
- </button>
- </form>
- </BottomPopup>
- </>
- )
-};
-
-export default Filter; \ No newline at end of file
diff --git a/src2/components/elements/Image.js b/src2/components/elements/Image.js
deleted file mode 100644
index 60e249b9..00000000
--- a/src2/components/elements/Image.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { LazyLoadImage } from "react-lazy-load-image-component"
-import "react-lazy-load-image-component/src/effects/opacity.css"
-
-const Image = ({ ...props }) => {
- return (
- <LazyLoadImage
- {...props}
- effect="opacity"
- src={props.src || '/images/noimage.jpeg'}
- alt={props.src ? props.alt : 'Image Not Found - Indoteknik'}
- />
- )
-}
-
-Image.defaultProps = LazyLoadImage.defaultProps
-
-export default Image \ No newline at end of file
diff --git a/src2/components/elements/LineDivider.js b/src2/components/elements/LineDivider.js
deleted file mode 100644
index 4e8c7b52..00000000
--- a/src2/components/elements/LineDivider.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const LineDivider = () => {
- return (
- <hr className="h-1 bg-gray_r-4 border-none"/>
- );
-};
-
-export default LineDivider; \ No newline at end of file
diff --git a/src2/components/elements/Link.js b/src2/components/elements/Link.js
deleted file mode 100644
index 065b5c9e..00000000
--- a/src2/components/elements/Link.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import NextLink from "next/link";
-
-const Link = ({ children, ...props }) => {
- return (
- <NextLink {...props} scroll={false}>
- {children}
- </NextLink>
- )
-}
-
-Link.defaultProps = NextLink.defaultProps
-
-export default Link \ No newline at end of file
diff --git a/src2/components/elements/Pagination.js b/src2/components/elements/Pagination.js
deleted file mode 100644
index ff2a8462..00000000
--- a/src2/components/elements/Pagination.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import Link from "./Link";
-
-export default function Pagination({ pageCount, currentPage, url }) {
- let firstPage = false;
- let lastPage = false;
- let dotsPrevPage = false;
- let dotsNextPage = false;
- let urlParameterPrefix = url.includes('?') ? '&' : '?';
-
- return pageCount > 1 && (
- <div className="pagination">
- {Array.from(Array(pageCount)).map((v, i) => {
- let page = i + 1;
- let rangePrevPage = currentPage - 2;
- let rangeNextPage = currentPage + 2;
- let PageComponent = <Link key={i} href={`${url + urlParameterPrefix}page=${page}`} className={"pagination-item" + (page == currentPage ? " pagination-item--active " : "")}>{page}</Link>;
- let DotsComponent = <div key={i} className="pagination-dots">...</div>;
-
- if (pageCount == 7) {
- return PageComponent;
- }
-
- if (currentPage == 1) rangeNextPage += 3;
- if (currentPage == 2) rangeNextPage += 2;
- if (currentPage == 3) rangeNextPage += 1;
- if (currentPage == 4) rangePrevPage -= 1;
- if (currentPage == pageCount) rangePrevPage -= 3;
- if (currentPage == pageCount - 1) rangePrevPage -= 2;
- if (currentPage == pageCount - 2) rangePrevPage -= 1;
- if (currentPage == pageCount - 3) rangeNextPage += 1;
-
- if (page > rangePrevPage && page < rangeNextPage) {
- return PageComponent;
- }
-
- if (page == 1 && rangePrevPage >= 1 && !firstPage) {
- firstPage = true;
- return PageComponent;
- }
-
- if (page == pageCount && rangeNextPage <= pageCount && !lastPage) {
- lastPage = true;
- return PageComponent;
- }
-
- if (page > currentPage && (pageCount - currentPage) > 1 && !dotsNextPage) {
- dotsNextPage = true;
- return DotsComponent;
- }
-
- if (page < currentPage && (currentPage - 1) > 1 && !dotsPrevPage) {
- dotsPrevPage = true;
- return DotsComponent;
- }
- })}
- </div>
- )
-} \ No newline at end of file
diff --git a/src2/components/elements/ProgressBar.js b/src2/components/elements/ProgressBar.js
deleted file mode 100644
index 0adedcdf..00000000
--- a/src2/components/elements/ProgressBar.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Fragment } from "react";
-
-const ProgressBar = ({ current, labels }) => {
- return (
- <div className="bg-gray_r-1 flex gap-x-2 p-4 rounded-md">
- {labels.map((label, index) => (
- <Fragment key={index}>
- <div className={"flex gap-x-2 items-center " + (index < current ? 'text-gray_r-12' : 'text-gray_r-11')}>
- <div className={"leading-none p-2 rounded-full w-7 text-center text-caption-2 " + (index < current ? 'bg-yellow_r-9' : 'bg-gray_r-5')}>
- { index + 1 }
- </div>
- <p className="font-medium text-caption-2">{ label }</p>
- </div>
- { index < (labels.length - 1) && (
- <div className="flex-1 flex items-center">
- <div className="h-0.5 w-full bg-gray_r-7"></div>
- </div>
- ) }
- </Fragment>
- ))}
- </div>
- )
-}
-
-export default ProgressBar; \ No newline at end of file
diff --git a/src2/components/elements/Skeleton.js b/src2/components/elements/Skeleton.js
deleted file mode 100644
index fbdbc245..00000000
--- a/src2/components/elements/Skeleton.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import ImagePlaceholderIcon from "../../icons/image-placeholder.svg";
-
-const SkeletonList = ({ number }) => (
- <div role="status" className="space-y-6 animate-pulse">
- { Array.from(Array(number), (e, i) => (
- <div className="flex items-center justify-between" key={i}>
- <div>
- <div className="h-2.5 bg-gray-300 rounded-full w-24 mb-2.5"></div>
- <div className="w-32 h-2 bg-gray-200 rounded-full"></div>
- </div>
- <div className="h-2.5 bg-gray-300 rounded-full w-12"></div>
- </div>
- )) }
- <span className="sr-only">Loading...</span>
- </div>
-);
-
-const SkeletonProduct = () => (
- <div className="grid grid-cols-2 gap-x-4">
- <div role="status" className="p-4 max-w-sm rounded border border-gray-300 shadow animate-pulse md:p-6">
- <div className="flex justify-center items-center mb-4 h-48 bg-gray-300 rounded">
- <ImagePlaceholderIcon className="w-12 h-12 text-gray-200" />
- </div>
- <div className="h-2 bg-gray-200 rounded-full w-10 mb-1"></div>
- <div className="h-2.5 bg-gray-200 rounded-full w-full mb-4"></div>
- <div className="h-2 bg-gray-200 rounded-full mb-2.5"></div>
- <div className="h-2 bg-gray-200 rounded-full mb-2.5"></div>
- <div className="h-2 bg-gray-200 rounded-full"></div>
- <span className="sr-only">Loading...</span>
- </div>
- <div role="status" className="p-4 max-w-sm rounded border border-gray-300 shadow animate-pulse md:p-6">
- <div className="flex justify-center items-center mb-4 h-48 bg-gray-300 rounded">
- <ImagePlaceholderIcon className="w-12 h-12 text-gray-200" />
- </div>
- <div className="h-2 bg-gray-200 rounded-full w-10 mb-1"></div>
- <div className="h-2.5 bg-gray-200 rounded-full w-full mb-4"></div>
- <div className="h-2 bg-gray-200 rounded-full mb-2.5"></div>
- <div className="h-2 bg-gray-200 rounded-full mb-2.5"></div>
- <div className="h-2 bg-gray-200 rounded-full"></div>
- <span className="sr-only">Loading...</span>
- </div>
- </div>
-);
-
-export {
- SkeletonList,
- SkeletonProduct
-}; \ No newline at end of file
diff --git a/src2/components/elements/Spinner.js b/src2/components/elements/Spinner.js
deleted file mode 100644
index 21006ecd..00000000
--- a/src2/components/elements/Spinner.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const Spinner = ({ className }) => {
- return (
- <div role="status">
- <svg aria-hidden="true" className={"animate-spin " + className} viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
- <path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
- </svg>
- <span className="sr-only">Loading...</span>
- </div>
- )
-}
-
-export default Spinner; \ No newline at end of file
diff --git a/src2/components/layouts/AppBar.js b/src2/components/layouts/AppBar.js
deleted file mode 100644
index fe74c940..00000000
--- a/src2/components/layouts/AppBar.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Bars3Icon, ChevronLeftIcon, HomeIcon, ShoppingCartIcon } from "@heroicons/react/24/outline";
-import Head from "next/head";
-import { useRouter } from "next/router";
-import Link from "../elements/Link";
-
-const AppBar = ({ title }) => {
- const router = useRouter();
-
- const handleBackButtonClick = (event) => {
- event.currentTarget.disabled = true;
- router.back();
- }
-
- return (
- <>
- <Head>
- <title>{ title } - Indoteknik</title>
- </Head>
- <div className="sticky-header flex justify-between !p-0 !pr-4 idt-transition">
- {/* --- Start Title */}
- <div className="flex items-center">
- <button type="button" onClick={handleBackButtonClick} className="text-gray_r-12 px-4 py-5">
- <ChevronLeftIcon className="w-6 stroke-2"/>
- </button>
- <h1 className="text-h-md">{ title }</h1>
- </div>
- {/* --- End Title */}
-
- {/* --- Start Icons */}
- <div className="flex gap-x-4 items-center">
- <Link href="/shop/cart">
- <ShoppingCartIcon className="w-6 stroke-2 text-gray_r-12"/>
- </Link>
- <Link href="/">
- <HomeIcon className="w-6 stroke-2 text-gray_r-12"/>
- </Link>
- <Link href="/my/menu">
- <Bars3Icon className="w-6 stroke-2 text-gray_r-12"/>
- </Link>
- </div>
- {/* --- End Icons */}
- </div>
- </>
- );
-};
-
-export default AppBar; \ No newline at end of file
diff --git a/src2/components/layouts/Footer.js b/src2/components/layouts/Footer.js
deleted file mode 100644
index d173a525..00000000
--- a/src2/components/layouts/Footer.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import {
- PhoneIcon,
- DevicePhoneMobileIcon,
- EnvelopeIcon
-} from "@heroicons/react/24/outline";
-import Image from "next/image";
-import InstagramIcon from "@/icons/instagram.svg";
-import LinkedinIcon from "@/icons/linkedin.svg";
-import Link from "../elements/Link";
-
-export default function Footer() {
- return (
- <div className="p-4 bg-gray_r-3">
- <div className="grid grid-cols-2 gap-x-2 mb-4">
- <div>
- <p className="font-medium mb-2">Kantor Pusat</p>
- <p className="text-gray_r-11 leading-6 text-caption-2">
- Jl. Bandengan Utara 85A No. 8-9 RT.3/RW.16, Penjaringan, Kec. Penjaringan
- </p>
-
- <p className="font-medium mb-2 mt-6">Layanan Informasi</p>
- <div className="flex items-center gap-x-2 text-gray_r-11 text-caption-2 mb-2">
- <PhoneIcon className="w-5 h-5 stroke-2"/>
- <a className="text-gray_r-11 font-normal" href="tel:02129338828">
- (021) 2933-8828
- </a>
- {'/'}
- <a className="text-gray_r-11 font-normal" href="tel:02129338829">
- 29
- </a>
- </div>
- <div className="flex items-center gap-x-2 text-gray_r-11 text-caption-2 mb-2">
- <DevicePhoneMobileIcon className="w-5 h-5 stroke-2"/>
- <a className="text-gray_r-11 font-normal" href="https://wa.me/628128080622">
- 0812-8080-622
- </a>
- </div>
- <div className="flex items-center gap-x-2 text-gray_r-11 text-caption-2">
- <EnvelopeIcon className="w-5 h-5 stroke-2"/>
- <a className="text-gray_r-11 font-normal" href="mailto:sales@indoteknik.com">
- sales@indoteknik.com
- </a>
- </div>
-
- <p className="font-medium mb-2 mt-6">Panduan Pelanggan</p>
- <div className="text-caption-2 flex flex-col gap-y-2">
- <Link className="text-gray_r-11 font-normal" href="/faqs">FAQ</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Kebijakan Privasi</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Pengajuan Tempo</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Garansi Produk</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Online Quotation</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Pengiriman</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Pembayaran</Link>
- <Link className="text-gray_r-11 font-normal" href="/">Syarat & Ketentuan</Link>
-
- </div>
- </div>
- <div>
- <p className="font-medium mb-2">Jam Operasional</p>
- <p className="text-gray_r-11 leading-6 text-caption-2">
- <span className="font-medium">Senin - Jumat:</span> 08:30 - 17:00
- </p>
- <p className="text-gray_r-11 leading-6 text-caption-2">
- <span className="font-medium">Sabtu:</span> 08:30 - 14:00
- </p>
-
- <p className="font-medium mb-2 mt-6">Temukan Kami</p>
- <div className="flex gap-x-2">
- <InstagramIcon className="w-5 h-5 stroke-gray_r-11" />
- <LinkedinIcon className="w-5 h-5 stroke-gray_r-11" />
- </div>
-
- <p className="font-medium mb-2 mt-6">Pembayaran</p>
- <div className="grid grid-cols-4 gap-2">
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- <Image src="/images/payments/bca.webp" alt="BCA Payment" width={48} height={48} className="w-full" />
- </div>
-
- {/* <p className="font-medium mb-2 mt-6">Pengiriman</p> */}
- </div>
- </div>
- <h6 className="h2">PT. Indoteknik Dotcom Gemilang</h6>
- </div>
- );
-} \ No newline at end of file
diff --git a/src2/components/layouts/Header.js b/src2/components/layouts/Header.js
deleted file mode 100644
index 23fda642..00000000
--- a/src2/components/layouts/Header.js
+++ /dev/null
@@ -1,253 +0,0 @@
-import Image from "next/image";
-import { Fragment, useCallback, useEffect, useRef, useState } from "react";
-import Head from "next/head";
-import { useRouter } from "next/router";
-import axios from "axios";
-import {
- MagnifyingGlassIcon,
- Bars3Icon,
- ShoppingCartIcon,
- ChevronRightIcon,
- Cog6ToothIcon,
- HeartIcon,
- ChevronDownIcon,
- ChevronUpIcon
-} from "@heroicons/react/24/outline";
-
-// Helpers
-import { useAuth } from "@/core/utils/auth";
-// Components
-import Link from "../elements/Link";
-// Images
-import Logo from "@/images/logo.png";
-import greeting from "@/core/utils/greeting";
-import apiOdoo from "@/core/utils/apiOdoo";
-
-const menus = [
- { name: 'Semua Brand', href: '/shop/brands' },
- { name: 'Blog Indoteknik', href: '/' },
- { name: 'Tentang Indoteknik', href: '/' },
- { name: 'Pusat Bantuan', href: '/' },
-];
-
-export default function Header({ title }) {
- const router = useRouter();
- const { q = '' } = router.query;
- const [searchQuery, setSearchQuery] = useState(q != '*' ? q : '');
- const [suggestions, setSuggestions] = useState([]);
- const searchQueryRef = useRef();
- const [isMenuActive, setIsMenuActive] = useState(false);
- const [auth] = useAuth();
-
- useEffect(() => {
- if (q) {
- searchQueryRef.current.blur();
- setSuggestions([]);
- };
- }, [q]);
-
- const clickSuggestion = (value) => {
- router.push(`/shop/search?q=${value}`, undefined, { scroll: false });
- };
-
- const getSuggestion = useCallback(async () => {
- if (searchQuery.trim().length > 0) {
- let result = await axios(`${process.env.SELF_HOST}/api/shop/suggest?q=${searchQuery.trim()}`);
- setSuggestions(result.data.suggest.mySuggester[searchQuery.trim()].suggestions);
- } else {
- setSuggestions([]);
- }
- }, [searchQuery]);
-
- useEffect(() => {
- if (document.activeElement == searchQueryRef.current) getSuggestion();
- }, [getSuggestion]);
-
- const openMenu = () => setIsMenuActive(true);
- const closeMenu = () => setIsMenuActive(false);
-
- const searchSubmit = (e) => {
- e.preventDefault();
- if (searchQuery.length > 0) {
- router.push(`/shop/search?q=${searchQuery}`, undefined, { scroll: false });
- } else {
- searchQueryRef.current.focus();
- }
- }
-
- const [ isOpenCategory, setOpenCategory ] = useState(false);
- const [ categories, setCategories ] = useState([]);
-
- useEffect(() => {
- const loadCategories = async () => {
- if (isOpenCategory && categories.length == 0) {
- let dataCategories = await apiOdoo('GET', '/api/v1/category/tree');
- dataCategories = dataCategories.map((category) => {
- category.childs = category.childs.map((child1Category) => {
- return {
- ...child1Category,
- isOpen: false
- }
- })
- return {
- ...category,
- isOpen: false
- }
- });
- setCategories(dataCategories);
- }
- }
- loadCategories();
- }, [ isOpenCategory, categories ]);
-
- const toggleCategories = (id = 0) => {
- let newCategories = categories.map((category) => {
- category.childs = category.childs.map((child1Category) => {
- return {
- ...child1Category,
- isOpen: id == child1Category.id ? !child1Category.isOpen : child1Category.isOpen
- }
- })
- return {
- ...category,
- isOpen: id == category.id ? !category.isOpen : category.isOpen
- }
- });
- setCategories(newCategories);
- }
-
- return (
- <>
- <Head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
- <title>{title}</title>
- </Head>
-
- <div className={'menu-wrapper' + (isMenuActive ? ' active ' : '')}>
- <div className="flex gap-x-2 items-center border-b border-gray_r-6 p-4">
- { auth && (
- <Link href="/my/menu" className="w-full flex items-center text-gray_r-12" onClick={closeMenu}>
- <div>
- <p className="text-gray_r-11 text-caption-2">{ greeting() },</p>
- <h1>{auth.name}</h1>
- </div>
- <div className="ml-auto">
- <Cog6ToothIcon className="w-5" />
- </div>
- </Link>
- ) }
-
- { !auth && (
- <>
- <Link href="/login" onClick={closeMenu} className="w-full py-2 btn-light text-gray_r-12">Masuk</Link>
- <Link href="/register" onClick={closeMenu} className="w-full py-2 btn-yellow text-gray_r-12">Daftar</Link>
- </>
- ) }
- </div>
- <div className="flex flex-col">
- { menus.map((menu, index) => (
- <Link className="flex w-full font-normal text-gray_r-11 border-b border-gray_r-6 p-4" href={menu.href} key={index} onClick={closeMenu}>
- <span>{ menu.name }</span>
- <div className="ml-auto">
- <ChevronRightIcon className="text-gray_r-12 w-5" />
- </div>
- </Link>
- )) }
- <div className="flex w-full font-normal text-gray_r-11 border-b border-gray_r-6 p-4" onClick={() => setOpenCategory(!isOpenCategory)}>
- <span>Kategori</span>
- <div className="ml-auto">
- { !isOpenCategory && <ChevronDownIcon className="text-gray_r-12 w-5" /> }
- { isOpenCategory && <ChevronUpIcon className="text-gray_r-12 w-5" /> }
- </div>
- </div>
- { isOpenCategory && categories.map((category) => (
- <Fragment key={category.id}>
- <div className="flex w-full text-gray_r-11 border-b border-gray_r-6 px-4 pl-8">
- <Link href={`/shop/search?category=${category.name}`} className="flex-1 font-normal text-gray_r-11 py-4">
- { category.name }
- </Link>
- <div className="ml-4 h-full py-4" onClick={() => toggleCategories(category.id)}>
- { !category.isOpen && <ChevronDownIcon className="text-gray_r-12 w-5" /> }
- { category.isOpen && <ChevronUpIcon className="text-gray_r-12 w-5" /> }
- </div>
- </div>
- { category.isOpen && category.childs.map((child1Category) => (
- <Fragment key={child1Category.id}>
- <div className={`flex w-full text-gray_r-11 border-b border-gray_r-6 p-4 pl-12 ${category.isOpen ? 'bg-gray_r-2' : ''}`}>
- <Link href={`/shop/search?category=${child1Category.name}`} className="flex-1 font-normal text-gray_r-11">
- { child1Category.name }
- </Link>
- { child1Category.childs.length > 0 && (
- <div className="ml-4 h-full" onClick={() => toggleCategories(child1Category.id)}>
- { !child1Category.isOpen && <ChevronDownIcon className="text-gray_r-12 w-5" /> }
- { child1Category.isOpen && <ChevronUpIcon className="text-gray_r-12 w-5" /> }
- </div>
- ) }
- </div>
- { child1Category.isOpen && child1Category.childs.map((child2Category) => (
- <Link key={child2Category.id} href={`/shop/search?category=${child2Category.name}`} className="flex w-full font-normal text-gray_r-11 border-b border-gray_r-6 p-4 pl-16">
- { child2Category.name }
- </Link>
- )) }
- </Fragment>
- )) }
- </Fragment>
- )) }
- </div>
- </div>
- <div className={isMenuActive ? 'menu-overlay block opacity-100' : 'menu-overlay hidden opacity-0'} onClick={closeMenu}></div>
-
- <div className="sticky-header">
- <div className="flex justify-between items-center">
- <Link href="/" scroll={false}>
- <Image src={Logo} alt="Logo Indoteknik" width={120} height={40} />
- </Link>
- <div className="flex gap-x-4">
- <Link href="/my/wishlist">
- <HeartIcon className="w-6 text-gray_r-12" />
- </Link>
- <Link href="/shop/cart">
- <ShoppingCartIcon className="w-6 text-gray_r-12" />
- </Link>
- <button onClick={openMenu}>
- <Bars3Icon className="w-6 text-gray_r-12" />
- </button>
- </div>
- </div>
- <form onSubmit={searchSubmit} className="relative flex mt-2">
- <input
- ref={searchQueryRef}
- type="text"
- name="q"
- onChange={(e) => setSearchQuery(e.target.value)}
- onFocus={getSuggestion}
- value={searchQuery}
- className="form-input rounded-r-none border-r-0 focus:border-gray_r-7"
- placeholder="Ketikan nama, merek, part number"
- autoComplete="off"
- />
-
- <button
- type="submit"
- aria-label="search"
- className="btn-light bg-transparent px-2 py-1 rounded-l-none border-l-0"
- >
- <MagnifyingGlassIcon className="w-6" />
- </button>
-
- {suggestions.length > 1 && (
- <div className="absolute w-full top-[50px] rounded-b bg-gray_r-2 border border-gray_r-6">
- {suggestions.map((suggestion, index) => (
- <p onClick={() => clickSuggestion(suggestion.term)} className="w-full p-2" key={index}>{suggestion.term}</p>
- ))}
- </div>
- )}
- </form>
- </div>
-
- {suggestions.length > 1 && (
- <div className="menu-overlay !z-40" onClick={() => setSuggestions([])}></div>
- )}
- </>
- )
-} \ No newline at end of file
diff --git a/src2/components/layouts/Layout.js b/src2/components/layouts/Layout.js
deleted file mode 100644
index fd507963..00000000
--- a/src2/components/layouts/Layout.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { motion } from 'framer-motion';
-
-export default function Layout({ children, ...pageProps }) {
- const transition = {
- ease: 'easeOut',
- duration: 0.3
- };
-
- return children && (
- <motion.main
- initial={{ opacity: 0, x: 30, y: 0 }}
- animate={{ opacity: 1, x: 0, y: 0 }}
- exit={{ opacity: 0, x: 30, y: 0 }}
- transition={transition}
- {...pageProps}
- >
- {children}
- </motion.main>
- );
-} \ No newline at end of file
diff --git a/src2/components/manufactures/ManufactureCard.js b/src2/components/manufactures/ManufactureCard.js
deleted file mode 100644
index 73a96902..00000000
--- a/src2/components/manufactures/ManufactureCard.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { createSlug } from "@/core/utils/slug";
-import Image from "../elements/Image";
-import Link from "../elements/Link";
-
-export default function ManufactureCard({ data }) {
- const manufacture = data;
- return (
- <Link href={`/shop/brands/${createSlug(manufacture.name, manufacture.id)}`} className="flex justify-center items-center border border-gray-300 p-1 rounded h-16 text-gray-800 text-sm text-center bg-white">
- {manufacture.logo ? (
- <Image
- src={manufacture.logo}
- alt={manufacture.name}
- className="w-full max-h-full object-contain object-center"
- />
- ) : manufacture.name}
- </Link>
- );
-} \ No newline at end of file
diff --git a/src2/components/products/ProductCard.js b/src2/components/products/ProductCard.js
deleted file mode 100644
index c79a4900..00000000
--- a/src2/components/products/ProductCard.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Link from "../elements/Link";
-import currencyFormat from "@/core/utils/currencyFormat";
-import { createSlug } from "@/core/utils/slug";
-import { ChevronRightIcon } from "@heroicons/react/20/solid";
-import Image from "../elements/Image";
-
-
-export default function ProductCard({
- data,
- simpleProductTitleLine = false
-}) {
- let product = data;
- return (
- <div className="product-card">
- <Link href={'/shop/product/' + createSlug(product.name, product.id)} className="block relative bg-white">
- <Image
- src={product.image}
- alt={product.name}
- className="product-card__image"
- />
- {product.variant_total > 1 ? (
- <div className="absolute bottom-2 left-2 badge-gray">{product.variant_total} Varian</div>
- ) : ''}
- </Link>
- <div className="product-card__content">
- <div>
- {typeof product.manufacture.name !== "undefined" ? (
- <Link href={'/shop/brands/' + createSlug(product.manufacture.name, product.manufacture.id)} className="product-card__brand">{product.manufacture.name}</Link>
- ) : (
- <span className="product-card__brand">-</span>
- )}
- <Link href={'/shop/product/' + createSlug(product.name, product.id)} className={`product-card__title ${simpleProductTitleLine ? 'wrap-line-ellipsis-2' : 'wrap-line-ellipsis-3'}`}>
- {product.name}
- </Link>
- </div>
- <div className="mt-2">
- {product.lowest_price.discount_percentage > 0 ? (
- <div className="flex gap-x-1 items-center mb-1">
- <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(product.lowest_price.price)}</p>
- <span className="badge-solid-red">{product.lowest_price.discount_percentage}%</span>
- </div>
- ) : ''}
-
- {product.lowest_price.price_discount > 0 ? (
- <p className="text-caption-1 text-gray_r-12 font-bold">
- {currencyFormat(product.lowest_price.price_discount)}
- </p>
- ) : (
- <a
- href="https://wa.me"
- target="_blank"
- rel="noreferrer"
- className="flex items-center gap-x-1 text-caption-1"
- >
- Tanya Harga <ChevronRightIcon className="text-yellow_r-11 w-5 h-5" />
- </a>
- )}
-
- {product.stock_total > 0 ? (
- <div className="flex gap-x-1 mt-2">
- <div className="badge-solid-red">Ready Stock</div>
- <div className="badge-gray">{product.stock_total > 5 ? '> 5' : '< 5'}</div>
- </div>
- ) : ''}
- </div>
- </div>
- </div>
- )
-} \ No newline at end of file
diff --git a/src2/components/products/ProductCategories.js b/src2/components/products/ProductCategories.js
deleted file mode 100644
index 3b671f29..00000000
--- a/src2/components/products/ProductCategories.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import { useEffect, useState } from "react";
-import ProductSlider from "./ProductSlider";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { LazyLoadComponent } from "react-lazy-load-image-component";
-import { SkeletonProduct } from "../elements/Skeleton";
-
-const ProductCategory = ({ id }) => {
- const [ content, setContent ] = useState(null);
-
- useEffect(() => {
- const loadContent = async () => {
- if (!content) {
- const dataContent = await apiOdoo('GET', `/api/v1/categories_homepage?id=${id}`);
- setContent(dataContent[0]);
- }
- }
- loadContent();
- }, [id, content]);
-
- return (
- <div className="p-4 relative bg-yellow_r-2">
- { content ? (
- <ProductSlider
- products={{
- products: content.products,
- banner: {
- image: content.image,
- name: content.name,
- url: `/shop/search?category=${content.name}`
- }
- }}
- simpleProductTitleLine
- bannerMode
- />
- ) : <SkeletonProduct /> }
- </div>
- );
-}
-
-export default function ProductCategories() {
- const [ contentIds, setContentIds ] = useState([]);
-
- useEffect(() => {
- const getContentIds = async () => {
- if (contentIds.length == 0) {
- const dataContentIds = await apiOdoo('GET', '/api/v1/categories_homepage/ids');
- setContentIds(dataContentIds);
- }
- }
- getContentIds();
- }, [ contentIds ]);
-
- return (
- <div className="flex flex-col gap-y-6">
- { contentIds.map((contentId) => (
- <LazyLoadComponent placeholder={<SkeletonProduct/>} key={contentId}>
- <ProductCategory id={contentId} />
- </LazyLoadComponent>
- )) }
- </div>
- )
-} \ No newline at end of file
diff --git a/src2/components/products/ProductSimilar.js b/src2/components/products/ProductSimilar.js
deleted file mode 100644
index 9e2292cb..00000000
--- a/src2/components/products/ProductSimilar.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import apiOdoo from '@/core/utils/apiOdoo';
-import { useEffect, useState } from 'react';
-import ProductSlider from './ProductSlider';
-
-export default function ProductSimilar({ productId }) {
- const [similarProducts, setSimilarProducts] = useState(null);
-
- useEffect(() => {
- const getSimilarProducts = async () => {
- if (productId && !similarProducts) {
- const dataSimilarProducts = await apiOdoo('GET', `/api/v1/product/${productId}/similar?limit=20`);
- setSimilarProducts(dataSimilarProducts);
- }
- }
- getSimilarProducts();
- }, [productId, similarProducts]);
-
-
- return (
- <div className="p-4">
- <h2 className="font-bold mb-4">Kamu Mungkin Juga Suka</h2>
- <ProductSlider products={similarProducts}/>
- </div>
- )
-} \ No newline at end of file
diff --git a/src2/components/products/ProductSlider.js b/src2/components/products/ProductSlider.js
deleted file mode 100644
index 662a6511..00000000
--- a/src2/components/products/ProductSlider.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Swiper, SwiperSlide } from "swiper/react";
-import ProductCard from "./ProductCard";
-import "swiper/css";
-import Image from "../elements/Image";
-import Link from "../elements/Link";
-import { SkeletonProduct } from "../elements/Skeleton";
-import { useState } from "react";
-
-export default function ProductSlider({
- products,
- simpleProductTitleLine = false,
- bannerMode = false
-}) {
- const [ activeIndex, setActiveIndex ] = useState(0);
- const swiperSliderFirstMove = (swiper) => {
- setActiveIndex(swiper.activeIndex);
- };
-
- return (
- <>
- { bannerMode && (
- <Image src={products.banner.image} alt={products.banner.name} className={`absolute rounded-r top-0 left-0 h-full max-w-[52%] idt-transition border border-gray_r-6 ` + (activeIndex > 0 ? 'opacity-0' : 'opacity-100')} />
- ) }
- <Swiper freeMode={true} slidesPerView={2.2} spaceBetween={8} onSlideChange={swiperSliderFirstMove} prefix="product">
- { bannerMode && (
- <SwiperSlide>
- <Link href={products.banner.url} className="w-full h-full block"></Link>
- </SwiperSlide>
- ) }
- {products?.products?.map((product, index) => (
- <SwiperSlide key={index}>
- <ProductCard data={product} simpleProductTitleLine={simpleProductTitleLine} />
- </SwiperSlide>
- ))}
- </Swiper>
- { !products ? <SkeletonProduct /> : ''}
- </>
- )
-} \ No newline at end of file
diff --git a/src2/components/transactions/TransactionDetail.js b/src2/components/transactions/TransactionDetail.js
deleted file mode 100644
index 295a4f9f..00000000
--- a/src2/components/transactions/TransactionDetail.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { useState } from "react";
-import DescriptionRow from "../elements/DescriptionRow";
-import Disclosure from "../elements/Disclosure";
-
-const DetailAddress = ({ address }) => {
- const fullAddress = [];
- if (address?.street) fullAddress.push(address.street);
- if (address?.sub_district?.name) fullAddress.push(address.sub_district.name);
- if (address?.district?.name) fullAddress.push(address.district.name);
- if (address?.city?.name) fullAddress.push(address.city.name);
- return (
- <div className="p-4 flex flex-col gap-y-4">
- <DescriptionRow label="Nama">{ address?.name }</DescriptionRow>
- <DescriptionRow label="Email">{ address?.email || '-' }</DescriptionRow>
- <DescriptionRow label="No Telepon">{ address?.mobile || '-' }</DescriptionRow>
- <DescriptionRow label="Alamat">{ fullAddress.join(', ') }</DescriptionRow>
- </div>
- );
-};
-
-const TransactionDetailAddress = ({ transaction }) => {
- const [ activeSection, setActiveSection ] = useState({
- purchase: false,
- shipping: false,
- invoice: false,
- });
-
- const toggleSection = ( name ) => {
- setActiveSection({
- ...activeSection,
- [name]: !activeSection[name]
- });
- };
-
- return (
- <div className="m-4 rounded-md border border-gray_r-6 divide-y divide-gray_r-6">
- <Disclosure
- label="Detail Pelanggan"
- active={activeSection.purchase}
- onClick={() => toggleSection('purchase')}
- />
- { activeSection.purchase && (
- <DetailAddress address={transaction?.address?.customer} />
- ) }
-
- <Disclosure
- label="Detail Pengiriman"
- active={activeSection.shipping}
- onClick={() => toggleSection('shipping')}
- />
- { activeSection.shipping && (
- <DetailAddress address={transaction?.address?.shipping} />
- ) }
-
- <Disclosure
- label="Detail Penagihan"
- active={activeSection.invoice}
- onClick={() => toggleSection('invoice')}
- />
- { activeSection.invoice && (
- <DetailAddress address={transaction?.address?.invoice} />
- ) }
- </div>
- );
-};
-
-export { TransactionDetailAddress }; \ No newline at end of file
diff --git a/src2/components/transactions/TransactionStatusBadge.js b/src2/components/transactions/TransactionStatusBadge.js
deleted file mode 100644
index f94fd3fd..00000000
--- a/src2/components/transactions/TransactionStatusBadge.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const TransactionStatusBadge = ({ status }) => {
- let badgeProps = {
- className: ['h-fit'],
- text: ''
- };
- switch (status) {
- case 'cancel':
- badgeProps.className.push('badge-solid-red');
- badgeProps.text = 'Pesanan Batal'
- break;
- case 'draft':
- badgeProps.className.push('badge-red');
- badgeProps.text = 'Pending Quotation'
- break;
- case 'waiting':
- badgeProps.className.push('badge-yellow');
- badgeProps.text = 'Pesanan diterima'
- break;
- case 'sale':
- badgeProps.className.push('badge-yellow');
- badgeProps.text = 'Pesanan diproses'
- break;
- case 'shipping':
- badgeProps.className.push('badge-green');
- badgeProps.text = 'Pesanan dikirim'
- break;
- case 'partial_shipping':
- badgeProps.className.push('badge-green');
- badgeProps.text = 'Dikirim sebagian'
- break;
- case 'done':
- badgeProps.className.push('badge-solid-green');
- badgeProps.text = 'Pesanan Selesai'
- break;
- }
- badgeProps.className = badgeProps.className.join(' ');
-
- return (
- <div className={badgeProps.className}>
- { badgeProps.text }
- </div>
- )
-};
-
-export default TransactionStatusBadge; \ No newline at end of file
diff --git a/src2/components/variants/VariantCard.js b/src2/components/variants/VariantCard.js
deleted file mode 100644
index a821480c..00000000
--- a/src2/components/variants/VariantCard.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { createSlug } from "@/core/utils/slug";
-import Image from "../elements/Image";
-import Link from "../elements/Link";
-import currencyFormat from "@/core/utils/currencyFormat";
-import { useRouter } from "next/router";
-import { toast } from "react-hot-toast";
-import { createOrUpdateItemCart } from "@/core/utils/cart";
-
-export default function VariantCard({
- data,
- openOnClick = true,
- buyMore = false
-}) {
- let product = data;
- const router = useRouter();
-
- const addItemToCart = () => {
- toast.success('Berhasil menambahkan ke keranjang', { duration: 1500 });
- createOrUpdateItemCart(product.id, 1);
- return;
- };
-
- const checkoutItem = () => {
- router.push(`/shop/checkout?product_id=${product.id}&qty=${product.quantity}`);
- }
-
- const Card = () => (
- <div className="flex gap-x-3">
- <div className="w-4/12 flex items-center gap-x-2">
- <Image
- src={product.parent.image}
- alt={product.parent.name}
- className="object-contain object-center border border-gray_r-6 h-32 w-full rounded-md"
- />
- </div>
- <div className="w-8/12 flex flex-col">
- <p className="product-card__title wrap-line-ellipsis-2">
- {product.parent.name}
- </p>
- <p className="text-caption-2 text-gray_r-11 mt-1">
- {product.code || '-'}
- {product.attributes.length > 0 ? ` ・ ${product.attributes.join(', ')}` : ''}
- </p>
- <div className="flex flex-wrap gap-x-1 items-center mt-auto">
- {product.price.discount_percentage > 0 && (
- <>
- <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(product.price.price)}</p>
- <span className="badge-red">{product.price.discount_percentage}%</span>
- </>
- )}
- <p className="text-caption-2 text-gray_r-12">{currencyFormat(product.price.price_discount)}</p>
- </div>
- <p className="text-caption-2 text-gray_r-11 mt-1">
- {currencyFormat(product.price.price_discount)} × {product.quantity} Barang
- </p>
- <p className="text-caption-2 text-gray_r-12 font-bold mt-2">
- {currencyFormat(product.quantity * product.price.price_discount)}
- </p>
- </div>
- </div>
- );
-
- if (openOnClick) {
- return (
- <>
- <Link href={'/shop/product/' + createSlug(product.parent.name, product.parent.id)}>
- <Card />
- </Link>
- { buyMore && (
- <div className="flex justify-end gap-x-2 mb-2">
- <button
- type="button"
- onClick={addItemToCart}
- className="btn-yellow text-gray_r-12 py-2 px-3"
- >
- Tambah Keranjang
- </button>
- <button
- type="button"
- onClick={checkoutItem}
- className="btn-solid-red py-2 px-3"
- >
- Beli Lagi
- </button>
- </div>
- ) }
- </>
- );
- }
-
- return <Card/>;
-} \ No newline at end of file
diff --git a/src2/components/variants/VariantGroupCard.js b/src2/components/variants/VariantGroupCard.js
deleted file mode 100644
index 462c63cf..00000000
--- a/src2/components/variants/VariantGroupCard.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useState } from "react"
-import VariantCard from "./VariantCard"
-
-export default function VariantGroupCard({
- variants,
- ...props
-}) {
- const [ showAll, setShowAll ] = useState(false)
- const variantsToShow = showAll ? variants : variants.slice(0, 2)
-
- return (
- <>
- { variantsToShow?.map((variant, index) => (
- <VariantCard
- key={index}
- data={variant}
- {...props}
- />
- )) }
- { variants.length > 2 && (
- <button
- type="button"
- className="btn-light py-2 w-full"
- onClick={() => setShowAll(!showAll)}
- >
- { !showAll ? `Lihat Semua +${variants.length - variantsToShow.length}` : 'Tutup' }
- </button>
- ) }
- </>
- )
-} \ No newline at end of file
diff --git a/src2/core/utils/address.js b/src2/core/utils/address.js
deleted file mode 100644
index c4a19af5..00000000
--- a/src2/core/utils/address.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const getAddress = () => {
- const address = localStorage.getItem('address');
- if (address) return JSON.parse(address);
- return {};
-}
-
-const setAddress = (address) => {
- localStorage.setItem('address', JSON.stringify(address));
- return true;
-}
-
-const getItemAddress = (key) => {
- let address = getAddress();
- return address[key];
-}
-
-const createOrUpdateItemAddress = (key, value) => {
- let address = getAddress();
- address[key] = value;
- setAddress(address);
- return true;
-}
-
-export {
- getItemAddress,
- createOrUpdateItemAddress
-}; \ No newline at end of file
diff --git a/src2/core/utils/apiOdoo.js b/src2/core/utils/apiOdoo.js
deleted file mode 100644
index 4d0adae3..00000000
--- a/src2/core/utils/apiOdoo.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { getCookie, setCookie } from 'cookies-next';
-import axios from 'axios';
-import { getAuth } from './auth';
-
-const renewToken = async () => {
- let token = await axios.get(process.env.SELF_HOST + '/api/token');
- setCookie('token', token.data);
- return token.data;
-};
-
-const getToken = async () => {
- let token = getCookie('token');
- if (token == undefined) token = await renewToken();
- return token;
-};
-
-let connectionTry = 0;
-const apiOdoo = async (method, url, data = {}, headers = {}) => {
- try {
- connectionTry++;
- let token = await getToken();
- let axiosParameter = {
- method,
- url: process.env.ODOO_HOST + url,
- headers: {'Authorization': token, ...headers}
- }
- const auth = getAuth();
-
- if (auth) axiosParameter.headers['Token'] = auth.token;
- if (method.toUpperCase() == 'POST') axiosParameter.headers['Content-Type'] = 'application/x-www-form-urlencoded';
- if (Object.keys(data).length > 0) axiosParameter.data = new URLSearchParams(Object.entries(data)).toString();
-
- let res = await axios(axiosParameter);
- if (res.data.status.code == 401 && connectionTry < 15) {
- await renewToken();
- return apiOdoo(method, url, data, headers);
- }
- return res.data.result || [];
- } catch (error) {
- console.log(error)
- }
-}
-
-export default apiOdoo; \ No newline at end of file
diff --git a/src2/core/utils/auth.js b/src2/core/utils/auth.js
deleted file mode 100644
index 62eba2c0..00000000
--- a/src2/core/utils/auth.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { deleteCookie, getCookie, setCookie } from 'cookies-next';
-import { useEffect, useState } from 'react';
-
-const getAuth = () => {
- let auth = getCookie('auth');
- if (auth) {
- return JSON.parse(auth);
- }
- return false;
-}
-
-const setAuth = (user) => {
- setCookie('auth', JSON.stringify(user));
- return true;
-}
-
-const deleteAuth = () => {
- deleteCookie('auth');
- return true;
-}
-
-const useAuth = () => {
- const [auth, setAuth] = useState(null);
-
- useEffect(() => {
- const handleIsAuthenticated = () => setAuth(getAuth());
- handleIsAuthenticated();
- }, []);
-
- return [auth, setAuth];
-}
-
-export {
- getAuth,
- setAuth,
- deleteAuth,
- useAuth
-}; \ No newline at end of file
diff --git a/src2/core/utils/cart.js b/src2/core/utils/cart.js
deleted file mode 100644
index 66efcbf2..00000000
--- a/src2/core/utils/cart.js
+++ /dev/null
@@ -1,36 +0,0 @@
-const getCart = () => {
- const cart = localStorage.getItem('cart');
- if (cart) return JSON.parse(cart);
- return {};
-}
-
-const setCart = (cart) => {
- localStorage.setItem('cart', JSON.stringify(cart));
- return true;
-}
-
-const getItemCart = (product_id) => {
- let cart = getCart();
- return cart[product_id];
-}
-
-const createOrUpdateItemCart = (product_id, quantity, selected = false) => {
- let cart = getCart();
- cart[product_id] = { product_id, quantity, selected };
- setCart(cart);
- return true;
-}
-
-const deleteItemCart = (product_id) => {
- let cart = getCart();
- delete cart[product_id];
- setCart(cart);
- return true;
-}
-
-export {
- getCart,
- getItemCart,
- createOrUpdateItemCart,
- deleteItemCart
-} \ No newline at end of file
diff --git a/src2/core/utils/convertToOption.js b/src2/core/utils/convertToOption.js
deleted file mode 100644
index 08fec08f..00000000
--- a/src2/core/utils/convertToOption.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const convertToOption = (data) => {
- if (data) {
- return {
- value: data.id,
- label: data.name,
- }
- }
- return null;
-};
-
-export default convertToOption; \ No newline at end of file
diff --git a/src2/core/utils/currencyFormat.js b/src2/core/utils/currencyFormat.js
deleted file mode 100644
index dadeaec6..00000000
--- a/src2/core/utils/currencyFormat.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function currencyFormat(value) {
- const currency = new Intl.NumberFormat('id-ID', {
- style: 'currency',
- currency: 'IDR',
- maximumFractionDigits: 0
- });
- return currency.format(value);
-} \ No newline at end of file
diff --git a/src2/core/utils/formValidation.js b/src2/core/utils/formValidation.js
deleted file mode 100644
index 0e83f4cc..00000000
--- a/src2/core/utils/formValidation.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import { useCallback, useEffect, useState } from "react";
-
-const validateForm = (data, queries, hasChangedInputs = null) => {
- let result = { valid: true, errors: {} };
-
- for (const query in queries) {
- if (!hasChangedInputs || (hasChangedInputs && hasChangedInputs[query])) {
- const value = data[query];
- const rules = queries[query];
- let errors = [];
- let label = null;
- for (const rule of rules) {
- let emailValidationRegex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- if (rule.startsWith('label:')) {
- label = rule.replace('label:', '');
- } else if (rule === 'required' && !value) {
- errors.push('tidak boleh kosong');
- } else if (rule === 'email' && !value.match(emailValidationRegex)) {
- errors.push('harus format johndoe@example.com');
- } else if (rule.startsWith('maxLength:')) {
- let maxLength = parseInt(rule.replace('maxLength:', ''));
- if (value && value.length > maxLength) errors.push(`maksimal ${maxLength} karakter`);
- }
- }
- if (errors.length > 0) {
- result.errors[query] = (label || query) + ' ' + errors.join(', ');
- }
- }
- }
-
- if (Object.keys(result.errors).length > 0) {
- result.valid = false;
- }
-
- return result;
-}
-
-const useFormValidation = ({ initialFormValue = {}, validationScheme = {} }) => {
- const [ formInputs, setFormInputs ] = useState(initialFormValue);
- const [ formErrors, setFormErrors ] = useState({});
- const [ formValidation ] = useState(validationScheme);
- const [ hasChangedInputs, setHasChangedInputs ] = useState({});
-
- const handleFormSubmit = (event, func) => {
- if (event) {
- event.preventDefault();
-
- // Make all input to be has changed mode to revalidate
- const changedInputs = {};
- for (const key in formInputs) changedInputs[key] = true;
- setHasChangedInputs(changedInputs);
-
- const { valid, errors } = validateForm(formInputs, formValidation, changedInputs);
- setFormErrors(errors);
-
- if (valid) func();
- }
- };
-
- const setChangedInput = (name, value = true) => {
- setHasChangedInputs((hasChangedInputs) => ({
- ...hasChangedInputs,
- [name]: value
- }));
- };
-
- const handleInputChange = (event) => {
- setFormInputs((formInputs) => ({
- ...formInputs,
- [event.target.name]: event.target.value
- }));
- setChangedInput(event.target.name);
- };
-
- const handleSelectChange = useCallback((name, value) => {
- setFormInputs((formInputs) => ({
- ...formInputs,
- [name]: value
- }));
- setChangedInput(name);
- }, []);
-
- const handleFormReset = () => {
- setFormInputs(initialFormValue);
- setFormErrors({});
- setHasChangedInputs({});
- }
-
- useEffect(() => {
- if (formInputs) {
- const { errors } = validateForm(formInputs, formValidation, hasChangedInputs);
- setFormErrors(errors);
- }
- }, [ formInputs, formValidation, hasChangedInputs ])
-
- return {
- handleFormReset,
- handleFormSubmit,
- handleInputChange,
- handleSelectChange,
- hasChangedInputs,
- formInputs,
- formErrors
- };
- };
-
-export default useFormValidation; \ No newline at end of file
diff --git a/src2/core/utils/getFileBase64.js b/src2/core/utils/getFileBase64.js
deleted file mode 100644
index 78013e43..00000000
--- a/src2/core/utils/getFileBase64.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const getFileBase64 = file => new Promise((resolve, reject) => {
- let reader = new FileReader();
- reader.readAsBinaryString(file);
- reader.onload = () => {
- let result = reader.result;
- resolve(btoa(result));
- };
- reader.onerror = error => reject(error);
-});
-
-export default getFileBase64; \ No newline at end of file
diff --git a/src2/core/utils/greeting.js b/src2/core/utils/greeting.js
deleted file mode 100644
index 7dc19f8f..00000000
--- a/src2/core/utils/greeting.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const greeting = () => {
- let hours = new Date().getHours();
- if (hours < 11) return 'Selamat Pagi';
- if (hours < 15) return 'Selamat Siang';
- if (hours < 18) return 'Selamat Sore';
- return 'Selamat Malam';
-}
-
-export default greeting; \ No newline at end of file
diff --git a/src2/core/utils/mailer.js b/src2/core/utils/mailer.js
deleted file mode 100644
index 4e7ff7cc..00000000
--- a/src2/core/utils/mailer.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const nodemailer = require('nodemailer');
-const mailer = nodemailer.createTransport({
- port: process.env.MAIL_PORT,
- host: process.env.MAIL_HOST,
- auth: {
- user: process.env.MAIL_USER,
- pass: process.env.MAIL_PASS
- },
- secure: true
-});
-
-export default mailer; \ No newline at end of file
diff --git a/src2/core/utils/slug.js b/src2/core/utils/slug.js
deleted file mode 100644
index 0a7d30fc..00000000
--- a/src2/core/utils/slug.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import toTitleCase from './toTitleCase';
-
-const createSlug = (name, id) => {
- let slug = name?.trim().replace(new RegExp(/[^A-Za-z0-9]/, 'g'), '-').toLowerCase() + '-' + id;
- let splitSlug = slug.split('-');
- let filterSlugFromEmptyChar = splitSlug.filter(x => x != '');
- return filterSlugFromEmptyChar.join('-');
-}
-
-const getIdFromSlug = (slug) => {
- let id = slug.split('-');
- return id[id.length-1];
-}
-
-const getNameFromSlug = (slug) => {
- let name = slug.split('-');
- name.pop();
- return toTitleCase(name.join(' '));
-}
-
-export {
- createSlug,
- getIdFromSlug,
- getNameFromSlug
-}; \ No newline at end of file
diff --git a/src2/core/utils/toTitleCase.js b/src2/core/utils/toTitleCase.js
deleted file mode 100644
index 5cfd70d0..00000000
--- a/src2/core/utils/toTitleCase.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function toTitleCase(str) {
- return str.replace(
- /\w\S*/g,
- function(txt) {
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
- }
- );
-} \ No newline at end of file
diff --git a/src2/icons/chevron-left.svg b/src2/icons/chevron-left.svg
deleted file mode 100644
index a22ce386..00000000
--- a/src2/icons/chevron-left.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left">
- <polyline points="15 18 9 12 15 6"></polyline>
-</svg> \ No newline at end of file
diff --git a/src2/icons/chevron-right.svg b/src2/icons/chevron-right.svg
deleted file mode 100644
index eb58f2f2..00000000
--- a/src2/icons/chevron-right.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="feather feather-chevron-right">
-<polyline points="9 18 15 12 9 6"></polyline>
-</svg> \ No newline at end of file
diff --git a/src2/icons/close.svg b/src2/icons/close.svg
deleted file mode 100644
index 50e0589d..00000000
--- a/src2/icons/close.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> \ No newline at end of file
diff --git a/src2/icons/filter.svg b/src2/icons/filter.svg
deleted file mode 100644
index c15ce7b9..00000000
--- a/src2/icons/filter.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-filter"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon></svg> \ No newline at end of file
diff --git a/src2/icons/image-placeholder.svg b/src2/icons/image-placeholder.svg
deleted file mode 100644
index 935e1097..00000000
--- a/src2/icons/image-placeholder.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" viewBox="0 0 640 512"><path d="M480 80C480 35.82 515.8 0 560 0C604.2 0 640 35.82 640 80C640 124.2 604.2 160 560 160C515.8 160 480 124.2 480 80zM0 456.1C0 445.6 2.964 435.3 8.551 426.4L225.3 81.01C231.9 70.42 243.5 64 256 64C268.5 64 280.1 70.42 286.8 81.01L412.7 281.7L460.9 202.7C464.1 196.1 472.2 192 480 192C487.8 192 495 196.1 499.1 202.7L631.1 419.1C636.9 428.6 640 439.7 640 450.9C640 484.6 612.6 512 578.9 512H55.91C25.03 512 .0006 486.1 .0006 456.1L0 456.1z"/></svg> \ No newline at end of file
diff --git a/src2/icons/instagram.svg b/src2/icons/instagram.svg
deleted file mode 100644
index d90842c6..00000000
--- a/src2/icons/instagram.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-instagram">
- <rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
- <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
- <line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
-</svg> \ No newline at end of file
diff --git a/src2/icons/linkedin.svg b/src2/icons/linkedin.svg
deleted file mode 100644
index a68aec96..00000000
--- a/src2/icons/linkedin.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-linkedin">
- <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
- <rect x="2" y="9" width="4" height="12"></rect>
- <circle cx="4" cy="4" r="2"></circle>
-</svg> \ No newline at end of file
diff --git a/src2/icons/menu.svg b/src2/icons/menu.svg
deleted file mode 100644
index 5d067e8e..00000000
--- a/src2/icons/menu.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg> \ No newline at end of file
diff --git a/src2/icons/minus.svg b/src2/icons/minus.svg
deleted file mode 100644
index 12a10199..00000000
--- a/src2/icons/minus.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-minus">
- <line x1="5" y1="12" x2="19" y2="12"></line>
-</svg> \ No newline at end of file
diff --git a/src2/icons/plus.svg b/src2/icons/plus.svg
deleted file mode 100644
index 2923c684..00000000
--- a/src2/icons/plus.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus">
- <line x1="12" y1="5" x2="12" y2="19"></line>
- <line x1="5" y1="12" x2="19" y2="12"></line>
-</svg> \ No newline at end of file
diff --git a/src2/icons/search.svg b/src2/icons/search.svg
deleted file mode 100644
index 6de1cdfa..00000000
--- a/src2/icons/search.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M9.71061 15.8333C13.3925 15.8333 16.3773 12.8486 16.3773 9.16667C16.3773 5.48477 13.3925 2.5 9.71061 2.5C6.02871 2.5 3.04395 5.48477 3.04395 9.16667C3.04395 12.8486 6.02871 15.8333 9.71061 15.8333Z" stroke="#2B2B2B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M18.0439 17.5L14.4189 13.875" stroke="#2B2B2B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
diff --git a/src2/icons/shopping-cart.svg b/src2/icons/shopping-cart.svg
deleted file mode 100644
index 09f14ca6..00000000
--- a/src2/icons/shopping-cart.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart"><circle cx="9" cy="21" r="1"></circle><circle cx="20" cy="21" r="1"></circle><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path></svg> \ No newline at end of file
diff --git a/src2/icons/trash.svg b/src2/icons/trash.svg
deleted file mode 100644
index e23673ee..00000000
--- a/src2/icons/trash.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash">
- <polyline points="3 6 5 6 21 6"></polyline>
- <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
-</svg> \ No newline at end of file
diff --git a/src2/images/logo.png b/src2/images/logo.png
deleted file mode 100644
index 87c696aa..00000000
--- a/src2/images/logo.png
+++ /dev/null
Binary files differ
diff --git a/src2/images/page-not-found.png b/src2/images/page-not-found.png
deleted file mode 100644
index 296c0443..00000000
--- a/src2/images/page-not-found.png
+++ /dev/null
Binary files differ
diff --git a/src2/lib/elements/hooks/useBottomPopup.js b/src2/lib/elements/hooks/useBottomPopup.js
deleted file mode 100644
index 88b72316..00000000
--- a/src2/lib/elements/hooks/useBottomPopup.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { useState } from "react";
-import dynamic from "next/dynamic";
-
-const DynamicBottomPopup = dynamic(() => import('@/components/elements/BottomPopup'));
-
-const useBottomPopup = ({
- title,
- children
-}) => {
- const [ isOpen, setIsOpen ] = useState(false);
- const [ dataPopup, setDataPopup ] = useState(null);
-
- const closePopup = () => {
- setIsOpen(false);
- setDataPopup(null);
- };
- const openPopup = ( data = null ) => {
- setIsOpen(true);
- setDataPopup(data);
- };
-
- const BottomPopup = (
- <DynamicBottomPopup
- title={title}
- active={isOpen}
- closePopup={closePopup}
- >
- { children(dataPopup) }
- </DynamicBottomPopup>
- );
-
- return {
- dataPopup,
- BottomPopup,
- closePopup,
- openPopup
- }
-}
-
-export default useBottomPopup; \ No newline at end of file
diff --git a/src2/lib/elements/hooks/useConfirmAlert.js b/src2/lib/elements/hooks/useConfirmAlert.js
deleted file mode 100644
index 4975c57d..00000000
--- a/src2/lib/elements/hooks/useConfirmAlert.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { useState } from "react";
-import dynamic from "next/dynamic";
-
-const DynamicConfirmAlert = dynamic(() => import('@/components/elements/ConfirmAlert'));
-
-const useConfirmAlert = ({
- title,
- caption,
- closeText,
- submitText,
- onSubmit,
-}) => {
- const [ isOpen, setIsOpen ] = useState(false);
- const [ data, setData ] = useState(null);
-
- const closeConfirmAlert = () => {
- setIsOpen(false);
- setData(null);
- };
- const openConfirmAlert = ( data = null ) => {
- setIsOpen(true);
- setData(data);
- };
- const handleSubmit = async () => {
- await onSubmit(data);
- closeConfirmAlert();
- };
-
- const ConfirmAlert = (
- <DynamicConfirmAlert
- title={title}
- caption={caption}
- closeText={closeText}
- submitText={submitText}
- onClose={closeConfirmAlert}
- onSubmit={handleSubmit}
- show={isOpen}
- />
- );
-
- return {
- isOpen,
- closeConfirmAlert,
- openConfirmAlert,
- ConfirmAlert
- };
-}
-
-export default useConfirmAlert; \ No newline at end of file
diff --git a/src2/pages/404.js b/src2/pages/404.js
deleted file mode 100644
index 1e1850f2..00000000
--- a/src2/pages/404.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Image from "next/image";
-import Link from "@/components/elements/Link";
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-import PageNotFoundImage from "../images/page-not-found.png";
-
-export default function PageNotFound() {
- return (
- <>
- <Header title="Halaman Tidak Ditemukan - Indoteknik" />
- <Layout>
- <main className="pb-8">
- <Image src={PageNotFoundImage} alt="Halaman Tidak Ditemukan - Indoteknik" className="w-full" />
- <p className="mt-3 h1 text-center">Halaman tidak ditemukan</p>
- <div className="mt-6 flex px-4 gap-x-3">
- <Link href="/" className="btn-light text-gray_r-12 flex-1">
- Kembali ke beranda
- </Link>
- <a href="https://send.whatsapp.com" className="btn-yellow text-gray_r-12 flex-1 h-fit">
- Tanya admin
- </a>
- </div>
- </main>
- </Layout>
- </>
- );
-} \ No newline at end of file
diff --git a/src2/pages/_app.js b/src2/pages/_app.js
deleted file mode 100644
index 6a40f4e6..00000000
--- a/src2/pages/_app.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import '../styles/globals.css';
-import NextProgress from 'next-progress';
-import { useRouter } from 'next/router';
-import { AnimatePresence } from 'framer-motion';
-import { Toaster } from "react-hot-toast";
-
-function MyApp({ Component, pageProps }) {
- const router = useRouter();
-
- return (
- <>
- <Toaster
- position="top-center"
- toastOptions={{
- duration: 3000,
- className: 'border border-gray_r-8'
- }}
- />
- <NextProgress color="#F01C21" options={{ showSpinner: false }} />
- <AnimatePresence
- mode='wait'
- initial={false}
- onExitComplete={() => window.scrollTo(0, 0)}
- >
- <Component {...pageProps} key={router.asPath} />
- </AnimatePresence>
- </>
- )
-}
-
-export default MyApp
diff --git a/src2/pages/_error.js b/src2/pages/_error.js
deleted file mode 100644
index 107ddf46..00000000
--- a/src2/pages/_error.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-
-export default function Error() {
- return (
- <Layout>
- <Header title="Kesalahan Internal"/>
-
- </Layout>
- );
-} \ No newline at end of file
diff --git a/src2/pages/activate.js b/src2/pages/activate.js
deleted file mode 100644
index d9b41bf4..00000000
--- a/src2/pages/activate.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import axios from "axios";
-import Head from "next/head";
-import Image from "next/image";
-import Link from "@/components/elements/Link";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-import Alert from "@/components/elements/Alert";
-import Layout from "@/components/layouts/Layout";
-import Spinner from "@/components/elements/Spinner";
-import { setAuth } from "@/core/utils/auth";
-import Logo from "@/images/logo.png";
-
-export default function Activate() {
- const [email, setEmail] = useState('');
- const [isInputFulfilled, setIsInputFulfilled] = useState(false);
- const [isLoading, setIsLoading] = useState(false);
- const [alert, setAlert] = useState();
- const router = useRouter();
- const { token } = router.query;
-
- useEffect(() => {
- if (router.query.email) setEmail(router.query.email);
- }, [router])
-
- useEffect(() => {
- const activateIfTokenExist = async () => {
- if (token) {
- let activation = await axios.post(`${process.env.SELF_HOST}/api/activation`, {token});
- if (activation.data.activation) {
- setAuth(activation.data.user);
- setAlert({
- component: <>Selamat, akun anda berhasil diaktifkan, <Link className="text-gray_r-12" href="/">kembali ke beranda</Link>.</>,
- type: 'success'
- });
- } else {
- setAlert({
- component: <>Mohon maaf token sudah tidak aktif, lakukan permintaan aktivasi akun kembali atau <Link className="text-gray_r-12" href="/login">masuk</Link> jika sudah memiliki akun.</>,
- type: 'info'
- });
- }
- }
- }
- activateIfTokenExist();
- }, [token]);
-
- useEffect(() => {
- setIsInputFulfilled(email != '');
- }, [email]);
-
- const activationRequest = async (e) => {
- e.preventDefault();
- setIsLoading(true);
- let activationRequest = await axios.post(`${process.env.SELF_HOST}/api/activation-request`, {email});
- if (activationRequest.data.activation_request) {
- setAlert({
- component: <>Mohon cek email anda untuk aktivasi akun Indoteknik</>,
- type: 'success'
- });
- } else {
- switch (activationRequest.data.reason) {
- case 'NOT_FOUND':
- setAlert({
- component: <>Email tersebut belum terdaftar, <Link className="text-gray_r-12" href="/register">daftar sekarang</Link>.</>,
- type: 'info'
- });
- break;
- case 'ACTIVE':
- setAlert({
- component: <>Email tersebut sudah terdaftar dan sudah aktif, <Link className="text-gray_r-12" href="/login">masuk sekarang</Link>.</>,
- type: 'info'
- });
- break;
- }
- }
- setIsLoading(false);
- }
- return (
- <>
- <Head>
- <title>Aktivasi Akun Indoteknik</title>
- </Head>
- <Layout className="max-w-lg mx-auto flex flex-col items-center px-4 pb-8">
- <Link href="/" className="mt-16">
- <Image src={Logo} alt="Logo Indoteknik" width={165} height={42} />
- </Link>
- <h1 className="text-2xl text-gray_r-12 mt-4 text-center">Aktivasi Akun Indoteknik Anda</h1>
- <h2 className="text-gray-800 mt-2 mb-4 text-center">Link aktivasi akan dikirimkan melalui email</h2>
- {alert ? (
- <Alert className="text-center" type={alert.type}>{alert.component}</Alert>
- ) : ''}
- <form onSubmit={activationRequest} className="w-full">
- <input
- type="text"
- className="form-input bg-gray-100 mt-4 focus:ring-1 focus:ring-yellow-900"
- placeholder="johndoe@gmail.com"
- value={email}
- onChange={(e) => setEmail(e.target.value)}
- autoFocus
- />
- <button type="submit" disabled={!isInputFulfilled} className="btn-yellow font-semibold mt-4 w-full">
- {isLoading ? (
- <div className="flex justify-center items-center gap-x-2">
- <Spinner className="w-4 h-4 text-gray-600 fill-gray-900" /> <span>Loading...</span>
- </div>
- ) : 'Kirim Email'}
- </button>
- </form>
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/pages/api/activation-request.js b/src2/pages/api/activation-request.js
deleted file mode 100644
index 3f33875c..00000000
--- a/src2/pages/api/activation-request.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import apiOdoo from "@/core/utils/apiOdoo";
-import mailer from "@/core/utils/mailer";
-
-export default async function handler(req, res) {
- try {
- const { email } = req.body;
- let result = await apiOdoo(
- 'POST',
- '/api/v1/user/activation-request',
- {email}
- );
- if (result.activation_request) {
- mailer.sendMail({
- from: 'sales@indoteknik.com',
- to: result.user.email,
- subject: 'Permintaan Aktivasi Akun Indoteknik',
- html: `
- <h1>Permintaan Aktivasi Akun Indoteknik</h1>
- <br>
- <p>Aktivasi akun anda melalui link berikut: <a href="${process.env.SELF_HOST}/activate?token=${result.token}">Aktivasi Akun</a></p>
- `
- });
- }
- delete result.user;
- delete result.token;
- res.status(200).json(result);
- } catch (error) {
- console.log(error);
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/activation.js b/src2/pages/api/activation.js
deleted file mode 100644
index 8b22af8d..00000000
--- a/src2/pages/api/activation.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import apiOdoo from "@/core/utils/apiOdoo";
-
-export default async function handler(req, res) {
- try {
- const { token } = req.body;
- let result = await apiOdoo(
- 'POST',
- '/api/v1/user/activation',
- {token}
- );
- res.status(200).json(result);
- } catch (error) {
- console.log(error);
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/login.js b/src2/pages/api/login.js
deleted file mode 100644
index e02a73cb..00000000
--- a/src2/pages/api/login.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import apiOdoo from "@/core/utils/apiOdoo";
-
-export default async function handler(req, res) {
- try {
- const { email, password } = req.body;
- let result = await apiOdoo(
- 'POST',
- '/api/v1/user/login',
- {email, password}
- );
- res.status(200).json(result);
- } catch (error) {
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/register.js b/src2/pages/api/register.js
deleted file mode 100644
index 7c8d8b39..00000000
--- a/src2/pages/api/register.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import apiOdoo from "@/core/utils/apiOdoo";
-
-export default async function handler(req, res) {
- try {
- const { email, name, password } = req.body;
- let result = await apiOdoo(
- 'POST',
- '/api/v1/user/register',
- {email, name, password}
- );
- res.status(200).json(result);
- } catch (error) {
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/shop/search.js b/src2/pages/api/shop/search.js
deleted file mode 100644
index ad986c86..00000000
--- a/src2/pages/api/shop/search.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import axios from "axios";
-
-const productResponseMap = (products) => {
- return products.map((product) => {
- let productMapped = {
- id: product.product_id ? product.product_id[0] : '',
- image: product.image ? product.image[0] : '',
- code: product.default_code ? product.default_code[0] : '',
- name: product.product_name ? product.product_name[0] : '',
- lowest_price: {
- price: product.price ? product.price[0] : 0,
- price_discount: product.price_discount ? product.price_discount[0] : 0,
- discount_percentage: product.discount ? product.discount[0] : 0,
- },
- variant_total: product.variant_total ? product.variant_total[0] : 0,
- stock_total: product.stock_total ? product.stock_total[0] : 0,
- weight: product.weight ? product.weight[0] : 0,
- manufacture: {},
- categories: [],
- };
-
- if (product.manufacture_id && product.brand) {
- productMapped.manufacture = {
- id: product.manufacture_id ? product.manufacture_id[0] : '',
- name: product.brand ? product.brand[0] : '',
- };
- }
-
- productMapped.categories = [
- {
- id: product.category_id ? product.category_id[0] : '',
- name: product.category_name ? product.category_name[0] : '',
- }
- ];
-
- return productMapped;
- });
-}
-
-export default async function handler(req, res) {
- const {
- q,
- page = 1,
- brand = '',
- category = '',
- price_from = 0,
- price_to = 0,
- order_by = ''
- } = req.query;
-
- let paramOrderBy = '';
- switch (order_by) {
- case 'price-asc':
- paramOrderBy = ', price_discount ASC';
- break;
- case 'price-desc':
- paramOrderBy = ', price_discount DESC';
- break;
- case 'popular':
- paramOrderBy = ', search_rank DESC';
- break;
- case 'stock':
- paramOrderBy = ', stock_total DESC';
- break;
- }
-
- let limit = 30;
- let offset = (page - 1) * limit;
- let parameter = [
- `facet.query=${q}`,
- 'facet=true',
- 'indent=true',
- 'q.op=AND',
- `q=${q}`,
- 'facet.field=brand_str',
- 'facet.field=category_name_str',
- `start=${offset}`,
- `rows=${limit}`,
- `sort=product_rating DESC ${paramOrderBy}`,
- `fq=price_discount:[${price_from == '' ? '*' : price_from} TO ${price_to == '' ? '*' : price_to}]`
- ];
-
- if (brand) parameter.push(`fq=brand:${brand}`);
- if (category) parameter.push(`fq=category_name:${category}`);
-
- let result = await axios(process.env.SOLR_HOST + '/solr/products/select?' + parameter.join('&'));
- try {
- result.data.response.products = productResponseMap(result.data.response.docs);
- 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;
- res.status(200).json(result.data);
- } catch (error) {
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/shop/suggest.js b/src2/pages/api/shop/suggest.js
deleted file mode 100644
index 6db1a851..00000000
--- a/src2/pages/api/shop/suggest.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import axios from "axios";
-
-export default async function handler(req, res) {
- const { q } = req.query;
-
- let result = await axios(process.env.SOLR_HOST + `/solr/products/suggest?suggest=true&suggest.dictionary=mySuggester&suggest.q=${q}`);
- try {
- res.status(200).json(result.data);
- } catch (error) {
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/api/token.js b/src2/pages/api/token.js
deleted file mode 100644
index ec048158..00000000
--- a/src2/pages/api/token.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import axios from "axios";
-
-export default async function handler(req, res) {
- try {
- let result = await axios.get(process.env.ODOO_HOST + '/api/token');
- res.status(200).json(result.data.result);
- } catch (error) {
- res.status(400).json({ error: error.message });
- }
-} \ No newline at end of file
diff --git a/src2/pages/faqs.js b/src2/pages/faqs.js
deleted file mode 100644
index cdb8ef52..00000000
--- a/src2/pages/faqs.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
-import { useEffect, useState } from "react";
-
-const dataFaqs = [
- {
- id: 1,
- name: 'Akun',
- description: 'Bantuan tentang pengelolaan fitur dan akun'
- },
- {
- id: 2,
- name: 'Pembelian',
- description: 'Bantuan seputar status stock, layanan pengiriman & asuransi hingga seluruh indonesia'
- },
- {
- id: 3,
- name: 'Metode Pembayaran',
- description: 'Bantuan terkait layanan metode pembayaran'
- },
- {
- id: 4,
- name: 'Quotation',
- description: 'Bantuan fitur RFQ & quotation Express'
- },
- {
- id: 5,
- name: 'Faktur Pajak & Invoice',
- description: 'Bantuan seputar layanan terbit faktur pajak & invoice'
- },
- {
- id: 6,
- name: 'Pengembalian & Garansi',
- description: 'Bantuan cara pengembalian produk & garansi produk'
- }
-];
-
-export default function Faqs() {
- const [ faqs, setFaqs ] = useState([]);
-
- useEffect(() => {
- if (faqs.length == 0) {
- setFaqs(dataFaqs.map((dataFaq) => ({
- ...dataFaq,
- isOpen: false
- })));
- }
- }, [ faqs ]);
-
- const toggleFaq = (id) => {
- const faqsToUpdate = faqs.map(faq => {
- if (faq.id == id) faq.isOpen = !faq.isOpen;
- return faq;
- });
- setFaqs(faqsToUpdate);
- };
-
- return (
- <Layout>
- <AppBar title="FAQ's" />
-
- <div className="divide-y divide-gray_r-6">
- { faqs.map((faq, index) => (
- <div className="p-4" key={index}>
- <div className="flex gap-x-3 items-center">
- <div className="flex-1">
- <p className="font-medium mb-1">{ faq.name }</p>
- <p className="text-caption-1 text-gray_r-11">
- { faq.description }
- </p>
- </div>
- <button type="button" className="p-2 rounded bg-gray_r-4 h-fit" onClick={() => toggleFaq(faq.id)}>
- { faq.isOpen ? (
- <ChevronUpIcon className="w-5"/>
- ) : (
- <ChevronDownIcon className="w-5"/>
- ) }
- </button>
- </div>
- { faq.isOpen && (
- <p className="text-caption-1 text-gray_r-11 leading-7 mt-4">
- { faq?.content || 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.' }
- </p>
- ) }
- </div>
- )) }
- </div>
- </Layout>
- )
-} \ No newline at end of file
diff --git a/src2/pages/index.js b/src2/pages/index.js
deleted file mode 100644
index 65999ff6..00000000
--- a/src2/pages/index.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import { useEffect, useState } from "react";
-import { Pagination, Autoplay } from "swiper";
-import axios from "axios";
-import { Swiper, SwiperSlide } from "swiper/react";
-import "swiper/css";
-import "swiper/css/pagination";
-import "swiper/css/autoplay";
-
-// Helpers
-import apiOdoo from "@/core/utils/apiOdoo";
-
-// Components
-import Header from "@/components/layouts/Header";
-import ProductSlider from "@/components/products/ProductSlider";
-import Layout from "@/components/layouts/Layout";
-import ManufactureCard from "@/components/manufactures/ManufactureCard";
-import Footer from "@/components/layouts/Footer";
-import Image from "@/components/elements/Image";
-import ProductCategories from "@/components/products/ProductCategories";
-
-const swiperBanner = {
- pagination: { dynamicBullets: true },
- autoplay: {
- delay: 6000,
- disableOnInteraction: false
- },
- modules: [Pagination, Autoplay]
-}
-
-export async function getServerSideProps() {
- const heroBanners = await apiOdoo('GET', `/api/v1/banner?type=index-a-1`);
-
- return { props: { heroBanners } };
-}
-
-export default function Home({ heroBanners }) {
- const [manufactures, setManufactures] = useState(null);
- const [popularProducts, setPopularProducts] = useState(null);
-
- useEffect(() => {
- const getManufactures = async () => {
- const dataManufactures = await apiOdoo('GET', `/api/v1/manufacture?level=prioritas`);
- setManufactures(dataManufactures);
- }
- getManufactures();
-
- const getPopularProducts = async () => {
- const dataPopularProducts = await axios(`${process.env.SELF_HOST}/api/shop/search?q=*&page=1&order_by=popular`);
- setPopularProducts(dataPopularProducts.data.response);
- }
- getPopularProducts();
- }, []);
-
- return (
- <>
- <Header title='Home - Indoteknik' />
- <Layout>
- <Swiper
- slidesPerView={1}
- pagination={swiperBanner.pagination}
- modules={swiperBanner.modules}
- autoplay={swiperBanner.autoplay}
- >
- {
- heroBanners?.map((banner, index) => (
- <SwiperSlide key={index}>
- <Image
- src={banner.image}
- alt={banner.name}
- className="w-full h-auto"
- />
- </SwiperSlide>
- ))
- }
- </Swiper>
- <div className="mt-6 px-4">
- <h2 className="mb-3">Brand Pilihan</h2>
- <Swiper slidesPerView={4} freeMode={true} spaceBetween={16}>
- {
- manufactures?.manufactures?.map((manufacture, index) => (
- <SwiperSlide key={index}>
- <ManufactureCard data={manufacture} key={index} />
- </SwiperSlide>
- ))
- }
- </Swiper>
- </div>
- <div className="my-6 p-4 py-0">
- <h2 className="mb-4">Produk Populer</h2>
- <ProductSlider products={popularProducts} simpleProductTitleLine />
- </div>
-
- <ProductCategories />
-
- <div className="px-4">
- <h5 className="h2 mb-2">Platform Belanja B2B Alat Teknik & Industri di Indonesia</h5>
- <p className="text-gray_r-11 leading-6 text-caption-2 mb-4">
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
- </p>
- </div>
-
- <Footer />
- </Layout>
- </>
- )
-}
diff --git a/src2/pages/login.js b/src2/pages/login.js
deleted file mode 100644
index e80de44e..00000000
--- a/src2/pages/login.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import axios from "axios";
-import Head from "next/head";
-import Image from "next/image";
-import Link from "@/components/elements/Link";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-import Alert from "@/components/elements/Alert";
-import Layout from "@/components/layouts/Layout";
-import Spinner from "@/components/elements/Spinner";
-import { setAuth } from "@/core/utils/auth";
-import Logo from "@/images/logo.png";
-
-export default function Login() {
- const router = useRouter();
- const [email, setEmail] = useState('');
- const [password, setPassword] = useState('');
- const [isInputFulfilled, setIsInputFulfilled] = useState(false);
- const [isLoading, setIsLoading] = useState(false);
- const [alert, setAlert] = useState();
-
- useEffect(() => {
- setIsInputFulfilled(email && password);
- }, [email, password]);
-
- const login = async (e) => {
- e.preventDefault();
- setIsLoading(true);
- let login = await axios.post(`${process.env.SELF_HOST}/api/login`, {email, password});
- if (login.data.is_auth) {
- setAuth(login.data.user);
- router.push('/');
- } else {
- switch (login.data.reason) {
- case 'NOT_FOUND':
- setAlert({
- component: <>Email atau password tidak cocok</>,
- type: 'info'
- });
- break;
- case 'NOT_ACTIVE':
- setAlert({
- component: <>Email belum diaktivasi, <Link className="text-gray-900" href={`/activate?email=${email}`}>aktivasi sekarang</Link></>,
- type: 'info'
- });
- break;
- }
- setIsLoading(false);
- }
- }
-
- return (
- <>
- <Head>
- <title>Masuk - Indoteknik</title>
- </Head>
- <Layout className="max-w-lg mx-auto flex flex-col items-center px-4 pb-8">
- <Link href="/" className="mt-16">
- <Image src={Logo} alt="Logo Indoteknik" width={165} height={42} />
- </Link>
- <h1 className="text-2xl mt-4 text-center">Mulai Belanja Sekarang</h1>
- <h2 className="text-gray_r-11 font-normal mt-2 mb-4">Masuk ke akun kamu untuk belanja</h2>
- {alert ? (
- <Alert className="text-center" type={alert.type}>{alert.component}</Alert>
- ) : ''}
- <form onSubmit={login} className="w-full">
- <label className="form-label mt-4 mb-2">Alamat Email</label>
- <input
- type="email"
- className="form-input bg-gray_r-2"
- placeholder="johndoe@gmail.com"
- value={email}
- onChange={(e) => setEmail(e.target.value)}
- />
- <label className="form-label mt-4 mb-2">Kata Sandi</label>
- <input
- type="password"
- className="form-input bg-gray_r-2"
- placeholder="••••••••"
- value={password}
- onChange={(e) => setPassword(e.target.value)}
- />
- <div className="flex justify-end mt-4 w-full">
- <Link href="/forgot-password">Lupa kata sandi</Link>
- </div>
- <button type="submit" disabled={!isInputFulfilled} className="btn-yellow font-semibold mt-4 w-full">
- {isLoading ? (
- <div className="flex justify-center items-center gap-x-2">
- <Spinner className="w-4 h-4 text-gray-600 fill-gray-900" /> <span>Loading...</span>
- </div>
- ) : 'Masuk'}
- </button>
- </form>
- <p className="text-gray-700 mt-4">Belum punya akun Indoteknik? <Link href="/register">Daftar</Link></p>
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/pages/logout.js b/src2/pages/logout.js
deleted file mode 100644
index 8ea21fab..00000000
--- a/src2/pages/logout.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { useRouter } from "next/router";
-import { useEffect } from "react";
-import { deleteAuth } from "@/core/utils/auth";
-
-export default function Logout() {
- const router = useRouter();
-
- useEffect(() => {
- deleteAuth();
- router.replace('/login');
- }, [router]);
-
- return null;
-} \ No newline at end of file
diff --git a/src2/pages/my/address/[id]/edit.js b/src2/pages/my/address/[id]/edit.js
deleted file mode 100644
index 838d39e7..00000000
--- a/src2/pages/my/address/[id]/edit.js
+++ /dev/null
@@ -1,249 +0,0 @@
-import { Controller, useForm } from "react-hook-form"
-import WithAuth from "@/components/auth/WithAuth";
-import Layout from "@/components/layouts/Layout";
-import AppBar from "@/components/layouts/AppBar";
-import { yupResolver } from "@hookform/resolvers/yup";
-import * as Yup from "yup";
-import { Select } from "@/components/elements/Fields";
-import { useEffect, useState } from "react";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { toast } from "react-hot-toast";
-import { useRouter } from "next/router";
-
-const validationSchema = Yup.object().shape({
- type: Yup.string().required('Harus di-pilih'),
- name: Yup.string().min(3, 'Minimal 3 karakter').required('Harus di-isi'),
- email: Yup.string().email('Format harus seperti johndoe@example.com').required('Harus di-isi'),
- mobile: Yup.string().required('Harus di-isi'),
- street: Yup.string().required('Harus di-isi'),
- zip: Yup.string().required('Harus di-isi'),
- city: Yup.string().required('Harus di-pilih'),
-});
-
-const types = [
- { value: 'contact', label: 'Contact Address' },
- { value: 'invoice', label: 'Invoice Address' },
- { value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' },
-];
-
-export async function getServerSideProps( context ) {
- const { id } = context.query;
- const address = await apiOdoo('GET', `/api/v1/partner/${id}/address`);
- let defaultValues = {
- type: address.type,
- name: address.name,
- email: address.email,
- mobile: address.mobile,
- street: address.street,
- zip: address.zip,
- city: address.city?.id || '',
- oldDistrict: address.district?.id || '',
- district: '',
- oldSubDistrict: address.sub_district?.id || '',
- subDistrict: '',
- };
- return { props: { id, defaultValues } };
-}
-
-export default function EditAddress({ id, defaultValues }) {
- const router = useRouter();
- const {
- register,
- formState: { errors },
- handleSubmit,
- watch,
- setValue,
- getValues,
- control,
- } = useForm({
- resolver: yupResolver(validationSchema),
- defaultValues
- });
-
- const [ cities, setCities ] = useState([]);
- const [ districts, setDistricts ] = useState([]);
- const [ subDistricts, setSubDistricts ] = useState([]);
-
- useEffect(() => {
- const loadCities = async () => {
- let dataCities = await apiOdoo('GET', '/api/v1/city');
- dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }));
- setCities(dataCities);
- };
- loadCities();
- }, []);
-
- const watchCity = watch('city');
- useEffect(() => {
- setValue('district', '');
- if (watchCity) {
- const loadDistricts = async () => {
- let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`);
- dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name }));
- setDistricts(dataDistricts);
- let oldDistrict = getValues('oldDistrict');
- if (oldDistrict) {
- setValue('district', oldDistrict);
- setValue('oldDistrict', '');
- }
- };
- loadDistricts();
- }
- }, [ watchCity, setValue, getValues ]);
-
- const watchDistrict = watch('district');
- useEffect(() => {
- setValue('subDistrict', '');
- if (watchDistrict) {
- const loadSubDistricts = async () => {
- let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${watchDistrict}`);
- dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name }));
- setSubDistricts(dataSubDistricts);
- let oldSubDistrict = getValues('oldSubDistrict');
- if (oldSubDistrict) {
- setValue('subDistrict', oldSubDistrict);
- setValue('oldSubDistrict', '');
- }
- };
- loadSubDistricts();
- }
- }, [ watchDistrict, setValue, getValues ])
-
- const onSubmitHandler = async (values) => {
- const parameters = {
- ...values,
- city_id: values.city,
- district_id: values.district,
- sub_district_id: values.subDistrict
- }
-
- const address = await apiOdoo('PUT', `/api/v1/partner/${id}/address`, parameters);
- if (address?.id) {
- toast.success('Berhasil mengubah alamat');
- router.back();
- }
- };
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Ubah Alamat" />
-
- <form className="p-4 flex flex-col gap-y-4" onSubmit={handleSubmit(onSubmitHandler)}>
- <div>
- <label className="form-label mb-2">Label Alamat</label>
- <Controller
- name="type"
- control={control}
- render={props => <Select {...props} isSearchable={false} options={types} />}
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.type?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Nama</label>
- <input
- {...register('name')}
- placeholder="John Doe"
- type="text"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.name?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Email</label>
- <input
- {...register('email')}
- placeholder="johndoe@example.com"
- type="email"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.email?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Mobile</label>
- <input
- {...register('mobile')}
- placeholder="08xxxxxxxx"
- type="tel"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.mobile?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Alamat</label>
- <input
- {...register('street')}
- placeholder="Jl. Bandengan Utara 85A"
- type="text"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.street?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kode Pos</label>
- <input
- {...register('zip')}
- placeholder="10100"
- type="number"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.zip?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kota</label>
- <Controller
- name="city"
- control={control}
- render={props => <Select {...props} options={cities} />}
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kecamatan</label>
- <Controller
- name="district"
- control={control}
- render={props => (
- <Select
- {...props}
- options={districts}
- disabled={!watchCity}
- />
- )}
- />
- </div>
-
- <div>
- <label className="form-label mb-2">Kelurahan</label>
- <Controller
- name="subDistrict"
- control={control}
- render={props => (
- <Select
- {...props}
- options={subDistricts}
- disabled={!watchDistrict}
- />
- )}
- />
- </div>
-
- <button
- type="submit"
- className="btn-yellow mt-2 w-full"
- >
- Simpan
- </button>
- </form>
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/my/address/create.js b/src2/pages/my/address/create.js
deleted file mode 100644
index 42cd117c..00000000
--- a/src2/pages/my/address/create.js
+++ /dev/null
@@ -1,234 +0,0 @@
-import { Controller, useForm } from "react-hook-form"
-import WithAuth from "@/components/auth/WithAuth";
-import Layout from "@/components/layouts/Layout";
-import AppBar from "@/components/layouts/AppBar";
-import { yupResolver } from "@hookform/resolvers/yup";
-import * as Yup from "yup";
-import { Select } from "@/components/elements/Fields";
-import { useEffect, useState } from "react";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useAuth } from "@/core/utils/auth";
-import { toast } from "react-hot-toast";
-import { useRouter } from "next/router";
-
-const validationSchema = Yup.object().shape({
- type: Yup.string().required('Harus di-pilih'),
- name: Yup.string().min(3, 'Minimal 3 karakter').required('Harus di-isi'),
- email: Yup.string().email('Format harus seperti johndoe@example.com').required('Harus di-isi'),
- mobile: Yup.string().required('Harus di-isi'),
- street: Yup.string().required('Harus di-isi'),
- zip: Yup.string().required('Harus di-isi'),
- city: Yup.string().required('Harus di-pilih'),
-});
-
-const defaultValues = {
- type: '',
- name: '',
- email: '',
- mobile: '',
- street: '',
- city: '',
- district: '',
- subDistrict: '',
- zip: '',
-};
-
-const types = [
- { value: 'contact', label: 'Contact Address' },
- { value: 'invoice', label: 'Invoice Address' },
- { value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' },
-];
-
-export default function CreateAddress() {
- const [ auth ] = useAuth();
- const router = useRouter();
- const {
- register,
- formState: { errors },
- handleSubmit,
- watch,
- setValue,
- control,
- } = useForm({
- resolver: yupResolver(validationSchema),
- defaultValues
- });
-
- const [ cities, setCities ] = useState([]);
- const [ districts, setDistricts ] = useState([]);
- const [ subDistricts, setSubDistricts ] = useState([]);
-
- useEffect(() => {
- const loadCities = async () => {
- let dataCities = await apiOdoo('GET', '/api/v1/city');
- dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }));
- setCities(dataCities);
- };
- loadCities();
- }, []);
-
- const watchCity = watch('city');
- useEffect(() => {
- setValue('district', '');
- if (watchCity) {
- const loadDistricts = async () => {
- let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`);
- dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name }));
- setDistricts(dataDistricts);
- };
- loadDistricts();
- }
- }, [ watchCity, setValue ]);
-
- const watchDistrict = watch('district');
- useEffect(() => {
- setValue('subDistrict', '');
- if (watchDistrict) {
- const loadSubDistricts = async () => {
- let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${watchDistrict}`);
- dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name }));
- setSubDistricts(dataSubDistricts);
- };
- loadSubDistricts();
- }
- }, [ watchDistrict, setValue ])
-
- const onSubmitHandler = async (values) => {
- const parameters = {
- ...values,
- city_id: values.city,
- district_id: values.district,
- sub_district_id: values.subDistrict,
- parent_id: auth.partner_id
- };
-
- const address = await apiOdoo('POST', '/api/v1/partner/address', parameters);
- if (address?.id) {
- toast.success('Berhasil menambahkan alamat');
- router.back();
- }
- };
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Tambah Alamat" />
-
- <form className="p-4 flex flex-col gap-y-4" onSubmit={handleSubmit(onSubmitHandler)}>
- <div>
- <label className="form-label mb-2">Label Alamat</label>
- <Controller
- name="type"
- control={control}
- render={props => <Select {...props} isSearchable={false} options={types} />}
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.type?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Nama</label>
- <input
- {...register('name')}
- placeholder="John Doe"
- type="text"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.name?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Email</label>
- <input
- {...register('email')}
- placeholder="johndoe@example.com"
- type="email"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.email?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Mobile</label>
- <input
- {...register('mobile')}
- placeholder="08xxxxxxxx"
- type="tel"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.mobile?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Alamat</label>
- <input
- {...register('street')}
- placeholder="Jl. Bandengan Utara 85A"
- type="text"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.street?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kode Pos</label>
- <input
- {...register('zip')}
- placeholder="10100"
- type="number"
- className="form-input"
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.zip?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kota</label>
- <Controller
- name="city"
- control={control}
- render={props => <Select {...props} options={cities} />}
- />
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city?.message }</div>
- </div>
-
- <div>
- <label className="form-label mb-2">Kecamatan</label>
- <Controller
- name="district"
- control={control}
- render={props => (
- <Select
- {...props}
- options={districts}
- disabled={!watchCity}
- />
- )}
- />
- </div>
-
- <div>
- <label className="form-label mb-2">Kelurahan</label>
- <Controller
- name="subDistrict"
- control={control}
- render={props => (
- <Select
- {...props}
- options={subDistricts}
- disabled={!watchDistrict}
- />
- )}
- />
- </div>
-
- <button
- type="submit"
- className="btn-yellow mt-2 w-full"
- >
- Simpan
- </button>
- </form>
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/my/address/index.js b/src2/pages/my/address/index.js
deleted file mode 100644
index 5cad4410..00000000
--- a/src2/pages/my/address/index.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import { useEffect, useState } from "react";
-import { useRouter } from "next/router";
-
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import Link from "@/components/elements/Link";
-import WithAuth from "@/components/auth/WithAuth";
-
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useAuth } from "@/core/utils/auth";
-import { createOrUpdateItemAddress, getItemAddress } from "@/core/utils/address";
-import { toast } from "react-hot-toast";
-
-export default function Address() {
- const router = useRouter();
- const { select } = router.query;
- const [ auth ] = useAuth();
- const [ addresses, setAddresses ] = useState(null);
- const [ selectedAdress, setSelectedAdress ] = useState(null);
-
- useEffect(() => {
- const getAddress = async () => {
- if (auth) {
- const dataAddress = await apiOdoo('GET', `/api/v1/user/${auth.id}/address`);
- setAddresses(dataAddress);
- }
- };
- getAddress();
- }, [auth]);
-
- useEffect(() => {
- if (select) {
- setSelectedAdress(getItemAddress(select));
- }
- }, [select]);
-
- const changeSelectedAddress = (id) => {
- if (select) {
- createOrUpdateItemAddress(select, id);
- router.back();
- }
- };
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Daftar Alamat" />
-
- <div className="text-right mt-4 px-4">
- <Link href="/my/address/create">Tambah Alamat</Link>
- </div>
-
- <div className="grid gap-y-4 p-4">
- { auth && addresses && addresses.map((address, index) => {
- let type = address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address';
- return (
- <div
- key={index}
- className={"p-4 rounded-md border " + (selectedAdress && selectedAdress == address.id ? "bg-gray_r-4" : "border-gray_r-7") }
- >
- <div onClick={() => changeSelectedAddress(address.id)}>
- <div className="flex gap-x-2" >
- <div className="badge-red">{ type }</div>
- { auth?.partner_id == address.id && (
- <div className="badge-green">Utama</div>
- ) }
- </div>
- <p className="font-medium mt-2">{ address.name }</p>
- { address.mobile && (
- <p className="mt-2 text-gray_r-11">{ address.mobile }</p>
- ) }
- <p className={`mt-1 leading-6 ${selectedAdress && selectedAdress == address.id ? "text-gray_r-12" : "text-gray_r-11"}`}>
- { address.street }
- </p>
- </div>
- <Link href={`/my/address/${address.id}/edit`} className="btn-light bg-white mt-3 w-full text-gray_r-11">Ubah Alamat</Link>
- </div>
- );
- }) }
- </div>
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/my/invoice/[id].js b/src2/pages/my/invoice/[id].js
deleted file mode 100644
index 820c9af8..00000000
--- a/src2/pages/my/invoice/[id].js
+++ /dev/null
@@ -1,149 +0,0 @@
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import LineDivider from "@/components/elements/LineDivider";
-import WithAuth from "@/components/auth/WithAuth";
-import { useEffect, useState } from "react";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useRouter } from "next/router";
-import { useAuth } from "@/core/utils/auth";
-import VariantCard from "@/components/variants/VariantCard";
-import currencyFormat from "@/core/utils/currencyFormat";
-import Disclosure from "@/components/elements/Disclosure";
-import DescriptionRow from "@/components/elements/DescriptionRow";
-import { SkeletonList } from "@/components/elements/Skeleton";
-import VariantGroupCard from "@/components/variants/VariantGroupCard";
-
-export default function DetailInvoice() {
- const router = useRouter();
- const { id } = router.query;
- const [ auth ] = useAuth();
- const [ invoice, setInvoice ] = useState(null);
-
- useEffect(() => {
- if (auth && id) {
- const loadInvoice = async () => {
- const dataInvoice = await apiOdoo('GET', `/api/v1/partner/${auth?.partner_id}/invoice/${id}`);
- setInvoice(dataInvoice);
- }
- loadInvoice();
- }
- }, [ auth, id ]);
-
- const Customer = () => {
- const customer = invoice?.customer;
- const fullAddress = [];
- if (customer?.street) fullAddress.push(customer.street);
- if (customer?.sub_district?.name) fullAddress.push(customer.sub_district.name);
- if (customer?.district?.name) fullAddress.push(customer.district.name);
- if (customer?.city?.name) fullAddress.push(customer.city.name);
-
- return (
- <div className="p-4 pt-0 flex flex-col gap-y-4">
- <DescriptionRow label="Nama">{ invoice?.customer?.name }</DescriptionRow>
- <DescriptionRow label="Email">{ invoice?.customer?.email || '-' }</DescriptionRow>
- <DescriptionRow label="No Telepon">{ invoice?.customer?.mobile || '-' }</DescriptionRow>
- <DescriptionRow label="Alamat">{ fullAddress.join(', ') }</DescriptionRow>
- </div>
- );
- };
-
- const downloadTaxInvoice = () => {
- window.open(`${process.env.ODOO_HOST}/api/v1/download/tax-invoice/${invoice.id}/${invoice.token}`, 'Download')
- }
-
- const downloadInvoice = () => {
- window.open(`${process.env.ODOO_HOST}/api/v1/download/invoice/${invoice.id}/${invoice.token}`, 'Download')
- }
-
- return (
- <WithAuth>
- <Layout className="pb-4">
- <AppBar title="Detail Invoice" />
-
- { invoice ? (
- <>
- <div className="p-4 flex flex-col gap-y-4">
- <DescriptionRow label="No Invoice">
- { invoice?.name }
- </DescriptionRow>
- <DescriptionRow label="Status Transaksi">
- { invoice?.amount_residual > 0 ? (
- <span className="badge-solid-red">Belum Lunas</span>
- ) : (
- <span className="badge-solid-green">Lunas</span>
- ) }
- </DescriptionRow>
- <DescriptionRow label="Purchase Order">
- { invoice?.purchase_order_name || '-' }
- </DescriptionRow>
- <DescriptionRow label="Ketentuan Pembayaran">
- { invoice?.payment_term }
- </DescriptionRow>
- { invoice?.amount_residual > 0 && invoice.invoice_date != invoice.invoice_date_due && (
- <DescriptionRow label="Tanggal Jatuh Tempo">
- { invoice?.invoice_date_due }
- </DescriptionRow>
- ) }
- <DescriptionRow label="Nama Sales">
- { invoice?.sales }
- </DescriptionRow>
- <DescriptionRow label="Tanggal Invoice">
- { invoice?.invoice_date }
- </DescriptionRow>
- <div className="flex items-center">
- <p className="text-gray_r-11 leading-none">Faktur Pembelian</p>
- <button
- type="button"
- className="btn-light py-1.5 px-3 ml-auto"
- onClick={downloadInvoice}
- >
- Download
- </button>
- </div>
- <div className="flex items-center">
- <p className="text-gray_r-11 leading-none">Faktur Pajak</p>
- <button
- type="button"
- className="btn-light py-1.5 px-3 ml-auto"
- onClick={downloadTaxInvoice}
- disabled={!invoice.efaktur}
- >
- Download
- </button>
- </div>
- </div>
-
- <LineDivider />
-
- <Disclosure
- label="Detail Penagihan"
- />
-
- <Customer />
-
- <LineDivider />
-
- <Disclosure
- label="Detail Produk"
- />
-
- <div className="mt-2 p-4 pt-0 flex flex-col gap-y-3">
- <VariantGroupCard
- variants={invoice?.products}
- buyMore
- />
- <div className="flex justify-between mt-3 font-medium">
- <p className="text-gray_r-11">Total Belanja</p>
- <p>{ currencyFormat(invoice?.amount_total || 0) }</p>
- </div>
- </div>
- </>
- ) : (
- <div className="p-4 py-6">
- <SkeletonList number={12} />
- </div>
- ) }
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/my/invoices.js b/src2/pages/my/invoices.js
deleted file mode 100644
index 9b2e77dc..00000000
--- a/src2/pages/my/invoices.js
+++ /dev/null
@@ -1,180 +0,0 @@
-import WithAuth from "@/components/auth/WithAuth"
-import Alert from "@/components/elements/Alert"
-import Link from "@/components/elements/Link"
-import Pagination from "@/components/elements/Pagination"
-import AppBar from "@/components/layouts/AppBar"
-import Layout from "@/components/layouts/Layout"
-import apiOdoo from "@/core/utils/apiOdoo"
-import { useAuth } from "@/core/utils/auth"
-import currencyFormat from "@/core/utils/currencyFormat"
-import useBottomPopup from "@/lib/elements/hooks/useBottomPopup"
-import { CheckIcon, ClockIcon, EllipsisVerticalIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"
-import { useRouter } from "next/router"
-import { useEffect, useRef, useState } from "react"
-
-export default function Invoices() {
- const [ auth ] = useAuth()
- const router = useRouter()
- const {
- q,
- page = 1
- } = router.query
-
- const [ invoices, setInvoices ] = useState([])
-
- const [ pageCount, setPageCount ] = useState(0)
- const [ isLoading, setIsLoading ] = useState(true)
-
- const searchQueryRef = useRef()
-
- useEffect(() => {
- const loadInvoices = async () => {
- if (auth) {
- const limit = 10
- let offset = (page - 1) * 10
- let queryParams = [`limit=${limit}`, `offset=${offset}`]
- if (q) queryParams.push(`name=${q}`)
- queryParams = queryParams.join('&')
- queryParams = queryParams ? '?' + queryParams : ''
-
- const dataInvoices = await apiOdoo('GET', `/api/v1/partner/${auth.partner_id}/invoice${queryParams}`)
- setInvoices(dataInvoices)
- setPageCount(Math.ceil(dataInvoices.sale_order_total / limit))
- setIsLoading(false)
- }
- }
- loadInvoices()
- }, [ auth, q, page ])
-
- const actionSearch = (e) => {
- e.preventDefault()
- let queryParams = []
- if (searchQueryRef.current.value) queryParams.push(`q=${searchQueryRef.current.value}`)
- queryParams = queryParams.join('&')
- queryParams = queryParams ? `?${queryParams}` : ''
- router.push(`/my/invoices${queryParams}`)
- }
-
- const downloadInvoice = (data) => {
- const url = `${process.env.ODOO_HOST}/api/v1/download/invoice/${data.id}/${data.token}`
- window.open(url, 'download')
- closePopup()
- }
-
- const downloadTaxInvoice = (data) => {
- const url = `${process.env.ODOO_HOST}/api/v1/download/tax-invoice/${data.id}/${data.token}`
- window.open(url, 'download')
- closePopup()
- }
-
- const childrenPopup = (data) => (
- <div className="flex flex-col gap-y-6">
- <button
- className="text-left disabled:opacity-60"
- onClick={() => downloadInvoice(data)}
- >
- Download Faktur Pembelian
- </button>
- <button
- className="text-left disabled:opacity-60"
- disabled={!data?.efaktur}
- onClick={() => downloadTaxInvoice(data)}
- >
- Download Faktur Pajak
- </button>
- </div>
- )
-
- const {
- closePopup,
- openPopup,
- BottomPopup
- } = useBottomPopup({
- title: 'Lainnya',
- children: childrenPopup
- })
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Invoice" />
-
- <form onSubmit={actionSearch} className="p-4 pb-0 flex gap-x-4">
- <input
- type="text"
- className="form-input"
- placeholder="Cari Transaksi"
- ref={searchQueryRef}
- defaultValue={q}
- />
- <button type="submit" className="border border-gray_r-7 rounded px-3">
- <MagnifyingGlassIcon className="w-5"/>
- </button>
- </form>
-
- <div className="p-4 flex flex-col gap-y-5">
- { invoices?.invoice_total === 0 && !isLoading && (
- <Alert type="info" className="text-center">
- Invoice tidak ditemukan
- </Alert>
- ) }
- { invoices?.invoices?.map((invoice, index) => (
- <div className="p-4 shadow border border-gray_r-3 rounded-md" key={index}>
- <div className="grid grid-cols-2">
- <Link href={`/my/invoice/${invoice.id}`}>
- <span className="text-caption-2 text-gray_r-11">No. Invoice</span>
- <h2 className="text-red_r-11 mt-1">{ invoice.name }</h2>
- </Link>
- <div className="flex gap-x-1 justify-end">
- { invoice.amount_residual > 0 ? (
- <div className="badge-solid-red h-fit ml-auto">Belum Lunas</div>
- ) : (
- <div className="badge-solid-green h-fit ml-auto">Lunas</div>
- ) }
- <EllipsisVerticalIcon className="w-5 h-5" onClick={() => openPopup(invoice)} />
- </div>
- </div>
- <Link href={`/my/invoice/${invoice.id}`}>
- <div className="grid grid-cols-2 text-caption-2 text-gray_r-11 mt-2 font-normal">
- <p>
- { invoice.invoice_date }
- </p>
- <p className="text-right">
- { invoice.payment_term }
- </p>
- </div>
- <hr className="my-3"/>
- <div className="grid grid-cols-2">
- <div>
- <span className="text-caption-2 text-gray_r-11">No. Purchase Order</span>
- <p className="mt-1 font-medium text-gray_r-12">{ invoice.purchase_order_name || '-' }</p>
- </div>
- <div className="text-right">
- <span className="text-caption-2 text-gray_r-11">Total Invoice</span>
- <p className="mt-1 font-medium text-gray_r-12">{ currencyFormat(invoice.amount_total) }</p>
- </div>
- </div>
- </Link>
- { invoice.efaktur ? (
- <div className="badge-green h-fit mt-3 ml-auto flex items-center gap-x-0.5">
- <CheckIcon className="w-4 stroke-2" />
- Faktur Pajak
- </div>
- ) : (
- <div className="badge-red h-fit mt-3 ml-auto flex items-center gap-x-0.5">
- <ClockIcon className="w-4 stroke-2" />
- Faktur Pajak
- </div>
- ) }
- </div>
- )) }
- </div>
-
- <div className="pb-6 pt-2">
- <Pagination currentPage={page} pageCount={pageCount} url={`/my/invoices${q ? `?q=${q}` : ''}`} />
- </div>
- { BottomPopup }
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/my/menu.js b/src2/pages/my/menu.js
deleted file mode 100644
index ae6c2af8..00000000
--- a/src2/pages/my/menu.js
+++ /dev/null
@@ -1,82 +0,0 @@
-
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import Link from "@/components/elements/Link";
-import { useAuth } from "@/core/utils/auth";
-import {
- ArrowRightOnRectangleIcon,
- ChatBubbleLeftRightIcon,
- ChevronRightIcon,
- MapIcon,
- PaperClipIcon,
- PencilSquareIcon,
- QuestionMarkCircleIcon,
- ReceiptPercentIcon,
- UserIcon,
- HeartIcon
-} from "@heroicons/react/24/outline";
-import WithAuth from "@/components/auth/WithAuth";
-
-const Menu = ({ icon, name, url }) => {
- return (
- <Link href={url} className="text-gray_r-11 font-normal flex gap-x-2 items-center py-4 border-b border-gray_r-6">
- <span className="flex gap-x-2">
- { icon }
- { name }
- </span>
- <ChevronRightIcon className="w-5 ml-auto"/>
- </Link>
- );
-};
-
-export default function MyMenu() {
- const [auth] = useAuth();
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Menu Utama" />
-
- <div className="p-4 flex gap-x-2 items-center">
- <div className="flex-1 flex gap-x-3 items-center">
- <div className="p-2 bg-gray_r-4 rounded-full h-fit">
- <UserIcon className="w-6" />
- </div>
- <div>
- <h2>{ auth?.name }</h2>
- { auth?.company ? (
- <div className="badge-red font-normal text-xs">Akun Bisnis</div>
- ) : (
- <div className="badge-gray font-normal text-xs">Akun Individu</div>
- ) }
- </div>
- </div>
- <Link href="/my/profile">
- <PencilSquareIcon className="w-6 text-yellow_r-12"/>
- </Link>
- </div>
-
- <div className="px-4 mt-4">
- <p className="font-medium mb-2">Aktivitas Pembelian</p>
- <div className="flex flex-col mb-6">
- <Menu icon={<ReceiptPercentIcon className="w-5" />} name="Daftar Transaksi" url="/my/transactions" />
- <Menu icon={<PaperClipIcon className="w-5" />} name="Invoice & Faktur Pajak" url="/my/invoices" />
- <Menu icon={<HeartIcon className="w-5" />} name="Wishlist" url="/my/wishlist" />
- </div>
-
- <p className="font-medium mb-2">Pusat Bantuan</p>
- <div className="flex flex-col mb-6">
- <Menu icon={<ChatBubbleLeftRightIcon className="w-5"/>} name="Layanan Pelanggan" url="/" />
- <Menu icon={<QuestionMarkCircleIcon className="w-5"/>} name="F.A.Q" url="/faqs" />
- </div>
-
- <p className="font-medium mb-2">Pengaturan Akun</p>
- <div className="flex flex-col mb-6">
- <Menu icon={<MapIcon className="w-5" />} name="Daftar Alamat" url="/my/address" />
- <Menu icon={<ArrowRightOnRectangleIcon className="w-5" />} name="Keluar Akun" url="/logout" />
- </div>
- </div>
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/my/profile.js b/src2/pages/my/profile.js
deleted file mode 100644
index 97891259..00000000
--- a/src2/pages/my/profile.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import { useState } from "react";
-import { toast } from "react-hot-toast";
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import WithAuth from "@/components/auth/WithAuth";
-import apiOdoo from "@/core/utils/apiOdoo";
-import {
- useAuth,
- setAuth as setAuthCookie,
- getAuth
-} from "@/core/utils/auth";
-
-export default function MyProfile() {
- const [auth, setAuth] = useAuth();
- const [editMode, setEditMode] = useState(false);
- const [password, setPassword] = useState('');
-
- const update = async (e) => {
- e.preventDefault();
- let dataToUpdate = {
- name: auth.name,
- phone: auth.phone,
- mobile: auth.mobile
- };
- if (password) dataToUpdate.password = password;
- let update = await apiOdoo('PUT', `/api/v1/user/${auth.id}`, dataToUpdate);
- setAuthCookie(update.user);
- cancelEdit();
- toast.success('Berhasil mengubah profil', { duration: 1500 });
- };
-
- const handleInput = (e) => {
- let authToUpdate = auth;
- authToUpdate[e.target.name] = e.target.value;
- setAuth({ ...authToUpdate });
- };
-
- const cancelEdit = () => {
- setEditMode(false);
- setAuth(getAuth());
- setPassword('');
- }
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Akun Saya" />
-
- <form onSubmit={update} className="w-full px-4">
- { auth && (
- <>
- <label className="form-label mt-4 mb-2">Email</label>
- <input
- type="text"
- className="form-input"
- placeholder="johndoe@gmail.com"
- name="email"
- value={auth.email}
- onChange={handleInput}
- disabled={true}
- />
-
- <label className="form-label mt-4 mb-2">Nama Lengkap</label>
- <input
- type="text"
- className="form-input"
- placeholder="John Doe"
- name="name"
- value={auth.name}
- onChange={handleInput}
- disabled={!editMode}
- />
-
- <label className="form-label mt-4 mb-2">No Telepon</label>
- <input
- type="tel"
- className="form-input"
- placeholder="08xxxxxxxx"
- name="phone"
- value={auth.phone}
- onChange={handleInput}
- disabled={!editMode}
- />
-
- <label className="form-label mt-4 mb-2">No Handphone</label>
- <input
- type="tel"
- className="form-input"
- placeholder="08xxxxxxxx"
- name="mobile"
- value={auth.mobile}
- onChange={handleInput}
- disabled={!editMode}
- />
-
- <label className="form-label mt-4 mb-2">Kata Sandi</label>
- <input
- type="password"
- className="form-input"
- placeholder="••••••••"
- value={password}
- onChange={(e) => setPassword(e.target.value)}
- disabled={!editMode}
- />
- </>
- ) }
-
- { editMode && (
- <div className="flex gap-x-3 mt-6">
- <button
- type="button"
- className="btn-light flex-1 float-right"
- onClick={cancelEdit}
- >
- Batal
- </button>
- <button type="submit" className="btn-yellow flex-1 float-right">Simpan</button>
- </div>
- ) }
-
- { !editMode && (
- <button
- type="button"
- className="btn-light float-right mt-6 w-full"
- onClick={() => setEditMode(true)}
- >
- Ubah Profil
- </button>
- ) }
- </form>
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/my/transaction/[id].js b/src2/pages/my/transaction/[id].js
deleted file mode 100644
index fb806aa4..00000000
--- a/src2/pages/my/transaction/[id].js
+++ /dev/null
@@ -1,265 +0,0 @@
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import LineDivider from "@/components/elements/LineDivider";
-import WithAuth from "@/components/auth/WithAuth";
-import { useCallback, useEffect, useRef, useState } from "react";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useRouter } from "next/router";
-import { useAuth } from "@/core/utils/auth";
-import currencyFormat from "@/core/utils/currencyFormat";
-import DescriptionRow from "@/components/elements/DescriptionRow";
-import { TransactionDetailAddress } from "@/components/transactions/TransactionDetail";
-import { SkeletonList } from "@/components/elements/Skeleton";
-import Link from "@/components/elements/Link";
-import { ChevronRightIcon } from "@heroicons/react/24/outline";
-import Alert from "@/components/elements/Alert";
-import TransactionStatusBadge from "@/components/transactions/TransactionStatusBadge";
-import useConfirmAlert from "@/lib/elements/hooks/useConfirmAlert";
-import { toast } from "react-hot-toast";
-import useBottomPopup from "@/lib/elements/hooks/useBottomPopup";
-import getFileBase64 from "@/core/utils/getFileBase64";
-import VariantGroupCard from "@/components/variants/VariantGroupCard";
-
-export default function DetailTransaction() {
- const router = useRouter();
- const { id } = router.query;
- const [ auth ] = useAuth();
- const [ transaction, setTransaction ] = useState(null);
-
- const loadTransaction = useCallback(async () => {
- if (auth && id) {
- const dataTransaction = await apiOdoo('GET', `/api/v1/partner/${auth?.partner_id}/sale_order/${id}`);
- setTransaction(dataTransaction);
- }
- }, [ auth, id ]);
-
- useEffect(() => {
- loadTransaction();
- }, [ loadTransaction ]);
-
- const submitCancelTransaction = async (data) => {
- const isCancelled = await apiOdoo('POST', `/api/v1/partner/${auth.partner_id}/sale_order/${data.id}/cancel`);
- if (isCancelled) {
- toast.success('Berhasil batalkan transaksi');
- loadTransaction();
- }
- }
-
- const {
- openConfirmAlert,
- ConfirmAlert
- } = useConfirmAlert({
- title: 'Batalkan Transaksi',
- caption: 'Apakah anda yakin untuk membatalkan transaksi?',
- closeText: 'Tidak',
- submitText: 'Iya, batalkan',
- onSubmit: submitCancelTransaction
- });
-
- const UploadPurchaseOrder = () => {
- const nameRef = useRef('');
- const fileRef = useRef('');
-
- const submitUploadPurchaseOrder = async (e) => {
- e.preventDefault();
- const file = fileRef.current.files[0];
- const name = nameRef.current.value;
- if (file.size > 5000000) {
- toast.error('Maksimal ukuran file adalah 5MB', {
- position: 'bottom-center'
- });
- return;
- }
- const parameter = {
- name,
- file: await getFileBase64(file)
- };
- const isUploaded = await apiOdoo('POST', `/api/v1/partner/${auth.partner_id}/sale_order/${transaction.id}/upload_po`, parameter);
- if (isUploaded) {
- toast.success('Berhasil upload PO');
- loadTransaction();
- closePopup();
- }
- };
-
- return (
- <form className="flex flex-col gap-y-4" onSubmit={submitUploadPurchaseOrder}>
- <div>
- <label className="form-label mb-2">Nama PO</label>
- <input className="form-input" type="text" ref={nameRef} required />
- </div>
- <div>
- <label className="form-label mb-2">Dokumen PO</label>
- <input className="form-input" type="file" ref={fileRef} required />
- </div>
- <button type="submit" className="btn-yellow w-full mt-2">Upload</button>
- </form>
- );
- }
-
- const {
- closePopup,
- BottomPopup,
- openPopup
- } = useBottomPopup({
- title: 'Upload PO',
- children: UploadPurchaseOrder
- });
-
- const downloadPurchaseOrder = () => {
- const url = `${process.env.ODOO_HOST}/api/v1/partner/${auth.partner_id}/sale_order/${transaction.id}/download_po/${transaction.token}`;
- window.open(url, 'download')
- };
-
- const downloadQuotation = () => {
- const url = `${process.env.ODOO_HOST}/api/v1/partner/${auth.partner_id}/sale_order/${transaction.id}/download/${transaction.token}`;
- window.open(url, 'download')
- };
-
- const checkout = async () => {
- if (!transaction.purchase_order_file) {
- toast.error('Mohon upload dokumen PO anda sebelum melanjutkan pesanan')
- return
- }
- await apiOdoo('POST', `/api/v1/partner/${auth?.partner_id}/sale_order/${id}/checkout`)
- toast.success('Berhasil melanjutkan pesanan')
- loadTransaction()
- }
-
- return (
- <WithAuth>
- <Layout className="pb-4">
- <AppBar title="Detail Transaksi" />
-
- { transaction ? (
- <>
- <div className="p-4 flex flex-col gap-y-4">
- <DescriptionRow label="Status Transaksi">
- <div className="flex justify-end">
- <TransactionStatusBadge status={transaction?.status} />
- </div>
- </DescriptionRow>
- <DescriptionRow label="No Transaksi">
- { transaction?.name }
- </DescriptionRow>
- <DescriptionRow label="Ketentuan Pembayaran">
- { transaction?.payment_term }
- </DescriptionRow>
- <DescriptionRow label="Nama Sales">
- { transaction?.sales }
- </DescriptionRow>
- <DescriptionRow label="Waktu Transaksi">
- { transaction?.date_order }
- </DescriptionRow>
- </div>
-
- <LineDivider />
-
- <div className="p-4 flex flex-col gap-y-4">
- <DescriptionRow label="Purchase Order">
- { transaction?.purchase_order_name || '-' }
- </DescriptionRow>
- <div className="flex items-center">
- <p className="text-gray_r-11 leading-none">Dokumen PO</p>
- <button
- type="button"
- className="btn-light py-1.5 px-3 ml-auto"
- onClick={transaction?.purchase_order_file ? downloadPurchaseOrder : openPopup}
- >
- { transaction?.purchase_order_file ? 'Download' : 'Upload' }
- </button>
- </div>
- </div>
-
- <LineDivider />
-
- <p className="h2 p-4">Detail Produk</p>
-
- <div className="mt-2 p-4 pt-0 flex flex-col gap-y-3">
- <VariantGroupCard
- variants={transaction?.products}
- buyMore
- />
- <div className="flex justify-between mt-3 font-medium">
- <p>Total Belanja</p>
- <p>{ currencyFormat(transaction?.amount_total || 0) }</p>
- </div>
- </div>
-
- <LineDivider />
-
- <TransactionDetailAddress transaction={transaction} />
-
- <LineDivider />
-
- <div className="p-4">
- <p className="h2">Invoice</p>
- <div className="flex flex-col gap-y-3 mt-4">
- { transaction?.invoices?.map((invoice, index) => (
- <Link href={`/my/invoice/${invoice.id}`} key={index}>
- <div className="shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between">
- <div>
- <p className="mb-2">{ invoice?.name }</p>
- <div className="flex items-center gap-x-1">
- { invoice.amount_residual > 0 ? (
- <div className="badge-red">Belum Lunas</div>
- ) : (
- <div className="badge-green">Lunas</div>
- ) }
- <p className="text-caption-2 text-gray_r-11">
- { currencyFormat(invoice.amount_total) }
- </p>
- </div>
- </div>
- <ChevronRightIcon className="w-5 stroke-2" />
- </div>
- </Link>
- )) }
- { transaction?.invoices?.length === 0 && (
- <Alert type='info' className='text-center'>
- Belum ada Invoice
- </Alert>
- ) }
- </div>
- </div>
-
- <LineDivider />
-
- <div className="px-4">
- { transaction?.status == 'draft' && (
- <button
- className="btn-yellow w-full mt-4"
- onClick={checkout}
- >
- Lanjutkan Transaksi
- </button>
- ) }
- <button
- className="btn-light w-full mt-4"
- disabled={transaction?.status != 'draft'}
- onClick={downloadQuotation}
- >
- Download Quotation
- </button>
- { transaction?.status != 'draft' && (
- <button
- className="btn-light w-full mt-4"
- disabled={transaction?.status != 'waiting'}
- onClick={() => openConfirmAlert(transaction)}
- >
- Batalkan Transaksi
- </button>
- ) }
- </div>
- </>
- ) : (
- <div className="p-4 py-6">
- <SkeletonList number={12} />
- </div>
- ) }
- { ConfirmAlert }
- { BottomPopup }
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/my/transactions.js b/src2/pages/my/transactions.js
deleted file mode 100644
index 8be43af7..00000000
--- a/src2/pages/my/transactions.js
+++ /dev/null
@@ -1,198 +0,0 @@
-import { useRouter } from "next/router";
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import WithAuth from "@/components/auth/WithAuth";
-import { useCallback, useEffect, useRef, useState } from "react";
-import { useAuth } from "@/core/utils/auth";
-import apiOdoo from "@/core/utils/apiOdoo";
-import currencyFormat from "@/core/utils/currencyFormat";
-import { EllipsisVerticalIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
-import Link from "@/components/elements/Link";
-import Pagination from "@/components/elements/Pagination";
-import Alert from "@/components/elements/Alert";
-import TransactionStatusBadge from "@/components/transactions/TransactionStatusBadge";
-import { toast } from "react-hot-toast";
-import useConfirmAlert from "@/lib/elements/hooks/useConfirmAlert";
-import useBottomPopup from "@/lib/elements/hooks/useBottomPopup";
-
-export default function Transactions() {
- const [ auth ] = useAuth();
- const router = useRouter();
- const {
- q,
- page = 1
- } = router.query;
-
- const [ transactions, setTransactions ] = useState([]);
-
- const [ pageCount, setPageCount ] = useState(0);
- const [ isLoading, setIsLoading ] = useState(true);
-
- const searchQueryRef = useRef();
- const loadTransactions = useCallback(async () => {
- if (auth) {
- const limit = 10;
- let offset = (page - 1) * 10;
- let queryParams = [`limit=${limit}`, `offset=${offset}`];
- if (q) queryParams.push(`name=${q}`);
- queryParams = queryParams.join('&');
- queryParams = queryParams ? '?' + queryParams : '';
-
- const dataTransactions = await apiOdoo('GET', `/api/v1/partner/${auth.partner_id}/sale_order${queryParams}`);
- setTransactions(dataTransactions);
- setPageCount(Math.ceil(dataTransactions?.sale_order_total / limit));
- setIsLoading(false);
- };
- }, [ auth, q, page ]);
-
- useEffect(() => {
- loadTransactions();
- }, [ loadTransactions ]);
-
- const actionSearch = (e) => {
- e.preventDefault();
- let queryParams = [];
- if (searchQueryRef.current.value) queryParams.push(`q=${searchQueryRef.current.value}`);
- queryParams = queryParams.join('&');
- queryParams = queryParams ? `?${queryParams}` : '';
- router.push(`/my/transactions${queryParams}`);
- };
-
- const downloadPurchaseOrder = (data) => {
- const url = `${process.env.ODOO_HOST}/api/v1/partner/${auth.partner_id}/sale_order/${data.id}/download_po/${data.token}`;
- window.open(url, 'download');
- closePopup();
- };
-
- const downloadQuotation = (data) => {
- const url = `${process.env.ODOO_HOST}/api/v1/partner/${auth.partner_id}/sale_order/${data.id}/download/${data.token}`;
- window.open(url, 'download');
- closePopup();
- };
-
- const childrenPopup = (data) => (
- <div className="flex flex-col gap-y-6">
- <button
- className="text-left disabled:opacity-60"
- disabled={!data?.purchase_order_file}
- onClick={() => downloadPurchaseOrder(data)}
- >
- Download PO
- </button>
- <button
- className="text-left disabled:opacity-60"
- disabled={data?.status != 'draft'}
- onClick={() => downloadQuotation(data)}
- >
- Download Quotation
- </button>
- <button
- className="text-left disabled:opacity-60"
- disabled={ data?.status != 'waiting' }
- onClick={() => {openConfirmAlert(data); closePopup()}}
- >
- Batalkan Transaksi
- </button>
- </div>
- );
-
- const {
- closePopup,
- openPopup,
- BottomPopup
- } = useBottomPopup({
- title: 'Lainnya',
- children: childrenPopup
- });
-
- const submitCancelTransaction = async (data) => {
- const isCancelled = await apiOdoo('POST', `/api/v1/partner/${auth.partner_id}/sale_order/${data.id}/cancel`);
- if (isCancelled) {
- toast.success('Berhasil batalkan transaksi');
- loadTransactions();
- }
- }
-
- const {
- openConfirmAlert,
- ConfirmAlert
- } = useConfirmAlert({
- title: 'Batalkan Transaksi',
- caption: 'Apakah anda yakin untuk membatalkan transaksi?',
- closeText: 'Tidak',
- submitText: 'Ya, Batalkan',
- onSubmit: submitCancelTransaction
- });
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Transaksi" />
-
- <form onSubmit={actionSearch} className="p-4 pb-0 flex gap-x-4">
- <input
- type="text"
- className="form-input"
- placeholder="Cari Transaksi"
- ref={searchQueryRef}
- defaultValue={q}
- />
- <button type="submit" className="border border-gray_r-7 rounded px-3">
- <MagnifyingGlassIcon className="w-5"/>
- </button>
- </form>
-
- <div className="p-4 flex flex-col gap-y-5">
- { transactions?.sale_order_total === 0 && !isLoading && (
- <Alert type="info" className="text-center">
- Transaksi tidak ditemukan
- </Alert>
- ) }
- { transactions?.sale_orders?.map((transaction, index) => (
- <div className="p-4 shadow border border-gray_r-3 rounded-md" key={index}>
- <div className="grid grid-cols-2">
- <Link href={`/my/transaction/${transaction.id}`}>
- <span className="text-caption-2 text-gray_r-11">No. Transaksi</span>
- <h2 className="text-red_r-11 mt-1">{ transaction.name }</h2>
- </Link>
- <div className="flex gap-x-1 justify-end">
- <TransactionStatusBadge status={transaction.status} />
- <EllipsisVerticalIcon className="w-5 h-5" onClick={() => openPopup(transaction)} />
- </div>
- </div>
- <Link href={`/my/transaction/${transaction.id}`}>
- <div className="grid grid-cols-2 mt-3">
- <div>
- <span className="text-caption-2 text-gray_r-11">No. Purchase Order</span>
- <p className="mt-1 font-medium text-gray_r-12">{ transaction.purchase_order_name || '-' }</p>
- </div>
- <div className="text-right">
- <span className="text-caption-2 text-gray_r-11">Total Invoice</span>
- <p className="mt-1 font-medium text-gray_r-12">{ transaction.invoice_count } Invoice</p>
- </div>
- </div>
- <div className="grid grid-cols-2 mt-3">
- <div>
- <span className="text-caption-2 text-gray_r-11">Sales</span>
- <p className="mt-1 font-medium text-gray_r-12">{ transaction.sales }</p>
- </div>
- <div className="text-right">
- <span className="text-caption-2 text-gray_r-11">Total Harga</span>
- <p className="mt-1 font-medium text-gray_r-12">{ currencyFormat(transaction.amount_total) }</p>
- </div>
- </div>
- </Link>
- </div>
- )) }
- </div>
-
- <div className="pb-6 pt-2">
- <Pagination currentPage={page} pageCount={pageCount} url={`/my/transactions${q ? `?q=${q}` : ''}`} />
- </div>
-
- { ConfirmAlert }
- { BottomPopup }
- </Layout>
- </WithAuth>
- );
-}; \ No newline at end of file
diff --git a/src2/pages/my/wishlist.js b/src2/pages/my/wishlist.js
deleted file mode 100644
index 3d479802..00000000
--- a/src2/pages/my/wishlist.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import WithAuth from "@/components/auth/WithAuth";
-import Alert from "@/components/elements/Alert";
-import Pagination from "@/components/elements/Pagination";
-import Spinner from "@/components/elements/Spinner";
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import ProductCard from "@/components/products/ProductCard";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useAuth } from "@/core/utils/auth";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-
-export default function Wishlist() {
- const [ auth ] = useAuth();
- const router = useRouter();
- const { page = 1 } = router.query;
- const [ wishlists, setWishlists ] = useState(null);
- const [ pageCount, setPageCount ] = useState(0);
-
- useEffect(() => {
- const loadWishlist = async () => {
- const limit = 10;
- const offset = (page - 1) * limit;
- if (auth) {
- const dataWishlist = await apiOdoo('GET', `/api/v1/user/${auth.id}/wishlist?limit=${limit}&offset=${offset}`);
- setWishlists(dataWishlist);
- setPageCount(Math.ceil(dataWishlist.product_total / limit));
- }
- }
- loadWishlist();
- }, [ auth, page ]);
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title='Wishlist' />
-
- <div className="px-4 py-6">
- { !wishlists && (
- <Spinner className="w-6 h-6 text-gray-600 fill-gray-900 mx-auto" />
- ) }
- { wishlists?.products?.length == 0 && (
- <Alert type='info' className='text-center'>
- Wishlist anda masih kosong
- </Alert>
- ) }
- <div className="grid grid-cols-2 gap-3">
- {wishlists?.products.map((product) => (
- <ProductCard key={product.id} data={product} />
- ))}
- </div>
-
- <div className="mt-6">
- <Pagination currentPage={page} pageCount={pageCount} url={`/my/wishlist`} />
- </div>
- </div>
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/register.js b/src2/pages/register.js
deleted file mode 100644
index 39bd137f..00000000
--- a/src2/pages/register.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import axios from "axios";
-import Head from "next/head";
-import Image from "next/image";
-import Link from "@/components/elements/Link";
-import { useEffect, useState } from "react";
-import Alert from "@/components/elements/Alert";
-import Layout from "@/components/layouts/Layout";
-import Spinner from "@/components/elements/Spinner";
-import Logo from "@/images/logo.png";
-
-export default function Login() {
- const [email, setEmail] = useState('');
- const [name, setName] = useState('');
- const [password, setPassword] = useState('');
- const [isInputFulfilled, setIsInputFulfilled] = useState(false);
- const [isLoading, setIsLoading] = useState(false);
- const [alert, setAlert] = useState();
-
- useEffect(() => {
- setIsInputFulfilled(email && name && password);
- }, [email, name, password]);
-
- const register = async (e) => {
- e.preventDefault();
- setIsLoading(true);
- let register = await axios.post(`${process.env.SELF_HOST}/api/register`, {email, name, password});
- if (register.data.register) {
- await axios.post(`${process.env.SELF_HOST}/api/activation-request`, {email});
- setAlert({
- component: <>Berhasil mendaftarkan akun anda, cek email untuk melakukan aktivasi akun</>,
- type: 'success'
- });
- setEmail('');
- setName('');
- setPassword('');
- } else {
- switch (register.data.reason) {
- case 'EMAIL_USED':
- setAlert({
- component: <>Email telah digunakan</>,
- type: 'info'
- });
- break;
- }
- }
- setIsLoading(false);
- }
-
- return (
- <>
- <Head>
- <title>Daftar - Indoteknik</title>
- </Head>
- <Layout className="max-w-lg mx-auto flex flex-col items-center px-4 pb-8">
- <Link href="/" className="mt-16">
- <Image src={Logo} alt="Logo Indoteknik" width={165} height={42} />
- </Link>
- <h1 className="text-2xl mt-4 text-center">Mudahkan Pembelian dengan Indoteknik</h1>
- <h2 className="text-gray_r-11 font-normal mt-2 mb-4">Daftar untuk melanjutkan belanja</h2>
- {alert ? (
- <Alert className="text-center" type={alert.type}>{alert.component}</Alert>
- ) : ''}
- <form onSubmit={register} className="w-full">
- <label className="form-label mt-4 mb-2">Alamat Email</label>
- <input
- type="email"
- className="form-input bg-gray_r-2"
- placeholder="johndoe@gmail.com"
- value={email}
- onChange={(e) => setEmail(e.target.value)}
- />
- <label className="form-label mt-4 mb-2">Nama Lengkap</label>
- <input
- type="text"
- className="form-input bg-gray_r-2"
- placeholder="John Doe"
- value={name}
- onChange={(e) => setName(e.target.value)}
- />
- <label className="form-label mt-4 mb-2">Kata Sandi</label>
- <input
- type="password"
- className="form-input bg-gray_r-2"
- placeholder="••••••••"
- value={password}
- onChange={(e) => setPassword(e.target.value)}
- />
- <button type="submit" disabled={!isInputFulfilled} className="btn-yellow font-semibold mt-4 w-full">
- {isLoading ? (
- <div className="flex justify-center items-center gap-x-2">
- <Spinner className="w-4 h-4 text-gray-600 fill-gray-900" /> <span>Loading...</span>
- </div>
- ) : 'Daftar'}
- </button>
- </form>
- <p className="text-gray-700 mt-4">Sudah punya akun Indoteknik? <Link href="/login">Masuk</Link></p>
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/brands/[slug].js b/src2/pages/shop/brands/[slug].js
deleted file mode 100644
index a387e55d..00000000
--- a/src2/pages/shop/brands/[slug].js
+++ /dev/null
@@ -1,178 +0,0 @@
-import axios from "axios";
-import { useEffect, useState } from "react";
-import Filter from "@/components/elements/Filter";
-import Footer from "@/components/layouts/Footer";
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-import Pagination from "@/components/elements/Pagination";
-import ProductCard from "@/components/products/ProductCard";
-import { getIdFromSlug, getNameFromSlug } from "@/core/utils/slug";
-import FilterIcon from "@/icons/filter.svg";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { Swiper, SwiperSlide } from "swiper/react";
-import "swiper/css";
-import "swiper/css/pagination";
-import "swiper/css/autoplay";
-import { Pagination as SwiperPagination } from "swiper";
-import Image from "@/components/elements/Image";
-import LineDivider from "@/components/elements/LineDivider";
-
-export async function getServerSideProps(context) {
- const {
- slug,
- page = 1,
- category = '',
- price_from = '',
- price_to = '',
- order_by = '',
- } = context.query;
-
- let urlParameter = [
- 'q=*',
- `page=${page}`,
- `brand=${getNameFromSlug(slug)}`,
- `category=${category}`,
- `price_from=${price_from}`,
- `price_to=${price_to}`,
- `order_by=${order_by}`
- ].join('&');
- let searchResults = await axios(`${process.env.SELF_HOST}/api/shop/search?${urlParameter}`);
- searchResults = searchResults.data;
-
- const manufacture = await apiOdoo('GET', `/api/v1/manufacture/${getIdFromSlug(slug)}`);
-
- return {
- props: {
- searchResults,
- page,
- slug,
- category,
- price_from,
- price_to,
- order_by,
- manufacture
- }
- };
-}
-
-export default function BrandDetail({
- searchResults,
- page,
- slug,
- category,
- price_from,
- price_to,
- order_by,
- manufacture
-}) {
- const pageCount = Math.ceil(searchResults.response.numFound / searchResults.responseHeader.params.rows);
- const productStart = searchResults.responseHeader.params.start;
- const productRows = searchResults.responseHeader.params.rows;
- const productFound = searchResults.response.numFound;
-
- const [activeFilter, setActiveFilter] = useState(false);
- const [filterCount, setFilterCount] = useState(0);
-
- const route = () => {
- let route = `/shop/brands/${slug}`;
- if (category) route += `&category=${category}`;
- if (price_from) route += `&price_from=${price_from}`;
- if (price_to) route += `&price_to=${price_to}`;
- if (order_by) route += `&order_by=${order_by}`;
- return route;
- }
-
- useEffect(() => {
- let calculateFilterCount = 0;
- if (category) calculateFilterCount++;
- if (price_from || price_to) calculateFilterCount++;
- if (order_by) calculateFilterCount++;
- setFilterCount(calculateFilterCount);
- }, [category, price_from, price_to, order_by]);
-
- return (
- <>
- <Header title={`Distributor ${getNameFromSlug(slug)} Indonesia Harga Official - Indoteknik`} />
- <Filter
- defaultRoute={`/shop/brands/${slug}`}
- isActive={activeFilter}
- closeFilter={() => setActiveFilter(false)}
- defaultPriceFrom={price_from}
- defaultPriceTo={price_to}
- defaultBrand=''
- defaultCategory={category}
- defaultOrderBy={order_by}
- searchResults={searchResults}
- disableFilter={['brand']}
- />
- <Layout>
- <Swiper slidesPerView={1} pagination={{dynamicBullets: true}} modules={[SwiperPagination]}>
- {
- manufacture.banners?.map((banner, index) => (
- <SwiperSlide key={index}>
- <Image
- src={banner}
- alt={`Banner ${manufacture.name}`}
- className="w-full h-auto border-b border-gray_r-6"
- />
- </SwiperSlide>
- ))
- }
- </Swiper>
- <div className="p-4 grid grid-cols-2">
- <div>
- <p className="text-caption-2 text-gray_r-11 mb-2">Produk dari brand:</p>
- { manufacture.logo ? (
- <div className="w-8/12">
- <Image src={manufacture?.logo} alt={manufacture.name} className="border border-gray_r-6 rounded p-3" />
- </div>
- ) : (
- <p className="badge-solid-red text-caption-1">{ manufacture.name }</p>
- ) }
- </div>
- <div className="text-right">
- <p className="text-caption-2 text-gray_r-11 mb-2">Jumlah Produk:</p>
- <p>{ searchResults.response.numFound }</p>
- </div>
- </div>
-
- <LineDivider />
-
- <div className="p-4">
- <h1 className="mb-2">Produk</h1>
- <div className="text-caption-1 mb-4">
- {productFound > 0 ? (
- <>
- Menampilkan&nbsp;
- {pageCount > 1 ? (
- <>
- {productStart + 1}-{
- (productStart + productRows) > productFound ? productFound : productStart + productRows
- }
- &nbsp;dari&nbsp;
- </>
- ) : ''}
- {searchResults.response.numFound}
- &nbsp;produk untuk brand <span className="font-semibold">{getNameFromSlug(slug)}</span>
- </>
- ) : 'Mungkin yang anda cari'}
- </div>
- <button className="btn-light py-2 flex items-center gap-x-2 mb-4" onClick={() => setActiveFilter(true)}>
- <FilterIcon className="w-4 h-4" /> <span>Filter {filterCount > 0 ? `(${filterCount})` : ''}</span>
- </button>
- <div className="grid grid-cols-2 gap-3">
- {searchResults.response.products.map((product) => (
- <ProductCard key={product.id} data={product} />
- ))}
- </div>
-
- <div className="mt-4">
- <Pagination pageCount={pageCount} currentPage={parseInt(page)} url={route()} />
- </div>
- </div>
-
- <Footer />
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/brands/index.js b/src2/pages/shop/brands/index.js
deleted file mode 100644
index bfdcd403..00000000
--- a/src2/pages/shop/brands/index.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import Header from "@/components/layouts/Header";
-import apiOdoo from "@/core/utils/apiOdoo";
-import InfiniteScroll from "react-infinite-scroll-component";
-import { useCallback, useEffect, useState } from "react";
-import Spinner from "@/components/elements/Spinner";
-import Layout from "@/components/layouts/Layout";
-import ManufactureCard from "@/components/manufactures/ManufactureCard";
-import Footer from "@/components/layouts/Footer";
-
-export async function getServerSideProps() {
- let initialManufactures = await apiOdoo('GET', '/api/v1/manufacture?limit=31');
- return {props: {initialManufactures}};
-}
-
-export default function Brands({ initialManufactures }) {
- const [manufactures, setManufactures] = useState(initialManufactures.manufactures);
- const [hasMoreManufacture, setHasMoreManufacture] = useState(true);
- const [manufactureStartwith, setManufactureStartWith] = useState('');
-
- const alpha = Array.from(Array(26)).map((e, i) => i + 65);
- const alphabets = alpha.map((x) => String.fromCharCode(x));
-
- const getMoreManufactures = useCallback(async () => {
- const name = manufactureStartwith != '' ? `${manufactureStartwith}%` : '';
- const result = await apiOdoo('GET', `/api/v1/manufacture?limit=30&offset=${manufactures.length}&name=${name}`);
- setHasMoreManufacture(manufactures.length + 30 < result.manufacture_total)
- setManufactures((manufactures) => [...manufactures, ...result.manufactures]);
- }, [ manufactureStartwith ]);
-
- const filterManufactureStartWith = (character) => {
- setManufactures([]);
- if (manufactureStartwith == character) {
- setManufactureStartWith('');
- } else {
- setManufactureStartWith(character);
- }
- };
-
- useEffect(() => {
- getMoreManufactures();
- }, [ getMoreManufactures ]);
-
- return (
- <>
- <Header title='Semua Brand di Indoteknik' />
- <Layout>
- <div className="p-4">
- <h1>Semua Brand di Indoteknik</h1>
- <div className="flex overflow-x-auto gap-x-2 py-2">
- {alphabets.map((alphabet, index) => (
- <button key={index} className={"p-2 py-1 border bg-white border-gray_r-6 rounded w-10 flex-shrink-0" + (manufactureStartwith == alphabet ? ' !bg-yellow_r-9 border-yellow_r-9 ' : '')} onClick={() => filterManufactureStartWith(alphabet)}>
- {alphabet}
- </button>
- ))}
- </div>
- <InfiniteScroll
- dataLength={manufactures.length}
- next={getMoreManufactures}
- hasMore={hasMoreManufacture}
- className="grid grid-cols-4 gap-4 mt-6 !overflow-x-hidden"
- loader={
- <div className="flex justify-center items-center border border-gray-300 p-2 rounded h-14">
- <Spinner className="w-6 h-6 text-gray-600 fill-gray-900"/>
- </div>
- }
- >
- {manufactures?.map((manufacture, index) => (
- manufacture.name ? (
- <ManufactureCard data={manufacture} key={index} />
- ) : ''
- ))}
- </InfiniteScroll>
- </div>
-
- <Footer />
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/cart.js b/src2/pages/shop/cart.js
deleted file mode 100644
index 1178781b..00000000
--- a/src2/pages/shop/cart.js
+++ /dev/null
@@ -1,282 +0,0 @@
-import { useEffect, useState } from "react";
-import { toast } from "react-hot-toast";
-import {
- TrashIcon,
- PlusIcon,
- MinusIcon,
- ExclamationCircleIcon,
-} from "@heroicons/react/24/solid";
-import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
-import { useRouter } from "next/router";
-
-// Helpers
-import {
- createOrUpdateItemCart,
- deleteItemCart,
- getCart
-} from "@/core/utils/cart";
-import { createSlug } from "@/core/utils/slug";
-import apiOdoo from "@/core/utils/apiOdoo";
-import currencyFormat from "@/core/utils/currencyFormat";
-
-// Components
-import Image from "@/components/elements/Image";
-import Layout from "@/components/layouts/Layout";
-import Link from "@/components/elements/Link";
-import Alert from "@/components/elements/Alert";
-import Spinner from "@/components/elements/Spinner";
-import AppBar from "@/components/layouts/AppBar";
-import ProgressBar from "@/components/elements/ProgressBar";
-import LineDivider from "@/components/elements/LineDivider";
-import useConfirmAlert from "@/lib/elements/hooks/useConfirmAlert";
-
-export default function Cart() {
- const router = useRouter();
- const [isLoadingProducts, setIsLoadingProducts] = useState(true);
- const [products, setProducts] = useState([]);
- const [totalPriceBeforeTax, setTotalPriceBeforeTax] = useState(0);
- const [totalTaxAmount, setTotalTaxAmount] = useState(0);
- const [totalDiscountAmount, setTotalDiscountAmount] = useState(0);
-
- useEffect(() => {
- const getProducts = async () => {
- let cart = getCart();
- let productIds = Object.keys(cart);
- if (productIds.length > 0) {
- productIds = productIds.join(',');
- let dataProducts = await apiOdoo('GET', `/api/v1/product_variant/${productIds}`);
- dataProducts = dataProducts.map((product) => ({
- ...product,
- quantity: cart[product.id].quantity,
- selected: cart[product.id].selected,
- }));
- setProducts(dataProducts);
- }
- setIsLoadingProducts(false);
- }
- getProducts();
- }, []);
-
- useEffect(() => {
- for (const product of products) {
- if (product.quantity != '') createOrUpdateItemCart(product.id, product.quantity, product.selected);
- }
- const productsSelected = products.filter((product) => product.selected == true);
- let calculateTotalPriceBeforeTax = 0;
- let calculateTotalTaxAmount = 0;
- let calculateTotalDiscountAmount = 0;
- productsSelected.forEach(product => {
- let priceBeforeTax = product.price.price / 1.11;
- calculateTotalPriceBeforeTax += priceBeforeTax * product.quantity;
- calculateTotalTaxAmount += (product.price.price - priceBeforeTax) * product.quantity;
- calculateTotalDiscountAmount += (product.price.price - product.price.price_discount) * product.quantity;
- });
- setTotalPriceBeforeTax(calculateTotalPriceBeforeTax);
- setTotalTaxAmount(calculateTotalTaxAmount);
- setTotalDiscountAmount(calculateTotalDiscountAmount);
- }, [products]);
-
- const getProductsSelected = () => {
- return products.filter((product) => product.selected == true);
- }
-
- const updateCart = (productId, quantity) => {
- let productIndexToUpdate = products.findIndex((product) => product.id == productId);
- let productsToUpdate = products;
- productsToUpdate[productIndexToUpdate].quantity = quantity;
- setProducts([...productsToUpdate]);
- };
-
- const blurQuantity = (productId, quantity) => {
- quantity = quantity == ('' || 0) ? 1 : parseInt(quantity);
- if (typeof quantity === 'number') {
- quantity = parseInt(quantity);
- quantity = Math.floor(quantity);
- }
- updateCart(productId, quantity);
- };
-
- const updateQuantity = (productId, quantity) => {
- quantity = quantity == '' ? '' : parseInt(quantity);
- updateCart(productId, quantity);
- };
-
- const plusQuantity = (productId) => {
- let productIndexToUpdate = products.findIndex((product) => product.id == productId);
- let quantity = products[productIndexToUpdate].quantity + 1;
- updateCart(productId, quantity);
- }
-
- const minusQuantity = (productId) => {
- let productIndexToUpdate = products.findIndex((product) => product.id == productId);
- let quantity = products[productIndexToUpdate].quantity - 1;
- updateCart(productId, quantity);
- }
-
- const toggleProductSelected = (productId) => {
- let productIndexToUpdate = products.findIndex((product) => product.id == productId);
- let productsToUpdate = products;
- productsToUpdate[productIndexToUpdate].selected = !productsToUpdate[productIndexToUpdate].selected;
- setProducts([...productsToUpdate]);
- }
-
- const deleteItem = (productId) => {
- let productIndexToUpdate = products.findIndex((product) => product.id == productId);
- let productsToUpdate = products;
- productsToUpdate.splice(productIndexToUpdate, 1);
- setProducts([...productsToUpdate]);
- deleteItemCart(productId);
- toast.success('Berhasil menghapus 1 barang dari keranjang', { duration: 1500 });
- }
-
- const {
- openConfirmAlert,
- ConfirmAlert
- } = useConfirmAlert({
- title: 'Hapus barang dari keranjang',
- caption:'Apakah anda yakin menghapus barang dari keranjang?',
- closeText: 'Batal',
- submitText: 'Hapus',
- onSubmit: deleteItem
- })
-
- return (
- <>
- { ConfirmAlert }
-
- <Layout>
- <AppBar title="Keranjang Saya" />
-
- {isLoadingProducts && (
- <div className="flex justify-center items-center gap-x-3 mt-14">
- <Spinner className="w-10 text-gray_r-8 fill-gray_r-12" />
- </div>
- ) }
-
- { !isLoadingProducts && products.length == 0 && (
- <div className="text-center mt-14">
- <ExclamationTriangleIcon className="w-12 mx-auto"/>
- <p className="mt-2 h2">Keranjang belanja anda masih kosong.</p>
- <Link href="/" className="btn-yellow text-gray_r-12 mx-auto mt-4">Mulai Belanja</Link>
- </div>
- ) }
-
- { !isLoadingProducts && products.length > 0 && (
- <>
- <ProgressBar
- current={1}
- labels={['Keranjang', 'Pembayaran', 'Selesai']}
- />
-
- <LineDivider />
-
- <div className="p-4">
- <Alert type="warning" className="text-caption-2 flex gap-x-3 items-center">
- <div>
- <ExclamationCircleIcon className="w-8 text-yellow_r-11"/>
- </div>
- <span>Mohon dicek kembali & pastikan pesanan kamu sudah sesuai dengan yang kamu butuhkan. Atau bisa hubungi kami.</span>
- </Alert>
- </div>
-
- <LineDivider />
-
- <div className="p-4 flex flex-col gap-y-6">
- <div className="flex justify-between items-center">
- <h2>Daftar Produk Belanja</h2>
- <Link href="/" className="text-caption-1">Cari Produk Lain</Link>
- </div>
- {products.map((product, index) => (
- <div className="flex gap-x-3" key={index}>
- <div className="w-4/12 flex items-center gap-x-2" onClick={() => toggleProductSelected(product.id)}>
- <button
- className={'p-2 rounded border-2 ' + (product.selected ? 'border-yellow_r-9 bg-yellow_r-9' : 'border-gray_r-12')}
- ></button>
- <Image
- src={product.parent.image}
- alt={product.parent.name}
- className="object-contain object-center border border-gray_r-6 h-32 w-full rounded-md"
- />
- </div>
- <div className="w-8/12 flex flex-col">
- <Link href={'/shop/product/' + createSlug(product.parent.name, product.parent.id)} className="product-card__title wrap-line-ellipsis-2">
- {product.parent.name}
- </Link>
- <p className="text-caption-2 text-gray_r-11 mt-1">
- {product.code || '-'}
- {product.attributes.length > 0 ? ` | ${product.attributes.join(', ')}` : ''}
- </p>
- <div className="flex flex-wrap gap-x-1 items-center mb-2 mt-auto">
- {product.price.discount_percentage > 0 && (
- <>
- <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(product.price.price)}</p>
- <span className="badge-red">{product.price.discount_percentage}%</span>
- </>
- )}
- <p className="text-caption-2 text-gray_r-12">{currencyFormat(product.price.price_discount)}</p>
- </div>
- <div className="flex items-center">
- <p className="mr-auto text-caption-2 text-gray_r-12 font-bold">{currencyFormat(product.quantity * product.price.price_discount)}</p>
- <div className="flex gap-x-2 items-center">
- <button
- className="btn-red p-2 rounded"
- onClick={() => openConfirmAlert(product.id)}
- >
- <TrashIcon className="text-red_r-11 w-3"/>
- </button>
- <button
- className="btn-light p-2 rounded"
- disabled={product.quantity == 1}
- onClick={() => minusQuantity(product.id)}
- >
- <MinusIcon className={'text-gray_r-12 w-3' + (product.quantity == 1 ? ' text-gray_r-11' : '')}/>
- </button>
- <input
- type="number"
- className="bg-transparent border-none w-6 text-center outline-none"
- onBlur={(e) => blurQuantity(product.id, e.target.value)}
- onChange={(e) => updateQuantity(product.id, e.target.value)}
- value={product.quantity}
- />
- <button className="btn-light p-2 rounded" onClick={() => plusQuantity(product.id)}>
- <PlusIcon className="text-gray_r-12 w-3"/>
- </button>
- </div>
- </div>
- </div>
- </div>
- ))}
- </div>
-
- <div className="p-4 bg-gray_r-1 sticky bottom-0 border-t-4 border-gray_r-4">
- <div className="flex">
- <p>Total</p>
- <p className="text-gray_r-11 ml-1">{getProductsSelected().length > 0 && (
- <>({ getProductsSelected().length } Barang)</>
- )}</p>
- <p className="font-semibold text-red_r-11 ml-auto">{currencyFormat(totalPriceBeforeTax + totalTaxAmount - totalDiscountAmount)}</p>
- </div>
-
- <div className="flex gap-x-3 mt-4">
- <button
- className="flex-1 btn-light"
- disabled={getProductsSelected().length == 0}
- onClick={() => router.push('/shop/quotation')}
- >
- Quotation {getProductsSelected().length > 0 && `(${getProductsSelected().length})`}
- </button>
- <button
- className="flex-1 btn-yellow"
- disabled={getProductsSelected().length == 0}
- onClick={() => router.push('/shop/checkout')}
- >
- Checkout {getProductsSelected().length > 0 && `(${getProductsSelected().length})`}
- </button>
- </div>
- </div>
- </>
- ) }
- </Layout>
- </>
- );
-} \ No newline at end of file
diff --git a/src2/pages/shop/checkout/finish.js b/src2/pages/shop/checkout/finish.js
deleted file mode 100644
index df284f8a..00000000
--- a/src2/pages/shop/checkout/finish.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import WithAuth from "@/components/auth/WithAuth";
-import Link from "@/components/elements/Link";
-import AppBar from "@/components/layouts/AppBar";
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useAuth } from "@/core/utils/auth";
-import { EnvelopeIcon } from "@heroicons/react/24/outline";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-
-export default function FinishCheckout() {
- const router = useRouter();
- const { id } = router.query;
- const [ auth ] = useAuth();
- const [ transaction, setTransactions ] = useState(null);
-
- useEffect(() => {
- const loadTransaction = async () => {
- if (auth && id) {
- const dataTransaction = await apiOdoo('GET', `/api/v1/partner/${auth.partner_id}/sale_order/${id}`);
- setTransactions(dataTransaction);
- }
- };
- loadTransaction();
- });
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Pembelian Berhasil" />
-
- <div className="m-4 rounded-xl bg-yellow_r-4 text-center border border-yellow_r-7">
- <div className="px-4 py-6 text-yellow_r-12">
- <p className="h2 mb-2">Terima Kasih atas Pembelian Anda</p>
- <p className="text-yellow_r-11 mb-4 leading-6">Rincian belanja sudah kami kirimkan ke email anda. Mohon dicek kembali. jika tidak menerima email, anda dapat menghubungi kami disini.</p>
- <p className="mb-2 font-medium">{ transaction?.name }</p>
- <p className="text-caption-2 text-yellow_r-11">No. Transaksi</p>
- </div>
- <Link href={transaction?.id ? `/my/transaction/${transaction.id}` : '/'} className="bg-yellow_r-6 text-yellow_r-12 rounded-b-xl py-4 block">
- Lihat detail pembelian Anda disini
- </Link>
- </div>
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/shop/checkout/index.js b/src2/pages/shop/checkout/index.js
deleted file mode 100644
index 0a77ebed..00000000
--- a/src2/pages/shop/checkout/index.js
+++ /dev/null
@@ -1,325 +0,0 @@
-import { ExclamationCircleIcon } from "@heroicons/react/24/solid"
-import { useEffect, useState } from "react"
-import Alert from "@/components/elements/Alert"
-import AppBar from "@/components/layouts/AppBar"
-import Layout from "@/components/layouts/Layout"
-import LineDivider from "@/components/elements/LineDivider"
-import Link from "@/components/elements/Link"
-import ProgressBar from "@/components/elements/ProgressBar"
-import Spinner from "@/components/elements/Spinner"
-import apiOdoo from "@/core/utils/apiOdoo"
-import { useAuth } from "@/core/utils/auth"
-import { deleteItemCart, getCart } from "@/core/utils/cart"
-import currencyFormat from "@/core/utils/currencyFormat"
-import { getItemAddress } from "@/core/utils/address"
-import { useRouter } from "next/router"
-import WithAuth from "@/components/auth/WithAuth"
-import { toast } from "react-hot-toast"
-import getFileBase64 from "@/core/utils/getFileBase64"
-import VariantCard from "@/components/variants/VariantCard"
-
-export default function Checkout() {
- const router = useRouter()
- const { product_id, qty } = router.query
- const [ auth ] = useAuth()
- const [ addresses, setAddresses ] = useState(null)
- const [ poNumber, setPoNumber ] = useState('')
- const [ poFile, setPoFile ] = useState('')
- const [ selectedAddress, setSelectedAddress ] = useState({
- shipping: null,
- invoicing: null
- })
- const [ selectedPayment, setSelectedPayment ] = useState(null)
- const [ products, setProducts ] = useState(null)
- const [ totalAmount, setTotalAmount ] = useState(0)
- const [ totalDiscountAmount, setTotalDiscountAmount ] = useState(0)
-
- const [ isLoading, setIsLoading ] = useState(false)
-
- const payments = [
- { name: 'BCA', number: '8870-4000-81' },
- { name: 'MANDIRI', number: '155-0067-6869-75' },
- ]
-
- useEffect(() => {
- const getAddresses = async () => {
- if (auth) {
- const dataAddresses = await apiOdoo('GET', `/api/v1/user/${auth.id}/address`)
- setAddresses(dataAddresses)
- }
- }
- getAddresses()
- }, [auth])
-
- useEffect(() => {
- const getProducts = async () => {
- let cart = getCart()
- let productIds = []
- if (product_id) {
- productIds = [parseInt(product_id)]
- } else {
- productIds = Object
- .values(cart)
- .filter((itemCart) => itemCart.selected == true)
- .map((itemCart) => itemCart.product_id)
- }
- if (productIds.length > 0) {
- productIds = productIds.join(',')
- let dataProducts = await apiOdoo('GET', `/api/v1/product_variant/${productIds}`)
- dataProducts = dataProducts.map((product) => {
- if (product_id) {
- product.quantity = 1
- if (qty) product.quantity = parseInt(qty)
- } else {
- product.quantity = cart[product.id].quantity
- }
- return product
- })
- setProducts(dataProducts)
- }
- }
- getProducts()
- }, [router, auth, product_id, qty])
-
- useEffect(() => {
- if (addresses) {
- const matchAddress = (key) => {
- const addressToMatch = getItemAddress(key)
- let foundAddress = addresses.filter((address) => address.id == addressToMatch)
- if (foundAddress.length > 0) {
- return foundAddress[0]
- }
- return addresses[0]
- }
- setSelectedAddress({
- shipping: matchAddress('shipping'),
- invoicing: matchAddress('invoicing'),
- })
- }
- }, [addresses])
-
- useEffect(() => {
- if (products) {
- let calculateTotalAmount = 0
- let calculateTotalDiscountAmount = 0
- products.forEach(product => {
- calculateTotalAmount += product.price.price * product.quantity
- calculateTotalDiscountAmount += (product.price.price - product.price.price_discount) * product.quantity
- })
- setTotalAmount(calculateTotalAmount)
- setTotalDiscountAmount(calculateTotalDiscountAmount)
- }
- }, [products])
-
- const checkout = async () => {
- if (!selectedPayment) {
- toast.error('Mohon pilih metode pembayaran', {
- position: 'bottom-center'
- })
- return
- }
- if (poFile && poFile.size > 5000000) {
- toast.error('Maksimal ukuran file adalah 5MB', {
- position: 'bottom-center'
- })
- return
- }
- setIsLoading(true)
- let productOrder = products.map((product) => ({ 'product_id': product.id, 'quantity': product.quantity }))
- let data = {
- 'partner_shipping_id': selectedAddress.shipping.id,
- 'partner_invoice_id': selectedAddress.invoicing.id,
- 'order_line': JSON.stringify(productOrder),
- 'type': 'sale_order'
- }
- if (poNumber) data.po_number = poNumber
- if (poFile) data.po_file = await getFileBase64(poFile)
-
- const checkoutToOdoo = await apiOdoo('POST', `/api/v1/partner/${auth.partner_id}/sale_order/checkout`, data)
- for (const product of products) {
- deleteItemCart(product.id)
- }
- router.push(`/shop/checkout/finish?id=${checkoutToOdoo.id}`)
- setIsLoading(false)
- }
-
- return (
- <WithAuth>
- <Layout>
- <AppBar title={"Checkout"} />
- { !products && !addresses && (
- <div className="flex justify-center items-center gap-x-3 mt-14">
- <Spinner className="w-10 text-gray_r-8 fill-gray_r-12" />
- </div>
- ) }
-
- { products && addresses && (
- <>
- <ProgressBar
- current={2}
- labels={['Keranjang', 'Pembayaran', 'Selesai']}
- />
-
- <LineDivider/>
-
- <div className="p-4">
- <Alert type="info" className="text-caption-2 flex gap-x-3 items-center">
- <div>
- <ExclamationCircleIcon className="w-6 text-blue-700"/>
- </div>
- <span>Jika mengalami kesulitan dalam melakukan pembelian di website Indoteknik. Hubungi kami disini</span>
- </Alert>
- </div>
-
- <LineDivider/>
-
- <div className="p-4">
- <div className="flex justify-between items-center">
- <h2>Alamat Pengiriman</h2>
- <Link className="text-caption-1" href="/my/address?select=shipping">Pilih Alamat Lain</Link>
- </div>
-
- { selectedAddress.shipping && (
- <div className="mt-4 text-caption-1">
- <div className="badge-red mb-2">{ selectedAddress.shipping.type.charAt(0).toUpperCase() + selectedAddress.shipping.type.slice(1) + ' Address' }</div>
- <p className="font-medium">{ selectedAddress.shipping.name }</p>
- <p className="mt-2 text-gray_r-11">{ selectedAddress.shipping.mobile }</p>
- <p className="mt-1 text-gray_r-11">{ selectedAddress.shipping.street }, { selectedAddress.shipping?.city?.name }</p>
- </div>
- ) }
- </div>
-
- <LineDivider/>
-
- <div className="p-4 flex flex-col gap-y-4">
- {products.map((product, index) => (
- <VariantCard
- data={product}
- openOnClick={false}
- key={index}
- />
- ))}
- </div>
-
- <LineDivider/>
-
- <div className="p-4">
- <div className="flex justify-between items-center">
- <h2>Ringkasan Pesanan</h2>
- <p className="text-gray_r-11 text-caption-1">{products.length} Barang</p>
- </div>
- <hr className="my-4 border-gray_r-6"/>
- <div className="flex flex-col gap-y-4">
- <div className="flex gap-x-2 justify-between">
- <p>Total Belanja</p>
- <p className="font-medium">{currencyFormat(totalAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>Total Diskon</p>
- <p className="font-medium text-red_r-11">- {currencyFormat(totalDiscountAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>Subtotal</p>
- <p className="font-medium">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>PPN 11% (Incl.)</p>
- <p className="font-medium">{currencyFormat((totalAmount - totalDiscountAmount) * 0.11)}</p>
- </div>
- </div>
- <hr className="my-4 border-gray_r-6"/>
- <div className="flex gap-x-2 justify-between mb-4">
- <p>Grand Total</p>
- <p className="font-medium text-yellow_r-11">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
- </div>
- <p className="text-caption-2 text-gray_r-10 mb-2">*) Belum termasuk biaya pengiriman</p>
- <p className="text-caption-2 text-gray_r-10 leading-5">
- Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui <Link href="/">Syarat & Ketentuan</Link> yang berlaku
- </p>
- </div>
-
- <LineDivider/>
-
- <div className="p-4">
- <div className="flex justify-between items-center">
- <h2>Alamat Penagihan</h2>
- <Link className="text-caption-1" href="/my/address?select=invoicing">Pilih Alamat Lain</Link>
- </div>
-
- { selectedAddress.invoicing && (
- <div className="mt-4 text-caption-1">
- <div className="badge-red mb-2">{ selectedAddress.invoicing.type.charAt(0).toUpperCase() + selectedAddress.invoicing.type.slice(1) + ' Address' }</div>
- <p className="font-medium">{ selectedAddress.invoicing.name }</p>
- <p className="mt-2 text-gray_r-11">{ selectedAddress.invoicing.mobile }</p>
- <p className="mt-1 text-gray_r-11">{ selectedAddress.invoicing.street } { selectedAddress.invoicing.street2 }</p>
- </div>
- ) }
- </div>
-
- <LineDivider/>
-
- <div className="p-4">
- <h2>Metode Pembayaran <span className="font-normal text-gray_r-11">(Wajib dipilih)</span></h2>
- <div className="grid gap-y-3 mt-4">
- { payments.map((payment, index) => (
- <button
- type="button"
- className={"text-left border border-gray_r-6 rounded-md p-3 " + (selectedPayment == payment.name && 'border-yellow_r-10 bg-yellow_r-3')}
- onClick={() => setSelectedPayment(payment.name)}
- key={index}
- >
- <p>{payment.name} - {payment.number}</p>
- <p className="mt-1 text-gray_r-11">PT. Indoteknik Dotcom Gemilang</p>
- </button>
- )) }
- </div>
- </div>
-
- <LineDivider/>
-
- <div className="p-4">
- <h2>Purchase Order</h2>
-
- <div className="mt-4 flex gap-x-3">
- <div className="w-6/12">
- <label className="form-label font-normal">
- Dokumen PO
- </label>
- <input
- type="file"
- className="form-input mt-2 h-12"
- accept="image/*,application/pdf"
- onChange={(e) => setPoFile(e.target.files[0])}
- />
- </div>
- <div className="w-6/12">
- <label className="form-label font-normal">Nomor PO</label>
- <input
- type="text"
- className="form-input mt-2 h-12"
- value={poNumber}
- onChange={(e) => setPoNumber(e.target.value)}
- />
- </div>
- </div>
- <p className="text-caption-2 text-gray_r-11 mt-2">Ukuran dokumen PO Maksimal 5MB</p>
- </div>
-
- <LineDivider/>
-
- <div className="flex gap-x-3 p-4">
- <button
- className="flex-1 btn-yellow"
- onClick={checkout}
- disabled={isLoading}
- >
- { isLoading && 'Loading...' }
- { !isLoading && 'Bayar' }
- </button>
- </div>
- </>
- ) }
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/product/[slug].js b/src2/pages/shop/product/[slug].js
deleted file mode 100644
index 61692c1c..00000000
--- a/src2/pages/shop/product/[slug].js
+++ /dev/null
@@ -1,305 +0,0 @@
-import Link from "@/components/elements/Link"
-import { useRouter } from "next/router"
-import { useEffect, useState } from "react"
-import Header from "@/components/layouts/Header"
-import apiOdoo from "@/core/utils/apiOdoo"
-import { createSlug, getIdFromSlug } from "@/core/utils/slug"
-import currencyFormat from "@/core/utils/currencyFormat"
-import Layout from "@/components/layouts/Layout"
-import { createOrUpdateItemCart } from "@/core/utils/cart"
-import toast from "react-hot-toast"
-import Footer from "@/components/layouts/Footer"
-import Image from "@/components/elements/Image"
-import LineDivider from "@/components/elements/LineDivider"
-import { HeartIcon as HeartIconSolid } from "@heroicons/react/24/solid"
-import { useAuth } from "@/core/utils/auth"
-import { HeartIcon } from "@heroicons/react/24/outline"
-import LazyLoad from "react-lazy-load"
-import ProductSimilar from "@/components/products/ProductSimilar"
-
-export async function getServerSideProps( context ) {
- const { slug } = context.query
- let product = await apiOdoo('GET', '/api/v1/product/' + getIdFromSlug(slug))
- if (product?.length == 1) {
- product = product[0]
- product.description = product.description.replaceAll('<p>', '||p||')
- product.description = product.description.replaceAll('</p>', '||/p||')
- product.description = product.description.replace(/(<([^>]+)>)/gi, ' ')
- product.description = product.description.replaceAll('||p||', '<p>')
- product.description = product.description.replaceAll('||/p||', '</p>')
- product.description = product.description.trim()
- }
- return { props: { product } }
-}
-
-export default function ProductDetail({ product }) {
- const [ auth ] = useAuth()
- const router = useRouter()
- const { slug } = router.query
- const [selectedVariant, setSelectedVariant] = useState("")
- const [quantity, setQuantity] = useState("1")
- const [activeVariant, setActiveVariant] = useState({
- id: product.id,
- code: product.code,
- price: product.lowest_price,
- stock: product.stock_total,
- weight: product.weight,
- attributes: '',
- })
-
- const [ isAddedToWishlist, setAddedToWishlist ] = useState(false)
- const [ activeTab, setActiveTab ] = useState('specification')
-
- const addOrDeleteWishlist = async () => {
- if (auth) {
- await apiOdoo('POST', `/api/v1/user/${auth.id}/wishlist/create-or-delete`, {
- product_id: product.id
- })
- if (isAddedToWishlist) {
- toast.success('Berhasil menghapus dari wishlist')
- } else {
- toast.success('Berhasil menambahkan ke wishlist')
- }
- setAddedToWishlist(!isAddedToWishlist)
- } else {
- toast.error('Login terlebih dahulu untuk melanjutkan')
- router.push('/login')
- }
- }
-
- useEffect(() => {
- if (auth) {
- const checkWishlist = async () => {
- const wishlist = await apiOdoo('GET', `/api/v1/user/${auth.id}/wishlist?product_id=${product.id}`)
- setAddedToWishlist(wishlist.product_total > 0 ? true : false)
- }
- checkWishlist()
- }
- }, [ auth, product ])
-
- useEffect(() => {
- if (product.variants.length == 1) {
- setSelectedVariant(product.variants[0].id)
- }
- }, [ product ])
-
- useEffect(() => {
- if (selectedVariant != '') {
- let newActiveVariant = product.variants.filter((variant) => {
- return variant.id == selectedVariant
- })
-
- if (newActiveVariant.length == 1) {
- newActiveVariant = newActiveVariant[0]
- setActiveVariant({
- id: newActiveVariant.id,
- code: newActiveVariant.code,
- price: newActiveVariant.price,
- stock: newActiveVariant.stock,
- weight: newActiveVariant.weight,
- attributes: newActiveVariant.attributes.join(', '),
- })
- }
- }
- }, [selectedVariant, product])
-
- const onchangeVariant = (e) => {
- setSelectedVariant(e.target.value)
- }
-
- const onChangeQuantity = (e) => {
- let inputValue = e.target.value
- inputValue = parseInt(inputValue)
- inputValue = Math.floor(inputValue)
- setQuantity(inputValue)
- }
-
- const addItemToCart = () => {
- if (product.variant_total > 1 && !selectedVariant) {
- toast.error('Pilih varian terlebih dahulu untuk menambahkan ke keranjang', { duration: 2000 })
- return false
- }
-
- if (quantity > 0) {
- toast.success('Berhasil menambahkan ke keranjang', { duration: 1500 })
- createOrUpdateItemCart(activeVariant.id, parseInt(quantity))
- } else {
- toast.error('Jumlah barang yang ditambahkan minimal 1 pcs', { duration: 2000 })
- }
-
- return true
- }
-
- const checkoutProduct = () => {
- if (!auth) {
- toast.error('Login terlebih dahulu untuk melanjutkan', { duration: 2000 })
- router.push('/login')
- return
- }
- if (product.variant_total > 1 && !selectedVariant) {
- toast.error('Pilih varian terlebih dahulu untuk melanjutkan pembelian', { duration: 2000 })
- return
- }
- if (quantity < 0) {
- toast.error('Jumlah barang yang ditambahkan minimal 1 pcs', { duration: 2000 })
- return
- }
- router.push(`/shop/checkout?product_id=${activeVariant.id}&qty=${quantity}`)
- }
-
- const TabButton = ({ children, name }) => (
- <button
- type="button"
- className={`font-medium pb-1 ${activeTab == name ? 'text-red_r-11 border-b border-red_r-10' : 'text-gray_r-11'}`}
- onClick={() => setActiveTab(name)}
- >
- { children }
- </button>
- )
-
- return (
- <>
- <Header title={`${product.name} - Indoteknik`}/>
- <Layout>
- <Image
- src={product.image}
- alt={product.name}
- className="border-b border-gray_r-6 w-full h-[300px] object-contain object-center bg-white"
- />
-
- <div className="p-4">
- <div className="flex justify-between gap-x-3">
- <div>
- <Link href={'/shop/brands/' + createSlug(product.manufacture.name, product.manufacture.id)}>
- {product.manufacture.name ?? '-'}
- </Link>
- <h1 className="h2 mt-2 mb-3">{product.name}{activeVariant.attributes ? ' - ' + activeVariant.attributes : ''}</h1>
- </div>
- <button className="h-fit" onClick={addOrDeleteWishlist}>
- { isAddedToWishlist && (
- <HeartIconSolid className="w-6 text-red_r-10" />
- ) }
- { !isAddedToWishlist && (
- <HeartIcon className="w-6" />
- ) }
- </button>
- </div>
-
- {product.variant_total > 1 && !selectedVariant && product.lowest_price.price > 0 ? (
- <p className="text-caption-2 text-gray-800 mb-1">Harga mulai dari:</p>
- ) : ''}
-
- {product.lowest_price.discount_percentage > 0 ? (
- <div className="flex gap-x-1 items-center mb-1">
- <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(activeVariant.price.price)}</p>
- <span className="badge-solid-red">{activeVariant.price.discount_percentage}%</span>
- </div>
- ) : ''}
-
- {product.lowest_price.price > 0 ? (
- <p className="text-body-lg font-semibold">{currencyFormat(activeVariant.price.price_discount)}</p>
- ) : (
- <p className="text-gray_r-11">Dapatkan harga terbaik, <a href="">hubungi kami.</a></p>
- )}
- </div>
-
- <LineDivider />
-
- <div className="p-4">
- <div className="">
- <label className="form-label mb-2">Pilih: <span className="text-gray_r-11 font-normal">{product.variant_total} Varian</span></label>
- <select name="variant" className="form-input" value={selectedVariant} onChange={onchangeVariant} >
- <option value="" disabled={selectedVariant != "" ? true : false}>Pilih Varian...</option>
- {product.variants.length > 1 ? (
- product.variants.map((variant) => {
- return (
- <option key={variant.id} value={variant.id}>{variant.attributes.join(', ')}</option>
- )
- })
- ) : (
- <option key={product.variants[0].id} value={product.variants[0].id}>{product.variants[0].name}</option>
- )}
- </select>
- </div>
-
- <label htmlFor="quantity" className="form-label mb-1 mt-3">Jumlah</label>
- <div className="flex gap-x-2 mt-2">
- <input type="number" name="quantity" id="quantity" className="form-input h-full w-5/12 text-center" value={quantity} onChange={onChangeQuantity} />
-
- <button
- className="btn-yellow w-full"
- onClick={addItemToCart}
- disabled={(product.lowest_price.price == 0 ? true : false)}
- >
- Keranjang
- </button>
- <button
- onClick={checkoutProduct}
- className="btn-solid-red w-full"
- >
- Beli
- </button>
- </div>
- </div>
-
- <LineDivider />
-
- <div className="p-4">
- <h2 className="font-bold mb-4">Informasi Produk</h2>
- <div className="flex gap-x-3 mb-4">
- <TabButton name="specification">Spesifikasi</TabButton>
- <TabButton name="description">Deskripsi</TabButton>
- <TabButton name="information">Info Penting</TabButton>
- </div>
-
- <div className={`border border-gray_r-6 rounded divide-y ${activeTab == 'specification' ? 'block' : 'hidden'}`}>
- <ProductSpecification label="Jumlah Varian">
- <p className="text-gray-800">{product.variant_total} Varian</p>
- </ProductSpecification>
- <ProductSpecification label="Nomor SKU">
- <p className="text-gray-800" id="sku_number">SKU-{activeVariant.id}</p>
- </ProductSpecification>
- <ProductSpecification label="Part Number">
- <p className="text-gray-800" id="part_number">{activeVariant.code}</p>
- </ProductSpecification>
- <ProductSpecification label="Stok">
- <div className="flex gap-x-2" id="stock">
- {activeVariant.stock > 0 ? (activeVariant.stock > 5 && (
- <>
- <div className="badge-solid-red">Ready Stock</div>
- <div className="badge-gray">{activeVariant.stock > 5 ? '> 5' : '< 5'}</div>
- </>
- )) : '0'}
- </div>
- </ProductSpecification>
- <ProductSpecification label="Part Number">
- <p className="text-gray-800" id="weight">{activeVariant.weight > 0 ? activeVariant.weight : '1'} KG</p>
- </ProductSpecification>
- </div>
-
- <div
- className={`text-gray-800 leading-7 ${activeTab == 'description' ? 'block' : 'hidden'}`}
- dangerouslySetInnerHTML={{__html: (product.description != '' ? product.description : 'Belum ada deskripsi produk.')}}
- ></div>
- </div>
-
- <LineDivider />
-
- <LazyLoad>
- <ProductSimilar productId={getIdFromSlug(slug || '')} />
- </LazyLoad>
-
- <Footer />
- </Layout>
- </>
- )
-}
-
-const ProductSpecification = ({ children, ...props }) => {
- return (
- <div className="flex p-3 justify-between items-center gap-x-1">
- <h3 className="text-gray-900">{ props.label }</h3>
- { children }
- </div>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/quotation/finish.js b/src2/pages/shop/quotation/finish.js
deleted file mode 100644
index f7983fef..00000000
--- a/src2/pages/shop/quotation/finish.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import WithAuth from "@/components/auth/WithAuth";
-import Link from "@/components/elements/Link";
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-import { useAuth } from "@/core/utils/auth";
-import { EnvelopeIcon } from "@heroicons/react/24/outline";
-import { useRouter } from "next/router";
-
-export default function FinishQuotation() {
- const router = useRouter();
- const { id } = router.query;
- const [ auth ] = useAuth();
-
- return (
- <WithAuth>
- <Layout>
- <Header title="Penawaran Harga" />
-
- <div className="m-4 px-4 py-6 shadow-md border border-gray_r-3">
- <div className="flex">
- <span className="p-3 mx-auto bg-yellow_r-3 border border-yellow_r-6 rounded">
- <EnvelopeIcon className="w-8 text-yellow_r-11" />
- </span>
- </div>
- <p className="h2 text-center mt-6">
- Terima Kasih { auth?.name }
- </p>
- <p className="text-center mt-3 leading-6 text-gray_r-11">
- Penawaran harga kamu di Indoteknik.com berhasil dikirimkan, tim kami akan segera menghubungi anda.
- </p>
- { id && (
- <Link href={`/my/transaction/${id}`} className="btn-yellow text-gray_r-12 mt-6 w-full">Lihat Penawaran</Link>
- )}
- <Link href="/" className="btn-light text-gray_r-12 mt-2 w-full">Ke Halaman Utama</Link>
- </div>
- </Layout>
- </WithAuth>
- );
-} \ No newline at end of file
diff --git a/src2/pages/shop/quotation/index.js b/src2/pages/shop/quotation/index.js
deleted file mode 100644
index e1c196db..00000000
--- a/src2/pages/shop/quotation/index.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import WithAuth from "@/components/auth/WithAuth";
-import LineDivider from "@/components/elements/LineDivider";
-import Link from "@/components/elements/Link";
-import AppBar from "@/components/layouts/AppBar";
-import Layout from "@/components/layouts/Layout";
-import VariantCard from "@/components/variants/VariantCard";
-import apiOdoo from "@/core/utils/apiOdoo";
-import { useAuth } from "@/core/utils/auth";
-import { deleteItemCart, getCart } from "@/core/utils/cart";
-import currencyFormat from "@/core/utils/currencyFormat";
-import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
-import { toast } from "react-hot-toast";
-
-export default function Quotation() {
- const router = useRouter();
- const [ auth ] = useAuth();
- const [ products, setProducts ] = useState([]);
- const [ totalAmount, setTotalAmount ] = useState(0);
- const [ totalDiscountAmount, setTotalDiscountAmount ] = useState(0);
-
- useEffect(() => {
- const getProducts = async () => {
- let cart = getCart();
- let productIds = Object
- .values(cart)
- .filter((itemCart) => itemCart.selected == true)
- .map((itemCart) => itemCart.product_id);
- if (productIds.length > 0) {
- productIds = productIds.join(',');
- let dataProducts = await apiOdoo('GET', `/api/v1/product_variant/${productIds}`);
- dataProducts = dataProducts.map((product) => ({
- ...product,
- quantity: cart[product.id].quantity,
- selected: cart[product.id].selected,
- }));
- setProducts(dataProducts);
- }
- };
- getProducts();
- }, [ router, auth ]);
-
- useEffect(() => {
- if (products) {
- let calculateTotalAmount = 0;
- let calculateTotalDiscountAmount = 0;
- products.forEach(product => {
- calculateTotalAmount += product.price.price * product.quantity;
- calculateTotalDiscountAmount += (product.price.price - product.price.price_discount) * product.quantity;
- });
- setTotalAmount(calculateTotalAmount);
- setTotalDiscountAmount(calculateTotalDiscountAmount);
- }
- }, [products]);
-
- const submitQuotation = async () => {
- let productOrder = products.map((product) => ({ 'product_id': product.id, 'quantity': product.quantity }));
- let data = {
- 'partner_shipping_id': auth.partner_id,
- 'partner_invoice_id': auth.partner_id,
- 'order_line': JSON.stringify(productOrder)
- };
- const quotation = await apiOdoo('POST', `/api/v1/partner/${auth.partner_id}/sale_order/checkout`, data);
- for (const product of products) {
- deleteItemCart(product.id);
- }
- if (quotation?.id) {
- router.push(`/shop/quotation/finish?id=${quotation.id}`);
- return;
- };
- toast.error('Terdapat kesalahan internal, hubungi kami');
- }
- return (
- <WithAuth>
- <Layout>
- <AppBar title="Penawaran Harga" />
-
- <div className="p-4 flex flex-col gap-y-4">
- <p className="h2">Produk</p>
- {products.map((product, index) => (
- <VariantCard
- data={product}
- openOnClick={false}
- key={index}
- />
- ))}
- </div>
-
- <LineDivider />
-
- <div className="p-4">
- <div className="flex justify-between items-center">
- <p className="h2">Ringkasan Penawaran</p>
- <p className="text-gray_r-11 text-caption-1">{products.length} Barang</p>
- </div>
- <hr className="my-4 border-gray_r-6"/>
- <div className="flex flex-col gap-y-4">
- <div className="flex gap-x-2 justify-between">
- <p>Total Belanja</p>
- <p className="font-medium">{currencyFormat(totalAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>Total Diskon</p>
- <p className="font-medium text-red_r-11">{'- ' + currencyFormat(totalDiscountAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>Subtotal</p>
- <p className="font-medium">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
- </div>
- <div className="flex gap-x-2 justify-between">
- <p>PPN 11% (Incl.)</p>
- <p className="font-medium">{currencyFormat((totalAmount - totalDiscountAmount) * 0.11)}</p>
- </div>
- </div>
- <hr className="my-4 border-gray_r-6"/>
- <div className="flex gap-x-2 justify-between mb-4">
- <p>Grand Total</p>
- <p className="font-medium text-yellow_r-11">{currencyFormat(totalAmount - totalDiscountAmount)}</p>
- </div>
- <p className="text-caption-2 text-gray_r-10 mb-2">*) Belum termasuk biaya pengiriman</p>
- <p className="text-caption-2 text-gray_r-10 leading-5">
- Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui <Link href="/">Syarat & Ketentuan</Link> yang berlaku
- </p>
- </div>
-
- <LineDivider />
-
- <div className="p-4">
- <button
- type="button"
- className="btn-yellow w-full"
- onClick={submitQuotation}
- >
- Kirim Penawaran
- </button>
- </div>
- </Layout>
- </WithAuth>
- )
-} \ No newline at end of file
diff --git a/src2/pages/shop/search.js b/src2/pages/shop/search.js
deleted file mode 100644
index 4152bd43..00000000
--- a/src2/pages/shop/search.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import axios from "axios";
-import Header from "@/components/layouts/Header";
-import Layout from "@/components/layouts/Layout";
-import Pagination from "@/components/elements/Pagination";
-import ProductCard from "@/components/products/ProductCard";
-import FilterIcon from "@/icons/filter.svg";
-import { useEffect, useState } from "react";
-import Filter from "@/components/elements/Filter";
-import Footer from "@/components/layouts/Footer";
-
-export async function getServerSideProps(context) {
- const {
- q = '*',
- page = 1,
- brand = '',
- category = '',
- price_from = '',
- price_to = '',
- order_by = '',
- } = context.query;
-
- let urlParameter = [
- `page=${page}`,
- `brand=${brand}`,
- `category=${category}`,
- `price_from=${price_from}`,
- `price_to=${price_to}`,
- `order_by=${order_by}`
- ].join('&');
- let searchResults = await axios(`${process.env.SELF_HOST}/api/shop/search?q=${q}&${urlParameter}`);
- searchResults = searchResults.data;
- return { props: { searchResults, q, page, brand, category, price_from, price_to, order_by } };
-}
-
-export default function ShopSearch({
- searchResults,
- q,
- page,
- brand,
- category,
- price_from,
- price_to,
- order_by
-}) {
- const pageCount = Math.ceil(searchResults.response.numFound / searchResults.responseHeader.params.rows);
- const productStart = searchResults.responseHeader.params.start;
- const productRows = searchResults.responseHeader.params.rows;
- const productFound = searchResults.response.numFound;
-
- // Variable for <Filter/> props state
- const [activeFilter, setActiveFilter] = useState(false);
- const [filterCount, setFilterCount] = useState(0);
-
- const route = () => {
- let route = `/shop/search?q=${q}`;
- if (brand) route += `&brand=${brand}`;
- if (category) route += `&category=${category}`;
- if (price_from) route += `&price_from=${price_from}`;
- if (price_to) route += `&price_to=${price_to}`;
- if (order_by) route += `&order_by=${order_by}`;
- return route;
- }
-
- useEffect(() => {
- let calculateFilterCount = 0;
- if (brand) calculateFilterCount++;
- if (category) calculateFilterCount++;
- if (price_from || price_to) calculateFilterCount++;
- if (order_by) calculateFilterCount++;
- setFilterCount(calculateFilterCount);
- }, [brand, category, price_from, price_to, order_by]);
-
- return (
- <>
- <Header title={`Jual ${q} - Indoteknik`} />
- <Filter
- defaultRoute={`/shop/search?q=${q}`}
- isActive={activeFilter}
- closeFilter={() => setActiveFilter(false)}
- defaultPriceFrom={price_from}
- defaultPriceTo={price_to}
- defaultBrand={brand}
- defaultCategory={category}
- defaultOrderBy={order_by}
- searchResults={searchResults}
- />
- <Layout>
- <div className="p-4">
- <h1 className="mb-2">Produk</h1>
- <div className="text-caption-1 mb-4">
- {productFound > 0 ? (
- <>
- Menampilkan&nbsp;
- {pageCount > 1 ? (
- <>
- {productStart + 1}-{
- (productStart + productRows) > productFound ? productFound : productStart + productRows
- }
- &nbsp;dari&nbsp;
- </>
- ) : ''}
- {searchResults.response.numFound}
- &nbsp;produk { q != '*' && (<>untuk pencarian <span className="font-semibold">{q}</span></>) }
- </>
- ) : 'Mungkin yang anda cari'}
- </div>
- <button className="btn-light py-2 flex items-center gap-x-2 mb-4" onClick={() => setActiveFilter(true)}>
- <FilterIcon className="w-4 h-4" /> <span>Filter {filterCount > 0 ? `(${filterCount})` : ''}</span>
- </button>
- <div className="grid grid-cols-2 gap-3">
- {searchResults.response.products.map((product) => (
- <ProductCard key={product.id} data={product} />
- ))}
- </div>
-
- <div className="mt-4">
- <Pagination pageCount={pageCount} currentPage={parseInt(page)} url={route()} />
- </div>
- </div>
-
- <Footer />
- </Layout>
- </>
- )
-} \ No newline at end of file
diff --git a/src2/styles/globals.css b/src2/styles/globals.css
deleted file mode 100644
index b871a325..00000000
--- a/src2/styles/globals.css
+++ /dev/null
@@ -1,468 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-* {
- -webkit-tap-highlight-color: transparent;
-}
-
-html, body {
- @apply
- w-screen
- text-body-2
- text-gray_r-12
- bg-gray_r-1
- overflow-x-clip
- ;
-}
-
-@layer base {
- input[type="number"]::-webkit-inner-spin-button,
- input[type="number"]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
-
- input[type=number] {
- -moz-appearance:textfield;
- }
-
- h1, .h1 {
- @apply
- text-h-md
- font-semibold
- ;
- }
-
- h2, .h2 {
- @apply
- text-body-2
- font-semibold
- leading-6
- ;
- }
-
- a {
- @apply
- font-medium
- text-red_r-11
- ;
- }
-}
-
-@layer components {
- .badge-red,
- .badge-solid-red,
- .badge-gray,
- .badge-yellow,
- .badge-blue,
- .badge-green,
- .badge-solid-green {
- @apply
- text-caption-2
- leading-none
- font-medium
- px-1
- py-1
- rounded
- w-fit
- ;
- }
-
- .badge-red {
- @apply
- bg-red_r-5
- text-red_r-10
- ;
- }
-
- .badge-solid-red {
- @apply
- bg-red_r-10
- text-white
- ;
- }
-
- .badge-gray {
- @apply
- bg-gray_r-5
- text-gray_r-10
- ;
- }
-
- .badge-yellow {
- @apply
- bg-yellow_r-3
- text-yellow_r-11
- ;
- }
-
- .badge-blue {
- @apply
- bg-blue-200
- text-blue-600
- ;
- }
-
- .badge-green {
- @apply
- bg-green_r-5
- text-green_r-10
- ;
- }
-
- .badge-solid-green {
- @apply
- bg-green_r-10
- text-white
- ;
- }
-
- .form-label {
- @apply
- font-medium
- block
- ;
- }
-
- .form-input {
- @apply
- p-3
- rounded
- border
- text-gray_r-12
- border-gray_r-7
- bg-transparent
- w-full
- leading-none
- focus:outline-none
- focus:border-yellow_r-9
- disabled:bg-gray_r-5
- ;
- }
-
- .form-input[aria-invalid] {
- @apply
- border-red_r-10
- focus:border-red_r-10
- ;
- }
-
- .btn-yellow,
- .btn-light,
- .btn-red,
- .btn-solid-red,
- .btn-green {
- @apply
- block
- w-fit
- py-3
- px-6
- rounded
- border
- text-center
- font-medium
- ease-linear
- duration-150
- ;
- }
-
- .btn-yellow {
- @apply
- bg-yellow_r-9
- border-yellow_r-9
- disabled:text-gray_r-10
- disabled:bg-yellow_r-7
- disabled:border-yellow_r-7
- ;
- }
-
- .btn-red {
- @apply
- bg-red_r-3
- border-red_r-6
- text-red_r-11
- disabled:text-red_r-10
- disabled:bg-red_r-6
- ;
- }
-
- .btn-solid-red {
- @apply
- bg-red_r-11
- border-red_r-11
- text-gray_r-1
- disabled:text-gray_r-1
- disabled:bg-red_r-8
- disabled:border-red_r-8
- ;
- }
-
- .btn-green {
- @apply
- bg-green_r-3
- border-green_r-6
- text-green_r-11
- disabled:text-green_r-10
- disabled:bg-green_r-6
- ;
- }
-
- .btn-light {
- @apply
- bg-gray_r-3
- border-gray_r-6
- disabled:text-gray_r-10
- disabled:bg-gray_r-6
- ;
- }
-
- .product-card {
- @apply
- w-full
- h-full
- border
- border-gray_r-3
- shadow
- bg-white
- rounded
- relative
- flex
- flex-col
- ;
- }
-
- .product-card__image {
- @apply
- w-full
- h-[160px]
- object-contain
- object-center
- border-b
- border-gray_r-6
- ;
- }
-
- .product-card__content {
- @apply
- p-2
- pb-3
- flex-1
- ;
- }
-
- .product-card__title {
- @apply
- text-caption-1
- text-gray_r-12
- leading-5
- ;
- }
-
- .product-card__brand {
- @apply
- text-caption-1
- mb-1
- block
- ;
- }
-}
-
-@layer utilities {
- .wrap-line-ellipsis-1,
- .wrap-line-ellipsis-2,
- .wrap-line-ellipsis-3 {
- display: -webkit-box;
- -webkit-box-orient: vertical;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .wrap-line-ellipsis-1 {
- -webkit-line-clamp: 1;
- }
-
- .wrap-line-ellipsis-2 {
- -webkit-line-clamp: 2;
- }
-
- .wrap-line-ellipsis-3 {
- -webkit-line-clamp: 3;
- }
-}
-
-.menu-wrapper {
- @apply
- fixed
- top-0
- left-0
- bg-white
- w-[80%]
- h-full
- z-[60]
- overflow-y-auto
- translate-x-[-100%]
- ease-linear
- duration-150
- ;
-}
-
-.menu-wrapper.active{
- @apply translate-x-0;
-}
-
-.menu-overlay {
- @apply
- fixed
- top-0
- left-0
- w-full
- h-full
- z-[55]
- bg-gray_r-12/40
- ;
-}
-
-.sticky-header {
- @apply
- px-4
- py-3
- bg-gray_r-1/90
- backdrop-blur-lg
- sticky
- top-0
- border-b
- border-gray_r-7
- z-50
- ;
-}
-
-.content-container {
- @apply
- max-w-full
- overflow-x-hidden
- ;
-}
-
-#indoteknik_toast {
- @apply
- fixed
- bottom-4
- translate-y-[200%]
- left-[50%]
- translate-x-[-50%]
- z-[100]
- flex
- items-center
- p-4
- mb-4
- w-[90%]
- text-gray-500
- bg-white
- border
- border-gray-300
- rounded-lg
- shadow
- ease-linear
- duration-300
- ;
-}
-
-#indoteknik_toast.active {
- @apply translate-y-0;
-}
-
-.category-menu {
- @apply hidden;
-}
-
-.swiper-slide {
- @apply !h-auto;
-}
-
-.lazy-load-image-background {
- @apply
- !block
- w-full
- ;
-}
-
-.swiper-pagination-bullet-active {
- @apply !bg-red_r-11;
-}
-
-.pagination {
- @apply
- flex
- justify-center
- gap-x-1
- ;
-}
-
-.pagination-item {
- @apply
- p-1
- flex
- justify-center
- items-center
- w-10
- rounded
- ease-linear
- duration-150
- border
- border-gray_r-6
- bg-gray_r-3
- hover:bg-gray_r-5
- text-gray_r-12
- ;
-}
-
-.pagination-item--active {
- @apply
- border-yellow_r-9
- bg-yellow_r-9
- ;
-}
-
-.pagination-dots {
- @apply
- p-1
- flex
- justify-center
- items-end
- w-10
- rounded
- ease-linear
- bg-gray_r-3
- text-caption-2
- ;
-}
-
-.idt-transition {
- @apply
- transition-all
- ease-linear
- duration-300
- ;
-}
-
-.form-select__placeholder {
- @apply
- !text-gray_r-9
- ;
-}
-
-.form-select__control {
- @apply
- !shadow-none
- !border-gray_r-7
- ;
-}
-
-.form-select__control--menu-is-open {
- @apply
- !border-yellow_r-9
- ;
-} \ No newline at end of file