This commit is contained in:
David Arranz 2024-07-10 11:53:13 +02:00
parent 54dc0a8442
commit b2a8073007
14 changed files with 123 additions and 105 deletions

View File

@ -21,5 +21,5 @@ export const StartPage = () => {
);
}
return <Navigate to={"/quotes"} replace />;
return <Navigate to={"/home"} replace />;
};

View File

@ -1,11 +1,11 @@
import { Container, FormTextField } from "@/components";
import { FormSubmitButton } from "@/components/Forms/FormSubmitButton";
import { UeckoLogo } from "@/components/UeckoLogo/UeckoLogo";
import { useLogin } from "@/lib/hooks";
import {
Alert,
AlertDescription,
AlertTitle,
Button,
Card,
CardContent,
CardDescription,
@ -18,7 +18,6 @@ import { ILogin_DTO } from "@shared/contexts";
import { t } from "i18next";
import Joi from "joi";
import { AlertCircleIcon } from "lucide-react";
import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { Trans } from "react-i18next";
import { Link } from "react-router-dom";
@ -27,7 +26,6 @@ import SpanishJoiMessages from "../../spanish-joi-messages.json";
type LoginDataForm = ILogin_DTO;
export const LoginPage = () => {
const [loading, setLoading] = useState(false);
const { mutate: login } = useLogin({
onSuccess: (data) => {
const { success, error } = data;
@ -57,12 +55,7 @@ export const LoginPage = () => {
});
const onSubmit: SubmitHandler<LoginDataForm> = async (data) => {
try {
setLoading(true);
login({ email: data.email, password: data.password });
} finally {
setLoading(false);
}
login({ email: data.email, password: data.password }, {});
};
return (
@ -121,9 +114,7 @@ export const LoginPage = () => {
</Alert>
)}
<Button disabled={loading} type='submit' className='w-full'>
<Trans i18nKey='login_page.login' />
</Button>
<FormSubmitButton className='w-full' label={t("login_page.login")} />
<div className='mt-4 text-sm text-center'>
<Trans i18nKey='login_page.become_dealer' />

View File

@ -1,12 +1,12 @@
import { Card, CardContent } from "@/ui";
import { Badge, Card, CardContent } from "@/ui";
import { DataTableSkeleton, ErrorOverlay, SimpleEmptyState } from "@/components";
import { DataTable } from "@/components";
import { DataTableToolbar } from "@/components/DataTable/DataTableToolbar";
import { useDataTable, useDataTableContext } from "@/lib/hooks";
import { IListQuotes_Response_DTO, MoneyValue } from "@shared/contexts";
import { ColumnDef, Row } from "@tanstack/react-table";
import { IListQuotes_Response_DTO, MoneyValue, UTCDateValue } from "@shared/contexts";
import { ColumnDef } from "@tanstack/react-table";
import { t } from "i18next";
import { useMemo } from "react";
import { useNavigate } from "react-router-dom";
@ -27,47 +27,51 @@ export const QuotesDataTable = () => {
const columns = useMemo<ColumnDef<IListQuotes_Response_DTO, any>[]>(
() => [
{
id: "id" as const,
accessorKey: "id",
id: "date" as const,
accessor: "date",
header: () => <>{t("quotes.list.columns.date")}</>,
cell: ({ table, row: { index, original }, column, getValue }) => {
console.log(original.date);
const quoteDate = UTCDateValue.create(original.date);
return quoteDate.isSuccess ? quoteDate.object.toLocaleDateString("es-ES") : "-";
},
enableResizing: false,
size: 10,
},
{
id: "article_id" as const,
accessorKey: "id_article",
enableResizing: false,
size: 10,
},
{
id: "catalog_name" as const,
accessorKey: "catalog_name",
enableResizing: false,
size: 10,
},
{
id: "description" as const,
accessorKey: "description",
header: () => <>{t("catalog.list.columns.description")}</>,
enableResizing: false,
size: 100,
},
{
id: "points" as const,
accessorKey: "points",
header: () => <div className='text-right'>{t("catalog.list.columns.points")}</div>,
id: "customer_information" as const,
accessorKey: "customer_information",
header: () => <>{t("quotes.list.columns.customer_information")}</>,
cell: ({ renderValue }: { renderValue: () => any }) => (
<div className='text-right'>{renderValue()}</div>
<div className='font-semibold'>{renderValue()}</div>
),
enableResizing: false,
size: 20,
size: 10,
},
{
id: "retail_price" as const,
accessorKey: "retail_price",
header: () => <div className='text-right'>{t("catalog.list.columns.retail_price")}</div>,
cell: ({ row }: { row: Row<any> }) => {
const price = MoneyValue.create(row.original.retail_price).object;
return <div className='text-right'>{price.toFormat()}</div>;
id: "reference" as const,
accessorKey: "reference",
header: () => <>{t("quotes.list.columns.reference")}</>,
enableResizing: false,
size: 10,
},
{
id: "status" as const,
accessorKey: "status",
header: () => <>{t("quotes.list.columns.status")}</>,
cell: ({ renderValue }: { renderValue: () => any }) => <Badge>{renderValue()}</Badge>,
enableResizing: false,
size: 10,
},
{
id: "total_price" as const,
accessor: "total_price",
header: () => <div className='text-right'>{t("quotes.list.columns.total_price")}</div>,
cell: ({ table, row: { index, original }, column, getValue }) => {
const price = MoneyValue.create(original.total_price);
return (
<div className='text-right'>{price.isSuccess ? price.object.toFormat() : "-"}</div>
);
},
enableResizing: false,
size: 20,

View File

@ -19,17 +19,21 @@ const customButtonVariants = cva("", {
});
export interface CustomButtonProps extends ButtonProps, VariantProps<typeof customButtonVariants> {
icon: LucideIcon; // Propiedad para proporcionar el icono personalizado
icon?: LucideIcon; // Propiedad para proporcionar el icono personalizado
label?: string;
}
const CustomButton = React.forwardRef<HTMLButtonElement, CustomButtonProps>(
({ className, label, size, icon: Icon, children, ...props }, ref) => (
<Button ref={ref} size={size} className={cn("gap-1", className)} {...props}>
<Icon className={cn(customButtonVariants({ size }))} />
<>{label ? label : children}</>
</Button>
)
({ className, label, size, icon: Icon, children, ...props }, ref) => {
const hasIcon = !!Icon;
return (
<Button ref={ref} size={size} className={cn(hasIcon ? "gap-1" : "", className)} {...props}>
{hasIcon && <Icon className={cn(customButtonVariants({ size }))} />}
<>{label ? label : children}</>
</Button>
);
}
);
CustomButton.displayName = "CustomButton";

View File

@ -1,13 +1,12 @@
import { ButtonProps } from "@/ui";
import { SaveIcon } from "lucide-react";
import { CustomButton } from "./CustomButton";
export interface SubmitButtonProps extends ButtonProps {
label?: string;
}
export const SubmitButton = ({ label = "Guardar", ...props }: SubmitButtonProps) => (
<CustomButton type='submit' label={label} icon={SaveIcon} variant='default' {...props} />
export const SubmitButton = ({ label = "Enviar", ...props }: SubmitButtonProps) => (
<CustomButton type='submit' label={label} variant='default' {...props} />
);
SubmitButton.displayName = "SubmitButton";

View File

@ -0,0 +1,11 @@
import { useFormState } from "react-hook-form";
import { SubmitButton, SubmitButtonProps } from "../Buttons";
export interface FromSubmitButtonProps extends SubmitButtonProps {}
export const FormSubmitButton = (props: FromSubmitButtonProps) => {
const { isSubmitting, isLoading, isValidating } = useFormState();
return <SubmitButton disabled={isSubmitting || isLoading || isValidating} {...props} />;
};
FormSubmitButton.displayName = "FormSubmitButton";

View File

@ -10,13 +10,6 @@ type ProctectRouteProps = {
export const ProtectedRoute = ({ children }: ProctectRouteProps) => {
const { isPending, isSuccess, data: { authenticated, redirectTo } = {} } = useIsLoggedIn();
console.debug("ProtectedRouter", {
isPending,
isSuccess,
authenticated,
redirectTo,
});
if (isPending) {
return <LoadingOverlay />;
}

View File

@ -76,7 +76,14 @@
},
"quotes": {
"list": {
"title": "Cotizaciones"
"title": "Cotizaciones",
"columns": {
"date": "Fecha",
"reference": "Referencia",
"status": "Estado",
"customer_information": "Cliente",
"total_price": "Imp. total"
}
},
"status": {
"draft": "Borrador"

View File

@ -11,12 +11,12 @@ export const CreateQuotePresenter: ICreateQuotePresenter = {
map: (quote: Quote, context: ISalesContext): ICreateQuote_Response_DTO => {
return {
id: quote.id.toString(),
//reference: quote.refe
reference: quote.reference.toString(),
status: quote.status.toString(),
date: quote.date.toString(),
date: quote.date.toISO8601(),
lang_code: quote.language.toString(),
currency_code: quote.currency.toString(),
customer_information: quote.customer,
customer_information: quote.customer.toString(),
subtotal: {
amount: 0,
precision: 2,

View File

@ -16,10 +16,10 @@ export const GetQuotePresenter: IGetQuotePresenter = {
return {
id: quote.id.toString(),
status: quote.status.toString(),
date: quote.date.toString(),
date: quote.date.toISO8601(),
reference: quote.reference.toString(),
customer_information: quote.customer.toString(),
lang_code: quote.language.code,
lang_code: quote.language.toString(),
currency_code: quote.currency.toString(),
payment_method: quote.paymentMethod.toString(),

View File

@ -20,10 +20,10 @@ export const ListQuotesPresenter: IListQuotesPresenter = {
return {
id: quote.id.toString(),
status: quote.status.toString(),
date: quote.date.toString(),
date: quote.date.toISO8601(),
reference: quote.reference.toString(),
customer_information: quote.customer.toString(),
lang_code: quote.date.toISO8601(),
lang_code: quote.language.toString(),
currency_code: quote.currency.toString(),
subtotal: {

View File

@ -12,20 +12,22 @@ export const UpdateQuotePresenter: IUpdateQuotePresenter = {
return {
id: quote.id.toString(),
status: quote.status.toString(),
date: quote.date.toString(),
language_code: quote.date.toString(),
date: quote.date.toISO8601(),
reference: quote.reference.toString(),
customer_information: quote.customer.toString(),
lang_code: quote.language.toString(),
currency_code: quote.currency.toString(),
subtotal: {
amount: 0,
precision: 2,
currency: "EUR",
},
total: {
amount: 0,
precision: 2,
currency: "EUR",
},
payment_method: quote.paymentMethod.toString(),
validity: quote.validity.toString(),
notes: quote.notes.toString(),
subtotal_price: quote.subtotalPrice.toObject(),
discount: quote.discount.toObject(),
total_price: quote.totalPrice.toObject(),
items: quoteItemPresenter(quote.items, context),
dealer_id: quote.dealerId.toString(),
};
},
};
@ -34,23 +36,12 @@ export const UpdateQuotePresenter: IUpdateQuotePresenter = {
const quoteItemPresenter = (items: ICollection<QuoteItem>, context: ISalesContext) =>
items.totalCount > 0
? items.items.map((item: QuoteItem) => ({
article_id: item.articleId,
description: item.description.toString(),
quantity: item.quantity.toString(),
unit_measure: "",
unit_price: {
amount: 0,
precision: 2,
currency: "EUR",
},
subtotal: {
amount: 0,
precision: 2,
currency: "EUR",
},
total: {
amount: 0,
precision: 2,
currency: "EUR",
},
quantity: item.quantity.toObject(),
unit_price: item.unitPrice.toObject(),
subtotal_price: item.subtotalPrice.toObject(),
discount: item.discount.toObject(),
total_price: item.totalPrice.toObject(),
}))
: [];

View File

@ -55,7 +55,25 @@ export class UTCDateValue extends ValueObject<Date> {
return this.isValid() ? this.props.toISOString() : "";
};
public toDateString = (): string => {
// Tue Jul 09 2024
return this.isValid() ? this.props.toDateString() : "";
};
public toLocaleDateString = (
locales?: Intl.LocalesArgument,
options?: Intl.DateTimeFormatOptions
): string => {
// DD/MM/YYYY
return this.isValid() ? this.props.toLocaleDateString(locales, options) : "";
};
public toLocaleTimeString = (): string => {
return this.isValid() ? this.props.toLocaleTimeString() : "";
};
public toString(): string {
// YYYY-MM-DD
if (!this.isEmpty()) {
const year = this.props.getFullYear();
const month = String(this.props.getMonth() + 1).padStart(2, "0");

View File

@ -1,4 +1,4 @@
import { IQuantuty_Response_DTO } from "../../../../../common";
import { IMoney_Response_DTO } from "../../../../../common";
export interface IListQuotes_Response_DTO {
id: string;
@ -9,6 +9,6 @@ export interface IListQuotes_Response_DTO {
lang_code: string;
currency_code: string;
subtotal: IQuantuty_Response_DTO;
total: IQuantuty_Response_DTO;
subtotal_price: IMoney_Response_DTO;
total_price: IMoney_Response_DTO;
}