Presupuestador_web/client/src/app/quotes/create.tsx
David Arranz c77a3a3af5 feat: internationalize button labels and UI components
- Updated CancelButton and SubmitButton to use i18next for localization.
- Modified DataTableColumnHeader and DataTableFacetedFilter to include translations for sorting and filtering messages.
- Enhanced DataTableSelectionColumn with localized aria-labels for accessibility.
- Localized titles and messages in SimpleEmptyState and ErrorOverlay components.
- Updated LayoutHeader to use i18next for navigation toggle label.
- Integrated i18next into useLogout for error messages.
- Localized alert dialog actions in useRemoveAlertDialog.
- Added new translations in en.json and es.json for various UI components.
- Updated breadcrumb and carousel components to use localized strings.
- Enhanced pagination component with i18next for navigation labels.
- Localized sheet component close button text.
2026-10-05 13:58:03 +02:00

162 lines
4.8 KiB
TypeScript

import {
BackHistoryButton,
FormDatePickerField,
FormGroup,
FormTextAreaField,
FormTextField,
LoadingOverlay,
} from "@/components";
import { t } from "i18next";
import { SubmitButton } from "@/components";
import { useUnsavedChangesNotifier } from "@/lib/hooks";
import { Button, Form, 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 { SubmitHandler, useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import SpanishJoiMessages from "../../spanish-joi-messages.json";
import { useQuotes } from "./hooks";
interface QuoteDataForm extends ICreateQuote_Request_DTO {}
export const QuoteCreate = () => {
const navigate = useNavigate();
const { toast } = useToast();
const { useCreate } = useQuotes();
const { mutate, isPending } = useCreate();
const defaultValues = useMemo(
() => ({
date: new Date(Date.now()).toUTCString(),
customer_reference: "",
customer_information: "",
//reference: "",
}),
[]
);
const form = useForm<QuoteDataForm>({
mode: "onBlur",
defaultValues,
resolver: joiResolver(
Joi.object({
customer_reference: Joi.string(),
date: Joi.date().required(),
customer_information: Joi.string().required(),
}),
{
messages: {
es: SpanishJoiMessages,
},
}
),
});
const { formState, reset, getValues, handleSubmit } = form;
const { isSubmitting, isDirty } = formState;
useUnsavedChangesNotifier({
isDirty,
});
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" });
},
});
} finally {
//setLoading(false);
}
};
if (isSubmitting) {
return <LoadingOverlay title={t("quotes.notifications.saving")} />;
}
/*if (isError) {
return <ErrorOverlay errorMessage={mutateError?.message} />;
}*/
if (isPending) {
return <LoadingOverlay />;
}
return (
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='mx-auto grid max-w-[90rem] flex-1 auto-rows-max gap-6'>
<div className='flex items-center gap-4'>
<BackHistoryButton />
<h1 className='flex-1 text-xl font-semibold tracking-tight shrink-0 whitespace-nowrap sm:grow-0'>
{t("quotes.create.title")}
</h1>
</div>
<div className='grid w-6/12 gap-6 mx-auto'>
<FormGroup
className='md:col-span-4'
title={t("quotes.create.form_groups.general.title")}
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")}>
{t("common.discard")}
</Button>
<SubmitButton size='sm' label={t("common.continue")}></SubmitButton>
</div>
}
>
<FormTextField
required
name='customer_reference'
label={t("quotes.form_fields.customer_reference.label")}
description={t("quotes.form_fields.customer_reference.desc")}
placeholder={t("quotes.form_fields.customer_reference.placeholder")}
/>
<FormDatePickerField
required
label={t("quotes.form_fields.date.label")}
description={t("quotes.form_fields.date.desc")}
placeholder={t("quotes.form_fields.date.placeholder")}
name='date'
/>
<Separator />
<FormTextAreaField
rows={4}
className='row-span-2'
name='customer_information'
required
label={t("quotes.form_fields.customer_information.label")}
description={t("quotes.form_fields.customer_information.desc")}
placeholder={t("quotes.form_fields.customer_information.placeholder")}
/>
</FormGroup>
</div>
</div>
</form>
</Form>
);
};