end package
This commit is contained in:
parent
6213253337
commit
5e0e0afd01
|
|
@ -1,24 +0,0 @@
|
|||
import React from "react";
|
||||
import { Spin } from "antd";
|
||||
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const KarimSpinner: React.FC<Props> = ({ loading, className, children }) => {
|
||||
return (
|
||||
<div className={className ?? ""}>
|
||||
{loading ? (
|
||||
<div className="text-center">
|
||||
<Spin />
|
||||
</div>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default KarimSpinner;
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
.SearchBar {
|
||||
// margin-top: 20px;
|
||||
.group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
max-width: 350px;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 1rem;
|
||||
padding-left: 2.5rem;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
font-weight: 500;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
border: none;
|
||||
box-shadow: 2px 2px 7px 0 var(--bg);
|
||||
}
|
||||
|
||||
.input::placeholder {
|
||||
color: var(--subtext);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
fill: var(--subtext);
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import React, { useState } from "react";
|
||||
import "./SearchBar.scss";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
const SearchBar = () => {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [searchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleChange = (event: any) => {
|
||||
const { value } = event.target;
|
||||
setSearchQuery(value);
|
||||
updateUrlParams(value);
|
||||
};
|
||||
|
||||
const updateUrlParams = (value: any) => {
|
||||
navigate(`?search=${value}`, { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="SearchBar">
|
||||
<div className="group">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-1b5stb0 icon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
data-testid="SearchIcon"
|
||||
>
|
||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
|
||||
</svg>
|
||||
<input
|
||||
placeholder="Search Product...."
|
||||
type="search"
|
||||
className="input"
|
||||
value={searchQuery}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchBar;
|
||||
|
|
@ -6,17 +6,16 @@ import {
|
|||
File,
|
||||
DataRange,
|
||||
SelectField,
|
||||
Default,
|
||||
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 NumberField from "./View/NumberField";
|
||||
|
||||
const components: { [key: string]: React.FC<any> } = {
|
||||
Select: SelectField,
|
||||
|
|
@ -31,12 +30,11 @@ const components: { [key: string]: React.FC<any> } = {
|
|||
MaltyFile: MaltyFile,
|
||||
Checkbox: CheckboxField,
|
||||
NumberFormate: NumberFormate,
|
||||
Number: NumberField,
|
||||
};
|
||||
|
||||
const ValidationField: React.FC<ValidationFieldProps> = React.memo(
|
||||
({ type, ...otherProps }: any) => {
|
||||
const Component = components[type as ValidationFieldType];
|
||||
({ type = "text", ...otherProps }) => {
|
||||
const Component = components[type ?? ("text" as ValidationFieldType)];
|
||||
|
||||
if (!Component) {
|
||||
return <Default {...otherProps} />;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { Checkbox, Form } from "antd";
|
||||
import { getNestedValue } from "../utils/getNestedValue";
|
||||
import { Checkbox } from "antd";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
const CheckboxField = ({
|
||||
name,
|
||||
label,
|
||||
|
|
@ -13,25 +13,21 @@ const CheckboxField = ({
|
|||
}: any) => {
|
||||
const { t, formik, isError, errorMsg } = useFormField(name, props);
|
||||
const CheckboxhandleChange = (value: any) => {
|
||||
formik.setFieldValue(name, value?.target?.checked ? 1 : 0);
|
||||
formik.setFieldValue(name, value?.target?.checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={Group ? "d-inline mt-3 Checkboxs" : ``}>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<div className={Group ? "d-inline mt-3 Checkbox" : ``}>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<Checkbox
|
||||
onChange={onChange || CheckboxhandleChange}
|
||||
disabled={isDisabled}
|
||||
checked={formik.values?.[name] === 1}
|
||||
checked={formik.values?.[name] ?? false}
|
||||
className={className}
|
||||
>
|
||||
{t(`input.${label ? label : name}`)}
|
||||
</Checkbox>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ 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";
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
|
|
@ -24,28 +26,16 @@ const DataRange = ({
|
|||
};
|
||||
return (
|
||||
<div className="ValidationField w-100 ">
|
||||
{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>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<RangePicker
|
||||
placeholder={placeholder}
|
||||
size="large"
|
||||
|
|
@ -55,8 +45,9 @@ const DataRange = ({
|
|||
onChange={onChange || onCalendarChange}
|
||||
disabled={isDisabled}
|
||||
defaultValue={formik.values[name]}
|
||||
id={name}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import React from "react";
|
|||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import dayjs from "dayjs";
|
||||
import { DateEnum } from "../../../enums/Date";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
|
||||
const Date = ({
|
||||
name,
|
||||
|
|
@ -21,34 +24,21 @@ const Date = ({
|
|||
const FormikValue = formik.values[name];
|
||||
const onCalendarChange = (value: any) => {
|
||||
formik.setFieldValue(name, value);
|
||||
// console.log(value,"value ");
|
||||
};
|
||||
|
||||
const Formater = "YYYY/MM/DD";
|
||||
const Formatter = [DateEnum?.FORMATE, DateEnum?.FORMATE2];
|
||||
return (
|
||||
<div className="ValidationField w-100 ">
|
||||
{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>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<DatePicker
|
||||
picker={picker}
|
||||
placeholder={t(`input.${placeholder}`)}
|
||||
|
|
@ -58,10 +48,11 @@ const Date = ({
|
|||
size="large"
|
||||
onChange={onChange || onCalendarChange}
|
||||
disabled={isDisabled}
|
||||
format={Formater}
|
||||
format={Formatter}
|
||||
id={name}
|
||||
/>
|
||||
{/* <DatePicker onChange={onChange} /> */}
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Form, Input } from "antd";
|
||||
import { Input } from "antd";
|
||||
import React from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { Field } from "formik";
|
||||
import { ValidationFieldPropsInput } from "../utils/types";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
import { FieldProps } from "../utils/types";
|
||||
|
||||
const Default = ({
|
||||
name,
|
||||
|
|
@ -14,52 +15,34 @@ const Default = ({
|
|||
type,
|
||||
no_label,
|
||||
label_icon,
|
||||
label2,
|
||||
...props
|
||||
}: ValidationFieldPropsInput) => {
|
||||
}: any) => {
|
||||
const { errorMsg, isError, t } = useFormField(name, props);
|
||||
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{label2 ? (
|
||||
<label htmlFor={name} className="text">
|
||||
{label2}
|
||||
</label>
|
||||
) : 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 : placeholder ? placeholder : name}`)}
|
||||
</label>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<Field
|
||||
as={Input}
|
||||
type={type ?? "text"}
|
||||
placeholder={t(
|
||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
name={name}
|
||||
id={name}
|
||||
disabled={isDisabled}
|
||||
size="large"
|
||||
{...(type === "number" && { min: 0 })}
|
||||
{...props}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
|
|||
import { message, Upload } from "antd";
|
||||
import type { GetProp, UploadProps } from "antd";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { ImageBaseURL } from "../../../api/config";
|
||||
|
||||
type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];
|
||||
|
||||
|
|
@ -12,7 +11,7 @@ const DropFile = ({
|
|||
label,
|
||||
onChange,
|
||||
isDisabled,
|
||||
placholder,
|
||||
placeholder,
|
||||
className,
|
||||
props,
|
||||
no_label,
|
||||
|
|
@ -23,7 +22,7 @@ const DropFile = ({
|
|||
|
||||
const FormikValue =
|
||||
typeof FormikName === "string"
|
||||
? ImageBaseURL + FormikName
|
||||
? FormikName
|
||||
: FormikName instanceof File
|
||||
? URL.createObjectURL(FormikName)
|
||||
: "";
|
||||
|
|
@ -71,6 +70,7 @@ const DropFile = ({
|
|||
showUploadList={false}
|
||||
customRequest={customRequest}
|
||||
onChange={onChange || handleChange}
|
||||
id={name}
|
||||
>
|
||||
{imageUrl ? (
|
||||
<img
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { Button, Upload, UploadFile } from "antd";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import { useMemo } from "react";
|
||||
import React, { useMemo } from "react";
|
||||
|
||||
const File = ({
|
||||
name,
|
||||
label,
|
||||
onChange,
|
||||
isDisabled,
|
||||
placholder,
|
||||
placeholder,
|
||||
className,
|
||||
props,
|
||||
}: any) => {
|
||||
|
|
@ -16,29 +16,29 @@ const File = ({
|
|||
let imageUrl = formik?.values?.[name] ?? null;
|
||||
|
||||
const fileList: UploadFile[] = useMemo(() => {
|
||||
if (!imageUrl) return [];
|
||||
if (!imageUrl) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
typeof imageUrl === "string"
|
||||
? {
|
||||
uid: "-1",
|
||||
name: "uploaded-image",
|
||||
name: "",
|
||||
status: "done",
|
||||
url: imageUrl,
|
||||
thumbUrl: imageUrl,
|
||||
}
|
||||
: {
|
||||
uid: imageUrl.uid || "-1",
|
||||
name: imageUrl.name || "uploaded-image",
|
||||
name: imageUrl.name || "",
|
||||
status: "done",
|
||||
originFileObj: imageUrl,
|
||||
},
|
||||
];
|
||||
}, [imageUrl]);
|
||||
// console.log(1);
|
||||
|
||||
const FilehandleChange = (value: any) => {
|
||||
// console.log(value,"filevalue");
|
||||
if (value.fileList.length === 0) {
|
||||
formik.setFieldValue(name, null);
|
||||
} else {
|
||||
|
|
@ -62,12 +62,15 @@ const File = ({
|
|||
onChange={onChange || FilehandleChange}
|
||||
customRequest={customRequest}
|
||||
className={` w-100`}
|
||||
id={name}
|
||||
>
|
||||
<Button
|
||||
className={isError ? "isError w-100 " : " w-100"}
|
||||
icon={<UploadOutlined />}
|
||||
>
|
||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
||||
{placeholder
|
||||
? t(`input.${placeholder}`)
|
||||
: t("input.Click_to_upload_the_image")}
|
||||
</Button>
|
||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
||||
{errorMsg}
|
||||
|
|
@ -76,4 +79,4 @@ const File = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default File;
|
||||
export default React.memo(File);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { Form, Select } from "antd";
|
||||
import { Select } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { translateOptions } from "../utils/translatedOptions";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
|
||||
const LocalSelectField = ({
|
||||
name,
|
||||
|
|
@ -13,9 +14,9 @@ const LocalSelectField = ({
|
|||
isMulti,
|
||||
onChange,
|
||||
className,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
...props
|
||||
}: any) => {
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||
|
||||
|
|
@ -29,13 +30,6 @@ const LocalSelectField = ({
|
|||
option?.label?.toString().toLowerCase().includes(input.toLowerCase()) ||
|
||||
option?.value?.toString().toLowerCase().includes(input.toLowerCase());
|
||||
|
||||
const SelectableChange = (value: {
|
||||
value: string;
|
||||
label: React.ReactNode;
|
||||
}) => {
|
||||
formik.setFieldValue(name, value);
|
||||
};
|
||||
|
||||
const handleSelectChange = (value: any) => {
|
||||
formik.setFieldValue(name, value);
|
||||
if (onChange) onChange(value);
|
||||
|
|
@ -47,35 +41,21 @@ const LocalSelectField = ({
|
|||
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{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>
|
||||
)}
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<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 ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
disabled={isDisabled}
|
||||
options={translateOptions(option, t)}
|
||||
size="large"
|
||||
className={`${className} ${isError ? "Select_error" : ""} w-100`}
|
||||
className={`${className} ${isError ? "SelectError" : ""} w-100`}
|
||||
value={formik.values[name]}
|
||||
allowClear
|
||||
{...(isMulti && { mode: "multiple" })}
|
||||
|
|
@ -84,8 +64,11 @@ const LocalSelectField = ({
|
|||
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}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useMemo } from "react";
|
||||
import { Button, Upload } from "antd";
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
|
||||
const MaltyFile = ({
|
||||
|
|
@ -15,11 +15,10 @@ const MaltyFile = ({
|
|||
const { formik, t, isError } = useFormField(name, props);
|
||||
let imageUrl = formik?.values?.[name] ?? null;
|
||||
|
||||
// Mapping formik values to fileList format
|
||||
const fileList = imageUrl
|
||||
// Memoizing the fileList to prevent unnecessary recalculations
|
||||
const fileList = useMemo(() => {
|
||||
return imageUrl
|
||||
? imageUrl.map((file: any, index: number) => {
|
||||
// console.log(file,"file");
|
||||
|
||||
return file instanceof File
|
||||
? {
|
||||
uid: index,
|
||||
|
|
@ -37,6 +36,7 @@ const MaltyFile = ({
|
|||
};
|
||||
})
|
||||
: [];
|
||||
}, [imageUrl]); // Dependency array ensures it recalculates only when imageUrl changes
|
||||
|
||||
const FilehandleChange = ({ fileList }: any) => {
|
||||
if (fileList.length === 0) {
|
||||
|
|
@ -48,6 +48,7 @@ const MaltyFile = ({
|
|||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Custom request function
|
||||
const customRequest = async ({ onSuccess }: any) => {
|
||||
// Perform any necessary actions before onSuccess is called
|
||||
|
|
@ -63,19 +64,20 @@ const MaltyFile = ({
|
|||
<Upload
|
||||
disabled={isDisabled}
|
||||
listType="picture"
|
||||
fileList={fileList} // Using fileList instead of defaultFileList
|
||||
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"}
|
||||
className={isError ? "isError w-100" : "w-100"}
|
||||
icon={<UploadOutlined />}
|
||||
>
|
||||
{t(`input.` + placeholder) ?? t("input.upload_image")}
|
||||
</Button>
|
||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
||||
<div className="Error_color">{isError ? "required" : ""}</div>
|
||||
</Upload>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
import { Form, Input, InputNumber } from "antd";
|
||||
import React from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { Field } from "formik";
|
||||
import { ValidationFieldPropsInput } from "../utils/types";
|
||||
|
||||
const NumberField = ({
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
isDisabled,
|
||||
onChange,
|
||||
type,
|
||||
no_label,
|
||||
label_icon,
|
||||
...props
|
||||
}: ValidationFieldPropsInput) => {
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
console.log("Change:", e);
|
||||
formik.setFieldValue(name, e);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{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 : placeholder ? placeholder : name}`)}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<Field
|
||||
as={InputNumber}
|
||||
type={type ?? "text"}
|
||||
placeholder={t(
|
||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
name={name}
|
||||
disabled={isDisabled}
|
||||
size="large"
|
||||
onChange={handleChange}
|
||||
{...(type === "number" && { min: 0 })}
|
||||
{...props}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(NumberField);
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
import { Form, Input, InputNumber } from "antd";
|
||||
import { InputNumber } 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 NumberFormate = ({
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
isDisabled,
|
||||
props,
|
||||
type,
|
||||
no_label,
|
||||
label_icon,
|
||||
...props
|
||||
}: any) => {
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||
const SelectableChange = (value: {
|
||||
|
|
@ -23,28 +24,15 @@ const NumberFormate = ({
|
|||
};
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{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 : placeholder ? placeholder : name}`)}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<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) =>
|
||||
|
|
@ -57,16 +45,16 @@ const NumberFormate = ({
|
|||
type={type ?? "text"}
|
||||
value={formik.values[name]}
|
||||
onChange={SelectableChange}
|
||||
placeholder={t(
|
||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
name={name}
|
||||
disabled={isDisabled}
|
||||
size="large"
|
||||
id={name}
|
||||
{...props}
|
||||
|
||||
// onChange={onChange ? onChange : handleChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,87 +1,143 @@
|
|||
import { Form, Select, Spin } from "antd";
|
||||
import { Select, Spin } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
import { SearchFieldProps } from "../utils/types";
|
||||
import { useValidationValidationParamState } from "../state/ValidationValidationParamState";
|
||||
import { useDebounce } from "../../../Hooks/useDebounce";
|
||||
|
||||
const SearchField = ({
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
isDisabled,
|
||||
searchBy,
|
||||
option,
|
||||
searchBy = "search",
|
||||
option = [],
|
||||
isMulti,
|
||||
onChange,
|
||||
className,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
isLoading,
|
||||
}: any) => {
|
||||
canChangePage,
|
||||
PageName,
|
||||
page,
|
||||
...props
|
||||
}: SearchFieldProps) => {
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||
const navigate = useNavigate();
|
||||
useEffect(() => {
|
||||
const searchParams = new URLSearchParams(window?.location?.search);
|
||||
setSearchQuery(searchParams?.get("search") || "");
|
||||
}, []);
|
||||
const { pushValidationParamState, setValidationParamState } =
|
||||
useValidationValidationParamState();
|
||||
|
||||
const SelectableChange = (value: {
|
||||
value: string;
|
||||
label: React.ReactNode;
|
||||
}) => {
|
||||
const [AllPagesOption, setAllPagesOption] = useState<any>([]);
|
||||
|
||||
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);
|
||||
}
|
||||
}, [option]);
|
||||
useEffect(() => {
|
||||
if (page === 1) {
|
||||
setAllPagesOption(option);
|
||||
}
|
||||
}, [page]);
|
||||
|
||||
const SelectableChange = (value: any) => {
|
||||
formik?.setFieldValue(name, value);
|
||||
};
|
||||
const SearchHandleChange = (value: any) => {
|
||||
navigate(`${window?.location?.pathname}?${searchBy}=${value}`, {
|
||||
replace: true,
|
||||
const isCleared = value?.length === 0 || !value;
|
||||
|
||||
if (isCleared) {
|
||||
if (PageName) {
|
||||
setValidationParamState({
|
||||
[PageName]: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(value, "value");
|
||||
};
|
||||
|
||||
const handleChange = useDebounce((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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
console.log(AllPagesOption);
|
||||
console.log(option,"option");
|
||||
|
||||
|
||||
return (
|
||||
<div className="ValidationField w-100 ">
|
||||
{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>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<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 ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
disabled={isDisabled}
|
||||
options={option}
|
||||
options={AllPagesOption}
|
||||
size="large"
|
||||
className={`${className} w-100`}
|
||||
value={formik.values[name]}
|
||||
loading={isLoading}
|
||||
// loading={isLoading}
|
||||
allowClear
|
||||
{...(isMulti && { mode: "multiple" })}
|
||||
onChange={onChange || SelectableChange}
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
notFoundContent={isLoading ? <Spin /> : "لا يوجد"}
|
||||
onSearch={SearchHandleChange}
|
||||
optionFilterProp="name"
|
||||
notFoundContent={isLoading ? <Spin /> : t("validation.undefined")}
|
||||
onSearch={handleChange}
|
||||
onBlur={handleBlur}
|
||||
id={name}
|
||||
onPopupScroll={handleScroll}
|
||||
fieldNames={{ label: "name", value: "id" }}
|
||||
{...props}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { Form, Select, Spin } from "antd";
|
||||
import { Select } from "antd";
|
||||
import React from "react";
|
||||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { translateOptions } from "../utils/translatedOptions";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||
import { SelectFieldProps } from "../utils/types";
|
||||
|
||||
const SelectField = ({
|
||||
name,
|
||||
|
|
@ -13,10 +15,11 @@ const SelectField = ({
|
|||
isMulti,
|
||||
onChange,
|
||||
className,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
}: any) => {
|
||||
isLoading,
|
||||
...props
|
||||
}: SelectFieldProps) => {
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||
const SelectableChange = (value: {
|
||||
value: string;
|
||||
|
|
@ -24,47 +27,35 @@ const SelectField = ({
|
|||
}) => {
|
||||
formik.setFieldValue(name, value);
|
||||
};
|
||||
// console.log(name,"Select");
|
||||
|
||||
const options = translateOptions(option, t);
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{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>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<Select
|
||||
placeholder={t(
|
||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
disabled={isDisabled}
|
||||
options={translateOptions(option, t)}
|
||||
loading={option?.length < 1}
|
||||
options={options}
|
||||
{...(isLoading && { loading: isLoading })}
|
||||
size="large"
|
||||
className={`${className} ${isError ? "Select_error" : ""} w-100`}
|
||||
className={`${className} ${isError ? "SelectError" : ""} w-100`}
|
||||
value={formik.values[name]}
|
||||
allowClear
|
||||
{...(isMulti && { mode: "multiple" })}
|
||||
onChange={onChange || SelectableChange}
|
||||
showSearch={false}
|
||||
id={name}
|
||||
{...props}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Form, Input } from "antd";
|
||||
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 = ({
|
||||
|
|
@ -11,14 +12,12 @@ const TextAreaField = ({
|
|||
isDisabled,
|
||||
onChange,
|
||||
props,
|
||||
type,
|
||||
}: any) => {
|
||||
const { formik, isError, errorMsg, t } = useFormField(name, props);
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
// console.log('Change:', e.target.value);
|
||||
formik.setFieldValue(name, e.target.value);
|
||||
};
|
||||
|
||||
|
|
@ -27,11 +26,7 @@ const TextAreaField = ({
|
|||
<label htmlFor={name} className="text">
|
||||
{t(`input.${label ? label : name}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<Field
|
||||
as={TextArea}
|
||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||
|
|
@ -39,10 +34,10 @@ const TextAreaField = ({
|
|||
disabled={isDisabled}
|
||||
size="large"
|
||||
onChange={onChange || handleChange}
|
||||
|
||||
id={name}
|
||||
// onChange={onChange ? onChange : handleChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ 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 = ({
|
||||
|
|
@ -21,33 +23,20 @@ const TextField = ({
|
|||
const TextFilehandleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
// console.log('Change:', e.target.value);
|
||||
formik.setFieldValue(name, e.target.value);
|
||||
};
|
||||
return (
|
||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||
{no_label ? (
|
||||
<label htmlFor={name} className="text">
|
||||
<span>empty</span>
|
||||
</label>
|
||||
) : label_icon ? (
|
||||
<div className="LabelWithIcon">
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
||||
</label>
|
||||
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
|
||||
</div>
|
||||
) : (
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
||||
</label>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||
<Field
|
||||
as={TextArea}
|
||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||
|
|
@ -58,8 +47,9 @@ const TextField = ({
|
|||
maxLength={1000}
|
||||
onChange={onChange || TextFilehandleChange}
|
||||
style={{ height: 120 }}
|
||||
id={name}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React from "react";
|
|||
import useFormField from "../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import dayjs from "dayjs";
|
||||
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||
|
||||
const Time = ({
|
||||
name,
|
||||
|
|
@ -20,27 +21,19 @@ const Time = ({
|
|||
formik.setFieldValue(name, value);
|
||||
};
|
||||
|
||||
const Formater = "H:mm";
|
||||
const Formatter = "H:mm";
|
||||
const FormikValue = formik.values[name];
|
||||
|
||||
return (
|
||||
<div className="ValidationField w-100 ">
|
||||
{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>
|
||||
)}
|
||||
<ValidationFieldLabel
|
||||
name={name}
|
||||
label={label}
|
||||
label_icon={label_icon}
|
||||
no_label={no_label}
|
||||
placeholder={placeholder}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
|
|
@ -51,14 +44,13 @@ const Time = ({
|
|||
allowClear
|
||||
className={`${className} w-100`}
|
||||
size="large"
|
||||
value={FormikValue ? dayjs(FormikValue, Formater) : null}
|
||||
value={FormikValue ? dayjs(FormikValue, Formatter) : null}
|
||||
onChange={onChange || onCalendarChange}
|
||||
disabled={isDisabled}
|
||||
placeholder={t(
|
||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
||||
)}
|
||||
format={Formater}
|
||||
placeholder={t(`input.${placeholder || label || name}`)}
|
||||
format={Formatter}
|
||||
needConfirm={false}
|
||||
id={name}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
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>
|
||||
);
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
@ -2,7 +2,6 @@ import { useState } from "react";
|
|||
import { ErrorMessage, useField, Field, useFormikContext } from "formik";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaExclamationCircle } from "react-icons/fa";
|
||||
import { convert_data_to_select } from "../../Layout/app/Const";
|
||||
|
||||
export {
|
||||
useState,
|
||||
|
|
@ -12,5 +11,4 @@ export {
|
|||
useFormikContext,
|
||||
useTranslation,
|
||||
FaExclamationCircle,
|
||||
convert_data_to_select,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
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: {},
|
||||
}),
|
||||
}));
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.Select_error {
|
||||
.SelectError {
|
||||
.ant-select-selector {
|
||||
border: 1px solid red !important;
|
||||
}
|
||||
|
|
@ -60,12 +60,9 @@
|
|||
.ant-upload-select {
|
||||
width: 100%;
|
||||
}
|
||||
.Checkboxs {
|
||||
.Checkbox {
|
||||
padding: 4%;
|
||||
}
|
||||
.ant-checkbox-wrapper {
|
||||
min-width: 100px;
|
||||
}
|
||||
.SearchField {
|
||||
button {
|
||||
background: var(--primary);
|
||||
|
|
@ -201,27 +198,3 @@ input:-webkit-autofill:hover {
|
|||
.TwoSelectGroupbutton {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ant-checkbox-wrapper {
|
||||
margin-top: 25px !important;
|
||||
}
|
||||
|
||||
.add_new_button {
|
||||
margin-bottom: 20px;
|
||||
svg {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
.ValidationField:has(.input_number) {
|
||||
max-width: 100px;
|
||||
|
||||
.input_number {
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
max-width: 80% !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
export function getNestedValue(obj: any, path: any) {
|
||||
return path
|
||||
.replace(/\?.\[|\]\[|\]\.?/g, ".") // Replace question mark and square brackets
|
||||
.split(".") // Split by dots
|
||||
.filter(Boolean) // Remove empty strings
|
||||
.reduce((acc: any, key: any) => acc && acc[key], obj); // Access nested properties
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
export const translateOptions = (options: any, t: any) => {
|
||||
return options.map((opt: any) => ({
|
||||
return options?.map((opt: any) => ({
|
||||
...opt,
|
||||
label: t(`${opt.label}`),
|
||||
label: t(`${opt?.label}`),
|
||||
name: t(`${opt?.name}`),
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,148 +1,60 @@
|
|||
import { InputProps } from "antd";
|
||||
import { InputProps, SelectProps } from "antd";
|
||||
|
||||
export type ValidationFieldType =
|
||||
| "text"
|
||||
| "Select"
|
||||
| "LocalSearch"
|
||||
| "Search"
|
||||
| "DataRange"
|
||||
| "Date"
|
||||
| "Time"
|
||||
| "File"
|
||||
| "MaltyFile"
|
||||
| "DropFile"
|
||||
| "Checkbox"
|
||||
| "number"
|
||||
| "password"
|
||||
| "email"
|
||||
| "TextArea";
|
||||
|
||||
export interface ValidationFieldPropsText {
|
||||
// Common properties for all field types
|
||||
interface BaseFieldProps {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "text";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
}
|
||||
|
||||
export interface ValidationFieldPropsSelect {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "Select";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: any;
|
||||
dir?: "ltr" | "rtl";
|
||||
// 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 interface ValidationFieldPropsLocalSearch {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "LocalSearch";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
option: any[];
|
||||
isMulti?: boolean;
|
||||
}
|
||||
export interface ValidationFieldPropsSearch {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
export type SearchFieldProps = BaseFieldProps &
|
||||
SelectProps & {
|
||||
type: "Search";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
option: any[];
|
||||
isMulti?: boolean;
|
||||
isLoading: boolean;
|
||||
searchBy: string;
|
||||
isLoading?: any;
|
||||
}
|
||||
export interface ValidationFieldPropsDataRange {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "DataRange";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
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";
|
||||
}
|
||||
export interface ValidationFieldPropsDate {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "Date";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
picker?: "data" | "week" | "month" | "quarter" | "year";
|
||||
}
|
||||
};
|
||||
|
||||
export interface ValidationFieldPropsTime {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type: "Time";
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
}
|
||||
|
||||
export interface ValidationFieldPropsFile {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
type FileFieldProps = BaseFieldProps & {
|
||||
type: "File" | "MaltyFile" | "DropFile";
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
}
|
||||
export interface ValidationFieldPropsCheckbox {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
};
|
||||
|
||||
type CheckboxFieldProps = BaseFieldProps & {
|
||||
type: "Checkbox";
|
||||
label?: string;
|
||||
className?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
Group?: boolean;
|
||||
}
|
||||
export interface ValidationFieldPropstext {
|
||||
name: string;
|
||||
no_label?: boolean;
|
||||
label_icon?: boolean;
|
||||
};
|
||||
|
||||
export type FieldProps = BaseFieldProps &
|
||||
InputProps & {
|
||||
type?:
|
||||
| "text"
|
||||
| "number"
|
||||
|
|
@ -150,45 +62,19 @@ export interface ValidationFieldPropstext {
|
|||
| "email"
|
||||
| "TextArea"
|
||||
| "NumberFormate";
|
||||
label?: string;
|
||||
label2?: string;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
isDisabled?: boolean;
|
||||
onChange?: (value: any) => void;
|
||||
dir?: "ltr" | "rtl";
|
||||
Group?: boolean;
|
||||
[key: string]: any; // Index signature to allow any additional props
|
||||
}
|
||||
|
||||
///// new
|
||||
export interface BaseField {
|
||||
name: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
export type OmitBaseType = "placeholder" | "name" | "label" | "type";
|
||||
|
||||
export type OmitPicker = OmitBaseType | "format";
|
||||
|
||||
export interface ValidationFieldPropsInput
|
||||
extends Omit<InputProps, OmitBaseType>,
|
||||
BaseField {
|
||||
type: "text" | "number" | "password" | "email" | "Number";
|
||||
isDisabled?: boolean;
|
||||
no_label?: string;
|
||||
label_icon?: string;
|
||||
label2?: string;
|
||||
}
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
// Union type for all field types
|
||||
export type ValidationFieldProps =
|
||||
| ValidationFieldPropsInput
|
||||
| ValidationFieldPropsSelect
|
||||
| ValidationFieldPropsLocalSearch
|
||||
| ValidationFieldPropsDataRange
|
||||
| ValidationFieldPropsDate
|
||||
| ValidationFieldPropsTime
|
||||
| ValidationFieldPropsFile
|
||||
| ValidationFieldPropsCheckbox
|
||||
| ValidationFieldPropstext
|
||||
| ValidationFieldPropsSearch;
|
||||
| SelectFieldProps
|
||||
| DateFieldProps
|
||||
| FileFieldProps
|
||||
| CheckboxFieldProps
|
||||
| SearchFieldProps
|
||||
| FieldProps;
|
||||
|
||||
// Validation field type
|
||||
export type ValidationFieldType = ValidationFieldProps["type"];
|
||||
|
|
|
|||
25
src/Hooks/useDebounce.ts
Normal file
25
src/Hooks/useDebounce.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { useCallback, useRef } from "react";
|
||||
|
||||
export const DEBOUNCE_DELAY = 500;
|
||||
|
||||
export const useDebounce = (
|
||||
callback: (...args: any[]) => void,
|
||||
delay: number = DEBOUNCE_DELAY,
|
||||
) => {
|
||||
const timeoutRef = useRef<any>(null);
|
||||
|
||||
const debouncedCallback = useCallback(
|
||||
(...args: any[]) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
callback(...args);
|
||||
}, delay);
|
||||
},
|
||||
[callback, delay],
|
||||
);
|
||||
|
||||
return debouncedCallback;
|
||||
};
|
||||
9
src/Pages/Package/Field/ConfigurationField.tsx
Normal file
9
src/Pages/Package/Field/ConfigurationField.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
|
||||
const ConfigurationField = () => {
|
||||
return (
|
||||
<div>ConfigurationField</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConfigurationField
|
||||
96
src/Pages/Package/Field/FieldGroup.tsx
Normal file
96
src/Pages/Package/Field/FieldGroup.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import React from "react";
|
||||
import { Input, Button } from "antd";
|
||||
import { useFormikContext } from "formik";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface FieldGroupProps {
|
||||
array_name: string;
|
||||
title:string;
|
||||
static?: boolean;
|
||||
only_value?: boolean;
|
||||
}
|
||||
|
||||
const FieldGroup: React.FC<FieldGroupProps> = ({ array_name ,title,static:isStatic,only_value}) => {
|
||||
const { values, setFieldValue } = useFormikContext<any>();
|
||||
const addFieldGroup = () => {
|
||||
setFieldValue(array_name, [
|
||||
...(values?.[array_name] || []),
|
||||
{ key: null, value: null },
|
||||
]);
|
||||
};
|
||||
const deleteFieldGroup = () => {
|
||||
const updatedArray = values?.[array_name]?.slice(0, -1) || [];
|
||||
setFieldValue(array_name, updatedArray);
|
||||
};
|
||||
|
||||
|
||||
const handleChangeKey = (
|
||||
e: React.ChangeEvent<HTMLInputElement>,
|
||||
index: number
|
||||
) => {
|
||||
const Selects = values?.[array_name] ?? [];
|
||||
Selects[index].key = e.target.value;
|
||||
setFieldValue(array_name, Selects);
|
||||
};
|
||||
|
||||
const handleChangeValue = (
|
||||
e: React.ChangeEvent<HTMLInputElement>,
|
||||
index: number
|
||||
) => {
|
||||
const Selects = values?.[array_name] ?? [];
|
||||
Selects[index].value = e.target.value;
|
||||
setFieldValue(array_name, Selects);
|
||||
};
|
||||
|
||||
const selectsArray = values?.[array_name] ?? [];
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<label htmlFor={array_name} className="text">
|
||||
<h5 className="mb-2">{t(`header.${title}`)}</h5>
|
||||
</label>
|
||||
{selectsArray.map((group: { key: string; value: string }, index: number) => (
|
||||
<div key={index} className="d-flex gap-2 mb-3">
|
||||
<Input
|
||||
placeholder={t("practical.key")}
|
||||
onChange={(e) => handleChangeKey(e, index)}
|
||||
value={group.key}
|
||||
size="large"
|
||||
style={{ width: "100%" }}
|
||||
allowClear
|
||||
disabled={only_value}
|
||||
/>
|
||||
<Input
|
||||
placeholder={t("practical.value")}
|
||||
onChange={(e) => handleChangeValue(e, index)}
|
||||
value={group.value}
|
||||
size="large"
|
||||
style={{ width: "100%" }}
|
||||
allowClear
|
||||
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{!isStatic &&
|
||||
<div className="d-flex gap-2 mb-4">
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={addFieldGroup}
|
||||
>
|
||||
{t("practical.add_new")}
|
||||
</Button>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={deleteFieldGroup}
|
||||
>
|
||||
{t("practical.delete_last")}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FieldGroup;
|
||||
|
|
@ -6,40 +6,48 @@ import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
|||
import ModelForm from "./ModelForm";
|
||||
import { useAddPackage } from "../../../api/package";
|
||||
import FormikForm from "../../../Layout/Dashboard/FormikForm";
|
||||
import { Spin } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
|
||||
import { PackageInitialValues } from "../../../types/Package";
|
||||
import { arrayToObject } from "../../../utils/arrayToObject";
|
||||
|
||||
const AddModel: React.FC = () => {
|
||||
const { mutate, status } = useAddPackage();
|
||||
const { mutate, status ,isLoading} = useAddPackage();
|
||||
const [t] = useTranslation();
|
||||
const navigate = useNavigate()
|
||||
const handleSubmit = (values: PackageInitialValues) => {
|
||||
const DataToSend = JSON.parse(JSON.stringify(values) );
|
||||
console.log(DataToSend,"DataToSend");
|
||||
console.log(values?.configuration);
|
||||
|
||||
const configuration = JSON.stringify(arrayToObject(values?.configuration )) ;
|
||||
console.log(configuration);
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
mutate({
|
||||
...values,
|
||||
});
|
||||
};
|
||||
|
||||
useSetPageTitle(t(`page_header.package`));
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <LayoutModel
|
||||
status={status as QueryStatusEnum}
|
||||
ModelEnum={ModalEnum.Package_ADD}
|
||||
modelTitle="package"
|
||||
handleSubmit={handleSubmit}
|
||||
getInitialValues={getInitialValues({})}
|
||||
getValidationSchema={getValidationSchema}
|
||||
>
|
||||
<ModelForm />
|
||||
moaz
|
||||
</LayoutModel> */}
|
||||
casascaas
|
||||
<div className="page">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues('')}
|
||||
initialValues={getInitialValues({})}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<header>
|
||||
{t("header.add_new_package")}
|
||||
</header>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
<ModelForm />
|
||||
|
||||
<div className="exercise_add_buttons">
|
||||
{/* <div onClick={handleCancel}>{t("practical.back")}</div> */}
|
||||
{/* <button disabled={isLoading} className="relative" type="submit">
|
||||
<button disabled={isLoading} className="relative button center" type="submit">
|
||||
{t("practical.add")}
|
||||
|
||||
{isLoading && (
|
||||
|
|
@ -47,11 +55,11 @@ const AddModel: React.FC = () => {
|
|||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button> */}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,72 @@
|
|||
import React from "react";
|
||||
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||
import { ModalEnum } from "../../../enums/Model";
|
||||
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||
import ModelForm from "./ModelForm";
|
||||
import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||
import FormikForm from "../../../Layout/Dashboard/FormikForm";
|
||||
import { Spin } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
|
||||
import { PackageInitialValues } from "../../../types/Package";
|
||||
import { arrayToObject } from "../../../utils/arrayToObject";
|
||||
import { useGetAllPackage, useUpdatePackage } from "../../../api/package";
|
||||
import { ParamsEnum } from "../../../enums/params";
|
||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
import { useUpdatePackage } from "../../../api/package";
|
||||
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
||||
|
||||
const EditModel: React.FC = () => {
|
||||
const { mutate, status } = useUpdatePackage();
|
||||
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||
const { mutate, status ,isLoading} = useUpdatePackage();
|
||||
const [t] = useTranslation();
|
||||
const {package_id} = useParams<ParamsEnum>();
|
||||
const {objectToEdit} = useObjectToEdit();
|
||||
|
||||
const {data,isLoading:isLoadingData} = useGetAllPackage({show:package_id})
|
||||
console.log(data?.data,"data");
|
||||
|
||||
const handleSubmit = (values: PackageInitialValues) => {
|
||||
const DataToSend = JSON.parse(JSON.stringify(values) );
|
||||
console.log(DataToSend,"DataToSend");
|
||||
console.log(values?.configuration);
|
||||
|
||||
const configuration = JSON.stringify(arrayToObject(values?.configuration )) ;
|
||||
console.log(configuration);
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
mutate({
|
||||
...values,
|
||||
});
|
||||
};
|
||||
|
||||
useSetPageTitle(t(`page_header.package`));
|
||||
if(isLoadingData){
|
||||
return <SpinContainer/>
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<LayoutModel
|
||||
status={status as QueryStatusEnum}
|
||||
ModelEnum={ModalEnum.Package_EDIT}
|
||||
modelTitle="package_details"
|
||||
<div className="page">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
getInitialValues={getInitialValues(objectToEdit)}
|
||||
getValidationSchema={getValidationSchema}
|
||||
isAddModal={false}
|
||||
initialValues={getInitialValues(data?.data)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<header>
|
||||
{t("header.edit_package")}
|
||||
</header>
|
||||
|
||||
<main className="w-100 exercise_Edit_main">
|
||||
<ModelForm />
|
||||
</LayoutModel>
|
||||
</>
|
||||
<div className="exercise_Edit_buttons">
|
||||
<button disabled={isLoading} className="relative button center" type="submit">
|
||||
{t("practical.edit")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,236 @@
|
|||
import { Col, Row } from "reactstrap";
|
||||
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
||||
import { useGetAllGrade } from "../../../api/grade";
|
||||
import { useGetAllSubject } from "../../../api/subject";
|
||||
import { useGetAllUnit } from "../../../api/unit";
|
||||
import { useGetAllCurriculum } from "../../../api/curriculum";
|
||||
import { useGetAllLesson } from "../../../api/lesson";
|
||||
import { useFormikContext } from "formik";
|
||||
import { PackageInitialValues } from "../../../types/Package";
|
||||
import { useValidationValidationParamState } from "../../../Components/ValidationField/state/ValidationValidationParamState";
|
||||
import { useEffect } from "react";
|
||||
import ConfigurationField from "../Field/ConfigurationField";
|
||||
import FieldGroup from "../Field/FieldGroup";
|
||||
|
||||
const Form = () => {
|
||||
const { values, setFieldValue } = useFormikContext<PackageInitialValues>();
|
||||
|
||||
const { ValidationParamState } = useValidationValidationParamState();
|
||||
const {
|
||||
GradeName, GradeCurrentPage,
|
||||
SubjectName, SubjectCurrentPage,
|
||||
UnitName, UnitCurrentPage,
|
||||
CurriculumName, CurriculumCurrentPage,
|
||||
LessonName, LessonCurrentPage
|
||||
|
||||
|
||||
} = ValidationParamState;
|
||||
|
||||
const { curriculums_ids, grade_id, subjects_ids, units_ids, lessons_ids } = values;
|
||||
|
||||
|
||||
|
||||
|
||||
/// grade_id
|
||||
const GradeDisabled = !!grade_id;
|
||||
const { data: Grade, isLoading: isLoadingGrade } = useGetAllGrade({
|
||||
name: GradeName,
|
||||
page: GradeCurrentPage
|
||||
});
|
||||
const GradeOption = Grade?.data ?? []
|
||||
const canChangeGradePage = !!Grade?.links?.next;
|
||||
const GradePage = Grade?.meta?.currentPage;
|
||||
|
||||
|
||||
/// subjects_ids
|
||||
const SubjectDisabled = !!subjects_ids && subjects_ids?.length > 0;
|
||||
const { data: Subject, isLoading: isLoadingSubject } = useGetAllSubject({
|
||||
grade_id: grade_id,
|
||||
name: SubjectName,
|
||||
page: SubjectCurrentPage
|
||||
}, { enabled: GradeDisabled });
|
||||
const SubjectOption = Subject?.data ?? []
|
||||
const canChangeSubjectPage = !!Subject?.links?.next;
|
||||
const SubjectPage = Subject?.meta?.currentPage;
|
||||
|
||||
/// units_ids
|
||||
const UnitDisabled = !!units_ids && units_ids?.length > 0;
|
||||
const { data: Unit, isLoading: isLoadingUnit } = useGetAllUnit({
|
||||
subjects_ids: subjects_ids,
|
||||
name: UnitName,
|
||||
page: UnitCurrentPage
|
||||
}, { enabled: SubjectDisabled });
|
||||
const UnitOption = Unit?.data ?? []
|
||||
const canChangeUnitPage = !!Unit?.links?.next;
|
||||
const UnitPage = Unit?.meta?.currentPage;
|
||||
|
||||
/// curriculums_ids
|
||||
const CurriculumDisabled = !!curriculums_ids && curriculums_ids?.length > 0;
|
||||
const { data: Curriculum, isLoading: isLoadingCurriculum } = useGetAllCurriculum({
|
||||
units_ids: units_ids,
|
||||
name: CurriculumName,
|
||||
page: CurriculumCurrentPage
|
||||
}, { enabled: UnitDisabled });
|
||||
const CurriculumOption = Curriculum?.data ?? []
|
||||
const canChangeCurriculumPage = !!Curriculum?.links?.next;
|
||||
const CurriculumPage = Curriculum?.meta?.currentPage;
|
||||
|
||||
/// lessons_ids
|
||||
const { data: Lesson, isLoading: isLoadingLesson } = useGetAllLesson({
|
||||
curriculums_ids: curriculums_ids,
|
||||
name: LessonName,
|
||||
page: LessonCurrentPage
|
||||
}, { enabled: CurriculumDisabled });
|
||||
const LessonOption = Lesson?.data ?? []
|
||||
const canChangeLessonPage = !!Lesson?.links?.next;
|
||||
const LessonPage = Lesson?.meta?.currentPage;
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const GradeChildren = (subjects_ids && subjects_ids?.length > 0 || units_ids && units_ids?.length > 0 || curriculums_ids && curriculums_ids?.length > 0 || lessons_ids && lessons_ids?.length > 0);
|
||||
|
||||
if (!grade_id && GradeChildren) {
|
||||
setFieldValue("subjects_ids", []);
|
||||
setFieldValue("units_ids", []);
|
||||
setFieldValue("curriculums_ids", []);
|
||||
setFieldValue("lessons_ids", []);
|
||||
return;
|
||||
}
|
||||
console.log(1);
|
||||
|
||||
const SubjectChildren = (units_ids && units_ids?.length > 0 || curriculums_ids && curriculums_ids?.length > 0 || lessons_ids && lessons_ids?.length > 0)
|
||||
console.log( subjects_ids && subjects_ids?.length < 1 && SubjectChildren);
|
||||
|
||||
if (subjects_ids && subjects_ids?.length < 1 && SubjectChildren) {
|
||||
console.log(1);
|
||||
|
||||
setFieldValue("units_ids", []);
|
||||
setFieldValue("curriculums_ids", []);
|
||||
setFieldValue("lessons_ids", []);
|
||||
return;
|
||||
}
|
||||
const UnitChildren = (curriculums_ids && curriculums_ids?.length > 0 || lessons_ids && lessons_ids?.length > 0)
|
||||
if (units_ids && units_ids?.length < 1 && UnitChildren) {
|
||||
setFieldValue("curriculums_ids", []);
|
||||
setFieldValue("lessons_ids", []);
|
||||
return;
|
||||
}
|
||||
const CurriculumChildren = (lessons_ids && lessons_ids?.length > 0)
|
||||
if (curriculums_ids && curriculums_ids?.length < 1 && CurriculumChildren) {
|
||||
setFieldValue("lessons_ids", []);
|
||||
return;
|
||||
}
|
||||
}, [grade_id, subjects_ids, units_ids, curriculums_ids])
|
||||
|
||||
|
||||
return (
|
||||
<Row className="w-100">
|
||||
<Col>
|
||||
<ValidationField placeholder="name" label="name" name="name" />
|
||||
<ValidationField placeholder="price" label="price" name="price" />
|
||||
<ValidationField placeholder="name" label="name" name="name" />
|
||||
<ValidationField placeholder="price" label="price" name="price" type="number" />
|
||||
<FieldGroup array_name='configuration' title='configuration' />
|
||||
</Col>
|
||||
<Col>
|
||||
|
||||
{/*
|
||||
grade_id
|
||||
*/}
|
||||
<ValidationField
|
||||
searchBy="GradeName"
|
||||
name="grade_id"
|
||||
label="grade"
|
||||
type="Search"
|
||||
option={GradeOption}
|
||||
isLoading={isLoadingGrade}
|
||||
canChangePage={canChangeGradePage}
|
||||
PageName={"GradeCurrentPage"}
|
||||
page={GradePage}
|
||||
|
||||
/>
|
||||
|
||||
{/*
|
||||
subjects_ids
|
||||
*/}
|
||||
|
||||
<ValidationField
|
||||
searchBy="SubjectName"
|
||||
name="subjects_ids"
|
||||
label="subject"
|
||||
type="Search"
|
||||
option={SubjectOption}
|
||||
isMulti
|
||||
isLoading={isLoadingSubject}
|
||||
canChangePage={canChangeSubjectPage}
|
||||
PageName={"SubjectCurrentPage"}
|
||||
page={SubjectPage}
|
||||
disabled={!GradeDisabled}
|
||||
|
||||
/>
|
||||
|
||||
|
||||
{/*
|
||||
units_ids
|
||||
*/}
|
||||
|
||||
<ValidationField
|
||||
searchBy="UnitName"
|
||||
name="units_ids"
|
||||
label="unit"
|
||||
type="Search"
|
||||
option={UnitOption}
|
||||
isMulti
|
||||
isLoading={isLoadingUnit}
|
||||
canChangePage={canChangeUnitPage}
|
||||
PageName={"UnitCurrentPage"}
|
||||
page={UnitPage}
|
||||
disabled={!SubjectDisabled}
|
||||
|
||||
/>
|
||||
|
||||
|
||||
{/*
|
||||
curriculums_ids
|
||||
*/}
|
||||
|
||||
<ValidationField
|
||||
searchBy="CurriculumName"
|
||||
name="curriculums_ids"
|
||||
label="curriculum"
|
||||
type="Search"
|
||||
option={CurriculumOption}
|
||||
isMulti
|
||||
isLoading={isLoadingCurriculum}
|
||||
canChangePage={canChangeCurriculumPage}
|
||||
PageName={"CurriculumCurrentPage"}
|
||||
page={CurriculumPage}
|
||||
disabled={!UnitDisabled}
|
||||
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{/*
|
||||
lessons_ids
|
||||
*/}
|
||||
|
||||
<ValidationField
|
||||
searchBy="LessonName"
|
||||
name="lessons_ids"
|
||||
label="lesson"
|
||||
type="Search"
|
||||
option={LessonOption}
|
||||
isMulti
|
||||
isLoading={isLoadingLesson}
|
||||
canChangePage={canChangeLessonPage}
|
||||
PageName={"LessonCurrentPage"}
|
||||
page={LessonPage}
|
||||
disabled={!CurriculumDisabled}
|
||||
|
||||
/>
|
||||
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,32 @@
|
|||
import * as Yup from "yup";
|
||||
export const getInitialValues = (objectToEdit: any): any => {
|
||||
import { Package, PackageInitialValues } from "../../../types/Package";
|
||||
import { arrayToObject } from "../../../utils/arrayToObject";
|
||||
import { objectToArray } from "../../../utils/objectToArray";
|
||||
export const getInitialValues = (objectToEdit: Partial<Package>): PackageInitialValues => {
|
||||
console.log(objectToEdit,"objectToEdit");
|
||||
|
||||
const configuration = Array.isArray(objectToEdit?.configuration) ? objectToEdit?.configuration : objectToArray(objectToEdit?.configuration)
|
||||
return {
|
||||
id: objectToEdit?.id ?? null,
|
||||
name: objectToEdit?.name ?? null,
|
||||
price: objectToEdit?.price ?? null,
|
||||
grade_id: objectToEdit?.grade_id ?? null,
|
||||
|
||||
curriculums_ids: objectToEdit?.curriculums_ids ?? [],
|
||||
lessons_ids: objectToEdit?.lessons_ids ?? [],
|
||||
subjects_ids: objectToEdit?.subjects_ids ?? [],
|
||||
units_ids: objectToEdit?.units_ids ?? [],
|
||||
configuration: configuration ?? [{key:"",value:""}],
|
||||
};
|
||||
};
|
||||
|
||||
export const getValidationSchema = () => {
|
||||
return Yup.object().shape({
|
||||
name: Yup.string().required("validation.required"),
|
||||
price: Yup.number().required("validation.required").typeError("validation.Must_be_a_number"),
|
||||
grade_id: Yup.string().required("validation.required"),
|
||||
curriculums_ids: Yup.array().of(Yup.number().required()).min(1,"validation.must_have_on_item").required("validation.required"),
|
||||
lessons_ids: Yup.array().of(Yup.number().required()).min(1,"validation.must_have_on_item").required("validation.required"),
|
||||
subjects_ids: Yup.array().of(Yup.number().required()).min(1,"validation.must_have_on_item").required("validation.required"),
|
||||
units_ids: Yup.array().of(Yup.number().required()).min(1,"validation.must_have_on_item").required("validation.required"),
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ const TableHeader = () => {
|
|||
deleteMutation={deleteMutation}
|
||||
ModelEnum={ModalEnum?.Package_DELETE}
|
||||
/>
|
||||
{/* <AddModalForm /> */}
|
||||
<EditModalForm />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ import { useModalState } from "../../zustand/Modal";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { canDeletePackage,canEditPackage } from "../../utils/hasAbilityFn";
|
||||
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export const useColumns = () => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const { setIsOpen } = useModalState((state) => state);
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||
const handelDelete = (record: any) => {
|
||||
setObjectToEdit(record);
|
||||
|
|
@ -19,6 +20,8 @@ export const useColumns = () => {
|
|||
const handleEdit = (record: any) => {
|
||||
setObjectToEdit(record);
|
||||
setIsOpen(ModalEnum?.Package_EDIT);
|
||||
navigate(`${record?.id}`)
|
||||
|
||||
};
|
||||
|
||||
const columns: TableColumnsType<any> = [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TCrudRoute, TMenuItem } from "./types/App";
|
||||
import { FaHome, FaMoneyBill } from "react-icons/fa";
|
||||
import { FaHome, FaKey, FaMoneyBill, FaUserGraduate } from "react-icons/fa";
|
||||
import { LuPackage } from "react-icons/lu";
|
||||
import React from "react";
|
||||
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
|
||||
|
|
@ -38,7 +38,7 @@ export const menuItems: TMenuItem[] = [
|
|||
{
|
||||
header: "page_header.grade",
|
||||
element: <Grade />,
|
||||
icon: <FaMoneyBill />,
|
||||
icon: <FaUserGraduate />,
|
||||
text: "sidebar.grade",
|
||||
path: `/${ABILITIES_ENUM?.GRADE}`,
|
||||
abilities: ABILITIES_ENUM?.GRADE,
|
||||
|
|
@ -68,7 +68,7 @@ export const menuItems: TMenuItem[] = [
|
|||
{
|
||||
header: "page_header.tags",
|
||||
element: <Tags />,
|
||||
icon: <FaMoneyBill />,
|
||||
icon: <FaKey />,
|
||||
text: "sidebar.tags",
|
||||
path: `/${ABILITIES_ENUM?.TAG}`,
|
||||
abilities: ABILITIES_ENUM?.TAG,
|
||||
|
|
@ -143,15 +143,15 @@ export const CrudRoute: TCrudRoute[] = [
|
|||
path: `/${ABILITIES_ENUM?.Package}/add`,
|
||||
abilities: ABILITIES_ENUM?.Package,
|
||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
prevPath: 0,
|
||||
prevPath: 1,
|
||||
},
|
||||
{
|
||||
header: "page_header.edit_package",
|
||||
element: <EditPackagePage />,
|
||||
path: `/${ABILITIES_ENUM?.Package}/add`,
|
||||
path: `/${ABILITIES_ENUM?.Package}/:${ParamsEnum?.PACKAGE_ID}`,
|
||||
abilities: ABILITIES_ENUM?.Package,
|
||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
prevPath: 0,
|
||||
prevPath: 1,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ export enum ParamsEnum {
|
|||
UNIT_ID = "unit_id",
|
||||
LESSON_ID = "lesson_id",
|
||||
QUESTION_ID = "question_id",
|
||||
PACKAGE_ID = "package_id",
|
||||
CHILDREN_QUESTION_ID = "children_question_id",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@
|
|||
"Due_date_must_be_before_assigning_date": "يجب أن يكون تاريخ الاستحقاق بعد تاريخ التعيين",
|
||||
"grade_to_pass_must_be_less_than_max_grade": "يجب أن تكون درجة النجاح أقل من الحد الأقصى للدرجة",
|
||||
"max_mark_must_be_greater_than_min_mark_to_pass": "يجب ان تكون اكبر من علامة النجاح",
|
||||
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل"
|
||||
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
||||
"must_have_on_item":"يجب ان يحتوي على عنصر واحد على الاقل"
|
||||
},
|
||||
"header": {
|
||||
"register_students": "تسجيل الطلاب",
|
||||
|
|
@ -107,7 +108,9 @@
|
|||
"malty_exercise": "تمرين متعدد",
|
||||
"add_new_question": "اضافة سؤال جديد",
|
||||
"exercise": "تمارين",
|
||||
"icon": "الايقونة"
|
||||
"icon": "الايقونة",
|
||||
"add_new_package":"اضافة حزمة جديدة",
|
||||
"configuration":"إعدادات"
|
||||
},
|
||||
"columns": {
|
||||
"id": "الرقم التعريفي",
|
||||
|
|
@ -199,7 +202,12 @@
|
|||
"Are you sure you want to go back and not save any changes?": "هل أنت متأكد أنك تريد العودة وعدم حفظ أي تغييرات؟",
|
||||
"accept_back": "قبول العودة ",
|
||||
"accept": "قبول ",
|
||||
"to_confirm_deletion_please_re_enter_id": "يرجى اعادة ادخال رقم التعريف"
|
||||
"to_confirm_deletion_please_re_enter_id": "يرجى اعادة ادخال رقم التعريف",
|
||||
"add_new":"اضافة عنصر",
|
||||
"delete_last":"حذف عنصر",
|
||||
"key":"الاسم",
|
||||
"value":"القيمة",
|
||||
"delete_this_item":"حذف هذا العنصر"
|
||||
},
|
||||
"Table": {
|
||||
"header": "",
|
||||
|
|
@ -365,7 +373,12 @@
|
|||
"question": "السؤال",
|
||||
"id": "الرقم التعريفي",
|
||||
"canAnswersBeShuffled": "يمكن خلط الإجابات",
|
||||
"hint": "تَلمِيح"
|
||||
"hint": "تَلمِيح",
|
||||
"grade":"الدرجات",
|
||||
"subject":"المادة",
|
||||
"curriculum":"مقرر",
|
||||
"lesson":"الدرس",
|
||||
"unit":"الوحدة"
|
||||
},
|
||||
|
||||
"select": {
|
||||
|
|
@ -725,6 +738,6 @@
|
|||
"edit_Question": "لوحة القيادة /تعديل اسئلة ",
|
||||
"grade": "لوحة القيادة /الدرجات ",
|
||||
"curriculum": "لوحة القيادة / تعديل مقرر ",
|
||||
"package":"حزمة"
|
||||
"package":"لوحة القيادة / الحزم "
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
src/types/Package.ts
Normal file
30
src/types/Package.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { Nullable } from "./App";
|
||||
|
||||
// Define the Teacher interface
|
||||
|
||||
export interface Package {
|
||||
id: number;
|
||||
name: string;
|
||||
price: string;
|
||||
grade_id: number;
|
||||
subjects_ids: any[];
|
||||
units_ids: any[];
|
||||
curriculums_ids: any[];
|
||||
lessons_ids: any[];
|
||||
configuration:{}
|
||||
|
||||
}
|
||||
|
||||
export interface InitialValues {
|
||||
id: number;
|
||||
name: string;
|
||||
price: string;
|
||||
grade_id: number;
|
||||
subjects_ids: any[];
|
||||
units_ids: any[];
|
||||
curriculums_ids: any[];
|
||||
lessons_ids: any[];
|
||||
configuration:{key:string,value:string}[]
|
||||
}
|
||||
|
||||
export type PackageInitialValues = Partial<Nullable<InitialValues>>;
|
||||
15
src/utils/arrayToObject.ts
Normal file
15
src/utils/arrayToObject.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
interface KeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
// Function to convert an array of key-value objects to an object
|
||||
export function arrayToObject(arr: KeyValue[] | null | undefined ): Record<string, string> {
|
||||
if(!arr){
|
||||
return {}
|
||||
}
|
||||
return arr.reduce((obj, item) => {
|
||||
obj[item.key] = item.value;
|
||||
return obj;
|
||||
}, {} as Record<string, string>);
|
||||
}
|
||||
14
src/utils/objectToArray.ts
Normal file
14
src/utils/objectToArray.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
interface KeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
export function objectToArray(obj: Record<string, string> | null | undefined): KeyValue[] {
|
||||
if(!obj){
|
||||
return [{key:"",value:""}]
|
||||
}
|
||||
return Object.entries(obj).map(([key, value]) => ({
|
||||
key,
|
||||
value
|
||||
}));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user