feat: agregar soporte para selección de idioma en la creación de cotizaciones

This commit is contained in:
David Arranz 2026-10-08 12:36:03 +02:00
parent 08f01e2b3b
commit b4a6ac18f7
2 changed files with 63 additions and 32 deletions

View File

@ -7,8 +7,6 @@ import { useMemo } from "react";
import { useFormContext, useWatch } from "react-hook-form";
const calculateQuoteTotals = (prices: any) => {
console.debug("calculateQuoteTotals", prices);
const discountOrError = Percentage.create(
prices[1] || {
amount: null,

View File

@ -10,35 +10,53 @@ import { t } from "i18next";
import { SubmitButton } from "@/components";
import { useUnsavedChangesNotifier } from "@/lib/hooks";
import { Button, Form, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator } from "@/ui";
import { documentedLanguages } from "@/lib/languages";
import {
Button,
Form,
Label,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Separator,
} from "@/ui";
import { useToast } from "@/ui/use-toast";
import { joiResolver } from "@hookform/resolvers/joi";
import { ICreateQuote_Request_DTO } from "@shared/contexts";
import Joi from "joi";
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import SpanishJoiMessages from "../../spanish-joi-messages.json";
import { useQuotes } from "./hooks";
import { documentedLanguages } from "@/lib/languages";
interface QuoteDataForm extends ICreateQuote_Request_DTO {}
export const QuoteCreate = () => {
const navigate = useNavigate();
const { i18n } = useTranslation();
const { toast } = useToast();
const { useCreate } = useQuotes();
const { mutate, isPending } = useCreate();
const { mutateAsync, isPending } = useCreate();
const [createdQuoteId, setCreatedQuoteId] = useState<string>();
const interfaceLanguage = i18n.resolvedLanguage ?? i18n.language;
const documentLanguage = documentedLanguages.some(({ code }) => code === interfaceLanguage)
? interfaceLanguage
: "es";
const defaultValues = useMemo(
() => ({
date: new Date(Date.now()).toUTCString(),
lang_code: "es",
lang_code: documentLanguage,
customer_reference: "",
customer_information: "",
//reference: "",
}),
[]
[documentLanguage]
);
const form = useForm<QuoteDataForm>({
@ -49,6 +67,9 @@ export const QuoteCreate = () => {
customer_reference: Joi.string(),
date: Joi.date().required(),
customer_information: Joi.string().required(),
lang_code: Joi.string()
.valid(...documentedLanguages.map(({ code }) => code))
.required(),
}),
{
messages: {
@ -58,35 +79,35 @@ export const QuoteCreate = () => {
),
});
const { formState, reset, getValues, handleSubmit } = form;
const { formState, reset, handleSubmit } = form;
const { isSubmitting, isDirty } = formState;
useUnsavedChangesNotifier({
isDirty,
});
useEffect(() => {
if (createdQuoteId) {
navigate(`/quotes/edit/${createdQuoteId}`, { relative: "path" });
}
}, [createdQuoteId, navigate]);
const onSubmit: SubmitHandler<QuoteDataForm> = async (formData) => {
try {
mutate(formData, {
onError: (error) => {
console.debug(error);
toast({
title: t("common.error"),
description: error.message,
variant: "destructive",
});
},
onSuccess: (data) => {
reset(getValues());
toast({
title: t("quotes.notifications.created"),
variant: "default",
});
navigate(`/quotes/edit/${data.id}`, { relative: "path" });
},
const data = await mutateAsync(formData);
reset(formData);
toast({
title: t("quotes.notifications.created"),
variant: "default",
});
setCreatedQuoteId(data.id);
} catch (error) {
console.debug(error);
toast({
title: t("common.error"),
description: (error as Error).message,
variant: "destructive",
});
} finally {
//setLoading(false);
}
};
@ -120,7 +141,12 @@ export const QuoteCreate = () => {
description={t("quotes.create.form_groups.general.desc")}
footerActions={
<div className='flex items-stretch justify-between flex-1'>
<Button size='sm' variant={"outline"} onClick={() => navigate("/quotes")}>
<Button
type='button'
size='sm'
variant={"outline"}
onClick={() => navigate("/quotes")}
>
{t("common.discard")}
</Button>
<SubmitButton size='sm' label={t("common.continue")}></SubmitButton>
@ -144,13 +170,18 @@ export const QuoteCreate = () => {
/>
<div className='grid gap-2'>
<Label htmlFor='lang_code'>{t("quotes.form_fields.lang_code.label")}</Label>
<Label htmlFor='lang_code' className='font-semibold'>
{t("quotes.form_fields.lang_code.label")}
</Label>
<Controller
control={form.control}
name='lang_code'
render={({ field }) => (
<Select value={field.value || "es"} onValueChange={field.onChange}>
<SelectTrigger id='lang_code' aria-label={t("quotes.form_fields.lang_code.label")}>
<SelectTrigger
id='lang_code'
aria-label={t("quotes.form_fields.lang_code.label")}
>
<SelectValue />
</SelectTrigger>
<SelectContent>
@ -164,7 +195,9 @@ export const QuoteCreate = () => {
</Select>
)}
/>
<p className='text-sm text-muted-foreground'>{t("quotes.form_fields.lang_code.desc")}</p>
<p className='text-sm text-muted-foreground'>
{t("quotes.form_fields.lang_code.desc")}
</p>
</div>
<Separator />