This commit is contained in:
David Arranz 2024-08-27 20:50:31 +02:00
parent 033d2363df
commit 1fd2d79bbe
7 changed files with 491 additions and 245 deletions

View File

@ -30,9 +30,12 @@ import {
TabsList, TabsList,
TabsTrigger, TabsTrigger,
} from "@/ui"; } from "@/ui";
import { useToast } from "@/ui/use-toast";
import { t } from "i18next"; import { t } from "i18next";
import { useCallback } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useQuotes } from "../hooks"; import { useQuotes } from "../hooks";
import { DownloadQuoteDialog } from "./DownloadQuoteDialog";
import { QuoteStatusEditor } from "./editors"; import { QuoteStatusEditor } from "./editors";
type QuoteResumeProps = { type QuoteResumeProps = {
@ -41,9 +44,37 @@ type QuoteResumeProps = {
}; };
export const QuoteResume = ({ quoteId, className }: QuoteResumeProps) => { export const QuoteResume = ({ quoteId, className }: QuoteResumeProps) => {
const { useOne, useUpdate } = useQuotes();
const { data, status, error: queryError } = useOne(quoteId);
const navigate = useNavigate(); const navigate = useNavigate();
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]);
if (status === "error") { if (status === "error") {
return null; return null;
@ -64,173 +95,197 @@ export const QuoteResume = ({ quoteId, className }: QuoteResumeProps) => {
} }
return ( return (
<Tabs defaultValue='resume'> <>
<Card className='w-full overflow-hidden'> <DownloadQuoteDialog {...downloadProps} onFinishDownload={handleFinishDownload} />
<CardHeader className='flex flex-row items-start border-b'> <Tabs defaultValue='resume'>
<div className='grid gap-0.5'> <Card className='w-full overflow-hidden'>
<CardTitle className='flex items-center gap-2 text-lg group'> <CardHeader className='gap-3 border-b'>
<CardTitle className='text-lg'>
{`${t("quotes.list.preview.quote")} #${data.reference}`} {`${t("quotes.list.preview.quote")} #${data.reference}`}
</CardTitle> </CardTitle>
<CardDescription>assaasassa</CardDescription> <CardDescription className='flex items-center gap-1 mr-auto text-foreground'>
</div> <Button
<div className='flex items-center gap-1 ml-auto'> size='sm'
<Button variant='outline'
size='sm' className='h-8 gap-1'
variant='outline' onClick={(e) => {
className='h-8 gap-1' e.preventDefault();
onClick={(e) => { navigate(`/quotes/edit/${data.id}`, { relative: "path" });
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'>
<FilePenLineIcon className='h-3.5 w-3.5' /> {t("quotes.list.columns.actions.edit")}
<span className='lg:sr-only xl:not-sr-only xl:whitespace-nowrap'> </span>
{t("quotes.list.columns.actions.edit")} </Button>
</span> <QuoteStatusEditor quote={data} onChangeStatus={handleOnChangeStatus} />
</Button>
<Button size='sm' variant='outline' className='h-8 gap-1' onClick={() => null}> <Button size='sm' variant='outline' className='h-8 gap-1' onClick={handleDownload}>
<DownloadIcon className='h-3.5 w-3.5' /> <DownloadIcon className='h-3.5 w-3.5' />
<span className='xl:sr-only 2xl:not-sr-only 2xl:whitespace-nowrap'> <span className='sr-only lg:not-sr-only lg:whitespace-nowrap'>
{t("quotes.list.preview.download_quote")} {t("quotes.list.preview.download_quote")}
</span> </span>
</Button> </Button>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button size='icon' variant='outline' className='w-8 h-8'> <Button size='icon' variant='outline' className='w-8 h-8'>
<MoreVertical className='h-3.5 w-3.5' /> <MoreVertical className='h-3.5 w-3.5' />
<span className='sr-only'>More</span> <span className='sr-only'>More</span>
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align='end'> <DropdownMenuContent align='end'>
<DropdownMenuItem>Edit</DropdownMenuItem> <DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Export</DropdownMenuItem> <DropdownMenuItem>Export</DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem>Trash</DropdownMenuItem> <DropdownMenuItem>Trash</DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</div> </CardDescription>
</CardHeader> </CardHeader>
<CardHeader className='flex flex-row items-start border-b'> <CardContent className='p-6 text-sm'>
<QuoteStatusEditor quote={data} onChangeStatus={() => null} /> <TabsList className='grid w-full grid-cols-2'>
</CardHeader> <TabsTrigger value='resume'>Resume</TabsTrigger>
<CardContent className='p-6 text-sm'> <TabsTrigger value='preview'>Preview</TabsTrigger>
<TabsList className='grid w-full grid-cols-2'> </TabsList>
<TabsTrigger value='resume'>Resume</TabsTrigger> <TabsContent value='resume' className='pt-4'>
<TabsTrigger value='preview'>Preview</TabsTrigger>
</TabsList>
<TabsContent value='resume' className='pt-4'>
<div className='grid gap-3'>
<div className='grid gap-3'> <div className='grid gap-3'>
<div className='font-semibold'>Customer Information</div> <div className='grid gap-3'>
Date: {new Date(data.date).toLocaleDateString()} <div className='font-semibold'>Quote information</div>
<div>{data.customer_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' />
<div className='grid gap-3'>
<div className='font-semibold'>Payment Information</div>
<dl className='grid gap-3'> <dl className='grid gap-3'>
<div className='flex items-center justify-between'> <div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Customer</dt> <dt className='flex items-center gap-1 text-muted-foreground'>
<dd>Liam Johnson</dd> <CreditCard className='w-4 h-4' />
</div> Visa
<div className='flex items-center justify-between'> </dt>
<dt className='text-muted-foreground'>Email</dt> <dd>**** **** **** 4532</dd>
<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> </div>
</dl> </dl>
</div> </div>
<Separator className='my-4' /> </TabsContent>
<div className='font-semibold'>Order Details</div> <TabsContent value='preview'></TabsContent>
<ul className='grid gap-3'> </CardContent>
<li className='flex items-center justify-between'> <CardFooter className='flex flex-row items-center px-6 py-3 border-t'>
<span className='text-muted-foreground'> <div className='text-xs text-muted-foreground'>Updated...</div>
Glimmer Lamps x <span>2</span> <Pagination className='w-auto ml-auto mr-0'>
</span> <PaginationContent>
<span>$250.00</span> <PaginationItem>
</li> <Button size='icon' variant='outline' className='w-6 h-6'>
<li className='flex items-center justify-between'> <ChevronLeft className='h-3.5 w-3.5' />
<span className='text-muted-foreground'> <span className='sr-only'>Previous Order</span>
Aqua Filters x <span>1</span> </Button>
</span> </PaginationItem>
<span>$49.00</span> <PaginationItem>
</li> <Button size='icon' variant='outline' className='w-6 h-6'>
</ul> <ChevronRight className='h-3.5 w-3.5' />
<Separator className='my-2' /> <span className='sr-only'>Next Order</span>
<ul className='grid gap-3'> </Button>
<li className='flex items-center justify-between'> </PaginationItem>
<span className='text-muted-foreground'>Subtotal</span> </PaginationContent>
<span>$299.00</span> </Pagination>
</li> </CardFooter>
<li className='flex items-center justify-between'> </Card>
<span className='text-muted-foreground'>Shipping</span> </Tabs>
<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' />
<div className='grid gap-3'>
<div className='font-semibold'>Payment Information</div>
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
<dt className='flex items-center gap-1 text-muted-foreground'>
<CreditCard className='w-4 h-4' />
Visa
</dt>
<dd>**** **** **** 4532</dd>
</div>
</dl>
</div>
</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>
); );
}; };

View File

@ -1,50 +1,113 @@
import { Button } from "@/ui/button"; import {
import { Select, SelectContent, SelectTrigger, SelectValue } from "@/ui/select"; Button,
import { SelectItem } from "@radix-ui/react-select"; Dialog,
import { useState } from "react"; DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Label,
Switch,
} from "@/ui";
import { DialogDescription } from "@radix-ui/react-dialog";
import { IGetQuote_Response_DTO } from "@shared/contexts";
import { t } from "i18next";
import { RefreshCwIcon } from "lucide-react";
import { useEffect, useState } from "react";
const QUOTE_STATUS = ["draft", "ready", "delivered", "accepted", "rejected", "archived"]; const QuoteStatus = ["draft", "ready", "delivered", "accepted", "rejected", "archived"];
const QUOTE_NEXT_STATUS = { type TQuoteStatus = "draft" | "ready" | "delivered" | "accepted" | "rejected" | "archived";
draft: ["ready", "archived"],
ready: ["delivered", "archived"], const quoteStatusTransitions: Record<TQuoteStatus, TQuoteStatus[]> = {
delivered: ["accepted", "rejected", "archived"], draft: ["draft", "ready", "archived"],
accepted: ["archived"], ready: ["ready", "delivered", "archived"],
rejected: ["archived"], delivered: ["delivered", "accepted", "rejected", "archived"],
archived: [], accepted: ["accepted", "archived"],
rejected: ["rejected", "archived"],
archived: ["archived", "draft", "ready", "delivered", "accepted", "rejected"],
}; };
export const QuoteStatusEditor = ({ quote, onChangeStatus }) => { export const QuoteStatusEditor = ({
const [status, changeStatus] = useState(quote.status); quote,
onChangeStatus,
}: {
quote: IGetQuote_Response_DTO;
onChangeStatus: (quoteId: string, newStatus: string) => void;
}) => {
const [newStatus, setNewStatus] = useState<string>("");
const changeStatus = (newStatus: string) => setNewStatus(newStatus);
useEffect(() => {
if (quote) {
setNewStatus(quote.status);
}
}, [quote]);
const handleChangeStatus = () => { const handleChangeStatus = () => {
if (status !== quote.status) { if (newStatus !== quote.status) {
onChangeStatus(quote.id, status); onChangeStatus(quote.id, newStatus);
} }
}; };
console.log(newStatus);
return ( return (
<div className='flex items-center space-x-2 '> <Dialog>
<Select value={status} onValueChange={changeStatus}> <DialogTrigger asChild>
<SelectTrigger className='w-[180px]'> <Button size='sm' variant='outline' className='h-8 gap-1'>
<SelectValue placeholder='Seleccionar estado' /> <RefreshCwIcon className='h-3.5 w-3.5' />
</SelectTrigger> <span className='sr-only md:not-sr-only md:whitespace-nowrap'>Cambiar estado</span>
<SelectContent> </Button>
{QUOTE_NEXT_STATUS[quote.status].map((_status) => ( </DialogTrigger>
<SelectItem key={_status} value={_status}> <DialogContent>
{_status} <DialogHeader>
</SelectItem> <DialogTitle>{t("quotes.quote_status_editor.title")}</DialogTitle>
</DialogHeader>
<DialogDescription></DialogDescription>
<div className='grid gap-4 py-4'>
{QuoteStatus.map((_status) => (
<div key={_status} className='flex items-start space-x-4'>
<Switch
id={_status}
checked={newStatus === _status}
onCheckedChange={() => changeStatus(_status)}
disabled={
!quoteStatusTransitions[quote.status as TQuoteStatus].includes(
_status as TQuoteStatus
)
}
/>
<div className='grid gap-1.5 leading-none'>
<Label htmlFor={_status} className='font-medium'>
{t(`quotes.quote_status_editor.status.${_status}.title`)}
</Label>
<p className='text-sm text-muted-foreground'>
{t(`quotes.quote_status_editor.status.${_status}.description`)}
</p>
</div>
</div>
))} ))}
</SelectContent> </div>
</Select>
<Button <DialogFooter className='pt-6 border-t'>
variant='secondary' <DialogClose asChild>
size='sm' <Button type='button' variant='secondary'>
onClick={handleChangeStatus} {t("common.cancel")}
disabled={status === quote.status} </Button>
> </DialogClose>
Cambiar estado
</Button> <DialogClose asChild>
</div> <Button onClick={handleChangeStatus} disabled={newStatus === quote.status}>
{t("quotes.quote_status_editor.submit_button")}
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
); );
}; };

View File

@ -10,6 +10,7 @@ import {
IGetQuote_Response_DTO, IGetQuote_Response_DTO,
IListQuotes_Response_DTO, IListQuotes_Response_DTO,
IListResponse_DTO, IListResponse_DTO,
ISetStatusQuote_Request_DTO,
IUpdateQuote_Request_DTO, IUpdateQuote_Request_DTO,
IUpdateQuote_Response_DTO, IUpdateQuote_Response_DTO,
UniqueID, UniqueID,
@ -150,6 +151,50 @@ export const useQuotes = () => {
}); });
}, },
useSetStatus: (id: string) => {
const queryClient = useQueryClient();
return useMutation<void, TDataSourceError, ISetStatusQuote_Request_DTO>({
mutationKey: keys().data().resource("quotes").action("one").id(id).params().get(),
mutationFn: (data) => {
const { newStatus } = data;
return dataSource.custom({
url: `${dataSource.getApiUrl()}/quotes/${id}/setStatus`,
method: "put",
data: {
newStatus,
},
});
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["data", "default", "quotes"],
});
},
});
/*return useMutation<void, TDataSourceError, ISetStatusQuote_Request_DTO>({
mutationKey: keys().data().resource("quotes").action("one").id(id).params().get(),
mutationFn: (data) => {
const { newStatus } = data;
return dataSource.updateOne({
resource: "quotes",
id,
data: {
newStatus,
},
});
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["data", "default", "quotes"],
});
},
});*/
},
useOne: (id?: string, params?: UseQuotesGetParamsType) => useOne: (id?: string, params?: UseQuotesGetParamsType) =>
useOne<IGetQuote_Response_DTO>({ useOne<IGetQuote_Response_DTO>({
queryKey: keys().data().resource("quotes").action("one").id(id).params().get(), queryKey: keys().data().resource("quotes").action("one").id(id).params().get(),

View File

@ -50,51 +50,60 @@
} }
}*/ }*/
/* https://ui.jln.dev/ unicscode89-stripe */
@layer base { @layer base {
:root { :root {
--background: 210 40% 96.08%; --background: 0 0% 100%;
--foreground: 334 55% 1%; --foreground: 222.2 84% 4.9%;
--muted: 214.29 31.82% 91.37%; --card: 0 0% 100%;
--muted-foreground: 334 9% 37%; --card-foreground: 222.2 84% 4.9%;
--popover: 334 62% 100%; --popover: 0 0% 100%;
--popover-foreground: 334 55% 1%; --popover-foreground: 222.2 84% 4.9%;
--card: 334 62% 100%; --primary: 221.2 83.2% 53.3%;
--card-foreground: 334 55% 1%; --primary-foreground: 210 40% 98%;
--border: 334 5% 95%; --secondary: 210 40% 96.1%;
--input: 214.29 31.82% 91.37%; --secondary-foreground: 222.2 47.4% 11.2%;
--primary: 242.93 100% 67.84%; --muted: 210 40% 96.1%;
--primary-foreground: 0 0% 100%; --muted-foreground: 215.4 16.3% 46.9%;
--secondary: 213.75 20.25% 69.02%; --accent: 210 40% 96.1%;
--secondary-foreground: 334 0% 100%; --accent-foreground: 222.2 47.4% 11.2%;
--accent: 214.29 31.82% 91.37%; --destructive: 0 84.2% 60.2%;
--accent-foreground: 334 20% 22%; --destructive-foreground: 210 40% 98%;
--destructive: 348.37 78.4% 49.02%; --border: 214.3 31.8% 91.4%;
--destructive-foreground: 18 0% 100%; --input: 214.3 31.8% 91.4%;
--ring: 228.33 94.74% 62.75%; --ring: 221.2 83.2% 53.3%;
--radius: 0.5rem; --radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
} }
.dark { .dark {
--background: 222.22 47.37% 11.18%; --background: 222.2 84% 4.9%;
--foreground: 334 34% 98%; --foreground: 210 40% 98%;
--muted: 215.38 16.32% 46.86%; --card: 222.2 84% 4.9%;
--muted-foreground: 334 0% 87.69%; --card-foreground: 210 40% 98%;
--popover: 217.24 32.58% 17.45%; --popover: 222.2 84% 4.9%;
--popover-foreground: 334 34% 98%; --popover-foreground: 210 40% 98%;
--card: 217.24 32.58% 17.45%; --primary: 217.2 91.2% 59.8%;
--card-foreground: 334 34% 98%; --primary-foreground: 222.2 47.4% 11.2%;
--border: 334 0% 32.31%; --secondary: 217.2 32.6% 17.5%;
--input: 215.29 25% 26.67%; --secondary-foreground: 210 40% 98%;
--primary: 227.56 53.78% 49.22%; --muted: 217.2 32.6% 17.5%;
--primary-foreground: 0 0% 100%; --muted-foreground: 215 20.2% 65.1%;
--secondary: 214.29 5.04% 27.25%; --accent: 217.2 32.6% 17.5%;
--secondary-foreground: 334 0% 100%; --accent-foreground: 210 40% 98%;
--accent: 222.22 47.37% 11.18%; --destructive: 0 62.8% 30.6%;
--accent-foreground: 226.73 0% 100%; --destructive-foreground: 210 40% 98%;
--destructive: 358.82 84.44% 64.71%; --border: 217.2 32.6% 17.5%;
--destructive-foreground: 0 0% 100%; --input: 217.2 32.6% 17.5%;
--ring: 227.56 53.78% 49.22%; --ring: 224.3 76.3% 48%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
} }
} }

