Customers
This commit is contained in:
parent
ce1c2c9b76
commit
b35b89ee2b
@ -149,7 +149,7 @@ export class Customer extends AggregateRoot<CustomerInternalProps> implements IC
|
||||
}
|
||||
|
||||
public update(partialCustomer: CustomerPatchProps): Result<void, Error> {
|
||||
const { address: partialAddress, ...rest } = partialCustomer;
|
||||
const { address: partialAddress, defaultTaxes: partialTaxes, ...rest } = partialCustomer;
|
||||
|
||||
Object.assign(this.props, rest);
|
||||
|
||||
@ -161,6 +161,14 @@ export class Customer extends AggregateRoot<CustomerInternalProps> implements IC
|
||||
}
|
||||
}
|
||||
|
||||
if (partialTaxes) {
|
||||
const taxesResult = this.defaultTaxes.update(partialTaxes);
|
||||
|
||||
if (taxesResult.isFailure) {
|
||||
return Result.fail(taxesResult.error);
|
||||
}
|
||||
}
|
||||
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
@ -17,11 +17,18 @@ export interface ICustomerItemTaxes {
|
||||
toKey(): string; // Clave para representar un trío.
|
||||
}
|
||||
|
||||
export type CustomerTaxesPatchProps = Partial<CustomerTaxesProps>;
|
||||
|
||||
export class CustomerTaxes extends ValueObject<CustomerTaxesProps> implements ICustomerItemTaxes {
|
||||
static create(props: CustomerTaxesProps) {
|
||||
return Result.ok(new CustomerTaxes(props));
|
||||
}
|
||||
|
||||
public update(partial: CustomerTaxesPatchProps): Result<CustomerTaxes, Error> {
|
||||
Object.assign(this.props, partial);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruye una instancia de CustomerTaxes a partir de una clave serializada.
|
||||
* Este método es la operación inversa de toKey().
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { FormFieldLabel, TextAreaField, TextField } from "@repo/rdx-ui/components";
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
FormControl,
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@repo/shadcn-ui/components";
|
||||
@ -19,15 +19,9 @@ import type { CustomerUpdateForm } from "../../entities";
|
||||
|
||||
import { CustomerTaxesMultiSelect } from "./customer-taxes-multi-select";
|
||||
|
||||
interface CustomerBasicInfoFieldsProps extends React.ComponentProps<typeof FieldSet> {
|
||||
focusRef?: React.RefObject<HTMLInputElement | null>;
|
||||
}
|
||||
interface CustomerBasicInfoFieldsProps extends React.ComponentProps<typeof FieldSet> {}
|
||||
|
||||
export const CustomerBasicInfoFields = ({
|
||||
focusRef,
|
||||
className,
|
||||
...props
|
||||
}: CustomerBasicInfoFieldsProps) => {
|
||||
export const CustomerBasicInfoFields = ({ className, ...props }: CustomerBasicInfoFieldsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { control, setFocus } = useFormContext<CustomerUpdateForm>();
|
||||
|
||||
@ -50,49 +44,68 @@ export const CustomerBasicInfoFields = ({
|
||||
required
|
||||
/>
|
||||
|
||||
<Field className="lg:col-span-1 lg:col-start-1">
|
||||
<Controller
|
||||
control={control}
|
||||
name="isCompany"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field className="gap-1" data-invalid={fieldState.invalid}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="isCompany"
|
||||
render={({ field, fieldState }) => {
|
||||
console.log(field.value);
|
||||
return (
|
||||
<Field
|
||||
className="gap-1 lg:col-span-1 lg:col-start-1"
|
||||
data-invalid={fieldState.invalid}
|
||||
>
|
||||
<FormFieldLabel required>{t("form_fields.customer_type.label")}</FormFieldLabel>
|
||||
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
className="gap-3"
|
||||
name={field.name}
|
||||
onValueChange={(value) => field.onChange(value === "true")}
|
||||
value={String(field.value)}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
<RadioGroupItem id="customer-type-company" value="true" />
|
||||
<label
|
||||
<RadioGroup
|
||||
className="gap-3"
|
||||
disabled={field.disabled}
|
||||
name={field.name}
|
||||
onValueChange={(value) => {
|
||||
console.log("Pongo ", value);
|
||||
field.onChange(value === "true");
|
||||
}}
|
||||
required
|
||||
value={field.value ? "true" : "false"}
|
||||
>
|
||||
<Field data-invalid={fieldState.invalid} orientation="horizontal">
|
||||
<FieldContent>
|
||||
<RadioGroupItem
|
||||
aria-invalid={fieldState.invalid}
|
||||
id="customer-type-company"
|
||||
value="true"
|
||||
/>
|
||||
<FieldLabel
|
||||
className="cursor-pointer text-sm font-medium leading-none"
|
||||
htmlFor="customer-type-company"
|
||||
>
|
||||
{t("form_fields.customer_type.company")}
|
||||
</label>
|
||||
</div>
|
||||
</FieldLabel>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<div className="flex items-start gap-2">
|
||||
<RadioGroupItem id="customer-type-individual" value="false" />
|
||||
<label
|
||||
<Field data-invalid={fieldState.invalid} orientation="horizontal">
|
||||
<FieldContent>
|
||||
<RadioGroupItem
|
||||
aria-invalid={fieldState.invalid}
|
||||
id="customer-type-individual"
|
||||
value="false"
|
||||
/>
|
||||
<FieldLabel
|
||||
className="cursor-pointer text-sm font-medium leading-none"
|
||||
htmlFor="customer-type-individual"
|
||||
>
|
||||
{t("form_fields.customer_type.individual")}
|
||||
</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FieldLabel>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
|
||||
<FieldDescription>{t("form_fields.customer_type.description")}</FieldDescription>
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
className="lg:col-span-1"
|
||||
|
||||
@ -9,14 +9,13 @@ type CustomerFormProps = {
|
||||
formId: string;
|
||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
||||
className?: string;
|
||||
focusRef?: React.RefObject<HTMLInputElement>;
|
||||
};
|
||||
|
||||
export const CustomerEditForm = ({ formId, onSubmit, className, focusRef }: CustomerFormProps) => {
|
||||
export const CustomerEditForm = ({ formId, onSubmit, className }: CustomerFormProps) => {
|
||||
return (
|
||||
<form id={formId} noValidate onSubmit={onSubmit}>
|
||||
<section className={cn("space-y-12 p-6", className)}>
|
||||
<CustomerBasicInfoFields focusRef={focusRef} />
|
||||
<CustomerBasicInfoFields />
|
||||
<CustomerAddressFields />
|
||||
<CustomerContactFields />
|
||||
<CustomerAdditionalConfigFields />
|
||||
|
||||
@ -5,33 +5,34 @@ import { useCallback, useMemo } from "react";
|
||||
|
||||
import { useTranslation } from "../../../i18n";
|
||||
|
||||
interface CustomerTaxesMultiSelect {
|
||||
interface CustomerTaxesMultiSelectProps {
|
||||
value?: string[];
|
||||
onChange: (selectedValues: string[]) => void;
|
||||
className?: string;
|
||||
inputId?: string;
|
||||
[key: string]: any; // Allow other props to be passed
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export const CustomerTaxesMultiSelect = (props: CustomerTaxesMultiSelect) => {
|
||||
const { value, onChange, className, inputId, ...otherProps } = props;
|
||||
export const CustomerTaxesMultiSelect = ({
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
inputId,
|
||||
...otherProps
|
||||
}: CustomerTaxesMultiSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const taxCatalog = useMemo(() => SpainTaxCatalogProvider(), []);
|
||||
const catalogLookup = useMemo(() => SpainTaxCatalogProvider().toOptionLookup(), []);
|
||||
const catalogLookup = useMemo(() => taxCatalog.toOptionLookup(), [taxCatalog]);
|
||||
|
||||
/**
|
||||
* Filtra para mantener solo un elemento por grupo.
|
||||
* Si hay duplicados dentro del mismo grupo, se queda con el último.
|
||||
*/
|
||||
const filterSelectedByGroup = useCallback(
|
||||
(selectedValues: string[]) => {
|
||||
const groupMap = new Map<string | undefined, string>();
|
||||
const groupMap = new Map<string, string>();
|
||||
|
||||
for (const code of selectedValues) {
|
||||
const item = taxCatalog.findByCode(code).getOrUndefined();
|
||||
const group = item?.group ?? "ungrouped";
|
||||
groupMap.set(group, code); // Sobrescribe el anterior del mismo grupo
|
||||
groupMap.set(group, code);
|
||||
}
|
||||
|
||||
return Array.from(groupMap.values());
|
||||
@ -43,19 +44,19 @@ export const CustomerTaxesMultiSelect = (props: CustomerTaxesMultiSelect) => {
|
||||
<div className={cn("w-full", "max-w-md")}>
|
||||
<MultiSelect
|
||||
animation={0}
|
||||
autoFilter={true}
|
||||
autoFilter
|
||||
className={cn(
|
||||
"flex w-full -mt-0.5 px-1 py-0.5 rounded-md border border-input min-h-8 h-auto items-center justify-between hover:bg-inherit [&_svg]:pointer-events-auto",
|
||||
"hover:border-ring hover:ring-ring/50 hover:ring-2 font-medium bg-muted/50",
|
||||
className
|
||||
)}
|
||||
defaultValue={value}
|
||||
filterSelected={filterSelectedByGroup}
|
||||
id={inputId}
|
||||
maxCount={3}
|
||||
onValueChange={onChange}
|
||||
options={catalogLookup}
|
||||
placeholder={t("components.customer_invoice_taxes_multi_select.placeholder")}
|
||||
value={value ?? []}
|
||||
variant="secondary"
|
||||
{...otherProps}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user