From f99e0aba70efad0deb907d8e27f09fc9f527c8a4 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 17 Feb 2023 17:07:50 +0700 Subject: Refactor --- src2/pages/404.js | 27 +++ src2/pages/_app.js | 31 ++++ src2/pages/_error.js | 11 ++ src2/pages/activate.js | 111 ++++++++++++ src2/pages/api/activation-request.js | 31 ++++ src2/pages/api/activation.js | 16 ++ src2/pages/api/login.js | 15 ++ src2/pages/api/register.js | 15 ++ src2/pages/api/shop/search.js | 96 +++++++++++ src2/pages/api/shop/suggest.js | 12 ++ src2/pages/api/token.js | 10 ++ src2/pages/faqs.js | 91 ++++++++++ src2/pages/index.js | 106 ++++++++++++ src2/pages/login.js | 97 +++++++++++ src2/pages/logout.js | 14 ++ src2/pages/my/address/[id]/edit.js | 249 +++++++++++++++++++++++++++ src2/pages/my/address/create.js | 234 +++++++++++++++++++++++++ src2/pages/my/address/index.js | 84 +++++++++ src2/pages/my/invoice/[id].js | 149 ++++++++++++++++ src2/pages/my/invoices.js | 180 +++++++++++++++++++ src2/pages/my/menu.js | 82 +++++++++ src2/pages/my/profile.js | 134 +++++++++++++++ src2/pages/my/transaction/[id].js | 265 ++++++++++++++++++++++++++++ src2/pages/my/transactions.js | 198 +++++++++++++++++++++ src2/pages/my/wishlist.js | 60 +++++++ src2/pages/register.js | 100 +++++++++++ src2/pages/shop/brands/[slug].js | 178 +++++++++++++++++++ src2/pages/shop/brands/index.js | 79 +++++++++ src2/pages/shop/cart.js | 282 ++++++++++++++++++++++++++++++ src2/pages/shop/checkout/finish.js | 47 +++++ src2/pages/shop/checkout/index.js | 325 +++++++++++++++++++++++++++++++++++ src2/pages/shop/product/[slug].js | 305 ++++++++++++++++++++++++++++++++ src2/pages/shop/quotation/finish.js | 39 +++++ src2/pages/shop/quotation/index.js | 140 +++++++++++++++ src2/pages/shop/search.js | 125 ++++++++++++++ 35 files changed, 3938 insertions(+) create mode 100644 src2/pages/404.js create mode 100644 src2/pages/_app.js create mode 100644 src2/pages/_error.js create mode 100644 src2/pages/activate.js create mode 100644 src2/pages/api/activation-request.js create mode 100644 src2/pages/api/activation.js create mode 100644 src2/pages/api/login.js create mode 100644 src2/pages/api/register.js create mode 100644 src2/pages/api/shop/search.js create mode 100644 src2/pages/api/shop/suggest.js create mode 100644 src2/pages/api/token.js create mode 100644 src2/pages/faqs.js create mode 100644 src2/pages/index.js create mode 100644 src2/pages/login.js create mode 100644 src2/pages/logout.js create mode 100644 src2/pages/my/address/[id]/edit.js create mode 100644 src2/pages/my/address/create.js create mode 100644 src2/pages/my/address/index.js create mode 100644 src2/pages/my/invoice/[id].js create mode 100644 src2/pages/my/invoices.js create mode 100644 src2/pages/my/menu.js create mode 100644 src2/pages/my/profile.js create mode 100644 src2/pages/my/transaction/[id].js create mode 100644 src2/pages/my/transactions.js create mode 100644 src2/pages/my/wishlist.js create mode 100644 src2/pages/register.js create mode 100644 src2/pages/shop/brands/[slug].js create mode 100644 src2/pages/shop/brands/index.js create mode 100644 src2/pages/shop/cart.js create mode 100644 src2/pages/shop/checkout/finish.js create mode 100644 src2/pages/shop/checkout/index.js create mode 100644 src2/pages/shop/product/[slug].js create mode 100644 src2/pages/shop/quotation/finish.js create mode 100644 src2/pages/shop/quotation/index.js create mode 100644 src2/pages/shop/search.js (limited to 'src2/pages') diff --git a/src2/pages/404.js b/src2/pages/404.js new file mode 100644 index 00000000..1e1850f2 --- /dev/null +++ b/src2/pages/404.js @@ -0,0 +1,27 @@ +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 ( + <> +
+ +
+ Halaman Tidak Ditemukan - Indoteknik +

Halaman tidak ditemukan

+
+ + Kembali ke beranda + + + Tanya admin + +
+
+
+ + ); +} \ No newline at end of file diff --git a/src2/pages/_app.js b/src2/pages/_app.js new file mode 100644 index 00000000..6a40f4e6 --- /dev/null +++ b/src2/pages/_app.js @@ -0,0 +1,31 @@ +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 ( + <> + + + window.scrollTo(0, 0)} + > + + + + ) +} + +export default MyApp diff --git a/src2/pages/_error.js b/src2/pages/_error.js new file mode 100644 index 00000000..107ddf46 --- /dev/null +++ b/src2/pages/_error.js @@ -0,0 +1,11 @@ +import Header from "@/components/layouts/Header"; +import Layout from "@/components/layouts/Layout"; + +export default function Error() { + return ( + +
+ + + ); +} \ No newline at end of file diff --git a/src2/pages/activate.js b/src2/pages/activate.js new file mode 100644 index 00000000..d9b41bf4 --- /dev/null +++ b/src2/pages/activate.js @@ -0,0 +1,111 @@ +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, kembali ke beranda., + type: 'success' + }); + } else { + setAlert({ + component: <>Mohon maaf token sudah tidak aktif, lakukan permintaan aktivasi akun kembali atau masuk 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, daftar sekarang., + type: 'info' + }); + break; + case 'ACTIVE': + setAlert({ + component: <>Email tersebut sudah terdaftar dan sudah aktif, masuk sekarang., + type: 'info' + }); + break; + } + } + setIsLoading(false); + } + return ( + <> + + Aktivasi Akun Indoteknik + + + + Logo Indoteknik + +

Aktivasi Akun Indoteknik Anda

+

Link aktivasi akan dikirimkan melalui email

+ {alert ? ( + {alert.component} + ) : ''} +
+ setEmail(e.target.value)} + autoFocus + /> + +
+
+ + ) +} \ No newline at end of file diff --git a/src2/pages/api/activation-request.js b/src2/pages/api/activation-request.js new file mode 100644 index 00000000..3f33875c --- /dev/null +++ b/src2/pages/api/activation-request.js @@ -0,0 +1,31 @@ +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: ` +

Permintaan Aktivasi Akun Indoteknik

+
+

Aktivasi akun anda melalui link berikut: Aktivasi Akun

+ ` + }); + } + 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 new file mode 100644 index 00000000..8b22af8d --- /dev/null +++ b/src2/pages/api/activation.js @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000..e02a73cb --- /dev/null +++ b/src2/pages/api/login.js @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000..7c8d8b39 --- /dev/null +++ b/src2/pages/api/register.js @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000..ad986c86 --- /dev/null +++ b/src2/pages/api/shop/search.js @@ -0,0 +1,96 @@ +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 new file mode 100644 index 00000000..6db1a851 --- /dev/null +++ b/src2/pages/api/shop/suggest.js @@ -0,0 +1,12 @@ +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 new file mode 100644 index 00000000..ec048158 --- /dev/null +++ b/src2/pages/api/token.js @@ -0,0 +1,10 @@ +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 new file mode 100644 index 00000000..cdb8ef52 --- /dev/null +++ b/src2/pages/faqs.js @@ -0,0 +1,91 @@ +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 ( + + + +
+ { faqs.map((faq, index) => ( +
+
+
+

{ faq.name }

+

+ { faq.description } +

+
+ +
+ { faq.isOpen && ( +

+ { 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.' } +

+ ) } +
+ )) } +
+
+ ) +} \ No newline at end of file diff --git a/src2/pages/index.js b/src2/pages/index.js new file mode 100644 index 00000000..65999ff6 --- /dev/null +++ b/src2/pages/index.js @@ -0,0 +1,106 @@ +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 ( + <> +
+ + + { + heroBanners?.map((banner, index) => ( + + {banner.name} + + )) + } + +
+

Brand Pilihan

+ + { + manufactures?.manufactures?.map((manufacture, index) => ( + + + + )) + } + +
+
+

Produk Populer

+ +
+ + + +
+
Platform Belanja B2B Alat Teknik & Industri di Indonesia
+

+ 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 +

+
+ +