Clientes
This commit is contained in:
parent
580beaba4c
commit
b3c14b061b
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"common": {
|
"common": {
|
||||||
"required": "required"
|
"required": "•"
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"taxes_multi_select": {
|
"taxes_multi_select": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"common": {
|
"common": {
|
||||||
"required": "requerido"
|
"required": "•"
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"taxes_multi_select": {
|
"taxes_multi_select": {
|
||||||
|
|||||||
@ -47,9 +47,15 @@ export function TaxesMultiSelectField<TFormValues extends FieldValues>({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className={cn("space-y-0", className)}>
|
<FormItem className={cn("space-y-0", className)}>
|
||||||
{label && (
|
{label && (
|
||||||
<div className='flex justify-between items-center'>
|
<div className='mb-1 flex justify-between gap-2'>
|
||||||
<FormLabel className='m-0'>{label}</FormLabel>
|
<div className='flex items-center gap-2'>
|
||||||
{required && <span className='text-xs text-destructive'>{t("common.required")}</span>}
|
<FormLabel htmlFor={name} className='m-0'>
|
||||||
|
{label}
|
||||||
|
</FormLabel>
|
||||||
|
{required && (
|
||||||
|
<span className='text-xs text-destructive'>{t("common.required")}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export class CustomerFullPresenter extends Presenter<Customer, GetCustomerByIdRe
|
|||||||
|
|
||||||
legal_record: toEmptyString(customer.legalRecord, (value) => value.toPrimitive()),
|
legal_record: toEmptyString(customer.legalRecord, (value) => value.toPrimitive()),
|
||||||
|
|
||||||
default_taxes: customer.defaultTaxes.getAll().join(", "),
|
default_taxes: customer.defaultTaxes.getAll().map((tax) => tax.toString()),
|
||||||
|
|
||||||
status: customer.isActive ? "active" : "inactive",
|
status: customer.isActive ? "active" : "inactive",
|
||||||
language_code: customer.languageCode.toPrimitive(),
|
language_code: customer.languageCode.toPrimitive(),
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
import { DomainError, ValidationErrorCollection, ValidationErrorDetail } from "@repo/rdx-ddd";
|
import {
|
||||||
|
DomainError,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { UpdateCustomerByIdRequestDTO } from "../../../../common";
|
||||||
|
import { CustomerPatchProps } from "../../../domain";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
City,
|
City,
|
||||||
@ -34,7 +41,7 @@ import { Collection, Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-ut
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO) {
|
export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerByIdRequestDTO) {
|
||||||
try {
|
try {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
const customerPatchProps: CustomerPatchProps = {};
|
const customerPatchProps: CustomerPatchProps = {};
|
||||||
@ -83,18 +90,50 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO)
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
toPatchField(dto.email).ifSet((email) => {
|
toPatchField(dto.email_primary).ifSet((email_primary) => {
|
||||||
customerPatchProps.email = extractOrPushError(
|
customerPatchProps.emailPrimary = extractOrPushError(
|
||||||
maybeFromNullableVO(email, (value) => EmailAddress.create(value)),
|
maybeFromNullableVO(email_primary, (value) => EmailAddress.create(value)),
|
||||||
"email",
|
"email_primary",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
toPatchField(dto.phone).ifSet((phone) => {
|
toPatchField(dto.email_secondary).ifSet((email_secondary) => {
|
||||||
customerPatchProps.phone = extractOrPushError(
|
customerPatchProps.emailSecondary = extractOrPushError(
|
||||||
maybeFromNullableVO(phone, (value) => PhoneNumber.create(value)),
|
maybeFromNullableVO(email_secondary, (value) => EmailAddress.create(value)),
|
||||||
"phone",
|
"email_secondary",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
toPatchField(dto.mobile_primary).ifSet((mobile_primary) => {
|
||||||
|
customerPatchProps.mobilePrimary = extractOrPushError(
|
||||||
|
maybeFromNullableVO(mobile_primary, (value) => PhoneNumber.create(value)),
|
||||||
|
"mobile_primary",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
toPatchField(dto.mobile_secondary).ifSet((mobile_secondary) => {
|
||||||
|
customerPatchProps.mobilePrimary = extractOrPushError(
|
||||||
|
maybeFromNullableVO(mobile_secondary, (value) => PhoneNumber.create(value)),
|
||||||
|
"mobile_secondary",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
toPatchField(dto.phone_primary).ifSet((phone_primary) => {
|
||||||
|
customerPatchProps.phonePrimary = extractOrPushError(
|
||||||
|
maybeFromNullableVO(phone_primary, (value) => PhoneNumber.create(value)),
|
||||||
|
"phone_primary",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
toPatchField(dto.phone_secondary).ifSet((phone_secondary) => {
|
||||||
|
customerPatchProps.phoneSecondary = extractOrPushError(
|
||||||
|
maybeFromNullableVO(phone_secondary, (value) => PhoneNumber.create(value)),
|
||||||
|
"phone_secondary",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -158,7 +197,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultTaxes!.split(",").forEach((taxCode, index) => {
|
defaultTaxes!.forEach((taxCode, index) => {
|
||||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
||||||
if (tax && customerPatchProps.defaultTaxes) {
|
if (tax && customerPatchProps.defaultTaxes) {
|
||||||
customerPatchProps.defaultTaxes.add(tax);
|
customerPatchProps.defaultTaxes.add(tax);
|
||||||
@ -173,7 +212,9 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return Result.fail(new ValidationErrorCollection("Customer props mapping failed", errors));
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Customer props mapping failed (update)", errors)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok(customerPatchProps);
|
return Result.ok(customerPatchProps);
|
||||||
@ -183,7 +224,7 @@ export function mapDTOToUpdateCustomerPatchProps(dto: UpdateCustomerRequestDTO)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapDTOToUpdatePostalAddressPatchProps(
|
function mapDTOToUpdatePostalAddressPatchProps(
|
||||||
dto: UpdateCustomerRequestDTO,
|
dto: UpdateCustomerByIdRequestDTO,
|
||||||
errors: ValidationErrorDetail[]
|
errors: ValidationErrorDetail[]
|
||||||
): PostalAddressPatchProps | undefined {
|
): PostalAddressPatchProps | undefined {
|
||||||
const postalAddressPatchProps: PostalAddressPatchProps = {};
|
const postalAddressPatchProps: PostalAddressPatchProps = {};
|
||||||
|
|||||||
@ -197,7 +197,9 @@ export class CustomerDomainMapper
|
|||||||
|
|
||||||
// Si hubo errores de mapeo, devolvemos colección de validación
|
// 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 props mapping failed", errors));
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Customer props mapping failed (CustomerMapper)", errors)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const customerProps: CustomerProps = {
|
const customerProps: CustomerProps = {
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export const CreateCustomerRequestSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string().default(""),
|
legal_record: z.string().default(""),
|
||||||
|
|
||||||
default_taxes: z.string().default(""),
|
default_taxes: z.array(z.string()).default([]),
|
||||||
status: z.string().toLowerCase().default("active"),
|
status: z.string().toLowerCase().default("active"),
|
||||||
language_code: z.string().toLowerCase().default("es"),
|
language_code: z.string().toLowerCase().default("es"),
|
||||||
currency_code: z.string().toUpperCase().default("EUR"),
|
currency_code: z.string().toUpperCase().default("EUR"),
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export const UpdateCustomerByIdRequestSchema = z.object({
|
|||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
trade_name: z.string().optional(),
|
trade_name: z.string().optional(),
|
||||||
tin: z.string().optional(),
|
tin: z.string().optional(),
|
||||||
|
default_taxes: z.array(z.string()).optional(), // completo (sustituye), o null => vaciar
|
||||||
|
|
||||||
street: z.string().optional(),
|
street: z.string().optional(),
|
||||||
street2: z.string().optional(),
|
street2: z.string().optional(),
|
||||||
@ -31,7 +32,6 @@ export const UpdateCustomerByIdRequestSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string().optional(),
|
legal_record: z.string().optional(),
|
||||||
|
|
||||||
default_taxes: z.string().optional(), // completo (sustituye), o null => vaciar
|
|
||||||
language_code: z.string().optional(),
|
language_code: z.string().optional(),
|
||||||
currency_code: z.string().optional(),
|
currency_code: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export const CreateCustomerResponseSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string(),
|
legal_record: z.string(),
|
||||||
|
|
||||||
default_taxes: z.string(),
|
default_taxes: z.array(z.string()),
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
language_code: z.string(),
|
language_code: z.string(),
|
||||||
currency_code: z.string(),
|
currency_code: z.string(),
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export const GetCustomerByIdResponseSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string(),
|
legal_record: z.string(),
|
||||||
|
|
||||||
default_taxes: z.string(),
|
default_taxes: z.array(z.string()),
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
language_code: z.string(),
|
language_code: z.string(),
|
||||||
currency_code: z.string(),
|
currency_code: z.string(),
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export const ListCustomersResponseSchema = createListViewResponseSchema(
|
|||||||
website: z.string(),
|
website: z.string(),
|
||||||
|
|
||||||
//legal_record: z.string(),
|
//legal_record: z.string(),
|
||||||
//default_taxes: z.string(),
|
//default_taxes: z.array(z.string()),
|
||||||
|
|
||||||
language_code: z.string(),
|
language_code: z.string(),
|
||||||
currency_code: z.string(),
|
currency_code: z.string(),
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export const UpdateCustomerByIdResponseSchema = z.object({
|
|||||||
|
|
||||||
legal_record: z.string(),
|
legal_record: z.string(),
|
||||||
|
|
||||||
default_taxes: z.string(),
|
default_taxes: z.array(z.string()),
|
||||||
language_code: z.string(),
|
language_code: z.string(),
|
||||||
currency_code: z.string(),
|
currency_code: z.string(),
|
||||||
|
|
||||||
|
|||||||
@ -79,7 +79,7 @@ export const CustomersListGrid = () => {
|
|||||||
size='icon'
|
size='icon'
|
||||||
className='size-8'
|
className='size-8'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(`${data.id}/edit`);
|
navigate(`${data.id}/edit`, { relative: "path" });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ChevronRightIcon />
|
<ChevronRightIcon />
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { TaxesMultiSelectField } from "@erp/core/components";
|
import { SelectField } from "@repo/rdx-ui/components";
|
||||||
import { SelectField, TextAreaField } from "@repo/rdx-ui/components";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@ -23,41 +22,29 @@ export const CustomerAdditionalConfigFields = ({
|
|||||||
<CardTitle>{t("form_groups.preferences.title")}</CardTitle>
|
<CardTitle>{t("form_groups.preferences.title")}</CardTitle>
|
||||||
<CardDescription>{t("form_groups.preferences.description")}</CardDescription>
|
<CardDescription>{t("form_groups.preferences.description")}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='grid grid-cols-1 gap-y-8 gap-x-6 @xl:grid-cols-2'>
|
<CardContent>
|
||||||
<TaxesMultiSelectField
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-12 '>
|
||||||
control={control}
|
<SelectField
|
||||||
name='default_taxes'
|
className='lg:col-span-2'
|
||||||
required
|
control={control}
|
||||||
label={t("form_fields.default_taxes.label")}
|
name='language_code'
|
||||||
placeholder={t("form_fields.default_taxes.placeholder")}
|
required
|
||||||
description={t("form_fields.default_taxes.description")}
|
label={t("form_fields.language_code.label")}
|
||||||
/>
|
placeholder={t("form_fields.language_code.placeholder")}
|
||||||
<SelectField
|
description={t("form_fields.language_code.description")}
|
||||||
control={control}
|
items={[...LANGUAGE_OPTIONS]}
|
||||||
name='language_code'
|
/>
|
||||||
required
|
<SelectField
|
||||||
label={t("form_fields.language_code.label")}
|
className='lg:col-span-2'
|
||||||
placeholder={t("form_fields.language_code.placeholder")}
|
control={control}
|
||||||
description={t("form_fields.language_code.description")}
|
name='currency_code'
|
||||||
items={[...LANGUAGE_OPTIONS]}
|
required
|
||||||
/>
|
label={t("form_fields.currency_code.label")}
|
||||||
<SelectField
|
placeholder={t("form_fields.currency_code.placeholder")}
|
||||||
control={control}
|
description={t("form_fields.currency_code.description")}
|
||||||
name='currency_code'
|
items={[...CURRENCY_OPTIONS]}
|
||||||
required
|
/>
|
||||||
label={t("form_fields.currency_code.label")}
|
</div>
|
||||||
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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export const CustomerAddressFields = ({ control }: { control: Control<CustomerUp
|
|||||||
description={t("form_fields.postal_code.description")}
|
description={t("form_fields.postal_code.description")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-12 '>
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-0 '>
|
||||||
<TextField
|
<TextField
|
||||||
className='lg:col-span-2'
|
className='lg:col-span-2'
|
||||||
control={control}
|
control={control}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { TaxesMultiSelectField } from "@erp/core/components";
|
import { TaxesMultiSelectField } from "@erp/core/components";
|
||||||
import { TextField } from "@repo/rdx-ui/components";
|
import { TextAreaField, TextField } from "@repo/rdx-ui/components";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@ -27,8 +27,8 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
<CardTitle>Identificación</CardTitle>
|
<CardTitle>Identificación</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className='grid grid-cols-1 gap-6 md:grid-cols-4'>
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-12 '>
|
||||||
<div className='sm:col-span-full'>
|
<div className='lg:col-span-full'>
|
||||||
<FormField
|
<FormField
|
||||||
control={control}
|
control={control}
|
||||||
name='is_company'
|
name='is_company'
|
||||||
@ -64,8 +64,9 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className='sm:col-span-2'>
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-4 mb-12 '>
|
||||||
|
<div className='lg:col-span-2'>
|
||||||
<TextField
|
<TextField
|
||||||
control={control}
|
control={control}
|
||||||
name='name'
|
name='name'
|
||||||
@ -76,7 +77,7 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:col-span-2'>
|
<div className='lg:col-span-2'>
|
||||||
<TextField
|
<TextField
|
||||||
control={control}
|
control={control}
|
||||||
name='trade_name'
|
name='trade_name'
|
||||||
@ -86,7 +87,7 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:col-span-2'>
|
<div className='lg:col-span-2'>
|
||||||
<TaxesMultiSelectField
|
<TaxesMultiSelectField
|
||||||
control={control}
|
control={control}
|
||||||
name='default_taxes'
|
name='default_taxes'
|
||||||
@ -96,7 +97,7 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
description={t("form_fields.default_taxes.description")}
|
description={t("form_fields.default_taxes.description")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='col-auto'>
|
<div className='lg:col-span-2'>
|
||||||
<TextField
|
<TextField
|
||||||
control={control}
|
control={control}
|
||||||
name='reference'
|
name='reference'
|
||||||
@ -105,6 +106,14 @@ export const CustomerBasicInfoFields = ({ control }: { control: Control<Customer
|
|||||||
description={t("form_fields.reference.description")}
|
description={t("form_fields.reference.description")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<TextAreaField
|
||||||
|
className='lg:col-span-full'
|
||||||
|
control={control}
|
||||||
|
name='legal_record'
|
||||||
|
label={t("form_fields.legal_record.label")}
|
||||||
|
placeholder={t("form_fields.legal_record.placeholder")}
|
||||||
|
description={t("form_fields.legal_record.description")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export const CustomerEditForm = ({ defaultValues, onSubmit, isPending }: Custome
|
|||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<FormDebug form={form} />
|
<FormDebug form={form} />
|
||||||
<form onSubmit={form.handleSubmit(handleSubmit, handleError)}>
|
<form id='customer-edit-form' onSubmit={form.handleSubmit(handleSubmit, handleError)}>
|
||||||
<div className='flex gap-6'>
|
<div className='flex gap-6'>
|
||||||
<div className='w-full xl:w-2/3 space-y-12'>
|
<div className='w-full xl:w-2/3 space-y-12'>
|
||||||
<CustomerBasicInfoFields control={form.control} />
|
<CustomerBasicInfoFields control={form.control} />
|
||||||
|
|||||||
@ -46,9 +46,15 @@ export function TextAreaField<TFormValues extends FieldValues>({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className={cn("space-y-0", className)}>
|
<FormItem className={cn("space-y-0", className)}>
|
||||||
{label && (
|
{label && (
|
||||||
<div className='flex justify-between items-center'>
|
<div className='mb-1 flex justify-between gap-2'>
|
||||||
<FormLabel className='m-0'>{label}</FormLabel>
|
<div className='flex items-center gap-2'>
|
||||||
{required && <span className='text-xs text-destructive'>{t("common.required")}</span>}
|
<FormLabel htmlFor={name} className='m-0'>
|
||||||
|
{label}
|
||||||
|
</FormLabel>
|
||||||
|
{required && (
|
||||||
|
<span className='text-xs text-destructive'>{t("common.required")}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user