validation field

This commit is contained in:
Moaz Dawalibi 2024-07-31 11:51:01 +03:00
parent fe9107dfb0
commit 956105e7c5
25 changed files with 314 additions and 1338 deletions

View File

@ -1,46 +1,55 @@
import React from "react";
import "./utils/ValidationField.scss";
import {
Date,
Time,
File,
DataRange,
SelectField,
CheckboxField,
MaltyFile,
SearchField,
TextField,
DropFile,
Default,
} from "./View";
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
import LocalSearchField from "./View/LocalSearch";
import NumberFormate from "./View/NumberFormate";
import "./ValidationField.scss";
import { Date, Time, File, DataRange, SelectField, Default, CheckboxField } from './View';
const components: { [key: string]: React.FC<any> } = {
Select: SelectField,
Search: SearchField,
LocalSearch: LocalSearchField,
DataRange: DataRange,
TextArea: TextField,
Date: Date,
Time: Time,
File: File,
DropFile: DropFile,
MaltyFile: MaltyFile,
Checkbox: CheckboxField,
NumberFormate: NumberFormate,
export interface ValidationFieldProps {
name: string;
type?: "text" | "Select" | "DataRange" | "Date" | "Time" | "File" | "number" | "Checkbox" | "password";
placeholder?: string;
label?: string;
className?: string;
option?: any[];
isMulti?: boolean;
isDisabled?: boolean;
picker?: "data" | "week" | "month" | "quarter" | "year";
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM";
accept?: any
onChange?: (value: any) => void;
Group?: boolean
dir?: 'ltr' | "rtl"
}
const ValidationField = (props: ValidationFieldProps) => {
switch (props?.type) {
case 'Select':
return <SelectField {...props} />;
case "DataRange":
return <DataRange {...props} />;
case "Date":
return <Date {...props} />;
case "Time":
return <Time {...props} />;
case "File":
return <File {...props} />;
case "Checkbox":
return <CheckboxField {...props} />;
default:
return <Default {...props} />;
}
};
const ValidationField: React.FC<ValidationFieldProps> = React.memo(
({ type = "text", ...otherProps }) => {
const Component = components[type ?? ("text" as ValidationFieldType)];
ValidationField.defaultProps = {
type: "text",
className: 'default-class',
option: [],
isMulti: false,
isDisabled: false,
picker: "date",
Format: "YYYY/MM/DD",
onChange: undefined,
Group: false,
dir: "ltr",
if (!Component) {
return <Default {...otherProps} />;
}
return <Component {...otherProps} />;
},
);
};
export default ValidationField;

View File

@ -1,35 +1,29 @@
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { Checkbox } from "antd";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
const CheckboxField = ({
name,
label,
isDisabled,
onChange,
Group,
className,
props,
}: any) => {
const { t, formik, isError, errorMsg } = useFormField(name, props);
const CheckboxhandleChange = (value: any) => {
formik.setFieldValue(name, value?.target?.checked);
};
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
import { Checkbox } from 'antd';
const CheckboxField = ({ name, label, placeholder, isDisabled, option, isMulti, onChange,Group, props }: any) => {
const { t, formik } = useFormField(name, props)
const CheckboxhandleChange = (value:any) => {
console.log(value.target.checked);
formik.setFieldValue(name, value.target.checked)
};
return (
<div className={Group ? "d-inline mt-3 Checkbox" : ``}>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<div className={Group ? "d-inline mt-3 Checkboxs" :``}>
<Checkbox
onChange={onChange || CheckboxhandleChange}
disabled={isDisabled}
checked={formik.values?.[name] ?? false}
className={className}
>
{t(`input.${label ? label : name}`)}
</Checkbox>
</ValidationFieldContainer>
</div>
);
};
checked={formik.getFieldProps(name).value}
export default CheckboxField;
>
{t(label)}
</Checkbox>
</div>
)
}
export default CheckboxField

View File

