-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Prince Muel <[email protected]>
- Loading branch information
1 parent
abd3311
commit b41ea03
Showing
8 changed files
with
454 additions
and
395 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
import { calculateTotal, formatAmount, hasValues } from "@/helpers/utils"; | ||
import { loader } from "@/routes/invoices.$slug"; | ||
import { useLoaderData } from "@remix-run/react"; | ||
import { format } from "date-fns"; | ||
import { Button } from "./button"; | ||
import { Text } from "./text"; | ||
|
||
type Props = { className?: string }; | ||
|
||
export function InvoiceDesktop({ className }: Props) { | ||
const data = useLoaderData<typeof loader>(); | ||
const invoice = data.invoice; | ||
return ( | ||
<section className={className}> | ||
<header className="container"> | ||
<div className="flex items-center gap-5 rounded-lg bg-white px-8 py-5 shadow-100 dark:bg-brand-700"> | ||
<Text as="p" variant="accent"> | ||
Status | ||
</Text> | ||
|
||
{/* <StatusButton status={invoice?.status} /> */} | ||
|
||
<div className="ml-auto flex items-center justify-between gap-2"> | ||
<Button variant="soft">Edit</Button> | ||
<Button variant="destructive">Delete</Button> | ||
<Button variant="primary">Mark as Paid</Button> | ||
</div> | ||
</div> | ||
</header> | ||
|
||
<article className="pb-20 container"> | ||
<div className="flex flex-col gap-12 rounded-lg bg-white px-8 py-8 shadow-100 dark:bg-brand-700"> | ||
<div className="flex justify-between gap-7"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" weight="bold" className="text-base uppercase"> | ||
<span className="text-brand-400">#</span> | ||
<span>{invoice.slug}</span> | ||
</Text> | ||
|
||
<Text as="h1" id="heading-desktop" variant="primary"> | ||
{invoice.description} | ||
</Text> | ||
</div> | ||
|
||
<address> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.street} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.city} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.postCode} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.country} | ||
</Text> | ||
</address> | ||
</div> | ||
|
||
{/* gap-x-14 */} | ||
<div className="flex justify-between gap-x-[clamp(3rem,10vw,5rem)] gap-y-10 max-md:flex-wrap"> | ||
<div className="flex flex-initial flex-col gap-7"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Invoice Date | ||
</Text> | ||
|
||
<Text | ||
as="time" | ||
dateTime={new Date(invoice?.paymentDue).toISOString()} | ||
size="sm" | ||
className="inline-block" | ||
> | ||
{format(new Date(invoice?.paymentDue), "dd MMM yyyy")} | ||
</Text> | ||
</div> | ||
|
||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Payment Due | ||
</Text> | ||
|
||
<Text | ||
as="time" | ||
dateTime={new Date(invoice?.paymentDue).toISOString()} | ||
size="sm" | ||
className="inline-block" | ||
> | ||
{format(new Date(invoice?.paymentDue), "dd MMM yyyy")} | ||
</Text> | ||
</div> | ||
</div> | ||
|
||
<div className="mr-auto flex flex-initial flex-col gap-5"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Bill To | ||
</Text> | ||
<Text size="sm" className="truncate"> | ||
{invoice?.clientName} | ||
</Text> | ||
</div> | ||
|
||
<address> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.street} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.city} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.postCode} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.country} | ||
</Text> | ||
</address> | ||
</div> | ||
|
||
<div className="> * + * flex-1 space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Sent to | ||
</Text> | ||
<Text size="sm" className="truncate"> | ||
{invoice?.clientEmail} | ||
</Text> | ||
</div> | ||
</div> | ||
<table className="grid grid-cols-1 overflow-clip rounded-lg bg-neutral-200 dark:bg-brand-600"> | ||
<caption className="sr-only">Items and Services Purchased</caption> | ||
|
||
<thead className="px-8 py-5"> | ||
<tr className="grid grid-cols-4 justify-items-end"> | ||
<Text | ||
as="th" | ||
variant="primary" | ||
size="xs" | ||
className="justify-self-start" | ||
> | ||
Item Name | ||
</Text> | ||
<Text as="th" variant="primary" size="xs" className=""> | ||
QTY. | ||
</Text> | ||
<Text as="th" variant="primary" size="xs" className=""> | ||
Price | ||
</Text> | ||
<Text as="th" variant="primary" size="xs" className=""> | ||
Total | ||
</Text> | ||
</tr> | ||
</thead> | ||
|
||
<tbody className="flex flex-col gap-8 px-8 py-5"> | ||
{/* {hasValues([]) ? ( */} | ||
{hasValues(invoice?.items || []) ? | ||
invoice.items.map((item) => ( | ||
<tr | ||
key={item?.slug} | ||
className="grid grid-cols-4 justify-items-end gap-2" | ||
> | ||
<Text as="td" weight="bold" className="justify-self-start"> | ||
{item?.name} | ||
</Text> | ||
|
||
<Text as="td" weight="bold"> | ||
{item?.quantity} | ||
</Text> | ||
|
||
<Text as="td" variant="secondary" weight="bold"> | ||
{formatAmount(item?.price)} | ||
</Text> | ||
<Text as="td" variant="secondary" weight="bold"> | ||
{formatAmount(item?.total)} | ||
</Text> | ||
</tr> | ||
)) | ||
: <tr className="grid grid-cols-4 justify-items-end gap-2"> | ||
<Text as="td" weight="bold"> | ||
No items to show | ||
</Text> | ||
</tr> | ||
} | ||
</tbody> | ||
|
||
<tfoot className="bg-accent-300 px-8 py-5 dark:bg-brand-900"> | ||
<tr className="flex items-center justify-between"> | ||
<Text as="th">Amount Due</Text> | ||
<Text | ||
as="td" | ||
modifier="inverted" | ||
weight="bold" | ||
className="text-2xl leading-8 -tracking-[0.5px]" | ||
> | ||
{formatAmount(calculateTotal(invoice.items, "total"))} | ||
</Text> | ||
</tr> | ||
</tfoot> | ||
</table> | ||
</div> | ||
</article> | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import { calculateTotal, formatAmount, hasValues } from "@/helpers/utils"; | ||
import { loader } from "@/routes/invoices.$slug"; | ||
import { useLoaderData } from "@remix-run/react"; | ||
import { format } from "date-fns"; | ||
import { Button } from "./button"; | ||
import { Text } from "./text"; | ||
|
||
type Props = { className?: string }; | ||
|
||
export function InvoiceMobile({ className }: Props) { | ||
const data = useLoaderData<typeof loader>(); | ||
const invoice = data.invoice; | ||
return ( | ||
<section className={className}> | ||
<header className="container"> | ||
<div className="flex items-center justify-between rounded-lg bg-white px-6 py-5 shadow-100 dark:bg-brand-700"> | ||
<Text as="p" variant="accent"> | ||
Status | ||
</Text> | ||
|
||
{/* <StatusButton status={invoice?.status} /> */} | ||
</div> | ||
</header> | ||
|
||
<article className="pb-14 container"> | ||
<div className="flex flex-col gap-12 rounded-lg bg-white px-6 py-8 shadow-100 dark:bg-brand-700"> | ||
<div className="flex flex-col justify-between gap-7 xs:flex-row"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" weight="bold" className="uppercase"> | ||
<span className="text-brand-400">#</span> | ||
<span>{invoice.slug}</span> | ||
</Text> | ||
|
||
<Text as="h1" id="heading-mobile" variant="primary"> | ||
{invoice.description} | ||
</Text> | ||
</div> | ||
|
||
<address> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.street} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.city} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.postCode} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.senderAddress?.country} | ||
</Text> | ||
</address> | ||
</div> | ||
|
||
<div className="flex justify-between gap-x-14 gap-y-10 max-md:flex-wrap"> | ||
<div className="flex flex-initial flex-col gap-7"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Invoice Date | ||
</Text> | ||
|
||
<Text | ||
as="time" | ||
dateTime={new Date(invoice?.paymentDue).toISOString()} | ||
size="sm" | ||
className="inline-block" | ||
> | ||
{format(new Date(invoice?.paymentDue), "dd MMM yyyy")} | ||
</Text> | ||
</div> | ||
|
||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Payment Due | ||
</Text> | ||
|
||
<Text | ||
as="time" | ||
dateTime={new Date(invoice?.paymentDue).toISOString()} | ||
size="sm" | ||
className="inline-block" | ||
> | ||
{format(new Date(invoice?.paymentDue), "dd MMM yyyy")} | ||
</Text> | ||
</div> | ||
</div> | ||
|
||
<div className="mr-auto flex flex-initial flex-col gap-5"> | ||
<div className="> * + * space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Bill To | ||
</Text> | ||
<Text size="sm" className="truncate"> | ||
{invoice?.clientName} | ||
</Text> | ||
</div> | ||
|
||
<address> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.street} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.city} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.postCode} | ||
</Text> | ||
<Text as="p" variant="primary" size="xs"> | ||
{invoice?.clientAddress?.country} | ||
</Text> | ||
</address> | ||
</div> | ||
|
||
<div className="> * + * flex-1 space-y-3"> | ||
<Text as="p" variant="primary"> | ||
Sent to | ||
</Text> | ||
<Text size="sm" className="truncate"> | ||
{invoice?.clientEmail} | ||
</Text> | ||
</div> | ||
</div> | ||
|
||
<section className="overflow-clip rounded-lg bg-neutral-200 dark:bg-brand-600"> | ||
<ul className="flex flex-col gap-6 p-6 "> | ||
{hasValues(invoice?.items || []) ? | ||
invoice.items.map((item) => ( | ||
<li key={item?.slug}> | ||
<article className="flex flex-col gap-2"> | ||
<header className="flex items-center justify-between"> | ||
<Text as="h4" weight="bold"> | ||
{item?.name} | ||
</Text> | ||
|
||
<Text as="output" weight="bold"> | ||
{formatAmount(item?.total)} | ||
</Text> | ||
</header> | ||
|
||
<div className=""> | ||
<Text as="p" variant="secondary" weight="bold"> | ||
{item?.quantity} x {formatAmount(item?.price)} | ||
</Text> | ||
</div> | ||
</article> | ||
</li> | ||
)) | ||
: <li></li>} | ||
</ul> | ||
|
||
<footer className="flex items-center justify-between bg-accent-300 p-6 dark:bg-brand-900"> | ||
<Text as="h4">Grand Total</Text> | ||
|
||
<Text | ||
as="output" | ||
modifier="inverted" | ||
weight="bold" | ||
className="text-xl leading-8 -tracking-[0.42px]" | ||
> | ||
{formatAmount(calculateTotal(invoice.items, "total"))} | ||
</Text> | ||
</footer> | ||
</section> | ||
</div> | ||
</article> | ||
|
||
<div className="sticky bottom-0 w-full bg-white p-6 shadow-100 dark:bg-brand-700"> | ||
<div className="flex items-center justify-between gap-2"> | ||
<Button variant="soft">Edit</Button> | ||
<Button variant="destructive">Delete</Button> | ||
<Button variant="primary">Mark as Paid</Button> | ||
</div> | ||
</div> | ||
</section> | ||
); | ||
} |
Oops, something went wrong.