Compare commits
No commits in common. "c8db3099a47abc0a7dcba81834c6dd557642f04d" and "096abdccb2e8684d4cc32642a1acaf2df1daac97" have entirely different histories.
c8db3099a4
...
096abdccb2
@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<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>
|
<title>FactuGES 2025</title>
|
||||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
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,11 +0,0 @@
|
|||||||
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,3 +1 @@
|
|||||||
export * from "./format-money-dto";
|
|
||||||
export * from "./format-percentage-dto";
|
|
||||||
export * from "./map-dto-to-customer-invoice-props";
|
export * from "./map-dto-to-customer-invoice-props";
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
import {
|
import { ValidationErrorCollection, ValidationErrorDetail } from "@repo/rdx-ddd";
|
||||||
ValidationErrorCollection,
|
|
||||||
ValidationErrorDetail,
|
|
||||||
extractOrPushError,
|
|
||||||
} from "@repo/rdx-ddd";
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CreateCustomerInvoiceRequestDTO } from "../../../common";
|
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItem,
|
CustomerInvoiceItem,
|
||||||
CustomerInvoiceItemDescription,
|
CustomerInvoiceItemDescription,
|
||||||
ItemAmount,
|
ItemAmount,
|
||||||
ItemDiscount,
|
ItemDiscount,
|
||||||
ItemQuantity,
|
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
|
import { extractOrPushError } from "./extract-or-push-error";
|
||||||
import { hasNoUndefinedFields } from "./has-no-undefined-fields";
|
import { hasNoUndefinedFields } from "./has-no-undefined-fields";
|
||||||
|
|
||||||
export function mapDTOToCustomerInvoiceItemsProps(
|
export function mapDTOToCustomerInvoiceItemsProps(
|
||||||
dtoItems: Pick<CreateCustomerInvoiceRequestDTO, "items">["items"]
|
dtoItems: Pick<CreateCustomerInvoiceCommandDTO, "items">["items"]
|
||||||
): Result<CustomerInvoiceItem[], ValidationErrorCollection> {
|
): Result<CustomerInvoiceItem[], ValidationErrorCollection> {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
const items: CustomerInvoiceItem[] = [];
|
const items: CustomerInvoiceItem[] = [];
|
||||||
@ -30,8 +25,9 @@ export function mapDTOToCustomerInvoiceItemsProps(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const quantity = extractOrPushError(
|
const quantity = extractOrPushError(
|
||||||
ItemQuantity.create({
|
CustomerInvoiceItemQuantity.create({
|
||||||
value: Number(item.quantity),
|
amount: item.quantity.amount,
|
||||||
|
scale: item.quantity.scale,
|
||||||
}),
|
}),
|
||||||
path("quantity"),
|
path("quantity"),
|
||||||
errors
|
errors
|
||||||
|
|||||||
@ -1,20 +1,14 @@
|
|||||||
import {
|
import { ValidationErrorCollection, ValidationErrorDetail } from "@erp/core/api";
|
||||||
CurrencyCode,
|
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
UniqueID,
|
|
||||||
UtcDate,
|
|
||||||
ValidationErrorCollection,
|
|
||||||
ValidationErrorDetail,
|
|
||||||
extractOrPushError,
|
|
||||||
maybeFromNullableVO,
|
|
||||||
} from "@repo/rdx-ddd";
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CreateCustomerInvoiceRequestDTO } from "../../../common";
|
import { CreateCustomerInvoiceCommandDTO } from "../../../common/dto";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceProps,
|
CustomerInvoiceProps,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
CustomerInvoiceStatus,
|
CustomerInvoiceStatus,
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
|
import { extractOrPushError } from "./extract-or-push-error";
|
||||||
import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice-items-props";
|
import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice-items-props";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,7 +21,7 @@ import { mapDTOToCustomerInvoiceItemsProps } from "./map-dto-to-customer-invoice
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDTO) {
|
export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceCommandDTO) {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
||||||
@ -38,7 +32,7 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDT
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const invoiceSeries = extractOrPushError(
|
const invoiceSeries = extractOrPushError(
|
||||||
maybeFromNullableVO(dto.invoice_series, (value) => CustomerInvoiceSerie.create(value)),
|
CustomerInvoiceSerie.create(dto.invoice_series),
|
||||||
"invoice_series",
|
"invoice_series",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
@ -48,16 +42,13 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDT
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const operationDate = extractOrPushError(
|
const operationDate = extractOrPushError(
|
||||||
maybeFromNullableVO(dto.operation_date, (value) => UtcDate.createFromISO(value)),
|
UtcDate.createFromISO(dto.operation_date),
|
||||||
"operation_date",
|
"operation_date",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
const currencyCode = extractOrPushError(
|
//const currency = extractOrPushError(Currency.(dto.currency), "currency", errors);
|
||||||
CurrencyCode.create(dto.currency_code),
|
const currency = dto.currency;
|
||||||
"currency",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
// 🔄 Validar y construir los items de factura con helper especializado
|
// 🔄 Validar y construir los items de factura con helper especializado
|
||||||
const itemsResult = mapDTOToCustomerInvoiceItemsProps(dto.items);
|
const itemsResult = mapDTOToCustomerInvoiceItemsProps(dto.items);
|
||||||
@ -66,16 +57,16 @@ export function mapDTOToCustomerInvoiceProps(dto: CreateCustomerInvoiceRequestDT
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(new ValidationErrorCollection("Customer dto mapping failed", errors));
|
return Result.fail(new ValidationErrorCollection(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceProps: CustomerInvoiceProps = {
|
const invoiceProps: CustomerInvoiceProps = {
|
||||||
invoiceNumber: invoiceNumber!,
|
invoiceNumber: invoiceNumber!,
|
||||||
series: invoiceSeries!,
|
invoiceSeries: invoiceSeries!,
|
||||||
invoiceDate: invoiceDate!,
|
invoiceDate: invoiceDate!,
|
||||||
operationDate: operationDate!,
|
operationDate: operationDate!,
|
||||||
status: CustomerInvoiceStatus.createDraft(),
|
status: CustomerInvoiceStatus.createDraft(),
|
||||||
currencyCode: currencyCode!,
|
currency,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
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,21 +0,0 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
|
||||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
|
||||||
import { formatMoneyDTO, formatPercentageDTO } from "../../helpers";
|
|
||||||
|
|
||||||
export class CustomerInvoiceReportPresenter extends Presenter<
|
|
||||||
GetCustomerInvoiceByIdResponseDTO,
|
|
||||||
unknown
|
|
||||||
> {
|
|
||||||
toOutput(invoiceDTO: GetCustomerInvoiceByIdResponseDTO) {
|
|
||||||
const locale = invoiceDTO.language_code;
|
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,2 +1 @@
|
|||||||
export * from "./customer-invoice.report.presenter";
|
|
||||||
export * from "./list-customer-invoices.presenter";
|
export * from "./list-customer-invoices.presenter";
|
||||||
|
|||||||
@ -11,20 +11,13 @@ export class CustomerInvoiceReportHTMLPresenter extends Presenter {
|
|||||||
projection: "FULL",
|
projection: "FULL",
|
||||||
});
|
});
|
||||||
|
|
||||||
const prePresenter = this.presenterRegistry.getPresenter({
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "JSON",
|
|
||||||
});
|
|
||||||
|
|
||||||
const invoiceDTO = dtoPresenter.toOutput(customerInvoice);
|
const invoiceDTO = dtoPresenter.toOutput(customerInvoice);
|
||||||
const prettyDTO = prePresenter.toOutput(invoiceDTO);
|
|
||||||
|
|
||||||
// Obtener y compilar la plantilla HTML
|
// Obtener y compilar la plantilla HTML
|
||||||
const templateHtml = readFileSync(
|
const templateHtml = readFileSync(
|
||||||
path.join(__dirname, "./templates/customer-invoice/template.hbs")
|
path.join(__dirname, "./templates/customer-invoice/template.hbs")
|
||||||
).toString();
|
).toString();
|
||||||
const template = handlebars.compile(templateHtml, {});
|
const template = handlebars.compile(templateHtml, {});
|
||||||
return template(prettyDTO);
|
return template(invoiceDTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,7 +139,7 @@
|
|||||||
<!-- Badge TOTAL superpuesto -->
|
<!-- Badge TOTAL superpuesto -->
|
||||||
<div class="absolute -top-7 right-0">
|
<div class="absolute -top-7 right-0">
|
||||||
<div class="relative bg-[#f08119] text-white text-sm font-semibold px-3 py-1 shadow">
|
<div class="relative bg-[#f08119] text-white text-sm font-semibold px-3 py-1 shadow">
|
||||||
TOTAL: {{total_amount}} €
|
TOTAL: {{total_amount.value}} €
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -182,29 +182,25 @@
|
|||||||
<div class="grow">
|
<div class="grow">
|
||||||
<table class="table-header min-w-full bg-transparent">
|
<table class="table-header min-w-full bg-transparent">
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#if percentage}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2 text-right">Importe neto</td>
|
<td class="px-4 py-2 text-right">Importe neto</td>
|
||||||
<td class="px-4 py-2 text-right">761,14 €</td>
|
<td class="px-4 py-2 text-right">761,14 €</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2 text-right">Descuento 0%</td>
|
<td class="px-4 py-2 text-right">Descuento 0%</td>
|
||||||
<td class="px-4 py-2 text-right">{{discount_amount.value}}</td>
|
<td class="px-4 py-2 text-right">0</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{else}}
|
|
||||||
<!-- dto 0-->
|
|
||||||
{{/if}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2 text-right">Base imponible</td>
|
<td class="px-4 py-2 text-right">Base imponible</td>
|
||||||
<td class="px-4 py-2 text-right">{{subtotal_amount}}</td>
|
<td class="px-4 py-2 text-right">765,14€</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2 text-right">IVA 21%</td>
|
<td class="px-4 py-2 text-right">IVA 21%</td>
|
||||||
<td class="px-4 py-2 text-right">{{taxes_amount}}</td>
|
<td class="px-4 py-2 text-right">159,84 €</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-[#f08119] text-white font-semibold">
|
<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 bg-amber-700">Total factura</td>
|
||||||
<td class="px-4 py-2 text-right">{{total_amount}}</td>
|
<td class="px-4 py-2 text-right">960,56 €</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
CustomerInvoiceItemsFullPresenter,
|
CustomerInvoiceItemsFullPresenter,
|
||||||
CustomerInvoiceReportHTMLPresenter,
|
CustomerInvoiceReportHTMLPresenter,
|
||||||
CustomerInvoiceReportPDFPresenter,
|
CustomerInvoiceReportPDFPresenter,
|
||||||
CustomerInvoiceReportPresenter,
|
|
||||||
GetCustomerInvoiceUseCase,
|
GetCustomerInvoiceUseCase,
|
||||||
ListCustomerInvoicesPresenter,
|
ListCustomerInvoicesPresenter,
|
||||||
ListCustomerInvoicesUseCase,
|
ListCustomerInvoicesUseCase,
|
||||||
@ -100,14 +99,6 @@ export function buildCustomerInvoiceDependencies(params: ModuleParams): Customer
|
|||||||
},
|
},
|
||||||
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "JSON",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceReportPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: {
|
key: {
|
||||||
resource: "customer-invoice",
|
resource: "customer-invoice",
|
||||||
|
|||||||
@ -119,7 +119,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
|
|
||||||
const discountPercentage = extractOrPushError(
|
const discountPercentage = extractOrPushError(
|
||||||
Percentage.create({
|
Percentage.create({
|
||||||
value: source.discount_percentage_value,
|
value: source.discount_amount_scale,
|
||||||
scale: source.discount_percentage_scale,
|
scale: source.discount_percentage_scale,
|
||||||
}),
|
}),
|
||||||
"discount_percentage_value",
|
"discount_percentage_value",
|
||||||
@ -206,7 +206,9 @@ export class CustomerInvoiceDomainMapper
|
|||||||
|
|
||||||
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(new ValidationErrorCollection("Customer mapping failed", errors));
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Customer invoice mapping failed", errors)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) Construcción del agregado (Dominio)
|
// 6) Construcción del agregado (Dominio)
|
||||||
|
|||||||
@ -1,34 +0,0 @@
|
|||||||
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,5 +3,4 @@ export * from "./customer-editor-skeleton";
|
|||||||
export * from "./customers-layout";
|
export * from "./customers-layout";
|
||||||
export * from "./customers-list-grid";
|
export * from "./customers-list-grid";
|
||||||
export * from "./error-alert";
|
export * from "./error-alert";
|
||||||
export * from "./form-debug";
|
|
||||||
export * from "./not-found-card";
|
export * from "./not-found-card";
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
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,16 +1,29 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { FieldErrors, useForm } from "react-hook-form";
|
import { FieldErrors, useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { Form } from "@repo/shadcn-ui/components";
|
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 { useUnsavedChangesNotifier } from "@erp/core/hooks";
|
import { useUnsavedChangesNotifier } from "@erp/core/hooks";
|
||||||
import { FormDebug } from "../../components/form-debug";
|
import { COUNTRY_OPTIONS, LANGUAGE_OPTIONS } from "../../constants/customer.constants";
|
||||||
import { useTranslation } from "../../i18n";
|
import { useTranslation } from "../../i18n";
|
||||||
import { CustomerData, CustomerUpdateData, CustomerUpdateSchema } from "../../schemas";
|
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 {
|
interface CustomerFormProps {
|
||||||
formId: string;
|
formId: string;
|
||||||
@ -50,16 +63,262 @@ export const CustomerEditForm = ({ formId, data, onSubmit, isPending }: Customer
|
|||||||
form.reset(data);
|
form.reset(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
formState: { isDirty, dirtyFields },
|
||||||
|
} = form;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<FormDebug 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>{" "}
|
||||||
<form id={formId} onSubmit={form.handleSubmit(handleSubmit, handleError)}>
|
<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'>
|
<div className='w-full grid grid-cols-1 space-y-8 space-x-8 xl:grid-cols-2'>
|
||||||
<CustomerBasicInfoFields control={form.control} />
|
{/* Información básica */}
|
||||||
<CustomerAddressFields control={form.control} />
|
<Card className='shadow-none'>
|
||||||
<CustomerContactFields control={form.control} />
|
<CardHeader>
|
||||||
<CustomerAdditionalConfigFields control={form.control} />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
<Button type='submit'>{t("pages.update.submit")}</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -207,7 +207,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Devuelve una cadena con el importe formateado.
|
* Devuelve una cadena con el importe formateado.
|
||||||
* Ejemplo: 123456 -> 1.234,56 €
|
* Ejemplo: 123456 -> €1,234.56
|
||||||
* @param locale Código de idioma y país (ej. "es-ES")
|
* @param locale Código de idioma y país (ej. "es-ES")
|
||||||
* @returns Importe formateado
|
* @returns Importe formateado
|
||||||
*/
|
*/
|
||||||
@ -222,6 +222,6 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
minimumFractionDigits: scale,
|
minimumFractionDigits: scale,
|
||||||
maximumFractionDigits: scale,
|
maximumFractionDigits: scale,
|
||||||
useGrouping: true,
|
useGrouping: true,
|
||||||
}).format(this.formattedValue);
|
}).format(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,9 +37,6 @@ export function TextField<TFormValues extends FieldValues>({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isDisabled = disabled || readOnly;
|
const isDisabled = disabled || readOnly;
|
||||||
|
|
||||||
const { getFieldState } = control;
|
|
||||||
const state = getFieldState(name);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormField
|
<FormField
|
||||||
control={control}
|
control={control}
|
||||||
@ -53,7 +50,12 @@ export function TextField<TFormValues extends FieldValues>({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input disabled={isDisabled} placeholder={placeholder} {...field} />
|
<Input
|
||||||
|
disabled={isDisabled}
|
||||||
|
placeholder={placeholder}
|
||||||
|
{...field}
|
||||||
|
className='font-medium'
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<p className={cn("text-xs text-muted-foreground", !description && "invisible")}>
|
<p className={cn("text-xs text-muted-foreground", !description && "invisible")}>
|
||||||
|
|||||||
@ -50,9 +50,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
/*--font-sans: Geist, sans-serif;
|
--font-sans: Geist, sans-serif;
|
||||||
--font-serif: Merriweather, serif;
|
--font-serif: Merriweather, serif;
|
||||||
--font-mono: "Geist Mono", monospace;*/
|
--font-mono: "Geist Mono", monospace;
|
||||||
|
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
@ -168,14 +168,6 @@
|
|||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
|
||||||
@apply font-semibold;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
@apply font-light;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@source "../components";
|
@source "../components";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user