.
This commit is contained in:
parent
a32ba80bb6
commit
1ac0533de5
@ -1,11 +1,17 @@
|
||||
import { CancelButton, FormDatePickerField, FormTextAreaField, FormTextField } from "@/components";
|
||||
import {
|
||||
BackHistoryButton,
|
||||
FormDatePickerField,
|
||||
FormTextAreaField,
|
||||
FormTextField,
|
||||
} from "@/components";
|
||||
import { t } from "i18next";
|
||||
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
|
||||
import { SubmitButton } from "@/components";
|
||||
import { Button, Form } from "@/ui";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import { FieldErrors, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useQuotes } from "./hooks";
|
||||
|
||||
type QuoteDataForm = {
|
||||
@ -32,14 +38,15 @@ export const QuoteCreate = () => {
|
||||
//const { data: userIdentity } = useGetIdentity();
|
||||
//console.log(userIdentity);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { useMutation } = useQuotes();
|
||||
const { mutate } = useMutation;
|
||||
const { mutate } = useMutation();
|
||||
|
||||
const form = useForm<QuoteDataForm>({
|
||||
defaultValues: {
|
||||
reference: "",
|
||||
date: Date.now().toLocaleString(),
|
||||
date: new Date(Date.now()).toUTCString(),
|
||||
customer_information: "",
|
||||
reference: "",
|
||||
},
|
||||
});
|
||||
|
||||
@ -48,15 +55,25 @@ export const QuoteCreate = () => {
|
||||
|
||||
try {
|
||||
//setLoading(true);
|
||||
mutate(formData);
|
||||
mutate(formData, {
|
||||
onSuccess: (data) => {
|
||||
navigate(`/quotes/edit/${data.id}`, { relative: "path", replace: true });
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
//setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onErrors: SubmitErrorHandler<QuoteDataForm> = async (
|
||||
errors: FieldErrors<QuoteDataForm>
|
||||
) => {
|
||||
console.log(errors);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit, onErrors)}>
|
||||
<div className='mx-auto grid max-w-[90rem] flex-1 auto-rows-max gap-6'>
|
||||
<div className='flex items-center gap-4'>
|
||||
<Button variant='outline' size='icon' className='h-7 w-7'>
|
||||
@ -70,47 +87,35 @@ export const QuoteCreate = () => {
|
||||
|
||||
<div className='grid max-w-lg gap-6'>
|
||||
<FormTextField
|
||||
className='row-span-2'
|
||||
name='reference'
|
||||
required
|
||||
label={t("quotes.create.form_fields.reference.label")}
|
||||
description={t("quotes.create.form_fields.reference.desc")}
|
||||
disabled={form.formState.disabled}
|
||||
placeholder={t("quotes.create.form_fields.reference.placeholder")}
|
||||
{...form.register("reference", {
|
||||
required: false,
|
||||
})}
|
||||
/>
|
||||
|
||||
<FormDatePickerField
|
||||
required
|
||||
label={t("quotes.create.form_fields.date.label")}
|
||||
description={t("quotes.create.form_fields.date.desc")}
|
||||
disabled={form.formState.disabled}
|
||||
placeholder={t("quotes.create.form_fields.date.placeholder")}
|
||||
{...form.register("date", {
|
||||
required: true,
|
||||
})}
|
||||
name='date'
|
||||
/>
|
||||
|
||||
<div className='grid grid-cols-1 grid-rows-2 gap-6'>
|
||||
<FormTextAreaField
|
||||
className='row-span-2'
|
||||
required
|
||||
label={t("quotes.create.form_fields.customer_information.label")}
|
||||
description={t("quotes.create.form_fields.customer_information.desc")}
|
||||
disabled={form.formState.disabled}
|
||||
placeholder={t("quotes.create.form_fields.customer_information.placeholder")}
|
||||
{...form.register("customer_information", {
|
||||
required: true,
|
||||
})}
|
||||
errors={form.formState.errors}
|
||||
/>
|
||||
</div>
|
||||
<FormTextAreaField
|
||||
rows={4}
|
||||
className='row-span-2'
|
||||
name='customer_information'
|
||||
required
|
||||
label={t("quotes.create.form_fields.customer_information.label")}
|
||||
description={t("quotes.create.form_fields.customer_information.desc")}
|
||||
placeholder={t("quotes.create.form_fields.customer_information.placeholder")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
<CancelButton
|
||||
variant='outline'
|
||||
size='sm'
|
||||
label={t("quotes.create.buttons.discard")}
|
||||
></CancelButton>
|
||||
<div className='flex items-center justify-start gap-2'>
|
||||
<BackHistoryButton size='sm' label={t("quotes.create.buttons.discard")} url='/quotes' />
|
||||
|
||||
<SubmitButton size='sm' label={t("common.continue")}></SubmitButton>
|
||||
</div>
|
||||
|
||||
@ -19,32 +19,36 @@ export const useQuotes = (params?: UseQuotesGetParamsType) => {
|
||||
const keys = useQueryKey();
|
||||
|
||||
return {
|
||||
useQuery: useOne<IGetQuote_Response_DTO>({
|
||||
queryKey: keys().data().resource("quotes").action("one").id("").params().get(),
|
||||
queryFn: () =>
|
||||
dataSource.getOne({
|
||||
resource: "quotes",
|
||||
id: "",
|
||||
}),
|
||||
...params,
|
||||
}),
|
||||
useMutation: useSave<ICreateQuote_Response_DTO, TDataSourceError, ICreateQuote_Request_DTO>({
|
||||
mutationKey: keys().data().resource("quotes").action("one").id("").params().get(),
|
||||
mutationFn: (data) => {
|
||||
let { id } = data;
|
||||
useQuery: () =>
|
||||
useOne<IGetQuote_Response_DTO>({
|
||||
queryKey: keys().data().resource("quotes").action("one").id("").params().get(),
|
||||
queryFn: () =>
|
||||
dataSource.getOne({
|
||||
resource: "quotes",
|
||||
id: "",
|
||||
}),
|
||||
...params,
|
||||
}),
|
||||
useMutation: () =>
|
||||
useSave<ICreateQuote_Response_DTO, TDataSourceError, ICreateQuote_Request_DTO>({
|
||||
mutationKey: keys().data().resource("quotes").action("one").id("").params().get(),
|
||||
mutationFn: (data) => {
|
||||
let { id, status } = data;
|
||||
|
||||
if (!id) {
|
||||
id = UniqueID.generateNewID().object.toString();
|
||||
}
|
||||
if (!id) {
|
||||
id = UniqueID.generateNewID().object.toString();
|
||||
status = "draft";
|
||||
}
|
||||
|
||||
return dataSource.createOne({
|
||||
resource: "quotes",
|
||||
data: {
|
||||
...data,
|
||||
id,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
return dataSource.createOne({
|
||||
resource: "quotes",
|
||||
data: {
|
||||
...data,
|
||||
status,
|
||||
id,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@ -4,12 +4,9 @@ export interface CancelButtonProps extends ButtonProps {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export const CancelButton = ({
|
||||
label = "Cancelar",
|
||||
...props
|
||||
}: CancelButtonProps): JSX.Element => {
|
||||
export const CancelButton = ({ label = "Cancelar", ...props }: CancelButtonProps): JSX.Element => {
|
||||
return (
|
||||
<Button type="button" variant="secondary" {...props}>
|
||||
<Button type='button' variant='secondary' {...props}>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@ -18,9 +18,7 @@ const customButtonVariants = cva("", {
|
||||
},
|
||||
});
|
||||
|
||||
export interface CustomButtonProps
|
||||
extends ButtonProps,
|
||||
VariantProps<typeof customButtonVariants> {
|
||||
export interface CustomButtonProps extends ButtonProps, VariantProps<typeof customButtonVariants> {
|
||||
icon: LucideIcon; // Propiedad para proporcionar el icono personalizado
|
||||
label?: string;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Button, ButtonProps } from "@/ui";
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
import { To, useNavigate } from "react-router-dom";
|
||||
import { CustomButton } from "../Buttons/CustomButton";
|
||||
|
||||
export interface BackHistoryButtonProps extends ButtonProps {
|
||||
label?: string;
|
||||
@ -15,16 +16,29 @@ export const BackHistoryButton = ({
|
||||
}: BackHistoryButtonProps): JSX.Element => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<CustomButton
|
||||
type='button'
|
||||
label={label}
|
||||
icon={ChevronLeft}
|
||||
variant='ghost'
|
||||
onClick={() => {
|
||||
url ? navigate(url) : navigate(-1);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
variant='ghost'
|
||||
onClick={() => {
|
||||
url ? navigate(url) : navigate(-1);
|
||||
}}
|
||||
size={size}
|
||||
{...props}
|
||||
>
|
||||
<ChevronLeft className="w-4 h-4" />
|
||||
<ChevronLeft className='w-4 h-4' />
|
||||
<span className={size === "icon" ? "sr-only" : "ml-2"}>{label}</span>
|
||||
</Button>
|
||||
);
|
||||
|
||||
@ -12,7 +12,6 @@ import {
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
InputProps,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
@ -28,14 +27,12 @@ import { CalendarIcon } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { t } from "i18next";
|
||||
import { FormErrorMessage } from "./FormErrorMessage";
|
||||
|
||||
type FormDatePickerFieldProps<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
> = InputProps &
|
||||
FormInputProps &
|
||||
Partial<FormLabelProps> &
|
||||
UseControllerProps<TFieldValues, TName> & {};
|
||||
> = InputProps & FormInputProps & Partial<FormLabelProps> & UseControllerProps<TFieldValues, TName>;
|
||||
|
||||
/*const loadDateFnsLocale = async (locale: Locale) => {
|
||||
return await import(`date-fns/locale/${locale.code}/index.js`);
|
||||
@ -45,19 +42,7 @@ export const FormDatePickerField = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & FormDatePickerFieldProps
|
||||
>((props: FormDatePickerFieldProps, ref) => {
|
||||
const {
|
||||
label,
|
||||
placeholder,
|
||||
hint,
|
||||
description,
|
||||
required,
|
||||
className,
|
||||
disabled,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
errors,
|
||||
name,
|
||||
type,
|
||||
} = props;
|
||||
const { label, placeholder, hint, description, required, className, name } = props;
|
||||
const { control } = useFormContext();
|
||||
//const { locale } = loadDateFnsLocale();
|
||||
|
||||
@ -72,11 +57,10 @@ export const FormDatePickerField = React.forwardRef<
|
||||
control={control}
|
||||
name={name}
|
||||
rules={{ required }}
|
||||
disabled={disabled}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
render={({ field, fieldState, formState }) => (
|
||||
<FormItem ref={ref} className={cn(className, "flex flex-col")}>
|
||||
{label && <FormLabel label={label} hint={hint} />}
|
||||
{label && <FormLabel label={label} hint={hint} required={required} />}
|
||||
|
||||
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
@ -90,6 +74,8 @@ export const FormDatePickerField = React.forwardRef<
|
||||
>
|
||||
{field.value ? (
|
||||
new Date(field.value).toLocaleDateString() //"en-US", DATE_OPTIONS)
|
||||
) : placeholder ? (
|
||||
placeholder
|
||||
) : (
|
||||
<span>{t("common.pick_date")}</span>
|
||||
)}
|
||||
@ -117,8 +103,9 @@ export const FormDatePickerField = React.forwardRef<
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
{description && <FormDescription>{description}</FormDescription>}
|
||||
<FormMessage />
|
||||
<FormErrorMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
30
client/src/components/Forms/FormErrorMessage.tsx
Normal file
30
client/src/components/Forms/FormErrorMessage.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { FormMessage, useFormField } from "@/ui";
|
||||
import { t } from "i18next";
|
||||
import * as React from "react";
|
||||
|
||||
export const FormErrorMessage = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ children, ...props }, ref) => {
|
||||
const { error } = useFormField();
|
||||
let message = children;
|
||||
|
||||
if (error) {
|
||||
if (error.message) {
|
||||
message = String(error?.message || error.root?.message);
|
||||
} else {
|
||||
if (error.type === "required") {
|
||||
message = t("common.required_field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(message);
|
||||
|
||||
return (
|
||||
<FormMessage ref={ref} {...props}>
|
||||
{message}
|
||||
</FormMessage>
|
||||
);
|
||||
});
|
||||
FormErrorMessage.displayName = "FormErrorMessage";
|
||||
@ -14,12 +14,14 @@ export const FormLabel = React.forwardRef<
|
||||
FormLabelProps &
|
||||
Pick<FormInputProps, "required">
|
||||
>(({ label, hint, required, ...props }, ref) => {
|
||||
const { error } = UI.useFormField();
|
||||
|
||||
const _hint = hint ? hint : required ? "obligatorio" : undefined;
|
||||
const _hintClassName = required ? "text-destructive" : "";
|
||||
const _hintClassName = error ? "text-destructive font-semibold" : "";
|
||||
return (
|
||||
<UI.FormLabel ref={ref} className='flex justify-between text-sm' {...props}>
|
||||
<span className='block font-semibold'>{label}</span>
|
||||
{_hint && <span className={`text-sm font-medium ${_hintClassName}`}>{_hint}</span>}
|
||||
<span className={`block font-semibold ${_hintClassName}`}>{label}</span>
|
||||
{_hint && <span className={`text-sm font-medium ${_hintClassName} `}>{_hint}</span>}
|
||||
</UI.FormLabel>
|
||||
);
|
||||
});
|
||||
|
||||
@ -5,7 +5,6 @@ import {
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
Textarea,
|
||||
} from "@/ui";
|
||||
import * as React from "react";
|
||||
@ -17,6 +16,7 @@ import {
|
||||
UseControllerProps,
|
||||
useFormContext,
|
||||
} from "react-hook-form";
|
||||
import { FormErrorMessage } from "./FormErrorMessage";
|
||||
import { FormLabel, FormLabelProps } from "./FormLabel";
|
||||
|
||||
export type FormTextAreaFieldProps<
|
||||
@ -41,12 +41,14 @@ export const FormTextAreaField = React.forwardRef<
|
||||
name,
|
||||
label,
|
||||
hint,
|
||||
description,
|
||||
placeholder,
|
||||
description,
|
||||
|
||||
required,
|
||||
disabled,
|
||||
autoSize,
|
||||
className,
|
||||
|
||||
autoSize,
|
||||
|
||||
...props
|
||||
},
|
||||
ref
|
||||
@ -57,7 +59,6 @@ export const FormTextAreaField = React.forwardRef<
|
||||
control={control}
|
||||
name={name}
|
||||
rules={{ required }}
|
||||
disabled={disabled}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
render={({ field, fieldState, formState }) => (
|
||||
<FormItem ref={ref} className={cn(className, "flex flex-col space-y-3")}>
|
||||
@ -65,17 +66,29 @@ export const FormTextAreaField = React.forwardRef<
|
||||
<FormControl className='grow'>
|
||||
{autoSize ? (
|
||||
<AutosizeTextarea
|
||||
{...field}
|
||||
placeholder={placeholder}
|
||||
className='resize-y'
|
||||
className={cn(
|
||||
fieldState.error ? "border-destructive focus-visible:ring-destructive" : "",
|
||||
"resize-y"
|
||||
)}
|
||||
{...props}
|
||||
{...field}
|
||||
/>
|
||||
) : (
|
||||
<Textarea {...field} placeholder={placeholder} className='resize-y' {...props} />
|
||||
<Textarea
|
||||
placeholder={placeholder}
|
||||
className={cn(
|
||||
fieldState.error ? "border-destructive focus-visible:ring-destructive" : "",
|
||||
"resize-y"
|
||||
)}
|
||||
{...props}
|
||||
{...field}
|
||||
/>
|
||||
)}
|
||||
</FormControl>
|
||||
|
||||
{description && <FormDescription>{description}</FormDescription>}
|
||||
<FormMessage />
|
||||
<FormErrorMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -1,23 +1,10 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
Input,
|
||||
InputProps,
|
||||
} from "@/ui";
|
||||
import { FormControl, FormDescription, FormField, FormItem, Input, InputProps } from "@/ui";
|
||||
|
||||
import * as React from "react";
|
||||
import { createElement } from "react";
|
||||
import {
|
||||
FieldErrors,
|
||||
FieldPath,
|
||||
FieldValues,
|
||||
UseControllerProps,
|
||||
useFormContext,
|
||||
} from "react-hook-form";
|
||||
import { FieldPath, FieldValues, UseControllerProps, useFormContext } from "react-hook-form";
|
||||
import { FormErrorMessage } from "./FormErrorMessage";
|
||||
import { FormLabel, FormLabelProps } from "./FormLabel";
|
||||
import { FormInputProps, FormInputWithIconProps } from "./FormProps";
|
||||
|
||||
@ -30,28 +17,25 @@ export type FormTextFieldProps<
|
||||
FormInputProps &
|
||||
Partial<FormLabelProps> &
|
||||
FormInputWithIconProps &
|
||||
UseControllerProps<TFieldValues, TName> & {
|
||||
errors?: FieldErrors<TFieldValues>;
|
||||
};
|
||||
UseControllerProps<TFieldValues, TName>;
|
||||
|
||||
export const FormTextField = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & FormTextFieldProps
|
||||
>((props, ref) => {
|
||||
const {
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
hint,
|
||||
placeholder,
|
||||
description,
|
||||
|
||||
required,
|
||||
className,
|
||||
leadIcon,
|
||||
trailIcon,
|
||||
button,
|
||||
disabled,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
errors,
|
||||
name,
|
||||
|
||||
type,
|
||||
} = props;
|
||||
|
||||
@ -62,55 +46,64 @@ export const FormTextField = React.forwardRef<
|
||||
control={control}
|
||||
name={name}
|
||||
rules={{ required }}
|
||||
disabled={disabled}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
render={({ field, fieldState, formState }) => (
|
||||
<FormItem ref={ref} className={cn(className, "space-y-3")}>
|
||||
{label && <FormLabel label={label} hint={hint} required={required} />}
|
||||
<div className={cn(button ? "flex" : null)}>
|
||||
<div
|
||||
className={cn(
|
||||
leadIcon ? "relative flex items-stretch flex-grow focus-within:z-10" : ""
|
||||
)}
|
||||
>
|
||||
{leadIcon && (
|
||||
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none'>
|
||||
{React.createElement(
|
||||
leadIcon,
|
||||
{
|
||||
className: "h-5 w-5 text-muted-foreground",
|
||||
"aria-hidden": true,
|
||||
},
|
||||
null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormControl
|
||||
className={cn("block", leadIcon ? "pl-10" : "", trailIcon ? "pr-10" : "")}
|
||||
render={({ field, fieldState, formState }) => {
|
||||
return (
|
||||
<FormItem ref={ref} className={cn(className, "space-y-3")}>
|
||||
{label && <FormLabel label={label} hint={hint} required={required} />}
|
||||
<div className={cn(button ? "flex" : null)}>
|
||||
<div
|
||||
className={cn(
|
||||
leadIcon ? "relative flex items-stretch flex-grow focus-within:z-10" : ""
|
||||
)}
|
||||
>
|
||||
<Input type={type} placeholder={placeholder} disabled={disabled} {...field} />
|
||||
</FormControl>
|
||||
{leadIcon && (
|
||||
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none'>
|
||||
{React.createElement(
|
||||
leadIcon,
|
||||
{
|
||||
className: "h-5 w-5 text-muted-foreground",
|
||||
"aria-hidden": true,
|
||||
},
|
||||
null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{trailIcon && (
|
||||
<div className='absolute inset-y-0 right-0 flex items-center pl-3 pointer-events-none'>
|
||||
{createElement(
|
||||
trailIcon,
|
||||
{
|
||||
className: "h-5 w-5 text-muted-foreground",
|
||||
"aria-hidden": true,
|
||||
},
|
||||
null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<FormControl
|
||||
className={cn("block", leadIcon ? "pl-10" : "", trailIcon ? "pr-10" : "")}
|
||||
>
|
||||
<Input
|
||||
type={type}
|
||||
placeholder={placeholder}
|
||||
className={cn(
|
||||
fieldState.error ? "border-destructive focus-visible:ring-destructive" : ""
|
||||
)}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
{trailIcon && (
|
||||
<div className='absolute inset-y-0 right-0 flex items-center pl-3 pointer-events-none'>
|
||||
{createElement(
|
||||
trailIcon,
|
||||
{
|
||||
className: "h-5 w-5 text-muted-foreground",
|
||||
"aria-hidden": true,
|
||||
},
|
||||
null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{button && <>{createElement(button)}</>}
|
||||
</div>
|
||||
{button && <>{createElement(button)}</>}
|
||||
</div>
|
||||
{description && <FormDescription>{description}</FormDescription>}
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
{description && <FormDescription>{description}</FormDescription>}
|
||||
<FormErrorMessage />
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export * from "./FormDatePickerField";
|
||||
export * from "./FormErrorMessage";
|
||||
export * from "./FormGroup";
|
||||
export * from "./FormLabel";
|
||||
export * from "./FormMoneyField";
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
--secondary-foreground: 25 18% 30%;
|
||||
--accent: 25 23% 83%;
|
||||
--accent-foreground: 25 23% 23%;
|
||||
--destructive: 13 96% 20%;
|
||||
--destructive-foreground: 13 96% 80%;
|
||||
--destructive: 0 72.2% 50.6%; /* 13 96% 20%; */
|
||||
--destructive-foreground: 0 85.7% 97.3%; /* 13 96% 80%; */
|
||||
--ring: 25 31% 75%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
@ -29,7 +29,8 @@
|
||||
"open_menu": "Abrir el menú",
|
||||
"duplicate_rows": "Duplicar",
|
||||
"duplicate_rows_tooltip": "Duplica las fila(s) seleccionadas(s)",
|
||||
"pick_date": "Elige una fecha"
|
||||
"pick_date": "Elige una fecha",
|
||||
"required_field": "Este campo es obligatorio"
|
||||
},
|
||||
"main_menu": {
|
||||
"home": "Inicio",
|
||||
|
||||
@ -22,9 +22,7 @@ type FormFieldContextValue<
|
||||
name: TName;
|
||||
};
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
);
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
@ -66,22 +64,19 @@ type FormItemContextValue = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
|
||||
|
||||
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => {
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const FormItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
});
|
||||
FormItem.displayName = "FormItem";
|
||||
|
||||
const FormLabel = React.forwardRef<
|
||||
@ -105,18 +100,13 @@ const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof Slot>,
|
||||
React.ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||
useFormField();
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={
|
||||
!error
|
||||
? `${formDescriptionId}`
|
||||
: `${formDescriptionId} ${formMessageId}`
|
||||
}
|
||||
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
@ -146,7 +136,8 @@ const FormMessage = React.forwardRef<
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField();
|
||||
const body = error ? String(error?.message) : children;
|
||||
|
||||
const body = error && error.message ? String(error?.message || error.root?.message) : children;
|
||||
|
||||
if (!body) {
|
||||
return null;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import * as React from "react"
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
@ -17,9 +16,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input }
|
||||
export { Input };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user