diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-01-25 11:17:37 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-01-25 11:17:37 +0700 |
| commit | ebc09c5062cc7996b0f2aaf879062fc950c2e1c2 (patch) | |
| tree | 3b031b68afa9aaaca156986382670490c32f0e18 /src | |
| parent | ee4297280c1305c7e03bedd4df63ccf136c28c6c (diff) | |
Transaction detail and variant card component
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/elements/DescriptionRow.js | 10 | ||||
| -rw-r--r-- | src/components/elements/Disclosure.js | 14 | ||||
| -rw-r--r-- | src/components/transactions/TransactionDetail.js | 21 | ||||
| -rw-r--r-- | src/components/variants/VariantCard.js | 48 | ||||
| -rw-r--r-- | src/pages/my/transactions/[id].js | 124 | ||||
| -rw-r--r-- | src/pages/my/transactions/[slug].js | 126 | ||||
| -rw-r--r-- | src/pages/shop/checkout.js | 30 | ||||
| -rw-r--r-- | src/styles/globals.css | 4 |
8 files changed, 227 insertions, 150 deletions
diff --git a/src/components/elements/DescriptionRow.js b/src/components/elements/DescriptionRow.js new file mode 100644 index 00000000..7fe9e3a1 --- /dev/null +++ b/src/components/elements/DescriptionRow.js @@ -0,0 +1,10 @@ +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/src/components/elements/Disclosure.js b/src/components/elements/Disclosure.js new file mode 100644 index 00000000..0aaedf87 --- /dev/null +++ b/src/components/elements/Disclosure.js @@ -0,0 +1,14 @@ +const { ChevronUpIcon, ChevronDownIcon } = require("@heroicons/react/24/outline"); + +const Disclosure = ({ label, active, onClick }) => ( + <div className="flex justify-between p-4" onClick={onClick}> + <p className="font-medium leading-normal">{ label }</p> + { onClick && ( active ? ( + <ChevronUpIcon className="w-5 h-5" /> + ) : ( + <ChevronDownIcon className="w-5 h-5" /> + ) ) } + </div> +); + +export default Disclosure;
\ No newline at end of file diff --git a/src/components/transactions/TransactionDetail.js b/src/components/transactions/TransactionDetail.js new file mode 100644 index 00000000..6d304d31 --- /dev/null +++ b/src/components/transactions/TransactionDetail.js @@ -0,0 +1,21 @@ +import DescriptionRow from "../elements/DescriptionRow"; + +const CustomerSection = ({ 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="px-4 pb-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> + ); +}; + +export { + CustomerSection +};
\ No newline at end of file diff --git a/src/components/variants/VariantCard.js b/src/components/variants/VariantCard.js new file mode 100644 index 00000000..cb4d8272 --- /dev/null +++ b/src/components/variants/VariantCard.js @@ -0,0 +1,48 @@ +import { createSlug } from "@/core/utils/slug"; +import Image from "../elements/Image"; +import Link from "../elements/Link"; +import currencyFormat from "@/core/utils/currencyFormat"; + +export default function VariantCard({ + data, + openOnClick = true +}) { + let product = data; + + 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> + <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> + ); + } + + return <Card/>; +}
\ No newline at end of file diff --git a/src/pages/my/transactions/[id].js b/src/pages/my/transactions/[id].js new file mode 100644 index 00000000..79337a29 --- /dev/null +++ b/src/pages/my/transactions/[id].js @@ -0,0 +1,124 @@ +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 { CustomerSection } from "@/components/transactions/TransactionDetail"; + +export default function DetailTransactions() { + const router = useRouter(); + const { id } = router.query; + const [ auth ] = useAuth(); + const [ transaction, setTransaction ] = useState(null); + const [ activeSection, setActiveSection ] = useState({ + purchase: false, + shipping: false, + invoice: false, + }); + + const toggleSection = ( name ) => { + setActiveSection({ + ...activeSection, + [name]: !activeSection[name] + }); + }; + + useEffect(() => { + if (auth) { + const loadTransaction = async () => { + const dataTransaction = await apiOdoo('GET', `/api/v1/partner/${auth?.partner_id}/sale_order/${id}`); + setTransaction(dataTransaction); + } + loadTransaction(); + } + }, [ auth, id ]); + + return ( + <WithAuth> + <Layout className="pb-4"> + <AppBar title="Detail Transaksi" /> + + <div className="p-4 flex flex-col gap-y-4"> + <DescriptionRow label="Status Transaksi"> + <span className="badge-green">Pending Quotation</span> + </DescriptionRow> + <DescriptionRow label="No Transaksi"> + { transaction?.name } + </DescriptionRow> + <DescriptionRow label="Purchase Order"> + { transaction?.po_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 /> + + <Disclosure + label="Detail Produk" + /> + + <div className="mt-2 p-4 pt-0 flex flex-col gap-y-3"> + { transaction?.products?.map((product, index) => ( + <VariantCard + key={index} + data={product} + /> + )) } + <div className="flex justify-between mt-3 font-medium"> + <p>Total Belanja</p> + <p>{ currencyFormat(transaction?.amount_total || 0) }</p> + </div> + </div> + + + <LineDivider /> + + <Disclosure + label="Detail Pembeli" + active={activeSection.purchase} + onClick={() => toggleSection('purchase')} + /> + { activeSection.purchase && ( + <CustomerSection address={transaction?.address?.customer} /> + ) } + + <LineDivider /> + + <Disclosure + label="Detail Pengiriman" + active={activeSection.shipping} + onClick={() => toggleSection('shipping')} + /> + { activeSection.shipping && ( + <CustomerSection address={transaction?.address?.shipping} /> + ) } + + <LineDivider /> + + <Disclosure + label="Detail Penagihan" + active={activeSection.invoice} + onClick={() => toggleSection('invoice')} + /> + { activeSection.invoice && ( + <CustomerSection address={transaction?.address?.invoice} /> + ) } + </Layout> + </WithAuth> + ); +}
\ No newline at end of file diff --git a/src/pages/my/transactions/[slug].js b/src/pages/my/transactions/[slug].js deleted file mode 100644 index a76b0c4d..00000000 --- a/src/pages/my/transactions/[slug].js +++ /dev/null @@ -1,126 +0,0 @@ -import { ArrowDownOnSquareIcon, ArrowDownTrayIcon, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon } from "@heroicons/react/24/outline"; -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 { useState } from "react"; - -const Row = ({ 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> -); - -const Section = ({ children }) => ( - <div className="px-4 pb-4 flex flex-col gap-y-4"> - { children } - </div> -); - -const TitleRow = ({ label, active, onClick }) => ( - <div className="flex justify-between p-4" onClick={onClick}> - <p className="font-medium leading-normal">{ label }</p> - { onClick && ( active ? ( - <ChevronUpIcon className="w-5 h-5" /> - ) : ( - <ChevronDownIcon className="w-5 h-5" /> - ) ) } - </div> -); - -export default function DetailTransactions() { - const [ activeSection, setActiveSection ] = useState({ - purchase: false, - shipping: false, - invoice: false, - }); - - const toggleSection = ( name ) => { - setActiveSection({ - ...activeSection, - [name]: !activeSection[name] - }); - }; - - return ( - <WithAuth> - <Layout> - <AppBar title="Detail Transaksi" /> - - <div className="text-caption-1"> - <div className="p-4 flex flex-col gap-y-4"> - <Row label="Status Transaksi"> - <span className="badge-green">Pending Quotation</span> - </Row> - <Row label="No Transaksi">SO/2023/03212</Row> - <Row label="Purchase Order">PO/2023/02123</Row> - <Row label="Dokumen PO"><a href="">Download</a></Row> - <Row label="Metode Pembayaran">BCA Transfer</Row> - <Row label="Ketentuan Pembayaran">Cash Before Delivery</Row> - <Row label="Nama Sales">Rafi Zadanly</Row> - <Row label="Waktu Transaksi">01 Januari 2023</Row> - </div> - - <LineDivider /> - - <TitleRow - label="Detail Produk" - active={false} - /> - - <LineDivider /> - - <TitleRow - label="Detail Pembeli" - active={activeSection.purchase} - onClick={() => toggleSection('purchase')} - /> - { activeSection.purchase && ( - <Section> - <Row label="Nama">John Doe</Row> - <Row label="Email">johndoe@gmail.com</Row> - <Row label="No Telepon">081223538754</Row> - <Row label="Alamat">Jalan Bandengan Utara No 85A, Kel. Penjaringan, Kec. Penjaringan, Jakarta Utara</Row> - </Section> - ) } - - <LineDivider /> - - <TitleRow - label="Detail Pengiriman" - active={activeSection.shipping} - onClick={() => toggleSection('shipping')} - /> - { activeSection.shipping && ( - <Section> - <Row label="Nama">John Doe</Row> - <Row label="Email">johndoe@gmail.com</Row> - <Row label="No Telepon">081223538754</Row> - <Row label="Alamat">Jalan Bandengan Utara No 85A, Kel. Penjaringan, Kec. Penjaringan, Jakarta Utara</Row> - </Section> - ) } - - <LineDivider /> - - <TitleRow - label="Detail Penagihan" - active={activeSection.invoice} - onClick={() => toggleSection('invoice')} - /> - { activeSection.invoice && ( - <Section> - <Row label="Nama">John Doe</Row> - <Row label="Email">johndoe@gmail.com</Row> - <Row label="No Telepon">081223538754</Row> - <Row label="Alamat">Jalan Bandengan Utara No 85A, Kel. Penjaringan, Kec. Penjaringan, Jakarta Utara</Row> - </Section> - ) } - - </div> - </Layout> - </WithAuth> - ); -}
\ No newline at end of file diff --git a/src/pages/shop/checkout.js b/src/pages/shop/checkout.js index 1849e0fe..49d1a848 100644 --- a/src/pages/shop/checkout.js +++ b/src/pages/shop/checkout.js @@ -17,6 +17,7 @@ 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(); @@ -201,30 +202,11 @@ export default function Checkout() { <div className="p-4 flex flex-col gap-y-4"> {products.map((product, index) => ( - <div className="flex gap-x-3" key={index}> - <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> - <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> + <VariantCard + data={product} + openOnClick={false} + key={index} + /> ))} </div> diff --git a/src/styles/globals.css b/src/styles/globals.css index 6c0a7607..e43ad1a9 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -4,6 +4,10 @@ @tailwind components; @tailwind utilities; +* { + -webkit-tap-highlight-color: transparent; +} + html, body { @apply w-screen |
