Arreglos estéticos y traducciones

This commit is contained in:
David Arranz 2024-08-12 12:52:11 +02:00
parent 37c87d820e
commit 95edcbcdb7
7 changed files with 313 additions and 263 deletions

View File

@ -99,187 +99,187 @@ export const SettingsEditor = () => {
}
return (
<>
<Form {...form}>
<div className='grid w-full max-w-6xl gap-2 mx-auto'>
<h1 className='text-2xl font-semibold md:text-3xl'>
<Trans i18nKey='settings.edit.title' />
</h1>
</div>
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]'>
{form.formState.errors.root?.message && (
<Alert variant='destructive'>
<AlertCircleIcon className='w-4 h-4' />
<AlertTitle>
<Trans i18nKey='common.error' />
</AlertTitle>
<AlertDescription>{form.formState.errors.root?.message}</AlertDescription>
</Alert>
)}
<form onSubmit={handleSubmit(onSubmit)}>
<div className='mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]'>
{form.formState.errors.root?.message && (
<Alert variant='destructive'>
<AlertCircleIcon className='w-4 h-4' />
<AlertTitle>
<Trans i18nKey='common.error' />
</AlertTitle>
<AlertDescription>{form.formState.errors.root?.message}</AlertDescription>
</Alert>
)}
<nav className='grid gap-4 text-sm text-muted-foreground'>
<a
onClick={() => setActiveSection("profile")}
className={
activeSection === "profile" ? "font-semibold text-primary" : "cursor-pointer"
}
>
<Trans i18nKey='settings.edit.tabs.profile' />
</a>
<a
onClick={() => setActiveSection("quotes")}
className={
activeSection === "quotes" ? "font-semibold text-primary" : "cursor-pointer "
}
>
<Trans i18nKey='settings.edit.tabs.quotes' />
</a>
<a
onClick={() => setActiveSection("legal")}
className={
activeSection === "legal" ? "font-semibold text-primary" : "cursor-pointer "
}
>
<Trans i18nKey='settings.edit.tabs.legal' />
</a>
</nav>
<div className={cn("grid gap-6", activeSection === "profile" ? "visible" : "hidden")}>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.contact_information.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.contact_information.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.contact_information.placeholder")}
{...form.register("contact_information", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
<div className={cn("grid gap-6", activeSection === "quotes" ? "visible" : "hidden")}>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_payment_method.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_payment_method.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_payment_method.placeholder")}
{...form.register("default_payment_method", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_quote_validity.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_quote_validity.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_quote_validity.placeholder")}
{...form.register("default_quote_validity", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_notes.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_notes.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_notes.placeholder")}
{...form.register("default_notes", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
<div className={cn("grid gap-6", activeSection === "legal" ? "visible" : "hidden")}>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_legal_terms.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_legal_terms.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_legal_terms.placeholder")}
{...form.register("default_legal_terms", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
<nav className='grid gap-4 text-sm text-muted-foreground'>
<a
onClick={() => setActiveSection("profile")}
className={
activeSection === "profile" ? "font-semibold text-primary" : "cursor-pointer"
}
>
<Trans i18nKey='settings.edit.tabs.profile' />
</a>
<a
onClick={() => setActiveSection("quotes")}
className={
activeSection === "quotes" ? "font-semibold text-primary" : "cursor-pointer "
}
>
<Trans i18nKey='settings.edit.tabs.quotes' />
</a>
<a
onClick={() => setActiveSection("legal")}
className={
activeSection === "legal" ? "font-semibold text-primary" : "cursor-pointer "
}
>
<Trans i18nKey='settings.edit.tabs.legal' />
</a>
</nav>
<div className={cn("grid gap-6", activeSection === "profile" ? "visible" : "hidden")}>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.contact_information.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.contact_information.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
//autoSize
rows={8}
placeholder={t("settings.form_fields.contact_information.placeholder")}
{...form.register("contact_information", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
</form>
</Form>
</>
<div className={cn("grid gap-6", activeSection === "quotes" ? "visible" : "hidden")}>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_payment_method.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_payment_method.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_payment_method.placeholder")}
{...form.register("default_payment_method", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_quote_validity.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_quote_validity.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_quote_validity.placeholder")}
{...form.register("default_quote_validity", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_notes.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_notes.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
autoSize
placeholder={t("settings.form_fields.default_notes.placeholder")}
{...form.register("default_notes", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
<div className={cn("grid gap-6", activeSection === "legal" ? "visible" : "hidden")}>
<Card className='h-'>
<CardHeader>
<CardTitle>
<Trans i18nKey='settings.form_fields.default_legal_terms.label' />
</CardTitle>
<CardDescription>
<Trans i18nKey='settings.form_fields.default_legal_terms.desc' />
</CardDescription>
</CardHeader>
<CardContent>
<FormTextAreaField
//autoSize
rows={25}
placeholder={t("settings.form_fields.default_legal_terms.placeholder")}
{...form.register("default_legal_terms", {
required: true,
})}
errors={form.formState.errors}
/>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>
<Trans i18nKey='common.save' />
</Button>
</CardFooter>
</Card>
</div>
</div>
</form>
</Form>
);
};

View File

@ -13,7 +13,7 @@ import {
} from "@/ui";
import { CellContext } from "@tanstack/react-table";
import { t } from "i18next";
import { MoreVerticalIcon } from "lucide-react";
import { MoreHorizontalIcon } from "lucide-react";
export type DataTablaRowActionFunction<TData> = (
props: CellContext<TData, unknown>
@ -46,7 +46,7 @@ export function DataTableRowActions<TData = any, TValue = unknown>({
variant='link'
className={cn("w-4 h-4 mt-2 text-ring hover:text-muted-foreground", className)}
>
<MoreVerticalIcon className='w-4 h-4' />
<MoreHorizontalIcon className='w-4 h-4' />
<span className='sr-only'>{t("common.open_menu")}</span>
</Button>
</DropdownMenuTrigger>

View File

@ -1,5 +1,6 @@
import * as UI from "@/ui";
import * as LabelPrimitive from "@radix-ui/react-label";
import { t } from "i18next";
import React from "react";
import { FormInputProps } from "./FormProps";
@ -16,7 +17,7 @@ export const FormLabel = React.forwardRef<
>(({ label, hint, required, ...props }, ref) => {
const { error } = UI.useFormField();
const _hint = hint ? hint : required ? "obligatorio" : undefined;
const _hint = hint ? hint : required ? t("common.required") : undefined;
const _hintClassName = error ? "text-destructive font-semibold" : "";
return (
<UI.FormLabel ref={ref} className='flex justify-between text-sm' {...props}>

View File

@ -10,7 +10,7 @@ export const LayoutContent = ({
return (
<main
className={cn(
"flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10",
"flex min-h-[calc(100vh_-_theme(spacing.36))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10",
className
)}
>

View File

@ -25,9 +25,10 @@ export const UserButton = () => {
const [userMenuOpened, setUserMenuOpened] = useState(false);
const navigate = useNavigate();
const { openDialog: openLogoutDialog, DialogComponent: LogoutDialog } = useCustomDialog({
title: "Salir de la cuenta",
description: "¿Desea salir de su cuenta?",
confirmLabel: t("main_menu.user.logout"),
title: t("main_menu.logout_dialog.title"),
description: t("main_menu.logout_dialog.description"),
confirmLabel: t("main_menu.logout_dialog.confirm_label"),
cancelLabel: t("main_menu.logout_dialog.cancel_label"),
onConfirm: () => {
navigate("/logout");
},

View File

@ -1,6 +1,7 @@
{
"translation": {
"common": {
"required": "required",
"cancel": "Cancel",
"no": "No",
"yes": "Yes",
@ -12,28 +13,35 @@
"upload": "Upload",
"continue": "Continue",
"sort_asc": "Asc",
"sort_asc_description": "En order ascendente. Click para ordenar descendentemente.",
"sort_asc_description": "In ascending order. Click to sort descending order.",
"sort_desc": "Desc",
"sort_desc_description": "En orden descendente. Click para ordenar ascendentemente.",
"sort_none_description": "Sin orden. Click para ordenar ascendentemente.",
"rows_selected": "{{count}} de {{total}} fila(s) seleccionadas.",
"rows_per_page": "Filas por página",
"num_page_of_total": "Página {{count}} de {{total}}",
"go_to_first_page": "Ir a la primera página",
"go_to_prev_page": "Ir a la página anterior",
"go_to_next_page": "Ir a la página siguiente",
"go_to_last_page": "Ir a la última página",
"filter_placeholder": "Escribe aquí para filtrar...",
"reset_filter": "Quitar el filtro",
"sort_desc_description": "In descending order. Click to sort in ascending order.",
"sort_none_description": "No sorting order. Click to sort in ascending order.",
"rows_selected": "{{count}} of {{total}} row(s) selected.",
"rows_per_page": "Rows per page",
"num_page_of_total": "Page {{count}} of {{total}}",
"go_to_first_page": "Go to first page",
"go_to_prev_page": "Go to previous page",
"go_to_next_page": "Go to next page",
"go_to_last_page": "Go to last page",
"filter_placeholder": "Type here to filter...",
"reset_filter": "Remove the results filter",
"error": "Error",
"actions": "Actions",
"open_menu": "Open menu",
"duplicate_rows": "Duplicate",
"duplicate_rows_tooltip": "Duplica las fila(s) seleccionadas(s)",
"pick_date": "Elige una fecha",
"required_field": "Este campo es obligatorio",
"unsaved_changes_prompt": "Los últimos cambios no se han guardado. Si continúas, se perderán",
"edit": "Editar"
"duplicate_rows_tooltip": "Duplicate selected row(s)",
"append_empty_row": "Append row",
"append_empty_row_tooltip": "Append a empty row",
"append_article": "Append article",
"append_article_tooltip": "Select and add an item from the catalog",
"remove_row": "Remove",
"insert_row_above": "Insert row above",
"insert_row_below": "Insert row below",
"pick_date": "Select a date",
"required_field": "This field is required",
"unsaved_changes_prompt": "There are unsaved changes. If you leave, you'll lose your changes.",
"edit": "Edit"
},
"main_menu": {
"home": "Home",
@ -50,29 +58,34 @@
"support": "Support",
"logout": "Logout"
},
"logout": {}
"logout_dialog": {
"title": "Confirm",
"description": "Are you sure you want to log out?",
"confirm_label": "Log out",
"cancel_label": "Cancel"
}
},
"login_page": {
"title": "Presupuestador para distribuidores",
"description": "Introduzca su dirección de correo electrónico y contraseña para acceder",
"title": "Partner intranet",
"description": "Enter your email address and password to login",
"email_label": "Email",
"email_placeholder": "micorreo@ejemplo.com",
"password_label": "Contraseña",
"forgotten_password": "¿Has olvidado tu contraseña?",
"become_dealer": "¿Quieres ser distribuidor de Uecko?",
"contact_us": "Contacta con nosotros",
"login": "Entrar"
"email_placeholder": "myemail@sample.com",
"password_label": "Password",
"forgotten_password": "Forgot your password?",
"become_dealer": "Do you want to become a Uecko partner?",
"contact_us": "Contact us",
"login": "Log in"
},
"dashboard": {
"welcome": "Bienvenido"
"welcome": "Welcome"
},
"catalog": {
"list": {
"title": "Catálogo de artículos",
"title": "Catalog of articles",
"columns": {
"description": "Descripción",
"points": "Puntos",
"retail_price": "PVP"
"description": "Description",
"points": "Points",
"retail_price": "Retail price"
}
}
},
@ -96,31 +109,32 @@
"create": {
"title": "New quote",
"tabs": {
"general": "Datos generales",
"items": "Contenido",
"documents": "Documentos",
"history": "Historial"
"general": "General data",
"items": "Quote items",
"preview": "Quote preview",
"documents": "Documents",
"history": "History"
},
"form_groups": {
"general": {
"title": "Datos generales",
"desc": "Datos generales y cliente al que va la cotización"
"title": "General Data",
"desc": "General data and quote customer"
},
"status": {
"title": "Estado",
"desc": "Estado de la cotización"
"title": "Status",
"desc": "Quote status"
},
"items": {
"title": "Contenido de la cotización",
"desc": "Líneas de detalle de la cotización. Ayúdese del catálogo para rellenar más fácilmente el contenido."
"title": "Quote Items",
"desc": "Quote detail lines. Use the catalog to make it easier to fill in the content."
},
"documents": {
"title": "Documentos",
"desc": "Añada adjuntar con su cotización documentos como fotos, planos, croquis, etc."
"title": "Attached Documents",
"desc": "Attach documents such as photos, drawings, sketches, etc. to your quotation."
},
"history": {
"title": "",
"desc": ""
"title": "History",
"desc": "Quote history"
}
},
"edit": {
@ -141,54 +155,69 @@
},
"reference": {
"label": "Reference",
"desc": "Referencia para esta cotización",
"desc": "Quote reference",
"placeholder": ""
},
"lang_code": {
"label": "Idioma",
"desc": "Idioma de la cotización",
"label": "Language",
"desc": "Quote language",
"placeholder": ""
},
"currency_code": {
"label": "Moneda",
"desc": "Moneda de la cotización",
"label": "Currency",
"desc": "Quote currency",
"placeholder": ""
},
"customer_information": {
"label": "Customer's contact data",
"desc": "Escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
"placeholder": "Nombre y apellidos\nCalle y número\nCódigo postal y ciudad..."
"desc": "Recommendation: enter the customer's name on the first line, the address on the second line, and the zip code and city/state on the third line.",
"placeholder": "Name and surname\nStreet and number\nzip code and city or state..."
},
"payment_method": {
"label": "Forma de pago",
"placeholder": "placeholder",
"desc": "desc"
"label": "Payment method",
"placeholder": "",
"desc": "Method of payment of the quote"
},
"notes": {
"label": "Notas",
"label": "Notes",
"placeholder": "",
"desc": "desc"
"desc": "Quote's notes"
},
"validity": {
"label": "Validez de la cotización",
"label": "Validity time",
"placeholder": "",
"desc": "desc"
"desc": "Quote's validity time"
},
"discount": {
"label": "Discount",
"placeholder": "%",
"desc": "Percentage discount"
},
"tax": {
"label": "Tax",
"placeholder": "%",
"desc": "Percentage Tax"
},
"subtotal_price": {
"label": "Subtotal",
"placeholder": "",
"desc": "Quote subtotal"
},
"items": {
"quantity": {
"label": "Cantidad",
"label": "Quantity",
"placeholder": "",
"desc": ""
},
"description": {
"label": "Descripción",
"label": "Description",
"placeholder": "",
"desc": ""
},
"unit_price": {
"label": "Imp. unitario",
"label": "Unit price",
"placeholder": "",
"desc": "Importe unitario del artículo"
"desc": "Item unit price"
},
"subtotal_price": {
"label": "Subtotal",
@ -198,12 +227,12 @@
"discount": {
"label": "Dto (%)",
"placeholder": "",
"desc": "Porcentaje de descuento"
"desc": "Percentage discount"
},
"total_price": {
"label": "Imp. total",
"label": "Total price",
"placeholder": "",
"desc": "Importe total con el descuento ya aplicado"
"desc": "Total price with percentage discount"
}
}
}
@ -220,34 +249,34 @@
},
"form_fields": {
"image": {
"label": "Información de contacto",
"label": "Logotype",
"placeholder": "placeholder",
"desc": "Información de contacto"
},
"contact_information": {
"label": "Información de contacto",
"label": "Your contact information",
"placeholder": "placeholder",
"desc": "Información de contacto"
"desc": "Your contact information as a dealer that will appear on the quotes given to your customers."
},
"default_legal_terms": {
"label": "Cláusulas legales",
"label": "Legal terms",
"placeholder": "",
"desc": "desc"
"desc": "Legal information to be included at the end of your quotes"
},
"default_payment_method": {
"label": "Forma de pago",
"label": "Payment method",
"placeholder": "placeholder",
"desc": "desc"
"desc": "Default payment method to be used for new quotes"
},
"default_notes": {
"label": "Notas",
"label": "Notes",
"placeholder": "",
"desc": "desc"
"desc": "Default notes to be used for new quotes"
},
"default_quote_validity": {
"label": "Validez por defecto",
"label": "Quote validity",
"placeholder": "",
"desc": ""
"desc": "Default validity time to be used for new quotes"
}
}
}

View File

@ -1,6 +1,7 @@
{
"translation": {
"common": {
"required": "obligatorio",
"cancel": "Cancelar",
"no": "No",
"yes": "Sí",
@ -30,9 +31,16 @@
"open_menu": "Abrir el menú",
"duplicate_rows": "Duplicar",
"duplicate_rows_tooltip": "Duplica las fila(s) seleccionadas(s)",
"append_empty_row": "Añadir fila",
"append_empty_row_tooltip": "Añadir una fila vacía",
"append_article": "Añadir artículo",
"append_article_tooltip": "Elegir un artículo del catálogo y añadirlo",
"remove_row": "Eliminar",
"insert_row_above": "Insertar fila encima",
"insert_row_below": "Insertar fila debajo",
"pick_date": "Elige una fecha",
"required_field": "Este campo es obligatorio",
"unsaved_changes_prompt": "Los últimos cambios no se han guardado. Si continúas, se perderán",
"unsaved_changes_prompt": "Los últimos cambios no se han guardado. Si continúas, se perderán.",
"edit": "Editar"
},
"main_menu": {
@ -50,7 +58,12 @@
"support": "Soporte",
"logout": "Salir"
},
"logout": {}
"logout_dialog": {
"title": "Salir de la cuenta",
"description": "¿Desea salir de su cuenta?",
"confirm_label": "Salir",
"cancel_label": "Cancelar"
}
},
"login_page": {
"title": "Presupuestador para distribuidores",
@ -99,6 +112,7 @@
"tabs": {
"general": "Datos generales",
"items": "Contenido",
"preview": "Vista previa",
"documents": "Documentos",
"history": "Historial"
},
@ -157,7 +171,7 @@
},
"customer_information": {
"label": "Datos del cliente",
"desc": "Escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
"desc": "Recomensación: escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
"placeholder": "Nombre y apellidos\nCalle y número\nCódigo postal y ciudad..."
},
"payment_method": {
@ -177,11 +191,16 @@
},
"discount": {
"label": "Descuento",
"placeholder": "",
"desc": ""
"placeholder": "%",
"desc": "Porcentaje de descuento"
},
"tax": {
"label": "IVA",
"placeholder": "%",
"desc": "Porcentaje de IVA"
},
"subtotal_price": {
"label": "Importe neto",
"placeholder": "",
"desc": ""
},