Presupuestador_web/client/src/app/quotes/components/QuoteResume.tsx

292 lines
11 KiB
TypeScript
Raw Normal View History

2024-08-26 18:29:41 +00:00
import {
ChevronLeft,
ChevronRight,
CreditCard,
DownloadIcon,
FilePenLineIcon,
MoreVertical,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
Button,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
Pagination,
PaginationContent,
PaginationItem,
Separator,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/ui";
2024-08-27 18:50:31 +00:00
import { useToast } from "@/ui/use-toast";
2024-08-26 18:29:41 +00:00
import { t } from "i18next";
2024-08-27 18:50:31 +00:00
import { useCallback } from "react";
2024-08-26 18:29:41 +00:00
import { useNavigate } from "react-router-dom";
import { useQuotes } from "../hooks";
2024-08-27 18:50:31 +00:00
import { DownloadQuoteDialog } from "./DownloadQuoteDialog";
2024-08-26 18:29:41 +00:00
import { QuoteStatusEditor } from "./editors";
type QuoteResumeProps = {
quoteId: string;
className: string;
};
export const QuoteResume = ({ quoteId, className }: QuoteResumeProps) => {
const navigate = useNavigate();
2024-08-27 18:50:31 +00:00
const { toast } = useToast();
const { useOne, useSetStatus, useDownloader, getQuotePDFFilename } = useQuotes();
const { data, status, error: queryError } = useOne(quoteId);
const { mutate: setStatusMutation } = useSetStatus(quoteId);
const { download, ...downloadProps } = useDownloader();
const handleOnChangeStatus = (quoteId: string, newStatus: string) => {
setStatusMutation(
{ newStatus },
{
onSuccess: () => {
toast({
description: t("quotes.quote_status_editor.toast_status_changed"),
});
},
}
);
};
const handleFinishDownload = useCallback(() => {
toast({
description: t("quotes.downloading_dialog.toast_success"),
});
}, [toast]);
const handleDownload = useCallback(() => {
if (data) download(data.id, getQuotePDFFilename(data));
}, [data]);
2024-08-26 18:29:41 +00:00
if (status === "error") {
return null;
}
if (status !== "success") {
return null;
}
if (!data) {
return (
<Card className={cn("overflow-hidden", className)}>
<CardContent className='px-4 py-6 text-center'>
<p className='mx-auto'>Select a quote</p>
</CardContent>
</Card>
);
}
return (
2024-08-27 18:50:31 +00:00
<>
<DownloadQuoteDialog {...downloadProps} onFinishDownload={handleFinishDownload} />
<Tabs defaultValue='resume'>
<Card className='w-full overflow-hidden'>
<CardHeader className='gap-3 border-b'>
<CardTitle className='text-lg'>
2024-08-26 18:29:41 +00:00
{`${t("quotes.list.preview.quote")} #${data.reference}`}
</CardTitle>
2024-08-27 18:50:31 +00:00
<CardDescription className='flex items-center gap-1 mr-auto text-foreground'>
<Button
size='sm'
variant='outline'
className='h-8 gap-1'
onClick={(e) => {
e.preventDefault();
navigate(`/quotes/edit/${data.id}`, { relative: "path" });
}}
>
<FilePenLineIcon className='h-3.5 w-3.5' />
<span className='sr-only md:not-sr-only md:whitespace-nowrap'>
{t("quotes.list.columns.actions.edit")}
</span>
</Button>
<QuoteStatusEditor quote={data} onChangeStatus={handleOnChangeStatus} />
<Button size='sm' variant='outline' className='h-8 gap-1' onClick={handleDownload}>
<DownloadIcon className='h-3.5 w-3.5' />
<span className='sr-only lg:not-sr-only lg:whitespace-nowrap'>
{t("quotes.list.preview.download_quote")}
</span>
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button size='icon' variant='outline' className='w-8 h-8'>
<MoreVertical className='h-3.5 w-3.5' />
<span className='sr-only'>More</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end'>
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Export</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Trash</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</CardDescription>
</CardHeader>
<CardContent className='p-6 text-sm'>
<TabsList className='grid w-full grid-cols-2'>
<TabsTrigger value='resume'>Resume</TabsTrigger>
<TabsTrigger value='preview'>Preview</TabsTrigger>
</TabsList>
<TabsContent value='resume' className='pt-4'>
<div className='grid gap-3'>
<div className='grid gap-3'>
<div className='font-semibold'>Quote information</div>
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>
{t("quotes.form_fields.date.label")}
</dt>
<dd>{new Date(data.date).toLocaleDateString()}</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Email</dt>
<dd>
<a href='mailto:'>liam@acme.com</a>
</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Phone</dt>
<dd>
<a href='tel:'>+1 234 567 890</a>
</dd>
</div>
</dl>
</div>
<Separator className='my-4' />
<div className='grid gap-3'>
<div className='font-semibold'>Customer Information</div>
Date: {new Date(data.date).toLocaleDateString()}
<div>{data.customer_information}</div>
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Customer</dt>
<dd>Liam Johnson</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Email</dt>
<dd>
<a href='mailto:'>liam@acme.com</a>
</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Phone</dt>
<dd>
<a href='tel:'>+1 234 567 890</a>
</dd>
</div>
</dl>
</div>
<Separator className='my-4' />
<div className='font-semibold'>Order Details</div>
<ul className='grid gap-3'>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>
Glimmer Lamps x <span>2</span>
</span>
<span>$250.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>
Aqua Filters x <span>1</span>
</span>
<span>$49.00</span>
</li>
</ul>
<Separator className='my-2' />
<ul className='grid gap-3'>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Subtotal</span>
<span>$299.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Shipping</span>
<span>$5.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Tax</span>
<span>$25.00</span>
</li>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>Total</span>
<span>$329.00</span>
</li>
</ul>
</div>
<Separator className='my-4' />
<div className='grid grid-cols-2 gap-4'>
<div className='grid gap-3'>
<div className='font-semibold'>Shipping Information</div>
<address className='grid gap-0.5 not-italic text-muted-foreground'>
<span>Liam Johnson</span>
<span>1234 Main St.</span>
<span>Anytown, CA 12345</span>
</address>
</div>
<div className='grid gap-3 auto-rows-max'>
<div className='font-semibold'>Billing Information</div>
<div className='text-muted-foreground'>Same as shipping address</div>
</div>
</div>
<Separator className='my-4' />
2024-08-26 18:29:41 +00:00
<div className='grid gap-3'>
2024-08-27 18:50:31 +00:00
<div className='font-semibold'>Payment Information</div>
2024-08-26 18:29:41 +00:00
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
2024-08-27 18:50:31 +00:00
<dt className='flex items-center gap-1 text-muted-foreground'>
<CreditCard className='w-4 h-4' />
Visa
</dt>
<dd>**** **** **** 4532</dd>
2024-08-26 18:29:41 +00:00
</div>
</dl>
</div>
2024-08-27 18:50:31 +00:00
</TabsContent>
<TabsContent value='preview'></TabsContent>
</CardContent>
<CardFooter className='flex flex-row items-center px-6 py-3 border-t'>
<div className='text-xs text-muted-foreground'>Updated...</div>
<Pagination className='w-auto ml-auto mr-0'>
<PaginationContent>
<PaginationItem>
<Button size='icon' variant='outline' className='w-6 h-6'>
<ChevronLeft className='h-3.5 w-3.5' />
<span className='sr-only'>Previous Order</span>
</Button>
</PaginationItem>
<PaginationItem>
<Button size='icon' variant='outline' className='w-6 h-6'>
<ChevronRight className='h-3.5 w-3.5' />
<span className='sr-only'>Next Order</span>
</Button>
</PaginationItem>
</PaginationContent>
</Pagination>
</CardFooter>
</Card>
</Tabs>
</>
2024-08-26 18:29:41 +00:00
);
};