@ -1,55 +1,40 @@
import { Form, DatePicker } from "antd";
import { Form, DatePicker } from 'antd'
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const { RangePicker } = DatePicker;
const DataRange = ({
name,
label,
Format,
props,
onChange,
isDisabled,
placeholder,
className,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const DataRange = ({ name, label, isDisabled, option, isMulti, Format, props }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
formik.setFieldValue(name, value)
};
return (
<div className="ValidationField w-100 ">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<RangePicker
placeholder={placeholder}
size="large"
allowClear
className={`${className} w-100`}
className='w-100'
format={Format}
onChange={onChange || onCalendarChange}
disabled={isDisabled}
defaultValue={formik.values[name]}
id={name}
onCalendarChange={onCalendarChange}
/>
</ValidationFieldContainer>
</div>
);
};
export default DataRange;
</Form.Item>
</div>
)
}
export default DataRange

View File

@ -1,57 +1,40 @@
import { Form, DatePicker } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import dayjs from "dayjs";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
import { Form, DatePicker } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
import dayjs from 'dayjs';
const Date = ({
name,
label,
picker = "date",
isDisabled,
props,
onChange,
placeholder,
className,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const Date = ({ name, label, isDisabled, option, isMulti, picker = "date", props }: any) => {
const FormikValue = formik.values[name];
const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
formik.setFieldValue(name, value)
};
return (
<div className="ValidationField w-100 ">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<DatePicker
picker={picker}
placeholder={t(`input.${placeholder}`)}
allowClear
className={`${className} w-100`}
value={FormikValue ? FormikValue : null}
size="large"
onChange={onChange || onCalendarChange}
disabled={isDisabled}
id={name}
/>
{/* <DatePicker onChange={onChange} /> */}
</ValidationFieldContainer>
</div>
);
};
className='w-100'
// defaultValue={formik.values[name]}
export default Date;
onChange={onCalendarChange} />
</Form.Item>
</div>
)
}
export default Date

View File

@ -1,50 +1,32 @@
import { Input } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { Field } from "formik";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
import { FieldProps } from "../utils/types";
import { Form, Input } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const Default = ({ name, label, placeholder, isDisabled, onChange, props }: any) => {
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
const Default = ({
name,
label,
placeholder,
isDisabled,
onChange,
type,
no_label,
label_icon,
...props
}: any) => {
const { errorMsg, isError, t } = useFormField(name, props);
return (
<div className="ValidationField w-100">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<div className="ValidationField">
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? 'error' : ''}
help={isError ? errorMsg : ''}
>
<Field
as={Input}
type={type ?? "text"}
placeholder={t(`input.${placeholder || label || name}`)}
type="text"
placeholder={t(`${placeholder ? placeholder : name}`)}
name={name}
id={name}
disabled={isDisabled}
size="large"
{...(type === "number" && { min: 0 })}
{...props}
// onChange={onChange ? onChange : handleChange}
/>
</ValidationFieldContainer>
</Form.Item>
</div>
);
};
export default React.memo(Default);
export default Default;

View File

@ -1,93 +0,0 @@
import React, { useEffect, useState } from "react";
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
import { message, Upload } from "antd";
import type { GetProp, UploadProps } from "antd";
import useFormField from "../../../Hooks/useFormField";
type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];
const DropFile = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
no_label,
label_icon,
}: any) => {
const { formik, t, isError } = useFormField(name, props);
let FormikName = formik?.values[name];
const FormikValue =
typeof FormikName === "string"
? FormikName
: FormikName instanceof File
? URL.createObjectURL(FormikName)
: "";
const [imageUrl, setImageUrl] = useState<any>(FormikValue ?? "");
useEffect(() => {
setImageUrl(FormikName);
}, [FormikName]);
const getBase64 = (img: FileType, callback: (url: string) => void) => {
const reader = new FileReader();
reader.addEventListener("load", () => callback(reader.result as string));
reader.readAsDataURL(img);
};
const handleChange: UploadProps["onChange"] = (info) => {
if (info.file.status === "done") {
getBase64(info.file.originFileObj as FileType, (url) => {
setImageUrl(url);
});
}
formik.setFieldValue(name, info.file.originFileObj);
};
const customRequest = async ({ onSuccess }: any) => {
onSuccess();
};
const uploadButton = (
<button style={{ border: 0, background: "none" }} type="button">
<div className={`CustomFile ${isError ? "uploader_error" : ""} `}>
{t("input.drag_and_drop_or_click_here_to_select_the_file")}
</div>
</button>
);
return (
<div className="ValidationField w-100">
<label htmlFor={name} className="text">
{t(`input.${label || name}`)}
</label>
<Upload
name="avatar"
listType="picture-card"
className={`avatar-uploader ${isError ? "uploader_error" : ""} ${className}`}
showUploadList={false}
customRequest={customRequest}
onChange={onChange || handleChange}
id={name}
>
{imageUrl ? (
<img
src={
imageUrl instanceof File
? URL.createObjectURL(imageUrl)
: imageUrl
}
alt=""
style={{ width: "100%" }}
/>
) : (
uploadButton
)}
</Upload>
</div>
);
};
export default DropFile;

