Clientes y facturas de cliente
This commit is contained in:
parent
ac11eaffdf
commit
c8db3099a4
@ -10,9 +10,6 @@
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&display=swap"
|
||||
rel="stylesheet">
|
||||
|
||||
<title>FactuGES 2025</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { PercentageDTO } from "@erp/core";
|
||||
import { Percentage } from "@repo/rdx-ddd";
|
||||
|
||||
export function formatPercentageDTO(Percentage_value: PercentageDTO) {
|
||||
const value = Percentage.create({
|
||||
value: Number(Percentage_value.value),
|
||||
scale: Number(Percentage_value.scale),
|
||||
}).data;
|
||||
|
||||
return value.toNumber;
|
||||
}
|
||||
@ -1,2 +1,3 @@
|
||||
export * from "./format-money-dto";
|
||||
export * from "./format-percentage-dto";
|
||||
export * from "./map-dto-to-customer-invoice-props";
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
import { MoneyDTO } from "@erp/core";
|
||||
import { MoneyValue } from "@repo/rdx-ddd";
|
||||
|
||||
export function formatMoneyDTO(amount: MoneyDTO, locale: string) {
|
||||
const money = MoneyValue.create({
|
||||
value: Number(amount.value),
|
||||
currency_code: amount.currency_code,
|
||||
scale: Number(amount.scale),
|
||||
}).data;
|
||||
|
||||
return money.format(locale);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { formatMoneyDTO } from "../../helpers";
|
||||
import { formatMoneyDTO, formatPercentageDTO } from "../../helpers";
|
||||
|
||||
export class CustomerInvoiceReportPresenter extends Presenter<
|
||||
GetCustomerInvoiceByIdResponseDTO,
|
||||
@ -11,6 +11,10 @@ export class CustomerInvoiceReportPresenter extends Presenter<
|
||||
|
||||
return {
|
||||
...invoiceDTO,
|
||||
subtotal_amount: formatMoneyDTO(invoiceDTO.subtotal_amount, locale),
|
||||
percentage: formatPercentageDTO(invoiceDTO.discount_percentage),
|
||||
discount_amount: formatMoneyDTO(invoiceDTO.discount_amount, locale),
|
||||
taxes_amount: formatMoneyDTO(invoiceDTO.taxes_amount, locale),
|
||||
total_amount: formatMoneyDTO(invoiceDTO.total_amount, locale),
|
||||
};
|
||||
}
|
||||
|
||||
@ -182,25 +182,29 @@
|
||||
<div class="grow">
|
||||
<table class="table-header min-w-full bg-transparent">
|
||||
<tbody>
|
||||
{{#if percentage}}
|
||||
<tr>
|
||||
<td class="px-4 py-2 text-right">Importe neto</td>
|
||||
<td class="px-4 py-2 text-right">761,14 €</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 text-right">Descuento 0%</td>
|
||||
<td class="px-4 py-2 text-right">0</td>
|
||||
<td class="px-4 py-2 text-right">{{discount_amount.value}}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<!-- dto 0-->
|
||||
{{/if}}
|
||||
<tr>
|
||||
<td class="px-4 py-2 text-right">Base imponible</td>
|
||||
<td class="px-4 py-2 text-right">765,14€</td>
|
||||
<td class="px-4 py-2 text-right">{{subtotal_amount}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 text-right">IVA 21%</td>
|
||||
<td class="px-4 py-2 text-right">159,84 €</td>
|
||||
<td class="px-4 py-2 text-right">{{taxes_amount}}</td>
|
||||
</tr>
|
||||
<tr class="bg-[#f08119] text-white font-semibold">
|
||||
<td class="px-4 py-2 text-right bg-amber-700">Total factura</td>
|
||||
<td class="px-4 py-2 text-right">960,56 €</td>
|
||||
<td class="px-4 py-2 text-right">{{total_amount}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
34
modules/customers/src/web/components/form-debug.tsx
Normal file
34
modules/customers/src/web/components/form-debug.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
|
||||
export const FormDebug = ({ form }: { form: UseFormReturn }) => {
|
||||
const {
|
||||
watch,
|
||||
formState: { isDirty, dirtyFields, defaultValues },
|
||||
} = form;
|
||||
|
||||
const currentValues = watch();
|
||||
|
||||
return (
|
||||
<div className='mt-6 p-4 border rounded bg-gray-50'>
|
||||
<p>
|
||||
<strong>¿Formulario modificado?</strong> {isDirty ? "Sí" : "No"}
|
||||
</p>
|
||||
<div className='mt-2'>
|
||||
<strong>Campos modificados:</strong>
|
||||
{Object.keys(dirtyFields).length > 0 ? (
|
||||
<ul className='list-disc list-inside mt-1'>
|
||||
{Object.keys(dirtyFields).map((campo) => (
|
||||
<li key={campo}>
|
||||
<span className='font-medium'>{campo}:</span>{" "}
|
||||
<span className='text-gray-500 line-through'>{String(defaultValues![campo])}</span>{" "}
|
||||
➝ <span className='text-green-600'>{String(currentValues[campo])}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>Ninguno</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -3,4 +3,5 @@ export * from "./customer-editor-skeleton";
|
||||
export * from "./customers-layout";
|
||||
export * from "./customers-list-grid";
|
||||
export * from "./error-alert";
|
||||
export * from "./form-debug";
|
||||
export * from "./not-found-card";
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
import { TaxesMultiSelectField } from "@erp/core/components";
|
||||
import { SelectField, TextAreaField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { CURRENCY_OPTIONS, LANGUAGE_OPTIONS } from "../../constants";
|
||||
import { useTranslation } from "../../i18n";
|
||||
|
||||
export function CustomerAdditionalConfigFields({ control }: { control: any }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.additional_config.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.additional_config.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TaxesMultiSelectField
|
||||
control={control}
|
||||
name='default_taxes'
|
||||
required
|
||||
label={t("form_fields.default_taxes.label")}
|
||||
placeholder={t("form_fields.default_taxes.placeholder")}
|
||||
description={t("form_fields.default_taxes.description")}
|
||||
/>
|
||||
<SelectField
|
||||
control={control}
|
||||
name='language_code'
|
||||
required
|
||||
label={t("form_fields.language_code.label")}
|
||||
placeholder={t("form_fields.language_code.placeholder")}
|
||||
description={t("form_fields.language_code.description")}
|
||||
items={[...LANGUAGE_OPTIONS]}
|
||||
/>
|
||||
<SelectField
|
||||
control={control}
|
||||
name='currency_code'
|
||||
required
|
||||
label={t("form_fields.currency_code.label")}
|
||||
placeholder={t("form_fields.currency_code.placeholder")}
|
||||
description={t("form_fields.currency_code.description")}
|
||||
items={[...CURRENCY_OPTIONS]}
|
||||
/>
|
||||
<TextAreaField
|
||||
control={control}
|
||||
name='legal_record'
|
||||
required
|
||||
label={t("form_fields.legal_record.label")}
|
||||
placeholder={t("form_fields.legal_record.placeholder")}
|
||||
description={t("form_fields.legal_record.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
import { SelectField, TextField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { COUNTRY_OPTIONS } from "../../constants";
|
||||
import { useTranslation } from "../../i18n";
|
||||
|
||||
export function CustomerAddressFields({ control }: { control: any }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.address.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.address.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TextField
|
||||
className='xl:col-span-2'
|
||||
control={control}
|
||||
name='street'
|
||||
required
|
||||
label={t("form_fields.street.label")}
|
||||
placeholder={t("form_fields.street.placeholder")}
|
||||
description={t("form_fields.street.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='city'
|
||||
required
|
||||
label={t("form_fields.city.label")}
|
||||
placeholder={t("form_fields.city.placeholder")}
|
||||
description={t("form_fields.city.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='postal_code'
|
||||
required
|
||||
label={t("form_fields.postal_code.label")}
|
||||
placeholder={t("form_fields.postal_code.placeholder")}
|
||||
description={t("form_fields.postal_code.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='province'
|
||||
required
|
||||
label={t("form_fields.province.label")}
|
||||
placeholder={t("form_fields.province.placeholder")}
|
||||
description={t("form_fields.province.description")}
|
||||
/>
|
||||
<SelectField
|
||||
control={control}
|
||||
name='country'
|
||||
required
|
||||
label={t("form_fields.country.label")}
|
||||
placeholder={t("form_fields.country.placeholder")}
|
||||
description={t("form_fields.country.description")}
|
||||
items={[...COUNTRY_OPTIONS]}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
import { TextField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { useTranslation } from "../../i18n";
|
||||
|
||||
export function CustomerBasicInfoFields({ control }: { control: any }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.basic_info.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.basic_info.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<FormField
|
||||
control={control}
|
||||
name='is_company'
|
||||
render={({ field }) => (
|
||||
<FormItem className='space-y-3'>
|
||||
<FormLabel>{t("form_fields.customer_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
value={field.value ? "1" : "0"}
|
||||
onValueChange={(val) => field.onChange(val === "1")}
|
||||
className='flex gap-6'
|
||||
>
|
||||
<FormItem className='flex items-center space-x-2'>
|
||||
<FormControl>
|
||||
<RadioGroupItem value='1' />
|
||||
</FormControl>
|
||||
<FormLabel className='font-normal'>
|
||||
{t("form_fields.customer_type.company")}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className='flex items-center space-x-2'>
|
||||
<FormControl>
|
||||
<RadioGroupItem value='0' />
|
||||
</FormControl>
|
||||
<FormLabel className='font-normal'>
|
||||
{t("form_fields.customer_type.individual")}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={control}
|
||||
name='name'
|
||||
required
|
||||
label={t("form_fields.name.label")}
|
||||
placeholder={t("form_fields.name.placeholder")}
|
||||
description={t("form_fields.name.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='trade_name'
|
||||
label={t("form_fields.trade_name.label")}
|
||||
placeholder={t("form_fields.trade_name.placeholder")}
|
||||
description={t("form_fields.trade_name.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='reference'
|
||||
label={t("form_fields.reference.label")}
|
||||
placeholder={t("form_fields.reference.placeholder")}
|
||||
description={t("form_fields.reference.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
import { TextField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { useTranslation } from "../../i18n";
|
||||
|
||||
export function CustomerContactFields({ control }: { control: any }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.contact_info.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.contact_info.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TextField
|
||||
control={control}
|
||||
name='email_primary'
|
||||
label={t("form_fields.email_primary.label")}
|
||||
placeholder={t("form_fields.email_primary.placeholder")}
|
||||
description={t("form_fields.email_primary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='email_secondary'
|
||||
label={t("form_fields.email_secondary.label")}
|
||||
placeholder={t("form_fields.email_secondary.placeholder")}
|
||||
description={t("form_fields.email_secondary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='phone_primary'
|
||||
label={t("form_fields.phone_primary.label")}
|
||||
placeholder={t("form_fields.phone_primary.placeholder")}
|
||||
description={t("form_fields.phone_primary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='phone_secondary'
|
||||
label={t("form_fields.phone_secondary.label")}
|
||||
placeholder={t("form_fields.phone_secondary.placeholder")}
|
||||
description={t("form_fields.phone_secondary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='mobile_primary'
|
||||
label={t("form_fields.mobile_primary.label")}
|
||||
placeholder={t("form_fields.mobile_primary.placeholder")}
|
||||
description={t("form_fields.mobile_primary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='mobile_secondary'
|
||||
label={t("form_fields.mobile_secondary.label")}
|
||||
placeholder={t("form_fields.mobile_secondary.placeholder")}
|
||||
description={t("form_fields.mobile_secondary.description")}
|
||||
/>
|
||||
<TextField
|
||||
control={control}
|
||||
name='fax'
|
||||
label={t("form_fields.fax.label")}
|
||||
placeholder={t("form_fields.fax.placeholder")}
|
||||
description={t("form_fields.fax.description")}
|
||||
/>
|
||||
<TextField
|
||||
className='xl:col-span-2'
|
||||
control={control}
|
||||
name='website'
|
||||
label={t("form_fields.website.label")}
|
||||
placeholder={t("form_fields.website.placeholder")}
|
||||
description={t("form_fields.website.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -1,29 +1,16 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { FieldErrors, useForm } from "react-hook-form";
|
||||
|
||||
import { TaxesMultiSelectField } from "@erp/core/components";
|
||||
import { SelectField, TextAreaField, TextField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
import { Form } from "@repo/shadcn-ui/components";
|
||||
|
||||
import { useUnsavedChangesNotifier } from "@erp/core/hooks";
|
||||
import { COUNTRY_OPTIONS, LANGUAGE_OPTIONS } from "../../constants/customer.constants";
|
||||
import { FormDebug } from "../../components/form-debug";
|
||||
import { useTranslation } from "../../i18n";
|
||||
import { CustomerData, CustomerUpdateData, CustomerUpdateSchema } from "../../schemas";
|
||||
import { CustomerAdditionalConfigFields } from "./customer-additional-config-fields";
|
||||
import { CustomerAddressFields } from "./customer-address-fields";
|
||||
import { CustomerBasicInfoFields } from "./customer-basic-info-fields";
|
||||
import { CustomerContactFields } from "./customer-contact-fields";
|
||||
|
||||
interface CustomerFormProps {
|
||||
formId: string;
|
||||
@ -63,262 +50,16 @@ export const CustomerEditForm = ({ formId, data, onSubmit, isPending }: Customer
|
||||
form.reset(data);
|
||||
};
|
||||
|
||||
const {
|
||||
formState: { isDirty, dirtyFields },
|
||||
} = form;
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<div className='mt-6 p-4 border rounded bg-gray-50'>
|
||||
<p>
|
||||
<strong>¿Formulario modificado?</strong> {isDirty ? "Sí" : "No"}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Campos modificados:</strong>{" "}
|
||||
{Object.keys(dirtyFields).length > 0 ? Object.keys(dirtyFields).join(", ") : "Ninguno"}
|
||||
</p>
|
||||
</div>{" "}
|
||||
<FormDebug form={form} />
|
||||
<form id={formId} onSubmit={form.handleSubmit(handleSubmit, handleError)}>
|
||||
<div className='w-full grid grid-cols-1 space-y-8 space-x-8 xl:grid-cols-2'>
|
||||
{/* Información básica */}
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.basic_info.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.basic_info.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='is_company'
|
||||
render={({ field }) => (
|
||||
<FormItem className='space-y-3'>
|
||||
<FormLabel>{t("form_fields.customer_type.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={(value) => field.onChange(value === "1")}
|
||||
defaultValue={field.value ? "1" : "0"}
|
||||
className='flex gap-6'
|
||||
>
|
||||
<FormItem className='flex items-center space-x-2'>
|
||||
<FormControl>
|
||||
<RadioGroupItem value='1' />
|
||||
</FormControl>
|
||||
<FormLabel className='font-normal'>
|
||||
{t("form_fields.customer_type.company")}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
|
||||
<FormItem className='flex items-center space-x-2'>
|
||||
<FormControl>
|
||||
<RadioGroupItem value='0' />
|
||||
</FormControl>
|
||||
<FormLabel className='font-normal'>
|
||||
{t("form_fields.customer_type.individual")}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='name'
|
||||
required
|
||||
label={t("form_fields.name.label")}
|
||||
placeholder={t("form_fields.name.placeholder")}
|
||||
description={t("form_fields.name.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='trade_name'
|
||||
label={t("form_fields.trade_name.label")}
|
||||
placeholder={t("form_fields.trade_name.placeholder")}
|
||||
description={t("form_fields.trade_name.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='reference'
|
||||
label={t("form_fields.reference.label")}
|
||||
placeholder={t("form_fields.reference.placeholder")}
|
||||
description={t("form_fields.reference.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Dirección */}
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.address.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.address.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TextField
|
||||
className='xl:col-span-2'
|
||||
control={form.control}
|
||||
name='street'
|
||||
required
|
||||
label={t("form_fields.street.label")}
|
||||
placeholder={t("form_fields.street.placeholder")}
|
||||
description={t("form_fields.street.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='city'
|
||||
required
|
||||
label={t("form_fields.city.label")}
|
||||
placeholder={t("form_fields.city.placeholder")}
|
||||
description={t("form_fields.city.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='postal_code'
|
||||
required
|
||||
label={t("form_fields.postal_code.label")}
|
||||
placeholder={t("form_fields.postal_code.placeholder")}
|
||||
description={t("form_fields.postal_code.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='province'
|
||||
required
|
||||
label={t("form_fields.province.label")}
|
||||
placeholder={t("form_fields.province.placeholder")}
|
||||
description={t("form_fields.province.description")}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
control={form.control}
|
||||
name='country'
|
||||
required
|
||||
label={t("form_fields.country.label")}
|
||||
placeholder={t("form_fields.country.placeholder")}
|
||||
description={t("form_fields.country.description")}
|
||||
items={COUNTRY_OPTIONS}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Contacto */}
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.contact_info.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.contact_info.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='email_primary'
|
||||
label={t("form_fields.email_primary.label")}
|
||||
placeholder={t("form_fields.email_primary.placeholder")}
|
||||
description={t("form_fields.email_primary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='email_secondary'
|
||||
label={t("form_fields.email_secondary.label")}
|
||||
placeholder={t("form_fields.email_secondary.placeholder")}
|
||||
description={t("form_fields.email_secondary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='phone_primary'
|
||||
label={t("form_fields.phone_primary.label")}
|
||||
placeholder={t("form_fields.phone_primary.placeholder")}
|
||||
description={t("form_fields.phone_primary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='phone_secondary'
|
||||
label={t("form_fields.phone_secondary.label")}
|
||||
placeholder={t("form_fields.phone_secondary.placeholder")}
|
||||
description={t("form_fields.phone_secondary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='mobile_primary'
|
||||
label={t("form_fields.mobile_primary.label")}
|
||||
placeholder={t("form_fields.mobile_primary.placeholder")}
|
||||
description={t("form_fields.mobile_primary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='mobile_secondary'
|
||||
label={t("form_fields.mobile_secondary.label")}
|
||||
placeholder={t("form_fields.mobile_secondary.placeholder")}
|
||||
description={t("form_fields.mobile_secondary.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
control={form.control}
|
||||
name='fax'
|
||||
label={t("form_fields.fax.label")}
|
||||
placeholder={t("form_fields.fax.placeholder")}
|
||||
description={t("form_fields.fax.description")}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
className='xl:col-span-2'
|
||||
control={form.control}
|
||||
name='website'
|
||||
label={t("form_fields.website.label")}
|
||||
placeholder={t("form_fields.website.placeholder")}
|
||||
description={t("form_fields.website.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Configuraciones Adicionales */}
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("form_groups.additional_config.title")}</CardTitle>
|
||||
<CardDescription>{t("form_groups.additional_config.description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
||||
<TaxesMultiSelectField
|
||||
control={form.control}
|
||||
name='default_tax'
|
||||
required
|
||||
label={t("form_fields.default_tax.label")}
|
||||
placeholder={t("form_fields.default_tax.placeholder")}
|
||||
description={t("form_fields.default_tax.description")}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
control={form.control}
|
||||
name='language_code'
|
||||
required
|
||||
label={t("form_fields.lang_code.label")}
|
||||
placeholder={t("form_fields.lang_code.placeholder")}
|
||||
description={t("form_fields.lang_code.description")}
|
||||
items={LANGUAGE_OPTIONS}
|
||||
/>
|
||||
|
||||
<TextAreaField
|
||||
className=''
|
||||
control={form.control}
|
||||
name='legal_record'
|
||||
required
|
||||
label={t("form_fields.legal_record.label")}
|
||||
placeholder={t("form_fields.legal_record.placeholder")}
|
||||
description={t("form_fields.legal_record.description")}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CustomerBasicInfoFields control={form.control} />
|
||||
<CustomerAddressFields control={form.control} />
|
||||
<CustomerContactFields control={form.control} />
|
||||
<CustomerAdditionalConfigFields control={form.control} />
|
||||
</div>
|
||||
<Button type='submit'>{t("pages.update.submit")}</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
|
||||
@ -37,6 +37,9 @@ export function TextField<TFormValues extends FieldValues>({
|
||||
const { t } = useTranslation();
|
||||
const isDisabled = disabled || readOnly;
|
||||
|
||||
const { getFieldState } = control;
|
||||
const state = getFieldState(name);
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={control}
|
||||
@ -50,12 +53,7 @@ export function TextField<TFormValues extends FieldValues>({
|
||||
</div>
|
||||
)}
|
||||
<FormControl>
|
||||
<Input
|
||||
disabled={isDisabled}
|
||||
placeholder={placeholder}
|
||||
{...field}
|
||||
className='font-medium'
|
||||
/>
|
||||
<Input disabled={isDisabled} placeholder={placeholder} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<p className={cn("text-xs text-muted-foreground", !description && "invisible")}>
|
||||
|
||||
@ -50,9 +50,9 @@
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: Geist, sans-serif;
|
||||
/*--font-sans: Geist, sans-serif;
|
||||
--font-serif: Merriweather, serif;
|
||||
--font-mono: "Geist Mono", monospace;
|
||||
--font-mono: "Geist Mono", monospace;*/
|
||||
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
@ -168,6 +168,14 @@
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply font-semibold;
|
||||
}
|
||||
|
||||
label {
|
||||
@apply font-light;
|
||||
}
|
||||
}
|
||||
|
||||
@source "../components";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user