chore: added outside click detector for custom attribute forms

This commit is contained in:
Aaryan Khandelwal 2023-10-03 14:57:17 +05:30
parent 4d158a6d8f
commit 2d3c1f93c1
5 changed files with 51 additions and 19 deletions

View File

@ -1,7 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
// react-hook-form
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// types // types
import { ICustomAttribute } from "types"; import { ICustomAttribute } from "types";
@ -14,6 +15,8 @@ type Props = {
export const CustomEmailAttribute: React.FC<Props> = ({ attributeDetails, onChange, value }) => { export const CustomEmailAttribute: React.FC<Props> = ({ attributeDetails, onChange, value }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const formRef = useRef(null);
const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { email: "" } }); const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { email: "" } });
const handleFormSubmit = (data: { email: string }) => { const handleFormSubmit = (data: { email: string }) => {
@ -42,6 +45,10 @@ export const CustomEmailAttribute: React.FC<Props> = ({ attributeDetails, onChan
}; };
}, []); }, []);
useOutsideClickDetector(formRef, () => {
setIsEditing(false);
});
return ( return (
<div className="flex-shrink-0"> <div className="flex-shrink-0">
{!isEditing && ( {!isEditing && (
@ -59,7 +66,7 @@ export const CustomEmailAttribute: React.FC<Props> = ({ attributeDetails, onChan
</div> </div>
)} )}
{isEditing && ( {isEditing && (
<form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center"> <form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center" ref={formRef}>
<Controller <Controller
control={control} control={control}
name="email" name="email"
@ -68,6 +75,7 @@ export const CustomEmailAttribute: React.FC<Props> = ({ attributeDetails, onChan
type="email" type="email"
className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none" className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none"
required={attributeDetails.is_required} required={attributeDetails.is_required}
placeholder={attributeDetails.display_name}
{...field} {...field}
/> />
)} )}

View File

@ -1,7 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
// react-hook-form
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// ui // ui
import { ProgressBar } from "components/ui"; import { ProgressBar } from "components/ui";
// types // types
@ -16,6 +17,8 @@ type Props = {
export const CustomNumberAttribute: React.FC<Props> = ({ attributeDetails, onChange, value }) => { export const CustomNumberAttribute: React.FC<Props> = ({ attributeDetails, onChange, value }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const formRef = useRef(null);
const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { number: "" } }); const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { number: "" } });
const handleFormSubmit = (data: { number: string }) => { const handleFormSubmit = (data: { number: string }) => {
@ -49,6 +52,10 @@ export const CustomNumberAttribute: React.FC<Props> = ({ attributeDetails, onCha
}; };
}, []); }, []);
useOutsideClickDetector(formRef, () => {
setIsEditing(false);
});
const extraSettings = attributeDetails.extra_settings; const extraSettings = attributeDetails.extra_settings;
return ( return (
@ -100,7 +107,7 @@ export const CustomNumberAttribute: React.FC<Props> = ({ attributeDetails, onCha
</div> </div>
)} )}
{isEditing && ( {isEditing && (
<form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center"> <form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center" ref={formRef}>
<Controller <Controller
control={control} control={control}
name="number" name="number"
@ -112,6 +119,7 @@ export const CustomNumberAttribute: React.FC<Props> = ({ attributeDetails, onCha
min={extraSettings.divided_by ? 0 : undefined} min={extraSettings.divided_by ? 0 : undefined}
max={extraSettings.divided_by ?? undefined} max={extraSettings.divided_by ?? undefined}
required={attributeDetails.is_required} required={attributeDetails.is_required}
placeholder={attributeDetails.display_name}
{...field} {...field}
/> />
)} )}

View File

@ -1,7 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
// react-hook-form
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// types // types
import { ICustomAttribute } from "types"; import { ICustomAttribute } from "types";
@ -18,6 +19,8 @@ export const CustomTextAttribute: React.FC<Props & { value: string | undefined }
}) => { }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const formRef = useRef(null);
const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { text: "" } }); const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { text: "" } });
const handleFormSubmit = (data: { text: string }) => { const handleFormSubmit = (data: { text: string }) => {
@ -48,6 +51,10 @@ export const CustomTextAttribute: React.FC<Props & { value: string | undefined }
}; };
}, []); }, []);
useOutsideClickDetector(formRef, () => {
setIsEditing(false);
});
return ( return (
<div className="flex-shrink-0"> <div className="flex-shrink-0">
{!isEditing && ( {!isEditing && (
@ -55,11 +62,11 @@ export const CustomTextAttribute: React.FC<Props & { value: string | undefined }
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 w-min max-w-full whitespace-nowrap rounded" className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 w-min max-w-full whitespace-nowrap rounded"
onClick={() => setIsEditing(true)} onClick={() => setIsEditing(true)}
> >
{value && value !== "" ? value : `Enter ${attributeDetails.display_name}`} {value && value !== "" ? value : "Empty"}
</div> </div>
)} )}
{isEditing && ( {isEditing && (
<form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center"> <form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center" ref={formRef}>
<Controller <Controller
control={control} control={control}
name="text" name="text"
@ -68,6 +75,7 @@ export const CustomTextAttribute: React.FC<Props & { value: string | undefined }
type="text" type="text"
className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none" className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none"
required={attributeDetails.is_required} required={attributeDetails.is_required}
placeholder={attributeDetails.display_name}
{...field} {...field}
/> />
)} )}

View File

@ -1,7 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
// react-hook-form
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// types // types
import { ICustomAttribute } from "types"; import { ICustomAttribute } from "types";
@ -18,6 +19,8 @@ export const CustomUrlAttribute: React.FC<Props & { value: string | undefined }>
}) => { }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const formRef = useRef(null);
const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { url: "" } }); const { control, handleSubmit, reset, setFocus } = useForm({ defaultValues: { url: "" } });
const handleFormSubmit = (data: { url: string }) => { const handleFormSubmit = (data: { url: string }) => {
@ -46,6 +49,10 @@ export const CustomUrlAttribute: React.FC<Props & { value: string | undefined }>
}; };
}, []); }, []);
useOutsideClickDetector(formRef, () => {
setIsEditing(false);
});
return ( return (
<div className="flex-shrink-0"> <div className="flex-shrink-0">
{!isEditing && ( {!isEditing && (
@ -63,7 +70,7 @@ export const CustomUrlAttribute: React.FC<Props & { value: string | undefined }>
</div> </div>
)} )}
{isEditing && ( {isEditing && (
<form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center"> <form onSubmit={handleSubmit(handleFormSubmit)} className="flex items-center" ref={formRef}>
<Controller <Controller
control={control} control={control}
name="url" name="url"
@ -72,6 +79,7 @@ export const CustomUrlAttribute: React.FC<Props & { value: string | undefined }>
type="url" type="url"
className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none" className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none"
required={attributeDetails.is_required} required={attributeDetails.is_required}
placeholder={attributeDetails.display_name}
{...field} {...field}
/> />
)} )}

View File

@ -221,7 +221,7 @@ export const ObjectModal: React.FC<Props> = observer((props) => {
<SecondaryButton onClick={handleClose}>Close</SecondaryButton> <SecondaryButton onClick={handleClose}>Close</SecondaryButton>
)} )}
<PrimaryButton type="submit" loading={isSubmitting}> <PrimaryButton type="submit" loading={isSubmitting}>
{data {objectId
? isSubmitting ? isSubmitting
? "Saving..." ? "Saving..."
: "Save changes" : "Save changes"
@ -234,7 +234,7 @@ export const ObjectModal: React.FC<Props> = observer((props) => {
</form> </form>
{objectId && ( {objectId && (
<> <>
<div className="px-6 pb-5"> <div className="px-6">
<h4 className="font-medium">Attributes</h4> <h4 className="font-medium">Attributes</h4>
<div className="mt-2 space-y-2"> <div className="mt-2 space-y-2">
{customAttributes.fetchObjectDetailsLoader ? ( {customAttributes.fetchObjectDetailsLoader ? (