View File

@ -1,82 +1,59 @@
import { Button, Upload, UploadFile } from "antd";
import useFormField from "../../../Hooks/useFormField";
import { UploadOutlined } from "@ant-design/icons";
import React, { useMemo } from "react";
import { Button, Upload, UploadFile } from 'antd'
import useFormField from '../../../Hooks/useFormField';
import { UploadOutlined } from '@ant-design/icons';
import { BaseURL, BaseURL_IMAGE } from '../../../api/config';
import { useTranslation } from 'react-i18next';
import { ErrorMessage } from 'formik';
const File = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}: any) => {
const { formik, t, isError, errorMsg } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null;
const fileList: UploadFile[] = useMemo(() => {
if (!imageUrl) {
return [];
}
const File = ({ name, label, onChange, isDisabled, accept, props }: any) => {
const { formik, t } = useFormField(name, props)
const imageUrl = formik.values[name] ? BaseURL_IMAGE + formik.values[name] : '';
return [
typeof imageUrl === "string"
? {
uid: "-1",
name: "",
status: "done",
const fileList: UploadFile[] = [
{
uid: '-1',
name: '',
status: 'done',
url: imageUrl,
thumbUrl: imageUrl,
}
: {
uid: imageUrl.uid || "-1",
name: imageUrl.name || "",
status: "done",
originFileObj: imageUrl,
},
];
}, [imageUrl]);
const FilehandleChange = (value: any) => {
if (value.fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(name, value?.file?.originFileObj);
}
formik.setFieldValue(name, value.file.originFileObj)
};
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
const customRequest = async ({ onSuccess }: any) => {
onSuccess();
};
return (
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
<div className="ValidationField">
<label htmlFor={name} className="text">
{t(`input.${label || name}`)}
{t(`${label || name}`)}
</label>
<Upload
accept={accept ?? undefined}
disabled={isDisabled}
listType="picture"
maxCount={1}
fileList={[...fileList]}
className='w-100'
defaultFileList={[...fileList]}
onChange={onChange || FilehandleChange}
customRequest={customRequest}
className={` w-100`}
id={name}
>
<Button
className={isError ? "isError w-100 " : " w-100"}
icon={<UploadOutlined />}
>
{placeholder
? t(`input.${placeholder}`)
: t("input.Click_to_upload_the_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg}
</Upload>
</div>
);
};
export default React.memo(File);
>
<Button className='w-100' icon={<UploadOutlined />}>{t("upload_image")}</Button>
<ErrorMessage name={name}>{msg => <div className='error'>{t(msg)}</div>}</ErrorMessage>
</Upload>
</div>
)
}
export default File

View File

@ -1,76 +0,0 @@
import { Select } from "antd";
import React, { useState } from "react";
import useFormField from "../../../Hooks/useFormField";
import { translateOptions } from "../utils/translatedOptions";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
const LocalSelectField = ({
name,
label,
placeholder,
isDisabled,
option,
isMulti,
onChange,
className,
no_label,
label_icon,
...props
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
// State to manage the search input value
const [searchValue, setSearchValue] = useState("");
const handleSearch = (
input: string,
option: { value: string; label: React.ReactNode | undefined },
) =>
option?.label?.toString().toLowerCase().includes(input.toLowerCase()) ||
option?.value?.toString().toLowerCase().includes(input.toLowerCase());
const handleSelectChange = (value: any) => {
formik.setFieldValue(name, value);
if (onChange) onChange(value);
};
const handleSearchChange = (input: string) => {
setSearchValue(input); // Update the search input value
};
return (
<div className="ValidationField w-100">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<Select
placeholder={t(`input.${placeholder || label || name}`)}
disabled={isDisabled}
options={translateOptions(option, t)}
size="large"
className={`${className} ${isError ? "SelectError" : ""} w-100`}
value={formik.values[name]}
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={handleSelectChange}
showSearch
filterOption={handleSearch} // Custom filter function
searchValue={searchValue} // Control the search input value
onSearch={handleSearchChange} // Update search input value on change
id={name}
fieldNames={{ label: "name", value: "id" }}
{...props}
/>
</ValidationFieldContainer>
</div>
);
};
export default React.memo(LocalSelectField);

View File

@ -1,86 +0,0 @@
import React, { useMemo } from "react";
import { Button, Upload } from "antd";
import { UploadOutlined } from "@ant-design/icons";
import useFormField from "../../../Hooks/useFormField";
const MaltyFile = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}: any) => {
const { formik, t, isError } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null;
// Memoizing the fileList to prevent unnecessary recalculations
const fileList = useMemo(() => {
return imageUrl
? imageUrl.map((file: any, index: number) => {
return file instanceof File
? {
uid: index,
name: file?.name,
status: "done",
originFileObj: file,
}
: {
uid: index,
id: file?.id,
name: file?.name,
status: "done",
url: file?.url || "",
thumbUrl: file?.url || "",
};
})
: [];
}, [imageUrl]); // Dependency array ensures it recalculates only when imageUrl changes
const FilehandleChange = ({ fileList }: any) => {
if (fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(
name,
fileList.map((file: any) => file?.originFileObj ?? file),
);
}
};
// Custom request function
const customRequest = async ({ onSuccess }: any) => {
// Perform any necessary actions before onSuccess is called
onSuccess();
};
return (
<div className="ValidationField upload_image_button">
<label htmlFor={name} className="text">
{t(`input.${label || name}`)}
</label>
<Upload
disabled={isDisabled}
listType="picture"
fileList={fileList} // Using memoized fileList
onChange={onChange || FilehandleChange}
customRequest={customRequest}
className={`${className} w-100`}
multiple // Allow multiple files to be selected
id={name}
>
<Button
className={isError ? "isError w-100" : "w-100"}
icon={<UploadOutlined />}
>
{t(`input.` + placeholder) ?? t("input.upload_image")}
</Button>
<div className="Error_color">{isError ? "required" : ""}</div>
</Upload>
</div>
);
};
export default MaltyFile;

View File

@ -1,62 +0,0 @@
import { InputNumber } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { Field } from "formik";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
const NumberFormate = ({
name,
label,
placeholder,
isDisabled,
type,
no_label,
label_icon,
...props
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
formik.setFieldValue(name, value);
};
return (
<div className="ValidationField w-100">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<Field
as={InputNumber}
formatter={(value: any) =>
`${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
parser={(value: any) =>
value?.replace(/\$\s?|(,*)/g, "") as unknown as number
}
min="0"
type={type ?? "text"}
value={formik.values[name]}
onChange={SelectableChange}
placeholder={t(`input.${placeholder || label || name}`)}
name={name}
disabled={isDisabled}
size="large"
id={name}
{...props}
// onChange={onChange ? onChange : handleChange}
/>
</ValidationFieldContainer>
</div>
);
};
export default React.memo(NumberFormate);

View File

@ -1,140 +1,44 @@
import { Select, Spin } from "antd";
import React, { useEffect, useState } from "react";
import useFormField from "../../../Hooks/useFormField";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
import { SearchFieldProps } from "../utils/types";
import { useValidationValidationParamState } from "../state/ValidationValidationParamState";
import { Input } from 'antd';
import { SearchProps } from 'antd/es/input'
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
const { Search } = Input;
const SearchField = ({
name,
label,
placeholder,
isDisabled,
searchBy = "search",
option = [],
isMulti,
onChange,
className,
no_label,
label_icon,
isLoading,
canChangePage,
PageName,
page,
...props
}: SearchFieldProps) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const { pushValidationParamState, setValidationParamState } =
useValidationValidationParamState();
const SearchField = () => {
const navigate = useNavigate()
const [searchParams,] = useSearchParams();
const location =useLocation()
const {t} = useTranslation();
const [AllPagesOption, setAllPagesOption] = useState<any>([]);
const [searchValue, setSearchValue] = useState(searchParams.get('search')|| "");
useEffect(() => {
if (option?.length > 0) {
const NewOption = [...option, ...AllPagesOption];
const FilteredOption = NewOption.filter(
(value, index, self) =>
index === self.findIndex((t) => t.id === value.id),
);
const sortedNewOption = FilteredOption.sort((a, b) => a.id - b.id);
setAllPagesOption(sortedNewOption);
const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
// console.log(value);
navigate(`${location?.pathname}?search=${value}`, { replace: true });
}
}, [option]);
useEffect(() => {
if (page === 1) {
setAllPagesOption(option);
}
}, [page]);
const onChange = (e :any) => {
setSearchValue(e.target.value);
const SelectableChange = (value: any) => {
formik?.setFieldValue(name, value);
const isCleared = value?.length === 0 || !value;
}
if (isCleared) {
if (PageName) {
setValidationParamState({
[PageName]: 1,
});
}
}
console.log(value, "value");
};
const handleChange = ((value: string) => {
if (PageName) {
pushValidationParamState({
[PageName]: 1,
});
}
pushValidationParamState({
[searchBy]: value,
});
});
const handleBlur = () => {
if (PageName && page === 1) {
setValidationParamState({
[PageName]: null,
});
}
if (PageName && page !== 1) {
setValidationParamState({
[PageName]: 1,
});
setAllPagesOption([]);
}
};
const handleScroll = (event: any) => {
const target = event.target;
const isAtBottom =
target.scrollHeight === target.scrollTop + target.clientHeight;
if (isAtBottom && canChangePage && PageName && page) {
console.log("Scrolled to the last option!");
let newPage = page + 1;
pushValidationParamState({
[PageName]: newPage,
});
}
};
return (
<div className="ValidationField w-100">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<Select
placeholder={t(`input.${placeholder || label || name}`)}
disabled={isDisabled}
options={AllPagesOption}
size="large"
className={`${className} w-100`}
value={formik.values[name]}
// loading={isLoading}
<div className='SearchField'>
<Search
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={onChange || SelectableChange}
showSearch
optionFilterProp="name"
notFoundContent={isLoading ? <Spin /> : t("validation.undefined")}
onSearch={handleChange}
onBlur={handleBlur}
id={name}
onPopupScroll={handleScroll}
fieldNames={{ label: "name", value: "id" }}
{...props}
enterButton={t("search")}
size="middle"
placeholder={t("search")}
onSearch={onSearch}
style={{ width: 250 }}
value={searchValue}
onChange={onChange}
/>
</ValidationFieldContainer>
</div>
);
};
export default React.memo(SearchField);
</div>
)
}
export default SearchField

View File

@ -1,63 +1,39 @@
import { Select } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { translateOptions } from "../utils/translatedOptions";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
import { SelectFieldProps } from "../utils/types";
import { Form, Select } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const SelectField = ({ name, label, placeholder, isDisabled, option, isMulti, onChange, props }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props)
const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
formik.setFieldValue(name, value)
const SelectField = ({
name,
label,
placeholder,
isDisabled,
option,
isMulti,
onChange,
className,
no_label,
label_icon,
isLoading,
...props
}: SelectFieldProps) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
formik.setFieldValue(name, value);
};
const options = translateOptions(option, t);
return (
<div className="ValidationField w-100">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Select
placeholder={t(`input.${placeholder || label || name}`)}
placeholder={t(`${placeholder ? placeholder : name}`)}
disabled={isDisabled}
options={options}
{...(isLoading && { loading: isLoading })}
size="large"
className={`${className} ${isError ? "SelectError" : ""} w-100`}
value={formik.values[name]}
options={option}
defaultValue={formik.values[name]}
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={onChange || SelectableChange}
showSearch={false}
id={name}
{...props}
/>
</ValidationFieldContainer>
</div>
);
};
onChange={onChange || SelecthandleChange}
export default React.memo(SelectField);
/>
</Form.Item>
</div>
)
}
export default SelectField

View File

@ -1,45 +0,0 @@
import { Input } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { Field } from "formik";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
const { TextArea } = Input;
const TextAreaField = ({
name,
label,
placeholder,
isDisabled,
onChange,
props,
}: any) => {
const { formik, isError, errorMsg, t } = useFormField(name, props);
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
formik.setFieldValue(name, e.target.value);
};
return (
<div className="ValidationField w-100">
<label htmlFor={name} className="text">
{t(`input.${label ? label : name}`)}
</label>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<Field
as={TextArea}
placeholder={t(`input.${placeholder ? placeholder : name}`)}
name={name}
disabled={isDisabled}
size="large"
onChange={onChange || handleChange}
id={name}
// onChange={onChange ? onChange : handleChange}
/>
</ValidationFieldContainer>
</div>
);
};
export default React.memo(TextAreaField);

View File

@ -1,57 +0,0 @@
import { Form, Input } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import { Field } from "formik";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
const { TextArea } = Input;
const TextField = ({
name,
label,
label2,
placeholder,
isDisabled,
onChange,
props,
no_label,
label_icon,
className,
}: any) => {
const { formik, isError, errorMsg, t } = useFormField(name, props);
const TextFilehandleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
formik.setFieldValue(name, e.target.value);
};
return (
<div className={`ValidationField w-100 ${className ?? ""} `}>
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
<Field
as={TextArea}
placeholder={t(`input.${placeholder ? placeholder : name}`)}
name={name}
disabled={isDisabled}
size="large"
showCount
maxLength={1000}
onChange={onChange || TextFilehandleChange}
style={{ height: 120 }}
id={name}
/>
</ValidationFieldContainer>
</div>
);
};
export default React.memo(TextField);

View File

@ -1,40 +1,21 @@
import { Form, TimePicker } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import dayjs from "dayjs";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
import { Form, TimePicker } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const Time = ({
name,
label,
className,
isDisabled,
onChange,
props,
placeholder,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const Time = ({ name, label, props }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
formik.setFieldValue(name, value)
};
const Formatter = "H:mm";
const FormikValue = formik.values[name];
return (
<div className="ValidationField w-100 ">
<ValidationFieldLabel
name={name}
label={label}
label_icon={label_icon}
no_label={no_label}
placeholder={placeholder}
t={t}
/>
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
@ -42,19 +23,16 @@ const Time = ({
>
<TimePicker
allowClear
className={`${className} w-100`}
size="large"
value={FormikValue ? dayjs(FormikValue, Formatter) : null}
onChange={onChange || onCalendarChange}
disabled={isDisabled}
placeholder={t(`input.${placeholder || label || name}`)}
format={Formatter}
className='w-100'
defaultValue={formik.values[name]}
onChange={onCalendarChange} />
id={name}
/>
</Form.Item>
</div>
);
};
)
}
export default Time;
export default Time

View File

@ -5,10 +5,10 @@ import DataRange from "./DataRange";
import CheckboxField from "./CheckboxField";
import Default from "./Default";
import File from "./File";
import MaltyFile from "./MaltyFile";
import SearchField from "./SearchField";
import TextField from "./TextField";
import DropFile from "./DropFile.tsx";
export {
Time,
@ -17,9 +17,6 @@ export {
DataRange,
CheckboxField,
Default,
File,
MaltyFile,
SearchField,
TextField,
DropFile,
};
File
}

View File

@ -1,24 +0,0 @@
import React, { FC } from "react";
import { Form } from "antd";
interface ValidationFieldContainerProps {
children: React.ReactNode;
isError: boolean;
errorMsg: string;
}
export const ValidationFieldContainer: FC<ValidationFieldContainerProps> = ({
children,
isError,
errorMsg,
}) => (
<div className="ValidationFieldContainer">
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
{children}
</Form.Item>
</div>
);

View File

@ -1,39 +0,0 @@
import React from "react";
import { MdOutlineEdit } from "react-icons/md";
interface ValidationFieldLabelProps {
name: string;
label?: string;
no_label?: boolean;
label_icon?: boolean;
placeholder?: string;
t: (key: string) => string;
}
export const ValidationFieldLabel: React.FC<ValidationFieldLabelProps> = ({
name,
label,
placeholder,
no_label,
label_icon,
t,
}) => (
<>
{no_label ? (
<label htmlFor={name} className="text">
<span>empty</span>
</label>
) : label_icon ? (
<div className="LabelWithIcon">
<label htmlFor={name} className="text">
{t(`input.${label ? label : name}`)}
</label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`input.${label ? label : name}`)}
</label>
)}
</>
);

View File

@ -1,14 +1,21 @@
import { useState } from "react";
import { ErrorMessage, useField, Field, useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
import { FaExclamationCircle } from "react-icons/fa";
import { useState } from 'react';
import { ErrorMessage, useField, Field, useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { FaExclamationCircle } from 'react-icons/fa';
import Select from 'react-select';
import { convert_data_to_select } from '../../Layout/app/Const';
export {
useState,
ErrorMessage,
useField,
Field,
useFormikContext,
ErrorMessage, useField, Field, useFormikContext,
useTranslation,
FaExclamationCircle,
};
Select,
convert_data_to_select,
}

View File

@ -1,36 +0,0 @@
import { create } from "zustand";
interface ValidationParamState {
[key: string]: any;
}
interface ModalState {
ValidationParamState: ValidationParamState;
setValidationParamState: (validationParamState: ValidationParamState) => void;
pushValidationParamState: (
validationParamState: ValidationParamState,
) => void;
clearValidationParamState: () => void;
}
export const useValidationValidationParamState = create<ModalState>((set) => ({
ValidationParamState: {},
setValidationParamState: (validationParamState) =>
set(() => ({
ValidationParamState: validationParamState,
})),
pushValidationParamState: (validationParamState) =>
set((state) => ({
ValidationParamState: {
...state.ValidationParamState,
...validationParamState,
},
})),
clearValidationParamState: () =>
set({
ValidationParamState: {},
}),
}));

View File

@ -1,200 +0,0 @@
.LabelWithIcon {
display: flex;
width: 100%;
justify-content: space-between;
}
.ValidationField {
margin-bottom: 1.3vw;
position: relative;
> * {
width: 100%;
}
.text,
.ant-form-item {
margin-bottom: 7px !important;
> span {
color: transparent;
}
}
.ant-select-outlined:not(.ant-select-customize-input) .ant-select-selector {
border: 1px solid var(--border-color);
}
.SelectError {
.ant-select-selector {
border: 1px solid red !important;
}
}
// .ValidationField{
// .ant-select-selector{
// border: 1px solid var(--border-color) ;
// }
// }
> span {
margin-bottom: 0px !important;
&:focus-within {
border-color: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
cursor: pointer;
}
&:has(.is-invalid) {
border-color: red !important ;
}
input {
color: var(--text);
background: var(--bg);
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0 30px white inset !important;
}
}
}
.ant-upload-select {
width: 100%;
}
.Checkbox {
padding: 4%;
}
.SearchField {
button {
background: var(--primary);
}
}
.text {
color: var(--text);
margin-bottom: 15px;
font-weight: bold;
}
input:disabled {
color: var(--text) !important;
}
.isError {
outline: red 1px solid;
color: red;
}
.Error_color {
color: red;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
/* Remove autofill background color on hover */
input:-webkit-autofill:hover {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
.upload_image_button {
.ant-btn {
min-height: 3vw !important;
border: 0.1vw solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
}
}
.ant-select-outlined:not(.ant-select-customize-input) .ant-select-selector {
min-height: 3vw !important;
}
.ant-select-multiple.ant-select-lg .ant-select-selection-overflow {
min-height: 3vw !important;
}
.ant-upload-list .ant-upload-list-item {
// height:3vw !important;
border: 1px solid var(--border-color) !important;
}
.TowValidationItems {
display: flex;
gap: 3%;
> label {
display: none;
}
}
.ant-select .ant-select-arrow {
inset-inline-end: 1vw;
}
.ant-input-affix-wrapper-lg {
padding: 0.5vw 1vw;
font-size: 1vw;
min-height: 3vw;
border-radius: 0.6vw;
}
.ant-picker-outlined {
padding: 0.5vw 1vw;
font-size: 1vw;
min-height: 3vw;
border-radius: 0.6vw;
border: 1px solid var(--border-color);
}
.ant-select-single.ant-select-lg .ant-select-selector {
min-height: 3vw;
border-radius: 0.6vw;
}
.ant-select-single .ant-select-selector .ant-select-selection-search-input {
min-height: 3vw;
}
.ant-select-outlined .ant-select-selector {
min-height: 3vw !important;
border-radius: 0.6vw !important;
}
.ant-select-single.ant-select-lg {
min-height: 3vw;
}
.ant-upload-wrapper .ant-upload-list .ant-upload-list-item {
width: 21.5vw;
}
.ant-input-number-outlined {
width: 100%;
height: 3vw;
}
.ant-input-number-lg input.ant-input-number-input {
width: 100%;
height: 3vw;
}
.bigRow {
width: 100%;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
> *.w-100 {
width: 48% !important;
}
}
.ant-input-number-affix-wrapper-lg {
width: 100%;
height: 3vw;
border-radius: 0.6vw;
border: 1px solid var(--border-color);
}
.TwoSelectGroup {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.TwoSelectGroupbutton {
margin-bottom: 20px;
}

View File

@ -1,11 +0,0 @@
import { create } from "zustand";
interface ValidationState {
Validation: any[];
setValidation: (value: any[]) => void;
}
export const useValidationState = create<ValidationState>((set) => ({
Validation: [],
setValidation: (value) => set((state) => ({ Validation: value })),
}));

View File

@ -1,7 +0,0 @@
export const translateOptions = (options: any, t: any) => {
return options?.map((opt: any) => ({
...opt,
label: t(`${opt?.label}`),
name: t(`${opt?.name}`),
}));
};

View File

@ -1,80 +0,0 @@
import { InputProps, SelectProps } from "antd";
// Common properties for all field types
interface BaseFieldProps {
name: string;
label?: string;
placeholder?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
no_label?: boolean;
label_icon?: boolean;
}
// Specific field type properties
export type SelectFieldProps = BaseFieldProps &
SelectProps & {
type: "Select" | "LocalSearch";
option: any[];
isMulti?: boolean;
isLoading?: boolean;
searchBy?: string;
canChangePage?: boolean;
PageName?: string;
page?: number;
};
export type SearchFieldProps = BaseFieldProps &
SelectProps & {
type: "Search";
option: any[];
isMulti?: boolean;
isLoading: boolean;
searchBy: string;
canChangePage: boolean;
PageName: string;
page: number;
};
type DateFieldProps = BaseFieldProps & {
type: "DataRange" | "Date" | "Time";
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
picker?: "data" | "week" | "month" | "quarter" | "year";
};
type FileFieldProps = BaseFieldProps & {
type: "File" | "MaltyFile" | "DropFile";
};
type CheckboxFieldProps = BaseFieldProps & {
type: "Checkbox";
Group?: boolean;
};
export type FieldProps = BaseFieldProps &
InputProps & {
type?:
| "text"
| "number"
| "password"
| "email"
| "TextArea"
| "NumberFormate";
label2?: string;
Group?: boolean;
[key: string]: any;
};
// Union type for all field types
export type ValidationFieldProps =
| SelectFieldProps
| DateFieldProps
| FileFieldProps
| CheckboxFieldProps
| SearchFieldProps
| FieldProps;
// Validation field type
export type ValidationFieldType = ValidationFieldProps["type"];

View File

@ -1,5 +1,5 @@
export const BaseURL = `http://127.0.0.1:8000/`;
export const BaseURL = `http://192.168.1.102:8000/`;
export const BaseURL_IMAGE = '';