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/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 +++++++++ 10 files changed, 1635 insertions(+) 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 (limited to 'src2/pages/my') diff --git a/src2/pages/my/address/[id]/edit.js b/src2/pages/my/address/[id]/edit.js new file mode 100644 index 00000000..838d39e7 --- /dev/null +++ b/src2/pages/my/address/[id]/edit.js @@ -0,0 +1,249 @@ +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 ( + + + + +
+
+ + +
{ errors.name?.message }
+
+ +
+ + +
{ errors.email?.message }
+
+ +
+ + +
{ errors.mobile?.message }
+
+ +
+ + +
{ errors.street?.message }
+
+ +
+ + +
{ errors.zip?.message }
+
+ +
+ + + )} + /> +
+ +
+ + ( + } + /> +
{ errors.type?.message }
+
+ +
+ + +
{ errors.name?.message }
+
+ +
+ + +
{ errors.email?.message }
+
+ +
+ + +
{ errors.mobile?.message }
+
+ +
+ + +
{ errors.street?.message }
+
+ +
+ + +
{ errors.zip?.message }
+
+ +
+ + + )} + /> +
+ +
+ + ( + + + + +
+ { invoices?.invoice_total === 0 && !isLoading && ( + + Invoice tidak ditemukan + + ) } + { invoices?.invoices?.map((invoice, index) => ( +
+
+ + No. Invoice +

{ invoice.name }

+ +
+ { invoice.amount_residual > 0 ? ( +
Belum Lunas
+ ) : ( +
Lunas
+ ) } + openPopup(invoice)} /> +
+
+ +
+

+ { invoice.invoice_date } +

+

+ { invoice.payment_term } +

+
+
+
+
+ No. Purchase Order +

{ invoice.purchase_order_name || '-' }

+
+
+ Total Invoice +

{ currencyFormat(invoice.amount_total) }

+
+
+ + { invoice.efaktur ? ( +
+ + Faktur Pajak +
+ ) : ( +
+ + Faktur Pajak +
+ ) } +
+ )) } +
+ +
+ +
+ { BottomPopup } + + + ) +} \ No newline at end of file diff --git a/src2/pages/my/menu.js b/src2/pages/my/menu.js new file mode 100644 index 00000000..ae6c2af8 --- /dev/null +++ b/src2/pages/my/menu.js @@ -0,0 +1,82 @@ + +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 ( + + + { icon } + { name } + + + + ); +}; + +export default function MyMenu() { + const [auth] = useAuth(); + + return ( + + + + +
+
+
+ +
+
+

{ auth?.name }

+ { auth?.company ? ( +
Akun Bisnis
+ ) : ( +
Akun Individu
+ ) } +
+
+ + + +
+ +
+

Aktivitas Pembelian

+
+ } name="Daftar Transaksi" url="/my/transactions" /> + } name="Invoice & Faktur Pajak" url="/my/invoices" /> + } name="Wishlist" url="/my/wishlist" /> +
+ +

Pusat Bantuan

+
+ } name="Layanan Pelanggan" url="/" /> + } name="F.A.Q" url="/faqs" /> +
+ +

Pengaturan Akun

+
+ } name="Daftar Alamat" url="/my/address" /> + } name="Keluar Akun" url="/logout" /> +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src2/pages/my/profile.js b/src2/pages/my/profile.js new file mode 100644 index 00000000..97891259 --- /dev/null +++ b/src2/pages/my/profile.js @@ -0,0 +1,134 @@ +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 ( + + + + +
+ { auth && ( + <> + + + + + + + + + + + + + + setPassword(e.target.value)} + disabled={!editMode} + /> + + ) } + + { editMode && ( +
+ + +
+ ) } + + { !editMode && ( + + ) } +
+
+
+ ); +} \ No newline at end of file diff --git a/src2/pages/my/transaction/[id].js b/src2/pages/my/transaction/[id].js new file mode 100644 index 00000000..fb806aa4 --- /dev/null +++ b/src2/pages/my/transaction/[id].js @@ -0,0 +1,265 @@ +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 ( +
+
+ + +
+
+ + +
+ +
+ ); + } + + 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 ( + + + + + { transaction ? ( + <> +
+ +
+ +
+
+ + { transaction?.name } + + + { transaction?.payment_term } + + + { transaction?.sales } + + + { transaction?.date_order } + +
+ + + +
+ + { transaction?.purchase_order_name || '-' } + +
+

Dokumen PO

+ +
+
+ + + +

Detail Produk

+ +
+ +
+

Total Belanja

+

{ currencyFormat(transaction?.amount_total || 0) }

+
+
+ + + + + + + +
+

Invoice

+
+ { transaction?.invoices?.map((invoice, index) => ( + +
+
+

{ invoice?.name }

+
+ { invoice.amount_residual > 0 ? ( +
Belum Lunas
+ ) : ( +
Lunas
+ ) } +

+ { currencyFormat(invoice.amount_total) } +

+
+
+ +
+ + )) } + { transaction?.invoices?.length === 0 && ( + + Belum ada Invoice + + ) } +
+
+ + + +
+ { transaction?.status == 'draft' && ( + + ) } + + { transaction?.status != 'draft' && ( + + ) } +
+ + ) : ( +
+ +
+ ) } + { ConfirmAlert } + { BottomPopup } +
+
+ ); +} \ No newline at end of file diff --git a/src2/pages/my/transactions.js b/src2/pages/my/transactions.js new file mode 100644 index 00000000..8be43af7 --- /dev/null +++ b/src2/pages/my/transactions.js @@ -0,0 +1,198 @@ +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) => ( +
+ + + +
+ ); + + 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 ( + + + + +
+ + +
+ +
+ { transactions?.sale_order_total === 0 && !isLoading && ( + + Transaksi tidak ditemukan + + ) } + { transactions?.sale_orders?.map((transaction, index) => ( +
+
+ + No. Transaksi +

{ transaction.name }

+ +
+ + openPopup(transaction)} /> +
+
+ +
+
+ No. Purchase Order +

{ transaction.purchase_order_name || '-' }

+
+
+ Total Invoice +

{ transaction.invoice_count } Invoice

+
+
+
+
+ Sales +

{ transaction.sales }

+
+
+ Total Harga +

{ currencyFormat(transaction.amount_total) }

+
+
+ +
+ )) } +
+ +
+ +
+ + { ConfirmAlert } + { BottomPopup } +
+
+ ); +}; \ No newline at end of file diff --git a/src2/pages/my/wishlist.js b/src2/pages/my/wishlist.js new file mode 100644 index 00000000..3d479802 --- /dev/null +++ b/src2/pages/my/wishlist.js @@ -0,0 +1,60 @@ +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 ( + + + + +
+ { !wishlists && ( + + ) } + { wishlists?.products?.length == 0 && ( + + Wishlist anda masih kosong + + ) } +
+ {wishlists?.products.map((product) => ( + + ))} +
+ +
+ +
+
+
+
+ ) +} \ No newline at end of file -- cgit v1.2.3