View File

@ -150,7 +150,7 @@ export const createAxiosDataProvider = (
}, },
custom: async <R>(params: ICustomDataProviderParam): Promise<R> => { custom: async <R>(params: ICustomDataProviderParam): Promise<R> => {
const { url, method, responseType, headers, signal, ...payload } = params; const { url, method, responseType, headers, signal, data, ...payload } = params;
const requestUrl = `${url}?`; const requestUrl = `${url}?`;
/*if (sort) { /*if (sort) {
@ -186,9 +186,12 @@ export const createAxiosDataProvider = (
case "put": case "put":
case "post": case "post":
case "patch": case "patch":
customResponse = await httpClient[method]<R>(url, { customResponse = await httpClient.request<R>({
url,
method,
responseType, responseType,
headers, headers,
data,
...payload, ...payload,
}); });
break; break;

View File

@ -197,8 +197,44 @@
"description": "To complete your quote, you can add items from the catalog.", "description": "To complete your quote, you can add items from the catalog.",
"toast_article_added": "Catalog item added:" "toast_article_added": "Catalog item added:"
}, },
"quote_status_editor": {
"title": "Change quote status",
"status": {
"draft": {
"title": "Draft",
"description": "The quote is in the initial stages of creation."
},
"ready": {
"title": "Ready",
"description": "The quote is completed and ready to be delivered to the customer."
},
"delivered": {
"title": "Delivered",
"description": "The quote has been sent to the client and a response is awaited."
},
"accepted": {
"title": "Accepted",
"description": "The customer has approved the quote."
},
"rejected": {
"title": "Rejected",
"description": "The customer has not accepted the quotation."
},
"archived": {
"title": "Archived",
"description": "The quote is archived."
}
},
"submit_button": "Change status",
"toast_status_changed": "Quote status changed to:"
},
"status": { "status": {
"draft": "Draft" "draft": "Draft",
"ready": "Ready",
"delivered": "Delivered",
"accepted": "Accepted",
"rejected": "Rejected",
"archived": "Archived"
}, },
"form_fields": { "form_fields": {
"date": { "date": {

View File

@ -122,9 +122,9 @@
"draft": "Borradores", "draft": "Borradores",
"ready": "Preparados", "ready": "Preparados",
"delivered": "Entregado", "delivered": "Entregado",
"accepted": "Accepted", "accepted": "Aceptados",
"rejected": "Rejected", "rejected": "Rechazados",
"archived": "Archivadas" "archived": "Archivados"
}, },
"columns": { "columns": {
"date": "Fecha", "date": "Fecha",
@ -193,8 +193,43 @@
"description": "Para rellenar su cotización, puede añadir artículos del catálogo.", "description": "Para rellenar su cotización, puede añadir artículos del catálogo.",
"toast_article_added": "Artículo del catálogo añadido:" "toast_article_added": "Artículo del catálogo añadido:"
}, },
"quote_status_editor": {
"title": "Cambiar el estado de la cotización",
"status": {
"draft": {
"title": "Borrador",
"description": "La cotización está en fase inicial de creación."
},
"ready": {
"title": "Preparado",
"description": "La cotización está completo y listo para ser entregado al cliente."
},
"delivered": {
"title": "Entregado",
"description": "La cotización ha sido enviado al cliente y se espera su respuesta."
},
"accepted": {
"title": "Aceptado",
"description": "El cliente ha aprobado la cotización."
},
"rejected": {
"title": "Rechazado",
"description": "El cliente no ha aceptado la cotización."
},
"archived": {
"title": "Archivado",
"description": "La cotización se ha guardado para referencia futura."
}
},
"submit_button": "Change status"
},
"status": { "status": {
"draft": "Borrador" "draft": "Borrador",
"ready": "Preparado",
"delivered": "Entregado",
"accepted": "Aceptado",
"rejected": "Rechazado",
"archived": "Archivado"
}, },
"form_fields": { "form_fields": {
"date": { "date": {