diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/components/elements/Sidebar/Sidebar.jsx | 37 | ||||
| -rw-r--r-- | src/core/components/layouts/AnimationLayout.jsx | 2 | ||||
| -rw-r--r-- | src/core/components/layouts/AppLayout.jsx | 2 | ||||
| -rw-r--r-- | src/core/hooks/useAuth.js | 3 | ||||
| -rw-r--r-- | src/lib/transaction/api/cancelTransactionApi.js | 8 | ||||
| -rw-r--r-- | src/lib/transaction/api/transactionsApi.js | 8 | ||||
| -rw-r--r-- | src/lib/transaction/components/TransactionStatusBadge.jsx | 45 | ||||
| -rw-r--r-- | src/lib/transaction/components/Transactions.jsx | 149 | ||||
| -rw-r--r-- | src/lib/transaction/hooks/useTransactions.js | 15 | ||||
| -rw-r--r-- | src/lib/transaction/utils/transactions.js | 14 | ||||
| -rw-r--r-- | src/pages/my/menu.jsx | 94 | ||||
| -rw-r--r-- | src/pages/my/transactions.jsx | 12 |
12 files changed, 373 insertions, 16 deletions
diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 74984393..412ed915 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -1,13 +1,22 @@ -import { getAuth } from "@/core/utils/auth" import Link from "../Link/Link" import greeting from "@/core/utils/greeting" import { Cog6ToothIcon } from "@heroicons/react/24/solid" +import useAuth from "@/core/hooks/useAuth" const Sidebar = ({ active, close }) => { - const auth = getAuth() + const auth = useAuth() + + const SidebarLink = ({ children, ...props }) => ( + <Link + {...props} + onClick={close} + >{ children }</Link> + ) + + const itemClassName = 'px-4 py-3 block !text-gray_r-12/80 font-normal' return ( <> @@ -24,29 +33,31 @@ const Sidebar = ({ { auth && ( <> <div className="text-caption-2 text-gray_r-11"> - {/* { greeting() }, */} + { greeting() }, <span className="text-body-2 text-gray_r-12 block mt-1 font-medium"> { auth?.name } </span> </div> - <Link href="/my/menu" className="!text-gray_r-11 ml-auto my-auto"> + <Link + onClick={close} + href="/my/menu" + className="!text-gray_r-11 ml-auto my-auto" + > <Cog6ToothIcon className="w-6" /> </Link> </> ) } </div> - <Link href="/" className="px-4 py-3 block !text-gray_r-12 font-normal"> + <SidebarLink className={itemClassName} href="/"> Semua Brand - </Link> - <Link href="/" className="px-4 py-3 block !text-gray_r-12 font-normal"> + </SidebarLink> + <SidebarLink className={itemClassName} href="/"> Tentang Indoteknik - </Link> - <Link href="/" className="px-4 py-3 block !text-gray_r-12 font-normal"> + </SidebarLink> + <SidebarLink className={itemClassName} href="/"> Pusat Bantuan - </Link> - <Link href="/" className="px-4 py-3 block !text-gray_r-12 font-normal"> - Kategori - </Link> + </SidebarLink> + <button className={`${itemClassName} w-full text-left`}>Kategori</button> </div> </div> </> diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index adb6b081..cf2b06d5 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -2,7 +2,7 @@ import { motion } from 'framer-motion' const AnimationLayout = ({ children, ...props }) => { const transition = { - ease: 'easeOut', + ease: 'easeIn', duration: 0.3 } diff --git a/src/core/components/layouts/AppLayout.jsx b/src/core/components/layouts/AppLayout.jsx index 7aaa52ca..3e986477 100644 --- a/src/core/components/layouts/AppLayout.jsx +++ b/src/core/components/layouts/AppLayout.jsx @@ -4,8 +4,8 @@ import AnimationLayout from "./AnimationLayout" const AppLayout = ({ children, title }) => { return ( <> - <AppBar title={title}/> <AnimationLayout> + <AppBar title={title}/> { children } </AnimationLayout> </> diff --git a/src/core/hooks/useAuth.js b/src/core/hooks/useAuth.js index 488562f6..13f04454 100644 --- a/src/core/hooks/useAuth.js +++ b/src/core/hooks/useAuth.js @@ -1,3 +1,4 @@ +import { useEffect, useState } from "react" import { getAuth } from "../utils/auth" const useAuth = () => { @@ -8,7 +9,7 @@ const useAuth = () => { handleIsAuthenticated() }, []) - return [auth, setAuth] + return auth } export default useAuth
\ No newline at end of file diff --git a/src/lib/transaction/api/cancelTransactionApi.js b/src/lib/transaction/api/cancelTransactionApi.js new file mode 100644 index 00000000..19891b5a --- /dev/null +++ b/src/lib/transaction/api/cancelTransactionApi.js @@ -0,0 +1,8 @@ +import odooApi from "@/core/api/odooApi" + +const cancelTransactionApi = async ({ partnerId, transaction }) => { + const dataCancelTransaction = await odooApi('POST', `/api/v1/partner/${partnerId}/sale_order/${transaction.id}/cancel`) + return dataCancelTransaction +} + +export default cancelTransactionApi
\ No newline at end of file diff --git a/src/lib/transaction/api/transactionsApi.js b/src/lib/transaction/api/transactionsApi.js new file mode 100644 index 00000000..d36c3664 --- /dev/null +++ b/src/lib/transaction/api/transactionsApi.js @@ -0,0 +1,8 @@ +import odooApi from "@/core/api/odooApi" + +const transactionsApi = async ({partnerId, query}) => { + const dataTransactions = await odooApi('GET', `/api/v1/partner/${partnerId}/sale_order?${query}`) + return dataTransactions +} + +export default transactionsApi
\ No newline at end of file diff --git a/src/lib/transaction/components/TransactionStatusBadge.jsx b/src/lib/transaction/components/TransactionStatusBadge.jsx new file mode 100644 index 00000000..28fe714a --- /dev/null +++ b/src/lib/transaction/components/TransactionStatusBadge.jsx @@ -0,0 +1,45 @@ +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/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx new file mode 100644 index 00000000..97eb5f91 --- /dev/null +++ b/src/lib/transaction/components/Transactions.jsx @@ -0,0 +1,149 @@ +import { useRouter } from "next/router" +import { getAuth } from "@/core/utils/auth" +import { useState } from "react" +import { toast } from "react-hot-toast" +import { EllipsisVerticalIcon } from "@heroicons/react/24/outline" + +import { downloadPurchaseOrder, downloadQuotation } from "../utils/transactions" +import useTransactions from "../hooks/useTransactions" +import currencyFormat from "@/core/utils/currencyFormat" +import cancelTransactionApi from "../api/cancelTransactionApi" +import TransactionStatusBadge from "./TransactionStatusBadge" +import Spinner from "@/core/components/elements/Spinner/Spinner" +import Link from "@/core/components/elements/Link/Link" +import BottomPopup from "@/core/components/elements/Popup/BottomPopup" + +const Transactions = () => { + const auth = getAuth() + const router = useRouter() + const { + q = '', + page = 1 + } = router.query + + const { transactions } = useTransactions({ + partnerId: auth?.partnerId, + query: { + name: q, + limit: 30, + offset: (page - 1) * 30 + } + }) + + const [ toOthers, setToOthers ] = useState(null) + const [ toDelete, setToDelete ] = useState(null) + + const submitCancelTransaction = async () => { + const isCancelled = await cancelTransactionApi({ + partnerId: auth.partnerId, + transaction: toDelete + }) + if (isCancelled) { + toast.success('Berhasil batalkan transaksi') + transactions.refetch() + } + setToDelete(null) + } + + return ( + <div className="p-4"> + <div className="flex flex-col gap-y-4"> + { transactions.isLoading && ( + <div className="flex justify-center my-4"> + <Spinner className="w-6 text-gray_r-12/50 fill-gray_r-12" /> + </div> + ) } + { transactions.data?.saleOrders?.map((saleOrder, 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/${saleOrder.id}`}> + <span className="text-caption-2 text-gray_r-11">No. Transaksi</span> + <h2 className="text-red_r-11 mt-1">{ saleOrder.name }</h2> + </Link> + <div className="flex gap-x-1 justify-end"> + <TransactionStatusBadge status={saleOrder.status} /> + <EllipsisVerticalIcon className="w-5 h-5" onClick={() => setToOthers(saleOrder)} /> + </div> + </div> + <Link href={`/my/transaction/${saleOrder.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">{ saleOrder.purchaseOrderName || '-' }</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">{ saleOrder.invoiceCount } 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">{ saleOrder.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(saleOrder.amountTotal) }</p> + </div> + </div> + </Link> + </div> + )) } + </div> + + <BottomPopup title="Lainnya" active={toOthers} close={() => setToOthers(null)}> + <div className="flex flex-col gap-y-4 mt-2"> + <button + className="text-left disabled:opacity-60" + disabled={!toOthers?.purchaseOrderFile} + onClick={() => { downloadPurchaseOrder(auth.partnerId, toOthers); setToOthers(null) }} + > + Download PO + </button> + <button + className="text-left disabled:opacity-60" + disabled={toOthers?.status != 'draft'} + onClick={() => { downloadQuotation(auth.partnerId, toOthers); setToOthers(null) }} + > + Download Quotation + </button> + <button + className="text-left disabled:opacity-60" + disabled={ toOthers?.status != 'waiting' } + onClick={() => { setToDelete(toOthers); setToOthers(null) }} + > + Batalkan Transaksi + </button> + </div> + </BottomPopup> + + <BottomPopup + active={toDelete} + close={() => setToDelete(null)} + title="Batalkan Transaksi" + > + <div className="leading-7 text-gray_r-12/80"> + Apakah anda yakin membatalkan transaksi <span className="underline">{toDelete?.name}</span>? + </div> + <div className="flex mt-6 gap-x-4"> + <button + className="btn-solid-red flex-1" + type="button" + onClick={() => submitCancelTransaction()} + > + Ya, Batalkan + </button> + <button + className="btn-light flex-1" + type="button" + onClick={() => setToDelete(null)} + > + Batal + </button> + </div> + </BottomPopup> + </div> + ) +} + +export default Transactions
\ No newline at end of file diff --git a/src/lib/transaction/hooks/useTransactions.js b/src/lib/transaction/hooks/useTransactions.js new file mode 100644 index 00000000..b5742cae --- /dev/null +++ b/src/lib/transaction/hooks/useTransactions.js @@ -0,0 +1,15 @@ +import { useQuery } from "react-query" +import transactionsApi from "../api/transactionsApi" +import _ from "lodash-contrib" + +const useTransactions = ({ partnerId, query }) => { + const queryString = _.toQuery(query) + const fetchTransactions = async () => await transactionsApi({ partnerId, query: queryString }) + const { data, isLoading, refetch } = useQuery(`transactions-${queryString}`, fetchTransactions) + + return { + transactions: { data, isLoading, refetch } + } +} + +export default useTransactions
\ No newline at end of file diff --git a/src/lib/transaction/utils/transactions.js b/src/lib/transaction/utils/transactions.js new file mode 100644 index 00000000..166e8a7e --- /dev/null +++ b/src/lib/transaction/utils/transactions.js @@ -0,0 +1,14 @@ +const downloadPurchaseOrder = (partnerId, transaction) => { + const url = `${process.env.ODOO_HOST}/api/v1/partner/${partnerId}/sale_order/${transaction.id}/download_po/${transaction.token}` + window.open(url, 'download') +} + +const downloadQuotation = (partnerId, transaction) => { + const url = `${process.env.ODOO_HOST}/api/v1/partner/${partnerId}/sale_order/${transaction.id}/download/${transaction.token}` + window.open(url, 'download') +} + +export { + downloadPurchaseOrder, + downloadQuotation +}
\ No newline at end of file diff --git a/src/pages/my/menu.jsx b/src/pages/my/menu.jsx new file mode 100644 index 00000000..d3edaa3b --- /dev/null +++ b/src/pages/my/menu.jsx @@ -0,0 +1,94 @@ +import Divider from "@/core/components/elements/Divider/Divider" +import Link from "@/core/components/elements/Link/Link" +import AppLayout from "@/core/components/layouts/AppLayout" +import { ChevronRightIcon, UserIcon } from "@heroicons/react/24/solid" + +export default function Menu() { + return ( + <AppLayout title="Menu Utama"> + <Link href="/my/profile" className="p-4 flex items-center"> + <div className="rounded-full p-3 bg-gray_r-6 text-gray_r-12/90"> + <UserIcon className="w-5" /> + </div> + <div className="ml-4"> + <div className="font-semibold text-gray_r-12">Rafi Zadanly</div> + <div className="badge-solid-red mt-1">Akun Bisnis</div> + </div> + <div className="ml-auto !text-gray_r-12"> + <ChevronRightIcon className="w-6" /> + </div> + </Link> + + <Divider /> + + <div className="flex flex-col gap-y-6 py-6"> + <div> + <MenuHeader> + Aktivitas Pembelian + </MenuHeader> + + <div className="divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4"> + <LinkItem href="/my/transactions"> + Daftar Transaksi + </LinkItem> + <LinkItem href="/"> + Invoice & Faktur Pajak + </LinkItem> + <LinkItem href="/"> + Wishlist + </LinkItem> + </div> + </div> + + <div> + <MenuHeader> + Pusat Bantuan + </MenuHeader> + + <div className="divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4"> + <LinkItem href="/"> + Customer Support + </LinkItem> + <LinkItem href="/"> + F.A.Q + </LinkItem> + </div> + </div> + + <div> + <MenuHeader> + Pengaturan Akun + </MenuHeader> + + <div className="divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4"> + <LinkItem href="/"> + Daftar Alamat + </LinkItem> + <LinkItem href="/"> + Ubah Password + </LinkItem> + <LinkItem href="/"> + Keluar Akun + </LinkItem> + </div> + </div> + </div> + </AppLayout> + ) +} + +const MenuHeader = ({ children, ...props }) => ( + <div {...props} className="font-medium px-4 flex"> + { children } + + </div> +) + +const LinkItem = ({ children, ...props }) => ( + <Link {...props} className="!text-gray_r-11 font-normal p-4 flex items-center"> + { children } + <div className="ml-auto !text-gray_r-11"> + <ChevronRightIcon className="w-5" /> + </div> + </Link> +)
\ No newline at end of file diff --git a/src/pages/my/transactions.jsx b/src/pages/my/transactions.jsx new file mode 100644 index 00000000..a530afcc --- /dev/null +++ b/src/pages/my/transactions.jsx @@ -0,0 +1,12 @@ +import AppLayout from "@/core/components/layouts/AppLayout" +import dynamic from "next/dynamic" + +const TransactionsComponent = dynamic(() => import("@/lib/transaction/components/Transactions")) + +export default function Transactions() { + return ( + <AppLayout title="Transaksi"> + <TransactionsComponent /> + </AppLayout> + ) +}
\ No newline at end of file |
