Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5f54f1794 | ||
|
|
ee5a3b7b14 | ||
|
|
8f993912fc | ||
|
|
7e8fa6431c | ||
|
|
5e0e0afd01 |
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -10,6 +10,7 @@
|
||||||
"Groupbutton",
|
"Groupbutton",
|
||||||
"handelnavigate",
|
"handelnavigate",
|
||||||
"Karim",
|
"Karim",
|
||||||
|
"latlng",
|
||||||
"queryqlent",
|
"queryqlent",
|
||||||
"registraion",
|
"registraion",
|
||||||
"SENDNOTIFICATION",
|
"SENDNOTIFICATION",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.11.5",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"path-to-regexp": "^6.2.2",
|
"path-to-regexp": "^6.2.2",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
"react-dragula": "^1.1.17",
|
"react-dragula": "^1.1.17",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
|
@ -66,6 +68,7 @@
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"@types/leaflet": "^1.9.12",
|
||||||
"@types/node": "^20.14.0",
|
"@types/node": "^20.14.0",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
|
|
||||||
8799
pnpm-lock.yaml
8799
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -5,11 +5,13 @@ import { Spin } from "antd";
|
||||||
import { hasAbility } from "./utils/hasAbility";
|
import { hasAbility } from "./utils/hasAbility";
|
||||||
import { renderRoutesRecursively } from "./Components/Routes/RenderRoutesRecursively";
|
import { renderRoutesRecursively } from "./Components/Routes/RenderRoutesRecursively";
|
||||||
import { RenderRouteElement } from "./Components/Routes/RenderRouteElement";
|
import { RenderRouteElement } from "./Components/Routes/RenderRouteElement";
|
||||||
|
import { UserTypeEnum } from "./enums/UserType";
|
||||||
|
import { RoleByType } from "./utils/RoleByType";
|
||||||
|
|
||||||
const Page404 = lazy(() => import("./Layout/Ui/NotFoundPage"));
|
const Page404 = lazy(() => import("./Layout/Ui/NotFoundPage"));
|
||||||
const Auth = lazy(() => import("./Pages/Auth/Page"));
|
const Auth = lazy(() => import("./Pages/Auth/Page"));
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
|
|
@ -31,10 +33,14 @@ const App = () => {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
{renderRoutesRecursively(menuItems)}
|
{renderRoutesRecursively(menuItems)}
|
||||||
|
|
||||||
{CrudRoute.map((route) => {
|
{CrudRoute.map((route) => {
|
||||||
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
||||||
|
if(!RoleByType(route)){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,17 @@ import { TMenuItem } from "../../types/App";
|
||||||
import { hasAbility } from "../../utils/hasAbility";
|
import { hasAbility } from "../../utils/hasAbility";
|
||||||
import { Route } from "react-router-dom";
|
import { Route } from "react-router-dom";
|
||||||
import { RenderRouteElement } from "./RenderRouteElement";
|
import { RenderRouteElement } from "./RenderRouteElement";
|
||||||
|
import { UserTypeEnum } from "../../enums/UserType";
|
||||||
|
import Item from "antd/es/list/Item";
|
||||||
|
import { RoleByType } from "../../utils/RoleByType";
|
||||||
|
|
||||||
export const renderRoutesRecursively = (routes: TMenuItem[]) =>
|
export const renderRoutesRecursively = (routes: TMenuItem[]) =>
|
||||||
routes.map((route: TMenuItem) => {
|
routes.map((route: TMenuItem) => {
|
||||||
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
||||||
|
if(!RoleByType(route)){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
File,
|
||||||
DataRange,
|
DataRange,
|
||||||
SelectField,
|
SelectField,
|
||||||
Default,
|
|
||||||
CheckboxField,
|
CheckboxField,
|
||||||
MaltyFile,
|
MaltyFile,
|
||||||
SearchField,
|
SearchField,
|
||||||
TextField,
|
TextField,
|
||||||
DropFile,
|
DropFile,
|
||||||
|
Default,
|
||||||
} from "./View";
|
} from "./View";
|
||||||
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
|
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
|
||||||
import LocalSearchField from "./View/LocalSearch";
|
import LocalSearchField from "./View/LocalSearch";
|
||||||
import NumberFormate from "./View/NumberFormate";
|
import NumberFormate from "./View/NumberFormate";
|
||||||
import NumberField from "./View/NumberField";
|
|
||||||
|
|
||||||
const components: { [key: string]: React.FC<any> } = {
|
const components: { [key: string]: React.FC<any> } = {
|
||||||
Select: SelectField,
|
Select: SelectField,
|
||||||
|
|
@ -31,12 +30,11 @@ const components: { [key: string]: React.FC<any> } = {
|
||||||
MaltyFile: MaltyFile,
|
MaltyFile: MaltyFile,
|
||||||
Checkbox: CheckboxField,
|
Checkbox: CheckboxField,
|
||||||
NumberFormate: NumberFormate,
|
NumberFormate: NumberFormate,
|
||||||
Number: NumberField,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ValidationField: React.FC<ValidationFieldProps> = React.memo(
|
const ValidationField: React.FC<ValidationFieldProps> = React.memo(
|
||||||
({ type, ...otherProps }: any) => {
|
({ type = "text", ...otherProps }) => {
|
||||||
const Component = components[type as ValidationFieldType];
|
const Component = components[type ?? ("text" as ValidationFieldType)];
|
||||||
|
|
||||||
if (!Component) {
|
if (!Component) {
|
||||||
return <Default {...otherProps} />;
|
return <Default {...otherProps} />;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { Checkbox, Form } from "antd";
|
import { Checkbox } from "antd";
|
||||||
import { getNestedValue } from "../utils/getNestedValue";
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
const CheckboxField = ({
|
const CheckboxField = ({
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
|
|
@ -13,25 +13,21 @@ const CheckboxField = ({
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { t, formik, isError, errorMsg } = useFormField(name, props);
|
const { t, formik, isError, errorMsg } = useFormField(name, props);
|
||||||
const CheckboxhandleChange = (value: any) => {
|
const CheckboxhandleChange = (value: any) => {
|
||||||
formik.setFieldValue(name, value?.target?.checked ? 1 : 0);
|
formik.setFieldValue(name, value?.target?.checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={Group ? "d-inline mt-3 Checkboxs" : ``}>
|
<div className={Group ? "d-inline mt-3 Checkbox" : ``}>
|
||||||
<Form.Item
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
onChange={onChange || CheckboxhandleChange}
|
onChange={onChange || CheckboxhandleChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
checked={formik.values?.[name] === 1}
|
checked={formik.values?.[name] ?? false}
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
{t(`input.${label ? label : name}`)}
|
{t(`input.${label ? label : name}`)}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import { Form, DatePicker } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
import { MdOutlineEdit } from "react-icons/md";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
|
|
@ -24,28 +26,16 @@ const DataRange = ({
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100 ">
|
<div className="ValidationField w-100 ">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{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
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<RangePicker
|
<RangePicker
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
size="large"
|
size="large"
|
||||||
|
|
@ -55,8 +45,9 @@ const DataRange = ({
|
||||||
onChange={onChange || onCalendarChange}
|
onChange={onChange || onCalendarChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
defaultValue={formik.values[name]}
|
defaultValue={formik.values[name]}
|
||||||
|
id={name}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
import { MdOutlineEdit } from "react-icons/md";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import { DateEnum } from "../../../enums/Date";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
|
||||||
const Date = ({
|
const Date = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -21,34 +24,21 @@ const Date = ({
|
||||||
const FormikValue = formik.values[name];
|
const FormikValue = formik.values[name];
|
||||||
const onCalendarChange = (value: any) => {
|
const onCalendarChange = (value: any) => {
|
||||||
formik.setFieldValue(name, value);
|
formik.setFieldValue(name, value);
|
||||||
// console.log(value,"value ");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Formater = "YYYY/MM/DD";
|
const Formatter = [DateEnum?.FORMATE];
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100 ">
|
<div className="ValidationField w-100 ">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{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
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
picker={picker}
|
picker={picker}
|
||||||
placeholder={t(`input.${placeholder}`)}
|
placeholder={t(`input.${placeholder}`)}
|
||||||
|
|
@ -58,10 +48,11 @@ const Date = ({
|
||||||
size="large"
|
size="large"
|
||||||
onChange={onChange || onCalendarChange}
|
onChange={onChange || onCalendarChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
format={Formater}
|
format={Formatter}
|
||||||
|
id={name}
|
||||||
/>
|
/>
|
||||||
{/* <DatePicker onChange={onChange} /> */}
|
{/* <DatePicker onChange={onChange} /> */}
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { Form, Input } from "antd";
|
import { Input } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { Field } from "formik";
|
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 = ({
|
const Default = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -14,52 +15,34 @@ const Default = ({
|
||||||
type,
|
type,
|
||||||
no_label,
|
no_label,
|
||||||
label_icon,
|
label_icon,
|
||||||
label2,
|
|
||||||
...props
|
...props
|
||||||
}: ValidationFieldPropsInput) => {
|
}: any) => {
|
||||||
const { errorMsg, isError, t } = useFormField(name, props);
|
const { errorMsg, isError, t } = useFormField(name, props);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100">
|
<div className="ValidationField w-100">
|
||||||
{label2 ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
{label2}
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : no_label ? (
|
no_label={no_label}
|
||||||
<label htmlFor={name} className="text">
|
placeholder={placeholder}
|
||||||
<span>empty</span>
|
t={t}
|
||||||
</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
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
<Field
|
||||||
as={Input}
|
as={Input}
|
||||||
type={type ?? "text"}
|
type={type ?? "text"}
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
|
||||||
)}
|
|
||||||
name={name}
|
name={name}
|
||||||
|
id={name}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
size="large"
|
size="large"
|
||||||
{...(type === "number" && { min: 0 })}
|
{...(type === "number" && { min: 0 })}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
|
||||||
import { message, Upload } from "antd";
|
import { message, Upload } from "antd";
|
||||||
import type { GetProp, UploadProps } from "antd";
|
import type { GetProp, UploadProps } from "antd";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { ImageBaseURL } from "../../../api/config";
|
|
||||||
|
|
||||||
type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];
|
type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];
|
||||||
|
|
||||||
|
|
@ -12,7 +11,7 @@ const DropFile = ({
|
||||||
label,
|
label,
|
||||||
onChange,
|
onChange,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
placholder,
|
placeholder,
|
||||||
className,
|
className,
|
||||||
props,
|
props,
|
||||||
no_label,
|
no_label,
|
||||||
|
|
@ -23,7 +22,7 @@ const DropFile = ({
|
||||||
|
|
||||||
const FormikValue =
|
const FormikValue =
|
||||||
typeof FormikName === "string"
|
typeof FormikName === "string"
|
||||||
? ImageBaseURL + FormikName
|
? FormikName
|
||||||
: FormikName instanceof File
|
: FormikName instanceof File
|
||||||
? URL.createObjectURL(FormikName)
|
? URL.createObjectURL(FormikName)
|
||||||
: "";
|
: "";
|
||||||
|
|
@ -71,6 +70,7 @@ const DropFile = ({
|
||||||
showUploadList={false}
|
showUploadList={false}
|
||||||
customRequest={customRequest}
|
customRequest={customRequest}
|
||||||
onChange={onChange || handleChange}
|
onChange={onChange || handleChange}
|
||||||
|
id={name}
|
||||||
>
|
>
|
||||||
{imageUrl ? (
|
{imageUrl ? (
|
||||||
<img
|
<img
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { Button, Upload, UploadFile } from "antd";
|
import { Button, Upload, UploadFile } from "antd";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { UploadOutlined } from "@ant-design/icons";
|
import { UploadOutlined } from "@ant-design/icons";
|
||||||
import { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
|
|
||||||
const File = ({
|
const File = ({
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
onChange,
|
onChange,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
placholder,
|
placeholder,
|
||||||
className,
|
className,
|
||||||
props,
|
props,
|
||||||
}: any) => {
|
}: any) => {
|
||||||
|
|
@ -16,29 +16,29 @@ const File = ({
|
||||||
let imageUrl = formik?.values?.[name] ?? null;
|
let imageUrl = formik?.values?.[name] ?? null;
|
||||||
|
|
||||||
const fileList: UploadFile[] = useMemo(() => {
|
const fileList: UploadFile[] = useMemo(() => {
|
||||||
if (!imageUrl) return [];
|
if (!imageUrl) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
typeof imageUrl === "string"
|
typeof imageUrl === "string"
|
||||||
? {
|
? {
|
||||||
uid: "-1",
|
uid: "-1",
|
||||||
name: "uploaded-image",
|
name: "",
|
||||||
status: "done",
|
status: "done",
|
||||||
url: imageUrl,
|
url: imageUrl,
|
||||||
thumbUrl: imageUrl,
|
thumbUrl: imageUrl,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
uid: imageUrl.uid || "-1",
|
uid: imageUrl.uid || "-1",
|
||||||
name: imageUrl.name || "uploaded-image",
|
name: imageUrl.name || "",
|
||||||
status: "done",
|
status: "done",
|
||||||
originFileObj: imageUrl,
|
originFileObj: imageUrl,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [imageUrl]);
|
}, [imageUrl]);
|
||||||
// console.log(1);
|
|
||||||
|
|
||||||
const FilehandleChange = (value: any) => {
|
const FilehandleChange = (value: any) => {
|
||||||
// console.log(value,"filevalue");
|
|
||||||
if (value.fileList.length === 0) {
|
if (value.fileList.length === 0) {
|
||||||
formik.setFieldValue(name, null);
|
formik.setFieldValue(name, null);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -62,12 +62,15 @@ const File = ({
|
||||||
onChange={onChange || FilehandleChange}
|
onChange={onChange || FilehandleChange}
|
||||||
customRequest={customRequest}
|
customRequest={customRequest}
|
||||||
className={` w-100`}
|
className={` w-100`}
|
||||||
|
id={name}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className={isError ? "isError w-100 " : " w-100"}
|
className={isError ? "isError w-100 " : " w-100"}
|
||||||
icon={<UploadOutlined />}
|
icon={<UploadOutlined />}
|
||||||
>
|
>
|
||||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
{placeholder
|
||||||
|
? t(`input.${placeholder}`)
|
||||||
|
: t("input.Click_to_upload_the_image")}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
<div className="Error_color"> {isError ? "required" : ""}</div>
|
||||||
{errorMsg}
|
{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 React, { useState } from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { translateOptions } from "../utils/translatedOptions";
|
import { translateOptions } from "../utils/translatedOptions";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
|
||||||
const LocalSelectField = ({
|
const LocalSelectField = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -13,9 +14,9 @@ const LocalSelectField = ({
|
||||||
isMulti,
|
isMulti,
|
||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
props,
|
|
||||||
no_label,
|
no_label,
|
||||||
label_icon,
|
label_icon,
|
||||||
|
...props
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||||
|
|
||||||
|
|
@ -29,13 +30,6 @@ const LocalSelectField = ({
|
||||||
option?.label?.toString().toLowerCase().includes(input.toLowerCase()) ||
|
option?.label?.toString().toLowerCase().includes(input.toLowerCase()) ||
|
||||||
option?.value?.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) => {
|
const handleSelectChange = (value: any) => {
|
||||||
formik.setFieldValue(name, value);
|
formik.setFieldValue(name, value);
|
||||||
if (onChange) onChange(value);
|
if (onChange) onChange(value);
|
||||||
|
|
@ -47,35 +41,21 @@ const LocalSelectField = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100">
|
<div className="ValidationField w-100">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{t(`input.${label ? label : name}`)}
|
/>
|
||||||
</label>
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
<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 : ""}
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
|
||||||
)}
|
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
options={translateOptions(option, t)}
|
options={translateOptions(option, t)}
|
||||||
size="large"
|
size="large"
|
||||||
className={`${className} ${isError ? "Select_error" : ""} w-100`}
|
className={`${className} ${isError ? "SelectError" : ""} w-100`}
|
||||||
value={formik.values[name]}
|
value={formik.values[name]}
|
||||||
allowClear
|
allowClear
|
||||||
{...(isMulti && { mode: "multiple" })}
|
{...(isMulti && { mode: "multiple" })}
|
||||||
|
|
@ -84,8 +64,11 @@ const LocalSelectField = ({
|
||||||
filterOption={handleSearch} // Custom filter function
|
filterOption={handleSearch} // Custom filter function
|
||||||
searchValue={searchValue} // Control the search input value
|
searchValue={searchValue} // Control the search input value
|
||||||
onSearch={handleSearchChange} // Update search input value on change
|
onSearch={handleSearchChange} // Update search input value on change
|
||||||
|
id={name}
|
||||||
|
fieldNames={{ label: "name", value: "id" }}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import React, { useMemo } from "react";
|
||||||
import { Button, Upload } from "antd";
|
import { Button, Upload } from "antd";
|
||||||
import { UploadOutlined } from "@ant-design/icons";
|
import { UploadOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
|
|
||||||
const MaltyFile = ({
|
const MaltyFile = ({
|
||||||
|
|
@ -15,11 +15,10 @@ const MaltyFile = ({
|
||||||
const { formik, t, isError } = useFormField(name, props);
|
const { formik, t, isError } = useFormField(name, props);
|
||||||
let imageUrl = formik?.values?.[name] ?? null;
|
let imageUrl = formik?.values?.[name] ?? null;
|
||||||
|
|
||||||
// Mapping formik values to fileList format
|
// Memoizing the fileList to prevent unnecessary recalculations
|
||||||
const fileList = imageUrl
|
const fileList = useMemo(() => {
|
||||||
|
return imageUrl
|
||||||
? imageUrl.map((file: any, index: number) => {
|
? imageUrl.map((file: any, index: number) => {
|
||||||
// console.log(file,"file");
|
|
||||||
|
|
||||||
return file instanceof File
|
return file instanceof File
|
||||||
? {
|
? {
|
||||||
uid: index,
|
uid: index,
|
||||||
|
|
@ -37,6 +36,7 @@ const MaltyFile = ({
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
}, [imageUrl]); // Dependency array ensures it recalculates only when imageUrl changes
|
||||||
|
|
||||||
const FilehandleChange = ({ fileList }: any) => {
|
const FilehandleChange = ({ fileList }: any) => {
|
||||||
if (fileList.length === 0) {
|
if (fileList.length === 0) {
|
||||||
|
|
@ -48,6 +48,7 @@ const MaltyFile = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Custom request function
|
// Custom request function
|
||||||
const customRequest = async ({ onSuccess }: any) => {
|
const customRequest = async ({ onSuccess }: any) => {
|
||||||
// Perform any necessary actions before onSuccess is called
|
// Perform any necessary actions before onSuccess is called
|
||||||
|
|
@ -63,11 +64,12 @@ const MaltyFile = ({
|
||||||
<Upload
|
<Upload
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
listType="picture"
|
listType="picture"
|
||||||
fileList={fileList} // Using fileList instead of defaultFileList
|
fileList={fileList} // Using memoized fileList
|
||||||
onChange={onChange || FilehandleChange}
|
onChange={onChange || FilehandleChange}
|
||||||
customRequest={customRequest}
|
customRequest={customRequest}
|
||||||
className={`${className} w-100`}
|
className={`${className} w-100`}
|
||||||
multiple // Allow multiple files to be selected
|
multiple // Allow multiple files to be selected
|
||||||
|
id={name}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className={isError ? "isError w-100" : "w-100"}
|
className={isError ? "isError w-100" : "w-100"}
|
||||||
|
|
|
||||||
|
|
@ -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 React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { Field } from "formik";
|
import { Field } from "formik";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
|
||||||
const NumberFormate = ({
|
const NumberFormate = ({
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
placeholder,
|
placeholder,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
props,
|
|
||||||
type,
|
type,
|
||||||
no_label,
|
no_label,
|
||||||
label_icon,
|
label_icon,
|
||||||
|
...props
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||||
const SelectableChange = (value: {
|
const SelectableChange = (value: {
|
||||||
|
|
@ -23,28 +24,15 @@ const NumberFormate = ({
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100">
|
<div className="ValidationField w-100">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{t(`input.${label ? label : name}`)}
|
/>
|
||||||
</label>
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
<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
|
<Field
|
||||||
as={InputNumber}
|
as={InputNumber}
|
||||||
formatter={(value: any) =>
|
formatter={(value: any) =>
|
||||||
|
|
@ -57,16 +45,16 @@ const NumberFormate = ({
|
||||||
type={type ?? "text"}
|
type={type ?? "text"}
|
||||||
value={formik.values[name]}
|
value={formik.values[name]}
|
||||||
onChange={SelectableChange}
|
onChange={SelectableChange}
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
|
||||||
)}
|
|
||||||
name={name}
|
name={name}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
size="large"
|
size="large"
|
||||||
|
id={name}
|
||||||
|
{...props}
|
||||||
|
|
||||||
// onChange={onChange ? onChange : handleChange}
|
// onChange={onChange ? onChange : handleChange}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,143 @@
|
||||||
import { Form, Select, Spin } from "antd";
|
import { Select, Spin } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
import { SearchFieldProps } from "../utils/types";
|
||||||
|
import { useValidationValidationParamState } from "../state/ValidationValidationParamState";
|
||||||
|
import { useDebounce } from "../../../Hooks/useDebounce";
|
||||||
|
|
||||||
const SearchField = ({
|
const SearchField = ({
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
placeholder,
|
placeholder,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
searchBy,
|
searchBy = "search",
|
||||||
option,
|
option = [],
|
||||||
isMulti,
|
isMulti,
|
||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
props,
|
|
||||||
no_label,
|
no_label,
|
||||||
label_icon,
|
label_icon,
|
||||||
isLoading,
|
isLoading,
|
||||||
}: any) => {
|
canChangePage,
|
||||||
|
PageName,
|
||||||
|
page,
|
||||||
|
...props
|
||||||
|
}: SearchFieldProps) => {
|
||||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
const { pushValidationParamState, setValidationParamState } =
|
||||||
const navigate = useNavigate();
|
useValidationValidationParamState();
|
||||||
useEffect(() => {
|
|
||||||
const searchParams = new URLSearchParams(window?.location?.search);
|
|
||||||
setSearchQuery(searchParams?.get("search") || "");
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const SelectableChange = (value: {
|
const [AllPagesOption, setAllPagesOption] = useState<any>([]);
|
||||||
value: string;
|
|
||||||
label: React.ReactNode;
|
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);
|
formik?.setFieldValue(name, value);
|
||||||
};
|
const isCleared = value?.length === 0 || !value;
|
||||||
const SearchHandleChange = (value: any) => {
|
|
||||||
navigate(`${window?.location?.pathname}?${searchBy}=${value}`, {
|
if (isCleared) {
|
||||||
replace: true,
|
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 (
|
return (
|
||||||
<div className="ValidationField w-100">
|
<div className="ValidationField w-100">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{t(`input.${label ? label : name}`)}
|
/>
|
||||||
</label>
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
<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 : ""}
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
|
||||||
)}
|
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
options={option}
|
options={AllPagesOption}
|
||||||
size="large"
|
size="large"
|
||||||
className={`${className} w-100`}
|
className={`${className} w-100`}
|
||||||
value={formik.values[name]}
|
value={formik.values[name]}
|
||||||
loading={isLoading}
|
// loading={isLoading}
|
||||||
allowClear
|
allowClear
|
||||||
{...(isMulti && { mode: "multiple" })}
|
{...(isMulti && { mode: "multiple" })}
|
||||||
onChange={onChange || SelectableChange}
|
onChange={onChange || SelectableChange}
|
||||||
showSearch
|
showSearch
|
||||||
optionFilterProp="label"
|
optionFilterProp="name"
|
||||||
notFoundContent={isLoading ? <Spin /> : "لا يوجد"}
|
notFoundContent={isLoading ? <Spin /> : t("validation.undefined")}
|
||||||
onSearch={SearchHandleChange}
|
onSearch={handleChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
id={name}
|
||||||
|
onPopupScroll={handleScroll}
|
||||||
|
fieldNames={{ label: "name", value: "id" }}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { Form, Select, Spin } from "antd";
|
import { Select } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { translateOptions } from "../utils/translatedOptions";
|
import { translateOptions } from "../utils/translatedOptions";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
import { SelectFieldProps } from "../utils/types";
|
||||||
|
|
||||||
const SelectField = ({
|
const SelectField = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -13,10 +15,11 @@ const SelectField = ({
|
||||||
isMulti,
|
isMulti,
|
||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
props,
|
|
||||||
no_label,
|
no_label,
|
||||||
label_icon,
|
label_icon,
|
||||||
}: any) => {
|
isLoading,
|
||||||
|
...props
|
||||||
|
}: SelectFieldProps) => {
|
||||||
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
const { errorMsg, isError, t, formik } = useFormField(name, props);
|
||||||
const SelectableChange = (value: {
|
const SelectableChange = (value: {
|
||||||
value: string;
|
value: string;
|
||||||
|
|
@ -24,47 +27,36 @@ const SelectField = ({
|
||||||
}) => {
|
}) => {
|
||||||
formik.setFieldValue(name, value);
|
formik.setFieldValue(name, value);
|
||||||
};
|
};
|
||||||
// console.log(name,"Select");
|
const options = translateOptions(option, t);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100">
|
<div className="ValidationField w-100">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{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
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
|
||||||
)}
|
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
options={translateOptions(option, t)}
|
options={options}
|
||||||
loading={option?.length < 1}
|
{...(isLoading && { loading: isLoading })}
|
||||||
size="large"
|
size="large"
|
||||||
className={`${className} ${isError ? "Select_error" : ""} w-100`}
|
className={`${className} ${isError ? "SelectError" : ""} w-100`}
|
||||||
value={formik.values[name]}
|
value={formik.values[name]}
|
||||||
allowClear
|
allowClear
|
||||||
{...(isMulti && { mode: "multiple" })}
|
{...(isMulti && { mode: "multiple" })}
|
||||||
onChange={onChange || SelectableChange}
|
onChange={onChange || SelectableChange}
|
||||||
|
showSearch={false}
|
||||||
|
id={name}
|
||||||
|
fieldNames={{label:"name",value:"id"}}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { Form, Input } from "antd";
|
import { Input } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { Field } from "formik";
|
import { Field } from "formik";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
const TextAreaField = ({
|
const TextAreaField = ({
|
||||||
|
|
@ -11,14 +12,12 @@ const TextAreaField = ({
|
||||||
isDisabled,
|
isDisabled,
|
||||||
onChange,
|
onChange,
|
||||||
props,
|
props,
|
||||||
type,
|
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { formik, isError, errorMsg, t } = useFormField(name, props);
|
const { formik, isError, errorMsg, t } = useFormField(name, props);
|
||||||
|
|
||||||
const handleChange = (
|
const handleChange = (
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
) => {
|
) => {
|
||||||
// console.log('Change:', e.target.value);
|
|
||||||
formik.setFieldValue(name, e.target.value);
|
formik.setFieldValue(name, e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -27,11 +26,7 @@ const TextAreaField = ({
|
||||||
<label htmlFor={name} className="text">
|
<label htmlFor={name} className="text">
|
||||||
{t(`input.${label ? label : name}`)}
|
{t(`input.${label ? label : name}`)}
|
||||||
</label>
|
</label>
|
||||||
<Form.Item
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
<Field
|
||||||
as={TextArea}
|
as={TextArea}
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||||
|
|
@ -39,10 +34,10 @@ const TextAreaField = ({
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
size="large"
|
size="large"
|
||||||
onChange={onChange || handleChange}
|
onChange={onChange || handleChange}
|
||||||
|
id={name}
|
||||||
// onChange={onChange ? onChange : handleChange}
|
// onChange={onChange ? onChange : handleChange}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
import { MdOutlineEdit } from "react-icons/md";
|
||||||
import { Field } from "formik";
|
import { Field } from "formik";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
const TextField = ({
|
const TextField = ({
|
||||||
|
|
@ -21,33 +23,20 @@ const TextField = ({
|
||||||
const TextFilehandleChange = (
|
const TextFilehandleChange = (
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
) => {
|
) => {
|
||||||
// console.log('Change:', e.target.value);
|
|
||||||
formik.setFieldValue(name, e.target.value);
|
formik.setFieldValue(name, e.target.value);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{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>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Form.Item
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
<Field
|
||||||
as={TextArea}
|
as={TextArea}
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||||
|
|
@ -58,8 +47,9 @@ const TextField = ({
|
||||||
maxLength={1000}
|
maxLength={1000}
|
||||||
onChange={onChange || TextFilehandleChange}
|
onChange={onChange || TextFilehandleChange}
|
||||||
style={{ height: 120 }}
|
style={{ height: 120 }}
|
||||||
|
id={name}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidationFieldContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import React from "react";
|
||||||
import useFormField from "../../../Hooks/useFormField";
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
import { MdOutlineEdit } from "react-icons/md";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
|
||||||
const Time = ({
|
const Time = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -20,27 +21,19 @@ const Time = ({
|
||||||
formik.setFieldValue(name, value);
|
formik.setFieldValue(name, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Formater = "H:mm";
|
const Formatter = "H:mm";
|
||||||
const FormikValue = formik.values[name];
|
const FormikValue = formik.values[name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ValidationField w-100 ">
|
<div className="ValidationField w-100 ">
|
||||||
{no_label ? (
|
<ValidationFieldLabel
|
||||||
<label htmlFor={name} className="text">
|
name={name}
|
||||||
<span>empty</span>
|
label={label}
|
||||||
</label>
|
label_icon={label_icon}
|
||||||
) : label_icon ? (
|
no_label={no_label}
|
||||||
<div className="LabelWithIcon">
|
placeholder={placeholder}
|
||||||
<label htmlFor={name} className="text">
|
t={t}
|
||||||
{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
|
<Form.Item
|
||||||
hasFeedback
|
hasFeedback
|
||||||
|
|
@ -51,14 +44,13 @@ const Time = ({
|
||||||
allowClear
|
allowClear
|
||||||
className={`${className} w-100`}
|
className={`${className} w-100`}
|
||||||
size="large"
|
size="large"
|
||||||
value={FormikValue ? dayjs(FormikValue, Formater) : null}
|
value={FormikValue ? dayjs(FormikValue, Formatter) : null}
|
||||||
onChange={onChange || onCalendarChange}
|
onChange={onChange || onCalendarChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
placeholder={t(
|
placeholder={t(`input.${placeholder || label || name}`)}
|
||||||
`input.${placeholder ? placeholder : label ? label : name}`,
|
format={Formatter}
|
||||||
)}
|
|
||||||
format={Formater}
|
|
||||||
needConfirm={false}
|
needConfirm={false}
|
||||||
|
id={name}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</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 { ErrorMessage, useField, Field, useFormikContext } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FaExclamationCircle } from "react-icons/fa";
|
import { FaExclamationCircle } from "react-icons/fa";
|
||||||
import { convert_data_to_select } from "../../Layout/app/Const";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useState,
|
useState,
|
||||||
|
|
@ -12,5 +11,4 @@ export {
|
||||||
useFormikContext,
|
useFormikContext,
|
||||||
useTranslation,
|
useTranslation,
|
||||||
FaExclamationCircle,
|
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);
|
border: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Select_error {
|
.SelectError {
|
||||||
.ant-select-selector {
|
.ant-select-selector {
|
||||||
border: 1px solid red !important;
|
border: 1px solid red !important;
|
||||||
}
|
}
|
||||||
|
|
@ -60,12 +60,9 @@
|
||||||
.ant-upload-select {
|
.ant-upload-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.Checkboxs {
|
.Checkbox {
|
||||||
padding: 4%;
|
padding: 4%;
|
||||||
}
|
}
|
||||||
.ant-checkbox-wrapper {
|
|
||||||
min-width: 100px;
|
|
||||||
}
|
|
||||||
.SearchField {
|
.SearchField {
|
||||||
button {
|
button {
|
||||||
background: var(--primary);
|
background: var(--primary);
|
||||||
|
|
@ -201,27 +198,3 @@ input:-webkit-autofill:hover {
|
||||||
.TwoSelectGroupbutton {
|
.TwoSelectGroupbutton {
|
||||||
margin-bottom: 20px;
|
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) => {
|
export const translateOptions = (options: any, t: any) => {
|
||||||
return options.map((opt: any) => ({
|
return options?.map((opt: any) => ({
|
||||||
...opt,
|
...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 =
|
// Common properties for all field types
|
||||||
| "text"
|
interface BaseFieldProps {
|
||||||
| "Select"
|
|
||||||
| "LocalSearch"
|
|
||||||
| "Search"
|
|
||||||
| "DataRange"
|
|
||||||
| "Date"
|
|
||||||
| "Time"
|
|
||||||
| "File"
|
|
||||||
| "MaltyFile"
|
|
||||||
| "DropFile"
|
|
||||||
| "Checkbox"
|
|
||||||
| "number"
|
|
||||||
| "password"
|
|
||||||
| "email"
|
|
||||||
| "TextArea";
|
|
||||||
|
|
||||||
export interface ValidationFieldPropsText {
|
|
||||||
name: string;
|
name: string;
|
||||||
no_label?: boolean;
|
|
||||||
label_icon?: boolean;
|
|
||||||
type: "text";
|
|
||||||
placeholder?: string;
|
|
||||||
label?: string;
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
onChange?: (value: any) => void;
|
onChange?: (value: any) => void;
|
||||||
dir?: "ltr" | "rtl";
|
dir?: "ltr" | "rtl";
|
||||||
|
no_label?: boolean;
|
||||||
|
label_icon?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ValidationFieldPropsSelect {
|
// Specific field type properties
|
||||||
name: string;
|
export type SelectFieldProps = BaseFieldProps &
|
||||||
no_label?: boolean;
|
SelectProps & {
|
||||||
label_icon?: boolean;
|
type: "Select" | "LocalSearch";
|
||||||
type: "Select";
|
|
||||||
placeholder?: string;
|
|
||||||
label?: string;
|
|
||||||
className?: string;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: any;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
option: any[];
|
option: any[];
|
||||||
isMulti?: boolean;
|
isMulti?: boolean;
|
||||||
}
|
isLoading?: boolean;
|
||||||
|
searchBy?: string;
|
||||||
|
canChangePage?: boolean;
|
||||||
|
PageName?: string;
|
||||||
|
page?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export interface ValidationFieldPropsLocalSearch {
|
export type SearchFieldProps = BaseFieldProps &
|
||||||
name: string;
|
SelectProps & {
|
||||||
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;
|
|
||||||
type: "Search";
|
type: "Search";
|
||||||
placeholder?: string;
|
|
||||||
label?: string;
|
|
||||||
className?: string;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: (value: any) => void;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
option: any[];
|
option: any[];
|
||||||
isMulti?: boolean;
|
isMulti?: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
searchBy: string;
|
searchBy: string;
|
||||||
isLoading?: any;
|
canChangePage: boolean;
|
||||||
}
|
PageName: string;
|
||||||
export interface ValidationFieldPropsDataRange {
|
page: number;
|
||||||
name: string;
|
};
|
||||||
no_label?: boolean;
|
|
||||||
label_icon?: boolean;
|
type DateFieldProps = BaseFieldProps & {
|
||||||
type: "DataRange";
|
type: "DataRange" | "Date" | "Time";
|
||||||
placeholder?: string;
|
|
||||||
label?: string;
|
|
||||||
className?: string;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: (value: any) => void;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
|
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";
|
picker?: "data" | "week" | "month" | "quarter" | "year";
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface ValidationFieldPropsTime {
|
type FileFieldProps = BaseFieldProps & {
|
||||||
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: "File" | "MaltyFile" | "DropFile";
|
type: "File" | "MaltyFile" | "DropFile";
|
||||||
placeholder?: string;
|
};
|
||||||
label?: string;
|
|
||||||
className?: string;
|
type CheckboxFieldProps = BaseFieldProps & {
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: (value: any) => void;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
}
|
|
||||||
export interface ValidationFieldPropsCheckbox {
|
|
||||||
name: string;
|
|
||||||
no_label?: boolean;
|
|
||||||
label_icon?: boolean;
|
|
||||||
type: "Checkbox";
|
type: "Checkbox";
|
||||||
label?: string;
|
|
||||||
className?: string;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: (value: any) => void;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
Group?: boolean;
|
Group?: boolean;
|
||||||
}
|
};
|
||||||
export interface ValidationFieldPropstext {
|
|
||||||
name: string;
|
export type FieldProps = BaseFieldProps &
|
||||||
no_label?: boolean;
|
InputProps & {
|
||||||
label_icon?: boolean;
|
|
||||||
type?:
|
type?:
|
||||||
| "text"
|
| "text"
|
||||||
| "number"
|
| "number"
|
||||||
|
|
@ -150,45 +62,19 @@ export interface ValidationFieldPropstext {
|
||||||
| "email"
|
| "email"
|
||||||
| "TextArea"
|
| "TextArea"
|
||||||
| "NumberFormate";
|
| "NumberFormate";
|
||||||
label?: string;
|
|
||||||
label2?: string;
|
label2?: string;
|
||||||
className?: string;
|
|
||||||
placeholder?: string;
|
|
||||||
isDisabled?: boolean;
|
|
||||||
onChange?: (value: any) => void;
|
|
||||||
dir?: "ltr" | "rtl";
|
|
||||||
Group?: boolean;
|
Group?: boolean;
|
||||||
[key: string]: any; // Index signature to allow any additional props
|
[key: string]: any;
|
||||||
}
|
};
|
||||||
|
|
||||||
///// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Union type for all field types
|
||||||
export type ValidationFieldProps =
|
export type ValidationFieldProps =
|
||||||
| ValidationFieldPropsInput
|
| SelectFieldProps
|
||||||
| ValidationFieldPropsSelect
|
| DateFieldProps
|
||||||
| ValidationFieldPropsLocalSearch
|
| FileFieldProps
|
||||||
| ValidationFieldPropsDataRange
|
| CheckboxFieldProps
|
||||||
| ValidationFieldPropsDate
|
| SearchFieldProps
|
||||||
| ValidationFieldPropsTime
|
| FieldProps;
|
||||||
| ValidationFieldPropsFile
|
|
||||||
| ValidationFieldPropsCheckbox
|
// Validation field type
|
||||||
| ValidationFieldPropstext
|
export type ValidationFieldType = ValidationFieldProps["type"];
|
||||||
| ValidationFieldPropsSearch;
|
|
||||||
|
|
|
||||||
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,6 +9,8 @@ import { useTranslation } from "react-i18next";
|
||||||
import { getLocalStorage } from "../../utils/LocalStorage";
|
import { getLocalStorage } from "../../utils/LocalStorage";
|
||||||
import { BRANCH_OBJECT_KEY } from "../../config/AppKey";
|
import { BRANCH_OBJECT_KEY } from "../../config/AppKey";
|
||||||
import { MenuItem } from "../../Components/Layout/SideBar/MenuItem";
|
import { MenuItem } from "../../Components/Layout/SideBar/MenuItem";
|
||||||
|
import { UserTypeEnum } from "../../enums/UserType";
|
||||||
|
import { RoleByType } from "../../utils/RoleByType";
|
||||||
|
|
||||||
const SideBar = () => {
|
const SideBar = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
@ -17,7 +19,6 @@ const SideBar = () => {
|
||||||
const { logout } = useAuthState();
|
const { logout } = useAuthState();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const branch_name = getLocalStorage(BRANCH_OBJECT_KEY)?.name;
|
const branch_name = getLocalStorage(BRANCH_OBJECT_KEY)?.name;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="side_bar">
|
<div className="side_bar">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
@ -31,6 +32,11 @@ const SideBar = () => {
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return <React.Fragment key={index}></React.Fragment>;
|
return <React.Fragment key={index}></React.Fragment>;
|
||||||
}
|
}
|
||||||
|
if(!RoleByType(item)){
|
||||||
|
|
||||||
|
return <React.Fragment key={index}></React.Fragment> ;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
import useAuthState from "../../zustand/AuthState";
|
import useAuthState from "../../zustand/AuthState";
|
||||||
import useNavigateOnSuccess from "../../Hooks/useNavigateOnSuccess";
|
import useNavigateOnSuccess from "../../Hooks/useNavigateOnSuccess";
|
||||||
|
|
@ -8,6 +8,9 @@ import { initialValues } from "./formutils";
|
||||||
import { FormValues } from "../../types/Auth";
|
import { FormValues } from "../../types/Auth";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { getLocalStorage } from "../../utils/LocalStorage";
|
||||||
|
import { USER_KEY } from "../../config/AppKey";
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
|
const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
|
||||||
|
|
@ -16,11 +19,27 @@ const LoginForm = () => {
|
||||||
mutate(values);
|
mutate(values);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { login } = useAuthState();
|
const { login,isAuthenticated} = useAuthState();
|
||||||
const LoginData = {
|
const LoginData = {
|
||||||
...data,
|
...data,
|
||||||
|
|
||||||
} as any;
|
} as any;
|
||||||
useNavigateOnSuccess(isSuccess, "/", () => login(LoginData?.data as any));
|
const navigate = useNavigate()
|
||||||
|
const LocalType = getLocalStorage(USER_KEY)?.type ?? false ;
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if(isSuccess){
|
||||||
|
login(LoginData?.data as any)
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [isSuccess])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(LocalType ){
|
||||||
|
window.location.href = ("/")
|
||||||
|
}
|
||||||
|
}, [LocalType])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="LoginForm">
|
<div className="LoginForm">
|
||||||
|
|
|
||||||
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;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { getInitialValues, getValidationSchema } from "./formUtil";
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
import { ModalEnum } from "../../../enums/Model";
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||||
|
|
@ -6,40 +6,53 @@ import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
import ModelForm from "./ModelForm";
|
import ModelForm from "./ModelForm";
|
||||||
import { useAddPackage } from "../../../api/package";
|
import { useAddPackage } from "../../../api/package";
|
||||||
import FormikForm from "../../../Layout/Dashboard/FormikForm";
|
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 AddModel: React.FC = () => {
|
||||||
const { mutate, status } = useAddPackage();
|
const { mutate, status ,isLoading,isSuccess} = 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({
|
mutate({
|
||||||
...values,
|
...values,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
if(isSuccess){
|
||||||
|
navigate("/package")
|
||||||
|
}
|
||||||
|
}, [isSuccess])
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.package`));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="page">
|
||||||
{/* <LayoutModel
|
|
||||||
status={status as QueryStatusEnum}
|
|
||||||
ModelEnum={ModalEnum.Package_ADD}
|
|
||||||
modelTitle="package"
|
|
||||||
handleSubmit={handleSubmit}
|
|
||||||
getInitialValues={getInitialValues({})}
|
|
||||||
getValidationSchema={getValidationSchema}
|
|
||||||
>
|
|
||||||
<ModelForm />
|
|
||||||
moaz
|
|
||||||
</LayoutModel> */}
|
|
||||||
casascaas
|
|
||||||
<FormikForm
|
<FormikForm
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
initialValues={getInitialValues('')}
|
initialValues={getInitialValues({})}
|
||||||
validationSchema={getValidationSchema}
|
validationSchema={getValidationSchema}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
{t("header.add_new_package")}
|
||||||
|
</header>
|
||||||
|
|
||||||
<main className="w-100 exercise_add_main">
|
<main className="w-100 exercise_add_main">
|
||||||
<ModelForm />
|
<ModelForm />
|
||||||
|
|
||||||
<div className="exercise_add_buttons">
|
<div className="exercise_add_buttons">
|
||||||
{/* <div onClick={handleCancel}>{t("practical.back")}</div> */}
|
<button disabled={isLoading} className="relative button center" type="submit">
|
||||||
{/* <button disabled={isLoading} className="relative" type="submit">
|
|
||||||
{t("practical.add")}
|
{t("practical.add")}
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
|
|
@ -47,11 +60,11 @@ const AddModel: React.FC = () => {
|
||||||
<Spin />
|
<Spin />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</button> */}
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</FormikForm>
|
</FormikForm>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,78 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { getInitialValues, getValidationSchema } from "./formUtil";
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
import { ModalEnum } from "../../../enums/Model";
|
|
||||||
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
|
||||||
import ModelForm from "./ModelForm";
|
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 { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
import { useUpdatePackage } from "../../../api/package";
|
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
||||||
|
|
||||||
const EditModel: React.FC = () => {
|
const EditModel: React.FC = () => {
|
||||||
const { mutate, status } = useUpdatePackage();
|
const { mutate, status ,isLoading,isSuccess} = useUpdatePackage();
|
||||||
const { objectToEdit } = useObjectToEdit((state) => state);
|
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({
|
mutate({
|
||||||
...values,
|
...values,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const navigate = useNavigate()
|
||||||
|
useEffect(() => {
|
||||||
|
if(isSuccess){
|
||||||
|
navigate("/package")
|
||||||
|
}
|
||||||
|
}, [isSuccess])
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.package`));
|
||||||
|
if(isLoadingData){
|
||||||
|
return <SpinContainer/>
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="page">
|
||||||
<LayoutModel
|
<FormikForm
|
||||||
status={status as QueryStatusEnum}
|
|
||||||
ModelEnum={ModalEnum.Package_EDIT}
|
|
||||||
modelTitle="package_details"
|
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
getInitialValues={getInitialValues(objectToEdit)}
|
initialValues={getInitialValues(data?.data)}
|
||||||
getValidationSchema={getValidationSchema}
|
validationSchema={getValidationSchema}
|
||||||
isAddModal={false}
|
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
{t("header.edit_package")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="w-100 exercise_Edit_main">
|
||||||
<ModelForm />
|
<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,237 @@
|
||||||
import { Col, Row } from "reactstrap";
|
import { Col, Row } from "reactstrap";
|
||||||
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
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 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 (
|
return (
|
||||||
<Row className="w-100">
|
<Row className="w-100">
|
||||||
<Col>
|
<Col>
|
||||||
<ValidationField placeholder="name" label="name" name="name" />
|
<ValidationField placeholder="name" label="name" name="name" />
|
||||||
<ValidationField placeholder="price" label="price" name="price" />
|
<ValidationField placeholder="price" label="price" name="price" type="number" />
|
||||||
<ValidationField placeholder="name" label="name" name="name" />
|
<FieldGroup array_name='configuration' title='configuration' />
|
||||||
|
|
||||||
</Col>
|
</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>
|
</Row>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,32 @@
|
||||||
import * as Yup from "yup";
|
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 {
|
return {
|
||||||
id: objectToEdit?.id ?? null,
|
id: objectToEdit?.id ?? null,
|
||||||
name: objectToEdit?.name ?? null,
|
name: objectToEdit?.name ?? null,
|
||||||
price: objectToEdit?.price ?? null,
|
price: objectToEdit?.price ?? null,
|
||||||
grade_id: objectToEdit?.grade_id ?? 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 = () => {
|
export const getValidationSchema = () => {
|
||||||
return Yup.object().shape({
|
return Yup.object().shape({
|
||||||
name: Yup.string().required("validation.required"),
|
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"),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const ConfigurationField = () => {
|
||||||
|
return (
|
||||||
|
<div>ConfigurationField</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfigurationField
|
||||||
96
src/Pages/Package/PackageItem/Field/FieldGroup.tsx
Normal file
96
src/Pages/Package/PackageItem/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;
|
||||||
66
src/Pages/Package/PackageItem/Model/AddModel.tsx
Normal file
66
src/Pages/Package/PackageItem/Model/AddModel.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
|
||||||
|
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 ,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);
|
||||||
|
|
||||||
|
mutate({
|
||||||
|
...values,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.package`));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page">
|
||||||
|
<FormikForm
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
initialValues={getInitialValues({})}
|
||||||
|
validationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
{t("header.add_new_package")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="w-100 exercise_add_main">
|
||||||
|
<ModelForm />
|
||||||
|
<div className="exercise_add_buttons">
|
||||||
|
<button disabled={isLoading} className="relative button center" type="submit">
|
||||||
|
{t("practical.add")}
|
||||||
|
|
||||||
|
{isLoading && (
|
||||||
|
<span className="Spinier_Div">
|
||||||
|
<Spin />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</FormikForm>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
73
src/Pages/Package/PackageItem/Model/EditModel.tsx
Normal file
73
src/Pages/Package/PackageItem/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
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 SpinContainer from "../../../../Components/Layout/SpinContainer";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
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);
|
||||||
|
|
||||||
|
mutate({
|
||||||
|
...values,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.package`));
|
||||||
|
if(isLoadingData){
|
||||||
|
return <SpinContainer/>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="page">
|
||||||
|
<FormikForm
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
initialValues={getInitialValues(data?.data)}
|
||||||
|
validationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
{t("header.edit_package")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="w-100 exercise_Edit_main">
|
||||||
|
<ModelForm />
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
238
src/Pages/Package/PackageItem/Model/ModelForm.tsx
Normal file
238
src/Pages/Package/PackageItem/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
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" 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
33
src/Pages/Package/PackageItem/Model/formUtil.ts
Normal file
33
src/Pages/Package/PackageItem/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Package, PackageInitialValues } from "../../../../types/Package";
|
||||||
|
import { arrayToObject } from "../../../../utils/arrayToObject";
|
||||||
|
import { objectToArray } from "../../../../utils/objectToArray";
|
||||||
|
export const getInitialValues = (objectToEdit: Partial<Package>): any => {
|
||||||
|
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:""}],
|
||||||
|
moiaed: [{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"),
|
||||||
|
});
|
||||||
|
};
|
||||||
59
src/Pages/Package/PackageItem/Page.tsx
Normal file
59
src/Pages/Package/PackageItem/Page.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import useModalHandler from "../../../utils/useModalHandler";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import { canAddPackage } from "../../../utils/hasAbilityFn";
|
||||||
|
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
|
||||||
|
import { useDeletePackage } from "../../../api/package";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { ABILITIES_ENUM } from "../../../enums/abilities";
|
||||||
|
const Table = lazy(() => import("./Table"));
|
||||||
|
|
||||||
|
const DeleteModalForm = lazy(
|
||||||
|
() => import("../../../Layout/Dashboard/DeleteModels"),
|
||||||
|
);
|
||||||
|
const SearchField = lazy(
|
||||||
|
() => import("../../../Components/DataTable/SearchField"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const { handel_open_model } = useModalHandler();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
useSetPageTitle(t(`page_header.package`));
|
||||||
|
const deleteMutation = useDeletePackage();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<header className="d-flex justify-content-between">
|
||||||
|
<SearchField
|
||||||
|
searchBy="name"
|
||||||
|
placeholder={t("practical.search_here")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{canAddPackage && (
|
||||||
|
<div className="Selects">
|
||||||
|
<button
|
||||||
|
onClick={() => navigate(`/${ABILITIES_ENUM?.Package}/add`)}
|
||||||
|
className="add_button"
|
||||||
|
>
|
||||||
|
{t("models.add_package")} <FaPlus />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<Table />
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.PACKAGE_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
21
src/Pages/Package/PackageItem/Table.tsx
Normal file
21
src/Pages/Package/PackageItem/Table.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import useSearchQuery from "../../../api/utils/useSearchQuery";
|
||||||
|
import { useGetAllPackage } from "../../../api/package";
|
||||||
|
import { useGetAllPackageItem } from "../../../api/packageItem";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { ParamsEnum } from "../../../enums/params";
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const [searchQuery] = useSearchQuery("name");
|
||||||
|
const {package_id} = useParams<ParamsEnum>()
|
||||||
|
const response = useGetAllPackageItem({
|
||||||
|
name: searchQuery,
|
||||||
|
package_id:package_id,
|
||||||
|
pagination: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
15
src/Pages/Package/PackageItem/index.tsx
Normal file
15
src/Pages/Package/PackageItem/index.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import Table from "./Table";
|
||||||
|
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
|
||||||
|
import AddModalForm from "./Model/AddModel";
|
||||||
|
import EditModalForm from "./Model/EditModel";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Table,
|
||||||
|
useColumns,
|
||||||
|
AddModalForm,
|
||||||
|
EditModalForm,
|
||||||
|
FaPlus,
|
||||||
|
};
|
||||||
66
src/Pages/Package/PackageItem/useTableColumns.tsx
Normal file
66
src/Pages/Package/PackageItem/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
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);
|
||||||
|
setIsOpen(ModalEnum?.PACKAGE_DELETE);
|
||||||
|
};
|
||||||
|
const handleEdit = (record: any) => {
|
||||||
|
setObjectToEdit(record);
|
||||||
|
setIsOpen(ModalEnum?.PACKAGE_EDIT);
|
||||||
|
navigate(`${record?.id}`)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: TableColumnsType<any> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("columns.name"),
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("columns.price"),
|
||||||
|
dataIndex: "price",
|
||||||
|
key: "price",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "",
|
||||||
|
key: "actions",
|
||||||
|
align: "end",
|
||||||
|
width: "25vw",
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canEditPackage}
|
||||||
|
canEdit={canDeletePackage}
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
@ -50,10 +50,8 @@ const TableHeader = () => {
|
||||||
<Table />
|
<Table />
|
||||||
<DeleteModalForm
|
<DeleteModalForm
|
||||||
deleteMutation={deleteMutation}
|
deleteMutation={deleteMutation}
|
||||||
ModelEnum={ModalEnum?.Package_DELETE}
|
ModelEnum={ModalEnum?.PACKAGE_DELETE}
|
||||||
/>
|
/>
|
||||||
{/* <AddModalForm /> */}
|
|
||||||
<EditModalForm />
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,33 @@
|
||||||
import { TableColumnsType } from "antd";
|
import { TableColumnsType } from "antd";
|
||||||
import { ModalEnum } from "../../enums/Model";
|
import { ModalEnum } from "../../enums/Model";
|
||||||
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";``
|
||||||
import { useModalState } from "../../zustand/Modal";
|
import { useModalState } from "../../zustand/Modal";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { canDeletePackage,canEditPackage } from "../../utils/hasAbilityFn";
|
import { canDeletePackage,canEditPackage, canShowPackage } from "../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../Components/Table/ActionButtons";
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { ABILITIES_ENUM } from "../../enums/abilities";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
||||||
const { setIsOpen } = useModalState((state) => state);
|
const { setIsOpen } = useModalState((state) => state);
|
||||||
|
const navigate = useNavigate()
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const handelDelete = (record: any) => {
|
const handelDelete = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
setIsOpen(ModalEnum?.Package_DELETE);
|
setIsOpen(ModalEnum?.PACKAGE_DELETE);
|
||||||
};
|
};
|
||||||
const handleEdit = (record: any) => {
|
const handleEdit = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
setIsOpen(ModalEnum?.Package_EDIT);
|
navigate(`${record?.id}`)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
// const handleShow = (record: any) => {
|
||||||
|
// setObjectToEdit(record);
|
||||||
|
// navigate(`${record?.id}/${ABILITIES_ENUM?.PACKAGE_ITEM}`)
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
const columns: TableColumnsType<any> = [
|
const columns: TableColumnsType<any> = [
|
||||||
{
|
{
|
||||||
|
|
@ -50,9 +58,11 @@ export const useColumns = () => {
|
||||||
<ActionButtons
|
<ActionButtons
|
||||||
canDelete={canEditPackage}
|
canDelete={canEditPackage}
|
||||||
canEdit={canDeletePackage}
|
canEdit={canDeletePackage}
|
||||||
|
// canShow={canShowPackage}
|
||||||
index={index}
|
index={index}
|
||||||
onDelete={() => handelDelete(record)}
|
onDelete={() => handelDelete(record)}
|
||||||
onEdit={() => handleEdit(record)}
|
onEdit={() => handleEdit(record)}
|
||||||
|
// onShow={() => handleShow(record)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
36
src/Pages/ReSeller/Model/AddModel.tsx
Normal file
36
src/Pages/ReSeller/Model/AddModel.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { useAddReSeller } from "../../../api/ReSeller";
|
||||||
|
|
||||||
|
const AddModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useAddReSeller();
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const newValue = JSON.parse(JSON.stringify({...values}))
|
||||||
|
const location = {lat:newValue?.lat,lng:newValue?.lng}
|
||||||
|
mutate({
|
||||||
|
...newValue,
|
||||||
|
location
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.RE_SELLER_ADD}
|
||||||
|
modelTitle="ReSeller"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues({})}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
40
src/Pages/ReSeller/Model/EditModel.tsx
Normal file
40
src/Pages/ReSeller/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema, getValidationSchemaEdit } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
import { useUpdateReSeller } from "../../../api/ReSeller";
|
||||||
|
import { handelImageState } from "../../../utils/DataToSendImageState";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useUpdateReSeller();
|
||||||
|
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const newValue = JSON.parse(JSON.stringify({...values}))
|
||||||
|
const location = {lat:newValue?.lat,lng:newValue?.lng}
|
||||||
|
mutate({
|
||||||
|
...newValue,
|
||||||
|
location
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.RE_SELLER_EDIT}
|
||||||
|
modelTitle="ReSeller"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
|
getValidationSchema={getValidationSchemaEdit}
|
||||||
|
isAddModal={false}
|
||||||
|
>
|
||||||
|
<ModelForm isEdit={true} />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
30
src/Pages/ReSeller/Model/ModelForm.tsx
Normal file
30
src/Pages/ReSeller/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
||||||
|
import MyMap from "./field/MyMap";
|
||||||
|
|
||||||
|
const Form = ({isEdit = false}:{isEdit?:boolean}) => {
|
||||||
|
return (
|
||||||
|
<Row className="w-100">
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="first_name" placeholder="first_name" label="first_name" />
|
||||||
|
<ValidationField name="last_name" placeholder="last_name" label="last_name" />
|
||||||
|
<ValidationField name="username" placeholder="username" label="username" />
|
||||||
|
{!isEdit &&
|
||||||
|
<ValidationField name="password" placeholder="password" label="password" />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="contact_number1" placeholder="contact_number1" label="contact_number1" />
|
||||||
|
<ValidationField name="contact_number2" placeholder="contact_number2" label="contact_number2" />
|
||||||
|
|
||||||
|
<ValidationField name="lat" placeholder="lat" label="lat" />
|
||||||
|
<ValidationField name="lng" placeholder="lng" label="lng" />
|
||||||
|
<MyMap/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
81
src/Pages/ReSeller/Model/field/MyMap.tsx
Normal file
81
src/Pages/ReSeller/Model/field/MyMap.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { MapContainer, TileLayer, Marker, Popup, useMapEvents, useMap } from 'react-leaflet';
|
||||||
|
import 'leaflet/dist/leaflet.css';
|
||||||
|
import L from 'leaflet';
|
||||||
|
import { Input, Button } from 'antd';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import { ReSellerInitialValues } from '../../../../types/ReSeller';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// Fix for marker icon issue
|
||||||
|
//@ts-ignore
|
||||||
|
delete L.Icon.Default.prototype._getIconUrl;
|
||||||
|
L.Icon.Default.mergeOptions({
|
||||||
|
iconRetinaUrl: 'https://unpkg.com/leaflet/dist/images/marker-icon-2x.png',
|
||||||
|
iconUrl: 'https://unpkg.com/leaflet/dist/images/marker-icon.png',
|
||||||
|
shadowUrl: 'https://unpkg.com/leaflet/dist/images/marker-shadow.png',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LocationMarker: React.FC = () => {
|
||||||
|
const { setFieldValue } = useFormikContext<ReSellerInitialValues>();
|
||||||
|
|
||||||
|
useMapEvents({
|
||||||
|
click(e) {
|
||||||
|
const { lat, lng } = e.latlng;
|
||||||
|
setFieldValue('lat', lat); // Update latitude in Formik
|
||||||
|
setFieldValue('lng', lng); // Update longitude in Formik
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CenterMapOnPosition: React.FC<{ position: [number, number] }> = ({ position }) => {
|
||||||
|
const map = useMap();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
map.setView(position, map.getZoom());
|
||||||
|
}, [position, map]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyMap: React.FC = () => {
|
||||||
|
const [showMap, setShowMap] = useState(false); // State to control map visibility
|
||||||
|
const [currentPosition] = useState<[number, number] | null>(null); // State to hold current position
|
||||||
|
const { values } = useFormikContext<ReSellerInitialValues>();
|
||||||
|
const { lat, lng } = values as any;
|
||||||
|
const position: [number, number] = [lat, lng];
|
||||||
|
|
||||||
|
const [t] = useTranslation()
|
||||||
|
return (
|
||||||
|
<div className='mb-4'>
|
||||||
|
<div className='MapInputs '>
|
||||||
|
<Button onClick={() => setShowMap(!showMap)} type="primary">
|
||||||
|
{showMap ? `${t("practical.Hide")} ${t("practical.Map")}` : `${t("practical.Show")} ${t("practical.Map")}`}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showMap && (
|
||||||
|
<MapContainer
|
||||||
|
center={currentPosition || position} // Use currentPosition if available, otherwise fallback to form values
|
||||||
|
zoom={13}
|
||||||
|
style={{ height: "200px", width: "100%" }}
|
||||||
|
>
|
||||||
|
<TileLayer
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
|
||||||
|
|
||||||
|
/>
|
||||||
|
<Marker position={currentPosition || position}>
|
||||||
|
|
||||||
|
</Marker>
|
||||||
|
<LocationMarker />
|
||||||
|
<CenterMapOnPosition position={currentPosition || position} />
|
||||||
|
</MapContainer>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyMap;
|
||||||
67
src/Pages/ReSeller/Model/formUtil.ts
Normal file
67
src/Pages/ReSeller/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { ReSeller, ReSellerInitialValues } from "../../../types/ReSeller";
|
||||||
|
|
||||||
|
export const getInitialValues = (
|
||||||
|
objectToEdit: Partial<ReSeller>,
|
||||||
|
): ReSellerInitialValues => {
|
||||||
|
console.log(objectToEdit,"objectToEdit");
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
id: objectToEdit?.id,
|
||||||
|
first_name: objectToEdit?.first_name ?? "",
|
||||||
|
last_name: objectToEdit?.last_name ?? "",
|
||||||
|
lat: objectToEdit?.location?.lat ?? 33.5138,
|
||||||
|
lng: objectToEdit?.location?.lng ?? 36.2765,
|
||||||
|
contact_number1:objectToEdit?.contact_number1 ?? null,
|
||||||
|
contact_number2:objectToEdit?.contact_number2 ?? null ,
|
||||||
|
username: objectToEdit?.user?.username ?? null ,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchema = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
|
contact_number1: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
contact_number2: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
password: Yup.string().min(8,"validation.Password_must_be_at_least_8_characters_long").required("validation.required"),
|
||||||
|
username: Yup.string().required("validation.required"),
|
||||||
|
lat: Yup.string().required("validation.required"),
|
||||||
|
lng: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchemaEdit = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
|
contact_number1: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
contact_number2: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
username: Yup.string().required("validation.required"),
|
||||||
|
lat: Yup.string().required("validation.required"),
|
||||||
|
lng: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
44
src/Pages/ReSeller/Page.tsx
Normal file
44
src/Pages/ReSeller/Page.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useDeleteReSeller } from "../../api/ReSeller";
|
||||||
|
import MyMap from "./Model/field/MyMap";
|
||||||
|
|
||||||
|
const Table = lazy(() => import("./Table"));
|
||||||
|
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
||||||
|
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
|
const DeleteModalForm = lazy(
|
||||||
|
() => import("../../Layout/Dashboard/DeleteModels"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const deleteMutation = useDeleteReSeller();
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.reSeller`));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<header>
|
||||||
|
<h6>{t("models.ReSeller")}</h6>
|
||||||
|
</header>
|
||||||
|
<Table />
|
||||||
|
<AddModalForm />
|
||||||
|
<EditModalForm />
|
||||||
|
|
||||||
|
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.RE_SELLER_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
12
src/Pages/ReSeller/Table.tsx
Normal file
12
src/Pages/ReSeller/Table.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useGetAllReSeller } from "../../api/ReSeller";
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const response = useGetAllReSeller({ pagination: true });
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
98
src/Pages/ReSeller/useTableColumns.tsx
Normal file
98
src/Pages/ReSeller/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { ReSeller } from "../../types/ReSeller";
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import useModalHandler from "../../utils/useModalHandler";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ABILITIES_ENUM } from "../../enums/abilities";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
canAddReSeller,
|
||||||
|
canDeleteReSeller,
|
||||||
|
canEditReSeller,
|
||||||
|
canShowReSeller,
|
||||||
|
} from "../../utils/hasAbilityFn";
|
||||||
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
import ColumnsImage from "../../Components/Columns/ColumnsImage";
|
||||||
|
|
||||||
|
export const useColumns = () => {
|
||||||
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
||||||
|
const handelDelete = (data: ReSeller) => {
|
||||||
|
setObjectToEdit(data);
|
||||||
|
handel_open_model(ModalEnum?.RE_SELLER_DELETE);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (record: ReSeller) => {
|
||||||
|
setObjectToEdit(record);
|
||||||
|
handel_open_model(ModalEnum?.RE_SELLER_EDIT);
|
||||||
|
};
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const columns: TableColumnsType<ReSeller> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.first_name")}`,
|
||||||
|
dataIndex: "first_name",
|
||||||
|
key: "first_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.first_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.last_name")}`,
|
||||||
|
dataIndex: "last_name",
|
||||||
|
key: "last_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.last_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.username")}`,
|
||||||
|
dataIndex: "username",
|
||||||
|
key: "username",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.user?.username,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: canAddReSeller ? (
|
||||||
|
<button
|
||||||
|
onClick={() => handel_open_model(ModalEnum?.RE_SELLER_ADD)}
|
||||||
|
className="add_button"
|
||||||
|
>
|
||||||
|
{t("practical.add")} {t("models.ReSeller")} <FaPlus />
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
),
|
||||||
|
|
||||||
|
key: "actions",
|
||||||
|
align: "end",
|
||||||
|
width: "25vw",
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canDeleteReSeller}
|
||||||
|
canEdit={canEditReSeller}
|
||||||
|
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
33
src/Pages/Student/Model/AddModel.tsx
Normal file
33
src/Pages/Student/Model/AddModel.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { useAddStudent } from "../../../api/student";
|
||||||
|
|
||||||
|
const AddModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useAddStudent();
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
mutate({
|
||||||
|
...values,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.STUDENT_ADD}
|
||||||
|
modelTitle="student"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues({})}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
37
src/Pages/Student/Model/EditModel.tsx
Normal file
37
src/Pages/Student/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
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 { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
import { useUpdateStudent } from "../../../api/student";
|
||||||
|
import { handelImageState } from "../../../utils/DataToSendImageState";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useUpdateStudent();
|
||||||
|
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const Data_to_send = { ...values };
|
||||||
|
mutate(Data_to_send);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.STUDENT_EDIT}
|
||||||
|
modelTitle="student"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
isAddModal={false}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
58
src/Pages/Student/Model/ModelForm.tsx
Normal file
58
src/Pages/Student/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
||||||
|
import { useGetAllGrade } from "../../../api/grade";
|
||||||
|
import { useValidationValidationParamState } from "../../../Components/ValidationField/state/ValidationValidationParamState";
|
||||||
|
|
||||||
|
const Form = ({ isEdit = false }: { isEdit?: boolean }) => {
|
||||||
|
const { ValidationParamState } = useValidationValidationParamState();
|
||||||
|
const {
|
||||||
|
GradeName, GradeCurrentPage,
|
||||||
|
} = ValidationParamState;
|
||||||
|
|
||||||
|
|
||||||
|
const { data: Grade, isLoading: isLoadingGrade } = useGetAllGrade({
|
||||||
|
name: GradeName,
|
||||||
|
page: GradeCurrentPage
|
||||||
|
});
|
||||||
|
const GradeOption = Grade?.data ?? []
|
||||||
|
const canChangeGradePage = !!Grade?.links?.next;
|
||||||
|
const GradePage = Grade?.meta?.currentPage;
|
||||||
|
|
||||||
|
const sex = [
|
||||||
|
{name:"male" , id :"male"},
|
||||||
|
{name:"female" , id :"female"}
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Row className="w-100">
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="first_name" placeholder="first_name" label="first_name" />
|
||||||
|
<ValidationField name="last_name" placeholder="last_name" label="last_name" />
|
||||||
|
<ValidationField name="username" placeholder="username" label="username" />
|
||||||
|
{!isEdit &&
|
||||||
|
<ValidationField name="password" placeholder="password" label="password" />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="phone_number" placeholder="contact_number1" label="contact_number1" />
|
||||||
|
<ValidationField
|
||||||
|
searchBy="GradeName"
|
||||||
|
name="grade_id"
|
||||||
|
label="grade"
|
||||||
|
type="Search"
|
||||||
|
option={GradeOption}
|
||||||
|
isLoading={isLoadingGrade}
|
||||||
|
canChangePage={canChangeGradePage}
|
||||||
|
PageName={"GradeCurrentPage"}
|
||||||
|
page={GradePage}
|
||||||
|
|
||||||
|
/>
|
||||||
|
<ValidationField type="Select" name="sex" option={sex} />
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
27
src/Pages/Student/Model/formUtil.ts
Normal file
27
src/Pages/Student/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Student, StudentInitialValues } from "../../../types/Student";
|
||||||
|
|
||||||
|
export const getInitialValues = (
|
||||||
|
objectToEdit: Partial<Student>,
|
||||||
|
): StudentInitialValues => {
|
||||||
|
return {
|
||||||
|
id: objectToEdit?.user_id,
|
||||||
|
first_name: objectToEdit?.first_name ?? "",
|
||||||
|
last_name: objectToEdit?.last_name ?? "",
|
||||||
|
// address: objectToEdit?.address ?? "",
|
||||||
|
// birthday: objectToEdit?.birthday ?? "",
|
||||||
|
// city: objectToEdit?.city ?? "",
|
||||||
|
grade_id: objectToEdit?.grade_id ,
|
||||||
|
// image: objectToEdit?.image ?? "",
|
||||||
|
sex: objectToEdit?.sex ,
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchema = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
39
src/Pages/Student/Page.tsx
Normal file
39
src/Pages/Student/Page.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useDeleteStudent } from "../../api/student";
|
||||||
|
|
||||||
|
const Table = lazy(() => import("./Table"));
|
||||||
|
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
||||||
|
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
|
const DeleteModalForm = lazy(
|
||||||
|
() => import("../../Layout/Dashboard/DeleteModels"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const deleteMutation = useDeleteStudent();
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.student`));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<header>
|
||||||
|
<h6>{t("models.student")}</h6>
|
||||||
|
</header>
|
||||||
|
<Table />
|
||||||
|
<AddModalForm />
|
||||||
|
<EditModalForm />
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.STUDENT_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
13
src/Pages/Student/Table.tsx
Normal file
13
src/Pages/Student/Table.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useGetAllStudent } from "../../api/student";
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const response = useGetAllStudent({ pagination: true });
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
||||||
101
src/Pages/Student/useTableColumns.tsx
Normal file
101
src/Pages/Student/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { Student } from "../../types/Student";
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import useModalHandler from "../../utils/useModalHandler";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
canAddStudent,
|
||||||
|
canDeleteStudent,
|
||||||
|
canEditStudent,
|
||||||
|
canShowStudent,
|
||||||
|
} from "../../utils/hasAbilityFn";
|
||||||
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
|
||||||
|
export const useColumns = () => {
|
||||||
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handelShow = (record: Student) => {
|
||||||
|
navigate(`${record?.user_id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handelDelete = (data: Student) => {
|
||||||
|
setObjectToEdit(data);
|
||||||
|
handel_open_model(ModalEnum?.STUDENT_DELETE);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (record: Student) => {
|
||||||
|
setObjectToEdit(record);
|
||||||
|
handel_open_model(ModalEnum?.STUDENT_EDIT);
|
||||||
|
};
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const columns: TableColumnsType<Student> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.user_id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.first_name")}`,
|
||||||
|
dataIndex: "first_name",
|
||||||
|
key: "first_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.first_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.last_name")}`,
|
||||||
|
dataIndex: "last_name",
|
||||||
|
key: "last_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.last_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.sex")}`,
|
||||||
|
dataIndex: "sex",
|
||||||
|
key: "sex",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.sex,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
title: canAddStudent ? (
|
||||||
|
<button
|
||||||
|
onClick={() => handel_open_model(ModalEnum?.STUDENT_ADD)}
|
||||||
|
className="add_button"
|
||||||
|
>
|
||||||
|
{t("practical.add")} {t("models.student")} <FaPlus />
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
),
|
||||||
|
|
||||||
|
key: "actions",
|
||||||
|
align: "end",
|
||||||
|
width: "25vw",
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canDeleteStudent}
|
||||||
|
canEdit={canEditStudent}
|
||||||
|
canShow={canShowStudent}
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
onShow={() => handelShow(record)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
@ -12,10 +12,13 @@ import {
|
||||||
} from "@dnd-kit/sortable";
|
} from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { Button, Table } from "antd";
|
import { Button, Table } from "antd";
|
||||||
import type { TableColumnsType } from "antd";
|
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { ParamsEnum } from "../../enums/params";
|
import { ParamsEnum } from "../../enums/params";
|
||||||
import { useGetAllUnit } from "../../api/unit";
|
import { useGetAllUnit, useUpdateUnitOrder } from "../../api/unit";
|
||||||
|
import Loading from "../../Components/DataState/Loading";
|
||||||
|
import EmptyData from "../../Components/DataState/EmptyData";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
|
||||||
interface DataType {
|
interface DataType {
|
||||||
id: string; // Unique identifier for each row
|
id: string; // Unique identifier for each row
|
||||||
|
|
@ -32,7 +35,7 @@ interface RowContextProps {
|
||||||
|
|
||||||
const RowContext = React.createContext<RowContextProps>({});
|
const RowContext = React.createContext<RowContextProps>({});
|
||||||
|
|
||||||
const DragHandle: React.FC = () => {
|
export const DragHandleUnit: React.FC = () => {
|
||||||
const { setActivatorNodeRef, listeners } = useContext(RowContext);
|
const { setActivatorNodeRef, listeners } = useContext(RowContext);
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -46,12 +49,6 @@ const DragHandle: React.FC = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: TableColumnsType<DataType> = [
|
|
||||||
{ key: "sort", align: "center", width: 80, render: () => <DragHandle /> },
|
|
||||||
{ title: "Name", dataIndex: "name" },
|
|
||||||
{ title: "Age", dataIndex: "age" },
|
|
||||||
{ title: "Address", dataIndex: "address" },
|
|
||||||
];
|
|
||||||
|
|
||||||
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
||||||
"data-row-key": string;
|
"data-row-key": string;
|
||||||
|
|
@ -96,13 +93,10 @@ const DrapableTable: React.FC = () => {
|
||||||
response?.data?.data?.map((item: any, index: number) => ({
|
response?.data?.data?.map((item: any, index: number) => ({
|
||||||
id: item.id, // Ensure this is a unique identifier
|
id: item.id, // Ensure this is a unique identifier
|
||||||
order: index + 1, // Assign order based on index
|
order: index + 1, // Assign order based on index
|
||||||
name: item.name,
|
...item
|
||||||
age: item.age,
|
|
||||||
address: item.address,
|
|
||||||
})) ?? [];
|
})) ?? [];
|
||||||
|
|
||||||
const [dataSource, setDataSource] = React.useState<DataType[]>(data);
|
const [dataSource, setDataSource] = React.useState<DataType[]>(data);
|
||||||
console.log(dataSource, "dataSource");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Update dataSource when the fetched data changes
|
// Update dataSource when the fetched data changes
|
||||||
|
|
@ -110,28 +104,51 @@ const DrapableTable: React.FC = () => {
|
||||||
setDataSource(sortedData);
|
setDataSource(sortedData);
|
||||||
}, [response?.data?.data]);
|
}, [response?.data?.data]);
|
||||||
|
|
||||||
|
const {mutate:orderUnit} = useUpdateUnitOrder({},{
|
||||||
|
retry:false
|
||||||
|
})
|
||||||
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
||||||
if (active.id !== over?.id) {
|
if (active.id !== over?.id) {
|
||||||
setDataSource((prevState) => {
|
setDataSource((prevState) => {
|
||||||
const activeIndex = prevState.findIndex(
|
const activeIndex = prevState.findIndex(
|
||||||
(record) => record.id === active.id,
|
(record) => record.id === active.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const overIndex = prevState.findIndex(
|
const overIndex = prevState.findIndex(
|
||||||
|
//@ts-ignore
|
||||||
(record) => record.id === over.id,
|
(record) => record.id === over.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Move the items in the array
|
// Move the items in the array
|
||||||
const newState = arrayMove(prevState, activeIndex, overIndex);
|
const newState = arrayMove(prevState, activeIndex, overIndex);
|
||||||
|
const orderedNewState = newState.map((item, index) => ({
|
||||||
// Update the order based on the new positions
|
|
||||||
return newState.map((item, index) => ({
|
|
||||||
...item,
|
...item,
|
||||||
order: index + 1, // Update the order based on the new index
|
order: index + 1, // Update the order based on the new index
|
||||||
}));
|
}));
|
||||||
|
// Update the order based on the new positions
|
||||||
|
const orderedNewStateWithNewChape = orderedNewState?.map((item:any)=>{
|
||||||
|
return {
|
||||||
|
"unit_id":item?.id,
|
||||||
|
"order":item?.order
|
||||||
|
}
|
||||||
|
})
|
||||||
|
orderUnit({units: orderedNewStateWithNewChape, _method:"PUT"})
|
||||||
|
return orderedNewState
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRowClassName = (record: any, index: number): string => {
|
||||||
|
return index % 2 === 0 ? "even-row" : "odd-row";
|
||||||
|
};
|
||||||
|
const isRefetching = response?.isRefetching;
|
||||||
|
const [t] = useTranslation()
|
||||||
|
const columns = useColumns();
|
||||||
|
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order) ;
|
||||||
|
console.log(sortedDataSource,"sortedDataSource");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
|
|
@ -141,9 +158,26 @@ const DrapableTable: React.FC = () => {
|
||||||
<Table
|
<Table
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
components={{ body: { row: Row } }}
|
components={{ body: { row: Row } }}
|
||||||
|
//@ts-ignore
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={dataSource.sort((a, b) => a.order - b.order)} // Sort by order for rendering
|
dataSource={sortedDataSource}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
rowClassName={(record, index) => getRowClassName(record, index)}
|
||||||
|
className="DataTable"
|
||||||
|
loading={{
|
||||||
|
spinning: response?.isLoading || isRefetching,
|
||||||
|
indicator: <Loading />,
|
||||||
|
size: "large",
|
||||||
|
}}
|
||||||
|
locale={{
|
||||||
|
emptyText: (
|
||||||
|
<EmptyData
|
||||||
|
loading={response?.isLoading}
|
||||||
|
header={t("Table.header")}
|
||||||
|
info={t("Table.info")}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ const Form = () => {
|
||||||
placeholder="term"
|
placeholder="term"
|
||||||
label="term"
|
label="term"
|
||||||
option={termsArray}
|
option={termsArray}
|
||||||
|
fieldNames={{label:"label",value:"value"}}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const TableHeader = () => {
|
||||||
<header>
|
<header>
|
||||||
<h6>{t("models.units")}</h6>
|
<h6>{t("models.units")}</h6>
|
||||||
</header>
|
</header>
|
||||||
<Table />
|
<DrapableTable />
|
||||||
<AddModalForm />
|
<AddModalForm />
|
||||||
<EditModalForm />
|
<EditModalForm />
|
||||||
<DeleteModalForm
|
<DeleteModalForm
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
} from "../../utils/hasAbilityFn";
|
} from "../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../Components/Table/ActionButtons";
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
import { Unit } from "../../types/Unit";
|
import { Unit } from "../../types/Unit";
|
||||||
|
import { DragHandleUnit } from "./DrapableTable";
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
|
|
@ -40,6 +40,7 @@ export const useColumns = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
||||||
const columns: TableColumnsType<Unit> = [
|
const columns: TableColumnsType<Unit> = [
|
||||||
|
{ key: "sort", align: "center", width: 80, render: () => <DragHandleUnit /> },
|
||||||
{
|
{
|
||||||
title: t("columns.id"),
|
title: t("columns.id"),
|
||||||
dataIndex: "id",
|
dataIndex: "id",
|
||||||
|
|
@ -60,7 +61,13 @@ export const useColumns = () => {
|
||||||
dataIndex: "term",
|
dataIndex: "term",
|
||||||
key: "term",
|
key: "term",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (text, record) => record?.term,
|
render: (text, record) => {
|
||||||
|
console.log(record);
|
||||||
|
|
||||||
|
return (
|
||||||
|
record?.term
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
185
src/Pages/lesson/DrapableTable.tsx
Normal file
185
src/Pages/lesson/DrapableTable.tsx
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
import React, { useContext, useEffect, useMemo } from "react";
|
||||||
|
import { HolderOutlined } from "@ant-design/icons";
|
||||||
|
import type { DragEndEvent } from "@dnd-kit/core";
|
||||||
|
import { DndContext } from "@dnd-kit/core";
|
||||||
|
import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities";
|
||||||
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
||||||
|
import {
|
||||||
|
arrayMove,
|
||||||
|
SortableContext,
|
||||||
|
useSortable,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
} from "@dnd-kit/sortable";
|
||||||
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
import { Button, Table } from "antd";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { ParamsEnum } from "../../enums/params";
|
||||||
|
import { useGetAllLesson, useUpdateLessonOrder } from "../../api/lesson";
|
||||||
|
import Loading from "../../Components/DataState/Loading";
|
||||||
|
import EmptyData from "../../Components/DataState/EmptyData";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
|
||||||
|
interface DataType {
|
||||||
|
id: string; // Unique identifier for each row
|
||||||
|
order: number;
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RowContextProps {
|
||||||
|
setActivatorNodeRef?: (element: HTMLElement | null) => void;
|
||||||
|
listeners?: SyntheticListenerMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RowContext = React.createContext<RowContextProps>({});
|
||||||
|
|
||||||
|
export const DragHandleLesson: React.FC = () => {
|
||||||
|
const { setActivatorNodeRef, listeners } = useContext(RowContext);
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<HolderOutlined />}
|
||||||
|
style={{ cursor: "move" }}
|
||||||
|
ref={setActivatorNodeRef}
|
||||||
|
{...listeners}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
||||||
|
"data-row-key": string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row: React.FC<RowProps> = (props) => {
|
||||||
|
const {
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
setActivatorNodeRef,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
isDragging,
|
||||||
|
} = useSortable({ id: props["data-row-key"] });
|
||||||
|
|
||||||
|
const style: React.CSSProperties = {
|
||||||
|
...props.style,
|
||||||
|
transform: CSS.Translate.toString(transform),
|
||||||
|
transition,
|
||||||
|
...(isDragging ? { position: "relative", zIndex: 9999 } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const contextValue = useMemo<RowContextProps>(
|
||||||
|
() => ({ setActivatorNodeRef, listeners }),
|
||||||
|
[setActivatorNodeRef, listeners],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RowContext.Provider value={contextValue}>
|
||||||
|
<tr {...props} ref={setNodeRef} style={style} {...attributes} />
|
||||||
|
</RowContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DrapableTable: React.FC = () => {
|
||||||
|
const { subject_id } = useParams<ParamsEnum>();
|
||||||
|
const response = useGetAllLesson({ subject_id: subject_id, pagination: false });
|
||||||
|
|
||||||
|
// Assuming the response contains a unique id for each item
|
||||||
|
const data =
|
||||||
|
response?.data?.data?.map((item: any, index: number) => ({
|
||||||
|
id: item.id, // Ensure this is a unique identifier
|
||||||
|
order: index + 1, // Assign order based on index
|
||||||
|
...item
|
||||||
|
})) ?? [];
|
||||||
|
|
||||||
|
const [dataSource, setDataSource] = React.useState<DataType[]>(data);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Update dataSource when the fetched data changes
|
||||||
|
const sortedData = data.sort((a: any, b: any) => a.order - b.order);
|
||||||
|
setDataSource(sortedData);
|
||||||
|
}, [response?.data?.data]);
|
||||||
|
|
||||||
|
const {mutate:orderLesson} = useUpdateLessonOrder()
|
||||||
|
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
||||||
|
if (active.id !== over?.id) {
|
||||||
|
setDataSource((prevState) => {
|
||||||
|
const activeIndex = prevState.findIndex(
|
||||||
|
(record) => record.id === active.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
const overIndex = prevState.findIndex(
|
||||||
|
//@ts-ignore
|
||||||
|
(record) => record.id === over.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Move the items in the array
|
||||||
|
const newState = arrayMove(prevState, activeIndex, overIndex);
|
||||||
|
const orderedNewState = newState.map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
order: index + 1, // Update the order based on the new index
|
||||||
|
}));
|
||||||
|
// Update the order based on the new positions
|
||||||
|
const orderedNewStateWithNewChape = orderedNewState?.map((item:any)=>{
|
||||||
|
return {
|
||||||
|
"lesson_id":item?.id,
|
||||||
|
"order":item?.order
|
||||||
|
}
|
||||||
|
})
|
||||||
|
orderLesson({lessons: orderedNewStateWithNewChape, _method:"PUT"})
|
||||||
|
return orderedNewState
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRowClassName = (record: any, index: number): string => {
|
||||||
|
return index % 2 === 0 ? "even-row" : "odd-row";
|
||||||
|
};
|
||||||
|
const isRefetching = response?.isRefetching;
|
||||||
|
const [t] = useTranslation()
|
||||||
|
const columns = useColumns();
|
||||||
|
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order) ;
|
||||||
|
console.log(sortedDataSource,"sortedDataSource");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||||
|
<SortableContext
|
||||||
|
items={dataSource.map((i) => i.id)}
|
||||||
|
strategy={verticalListSortingStrategy}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
components={{ body: { row: Row } }}
|
||||||
|
//@ts-ignore
|
||||||
|
columns={columns}
|
||||||
|
dataSource={sortedDataSource}
|
||||||
|
pagination={false}
|
||||||
|
rowClassName={(record, index) => getRowClassName(record, index)}
|
||||||
|
className="DataTable"
|
||||||
|
loading={{
|
||||||
|
spinning: response?.isLoading || isRefetching,
|
||||||
|
indicator: <Loading />,
|
||||||
|
size: "large",
|
||||||
|
}}
|
||||||
|
locale={{
|
||||||
|
emptyText: (
|
||||||
|
<EmptyData
|
||||||
|
loading={response?.isLoading}
|
||||||
|
header={t("Table.header")}
|
||||||
|
info={t("Table.info")}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SortableContext>
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DrapableTable;
|
||||||
|
|
@ -12,14 +12,14 @@ import { useModalState } from "../../../zustand/Modal";
|
||||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
|
||||||
const AddModel: React.FC = () => {
|
const AddModel: React.FC = () => {
|
||||||
const { isOpen, setIsOpen } = useModalState((state) => state);
|
const { setIsOpen } = useModalState((state) => state);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { mutate, isSuccess, status } = useAddLesson();
|
const { mutate, isSuccess, status } = useAddLesson();
|
||||||
const { OldObjectToEdit } = useObjectToEdit();
|
const { OldObjectToEdit } = useObjectToEdit();
|
||||||
const { unit_id } = useParams<ParamsEnum>();
|
const { unit_id } = useParams<ParamsEnum>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
setIsOpen("");
|
setIsOpen("isSuccess");
|
||||||
queryClient.invalidateQueries(["Lesson"]);
|
queryClient.invalidateQueries(["Lesson"]);
|
||||||
}
|
}
|
||||||
}, [setIsOpen, isSuccess, queryClient]);
|
}, [setIsOpen, isSuccess, queryClient]);
|
||||||
|
|
@ -40,8 +40,9 @@ const AddModel: React.FC = () => {
|
||||||
ModelEnum={ModalEnum.LESSON_ADD}
|
ModelEnum={ModalEnum.LESSON_ADD}
|
||||||
modelTitle="lesson"
|
modelTitle="lesson"
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
getInitialValues={getInitialValues({})}
|
getInitialValues={getInitialValues({name:null})}
|
||||||
getValidationSchema={getValidationSchema}
|
getValidationSchema={getValidationSchema}
|
||||||
|
width="40vw"
|
||||||
>
|
>
|
||||||
<ModelForm />
|
<ModelForm />
|
||||||
</LayoutModel>
|
</LayoutModel>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const ModalForm: React.FC = () => {
|
||||||
const { isOpen, setIsOpen } = useModalState((state) => state);
|
const { isOpen, setIsOpen } = useModalState((state) => state);
|
||||||
|
|
||||||
const { mutate, isSuccess, status } = useUpdateLesson();
|
const { mutate, isSuccess, status } = useUpdateLesson();
|
||||||
const { objectToEdit, setObjectToEdit } = useObjectToEdit();
|
const { objectToEdit } = useObjectToEdit();
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
|
@ -43,6 +43,7 @@ const ModalForm: React.FC = () => {
|
||||||
getInitialValues={getInitialValues(objectToEdit)}
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
getValidationSchema={getValidationSchema}
|
getValidationSchema={getValidationSchema}
|
||||||
isAddModal={false}
|
isAddModal={false}
|
||||||
|
width="40vw"
|
||||||
>
|
>
|
||||||
<ModelForm />
|
<ModelForm />
|
||||||
</LayoutModel>
|
</LayoutModel>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
|
|
||||||
export const getInitialValues = (objectToEdit: any): any => {
|
export const getInitialValues = (objectToEdit: any): any => {
|
||||||
|
console.log(objectToEdit,"objectToEdit");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: objectToEdit?.id ?? null,
|
id: objectToEdit?.id ?? null,
|
||||||
name: objectToEdit?.name ?? "",
|
name: objectToEdit?.name ?? null,
|
||||||
unit_id: objectToEdit?.term ?? null,
|
unit_id: objectToEdit?.term ?? null,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { useGetAllGrade } from "../../api/grade";
|
||||||
import { useGetAllCurriculum } from "../../api/curriculum";
|
import { useGetAllCurriculum } from "../../api/curriculum";
|
||||||
import { useGetAllSubject } from "../../api/subject";
|
import { useGetAllSubject } from "../../api/subject";
|
||||||
|
|
||||||
const Table = lazy(() => import("./Table"));
|
const Table = lazy(() => import("./DrapableTable"));
|
||||||
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
||||||
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
const DeleteModelsForm = lazy(
|
const DeleteModelsForm = lazy(
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
canShowLesson,
|
canShowLesson,
|
||||||
} from "../../utils/hasAbilityFn";
|
} from "../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../Components/Table/ActionButtons";
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
import { DragHandleLesson } from "./DrapableTable";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
@ -37,6 +38,7 @@ export const useColumns = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
||||||
const columns: TableColumnsType<Lesson> = [
|
const columns: TableColumnsType<Lesson> = [
|
||||||
|
{ key: "sort", align: "center", width: 80, render: () => <DragHandleLesson /> },
|
||||||
{
|
{
|
||||||
title: t("columns.id"),
|
title: t("columns.id"),
|
||||||
dataIndex: "id",
|
dataIndex: "id",
|
||||||
|
|
|
||||||
33
src/Pages/studentPackage/Model/AddModel.tsx
Normal file
33
src/Pages/studentPackage/Model/AddModel.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { useAddStudentPackage } from "../../../api/StudentPackage";
|
||||||
|
|
||||||
|
const AddModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useAddStudentPackage();
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
mutate({
|
||||||
|
...values,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.STUDENT_PACKAGE_ADD}
|
||||||
|
modelTitle="StudentPackage"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues({})}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
38
src/Pages/studentPackage/Model/EditModel.tsx
Normal file
38
src/Pages/studentPackage/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
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 { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
import { useUpdateStudentPackage } from "../../../api/StudentPackage";
|
||||||
|
import { handelImageState } from "../../../utils/DataToSendImageState";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useUpdateStudentPackage();
|
||||||
|
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const Data_to_send = { ...values };
|
||||||
|
const handelImage = handelImageState(Data_to_send, "icon");
|
||||||
|
mutate(handelImage);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.STUDENT_PACKAGE_EDIT}
|
||||||
|
modelTitle="StudentPackage"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
isAddModal={false}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
71
src/Pages/studentPackage/Model/ModelForm.tsx
Normal file
71
src/Pages/studentPackage/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
||||||
|
import { useGetAllPackage } from "../../../api/package";
|
||||||
|
import { useValidationValidationParamState } from "../../../Components/ValidationField/state/ValidationValidationParamState";
|
||||||
|
import { useGetAllStudent } from "../../../api/student";
|
||||||
|
|
||||||
|
const Form = () => {
|
||||||
|
|
||||||
|
const { ValidationParamState } = useValidationValidationParamState();
|
||||||
|
const {
|
||||||
|
PackageName, PackageCurrentPage,
|
||||||
|
StudentName, StudentCurrentPage,
|
||||||
|
} = ValidationParamState;
|
||||||
|
|
||||||
|
|
||||||
|
/// Package_id
|
||||||
|
const { data: Package, isLoading: isLoadingPackage } = useGetAllPackage({
|
||||||
|
name: PackageName,
|
||||||
|
page: PackageCurrentPage
|
||||||
|
});
|
||||||
|
const PackageOption = Package?.data ?? []
|
||||||
|
const canChangePackagePage = !!Package?.links?.next;
|
||||||
|
const PackagePage = Package?.meta?.currentPage;
|
||||||
|
|
||||||
|
|
||||||
|
/// Student_id
|
||||||
|
const { data: Student, isLoading: isLoadingStudent } = useGetAllStudent({
|
||||||
|
name: StudentName,
|
||||||
|
page: StudentCurrentPage
|
||||||
|
});
|
||||||
|
const StudentOption = Student?.data ?? []
|
||||||
|
const canChangeStudentPage = !!Student?.links?.next;
|
||||||
|
const StudentPage = Student?.meta?.currentPage;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row className="w-100">
|
||||||
|
<Col>
|
||||||
|
<ValidationField
|
||||||
|
searchBy="StudentName"
|
||||||
|
name="student_id"
|
||||||
|
label="Student"
|
||||||
|
type="Search"
|
||||||
|
option={StudentOption}
|
||||||
|
isLoading={isLoadingStudent}
|
||||||
|
canChangePage={canChangeStudentPage}
|
||||||
|
PageName={"StudentCurrentPage"}
|
||||||
|
page={StudentPage}
|
||||||
|
|
||||||
|
/>
|
||||||
|
<ValidationField
|
||||||
|
searchBy="PackageName"
|
||||||
|
name="package_id"
|
||||||
|
label="Package"
|
||||||
|
type="Search"
|
||||||
|
option={PackageOption}
|
||||||
|
isLoading={isLoadingPackage}
|
||||||
|
canChangePage={canChangePackagePage}
|
||||||
|
PageName={"PackageCurrentPage"}
|
||||||
|
page={PackagePage}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="activation_date" type="Date" />
|
||||||
|
<ValidationField name="expiration_date" type="Date" />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
23
src/Pages/studentPackage/Model/formUtil.ts
Normal file
23
src/Pages/studentPackage/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { StudentPackage, StudentPackageInitialValues } from "../../../types/studentPackage";
|
||||||
|
import { formateDateInitialValue } from "../../../utils/formateDateInitialValue";
|
||||||
|
|
||||||
|
export const getInitialValues = (
|
||||||
|
objectToEdit: Partial<StudentPackage>,
|
||||||
|
): StudentPackageInitialValues => {
|
||||||
|
return {
|
||||||
|
id: objectToEdit?.id ?? null,
|
||||||
|
package_id: objectToEdit?.package?.id ?? null,
|
||||||
|
student_id: objectToEdit?.student?.user_id ?? null,
|
||||||
|
activation_date: formateDateInitialValue(objectToEdit?.activation_date) ,
|
||||||
|
expiration_date: formateDateInitialValue(objectToEdit?.expiration_date) ,
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchema = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
name: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
39
src/Pages/studentPackage/Page.tsx
Normal file
39
src/Pages/studentPackage/Page.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useDeleteStudentPackage } from "../../api/StudentPackage";
|
||||||
|
|
||||||
|
const Table = lazy(() => import("./Table"));
|
||||||
|
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
||||||
|
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
|
const DeleteModalForm = lazy(
|
||||||
|
() => import("../../Layout/Dashboard/DeleteModels"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const deleteMutation = useDeleteStudentPackage();
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.studentPackage`));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<header>
|
||||||
|
<h6>{t("models.StudentPackage")}</h6>
|
||||||
|
</header>
|
||||||
|
<Table />
|
||||||
|
<AddModalForm />
|
||||||
|
<EditModalForm />
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.STUDENT_PACKAGE_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
12
src/Pages/studentPackage/Table.tsx
Normal file
12
src/Pages/studentPackage/Table.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useGetAllStudentPackage } from "../../api/StudentPackage";
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const response = useGetAllStudentPackage({ pagination: true });
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
87
src/Pages/studentPackage/useTableColumns.tsx
Normal file
87
src/Pages/studentPackage/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { StudentPackage } from "../../types/studentPackage";
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import useModalHandler from "../../utils/useModalHandler";
|
||||||
|
import { ModalEnum } from "../../enums/Model";
|
||||||
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ABILITIES_ENUM } from "../../enums/abilities";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
canAddStudentPackage,
|
||||||
|
canDeleteStudentPackage,
|
||||||
|
canEditStudentPackage,
|
||||||
|
canShowStudentPackage,
|
||||||
|
} from "../../utils/hasAbilityFn";
|
||||||
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
import ColumnsImage from "../../Components/Columns/ColumnsImage";
|
||||||
|
|
||||||
|
export const useColumns = () => {
|
||||||
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handelShow = (record: StudentPackage) => {
|
||||||
|
navigate(`${record?.id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handelDelete = (data: StudentPackage) => {
|
||||||
|
setObjectToEdit(data);
|
||||||
|
handel_open_model(ModalEnum?.STUDENT_PACKAGE_DELETE);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (record: StudentPackage) => {
|
||||||
|
setObjectToEdit(record);
|
||||||
|
handel_open_model(ModalEnum?.STUDENT_PACKAGE_EDIT);
|
||||||
|
};
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const columns: TableColumnsType<StudentPackage> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.name")}`,
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: canAddStudentPackage ? (
|
||||||
|
<button
|
||||||
|
onClick={() => handel_open_model(ModalEnum?.STUDENT_PACKAGE_ADD)}
|
||||||
|
className="add_button"
|
||||||
|
>
|
||||||
|
{t("practical.add")} {t("models.StudentPackage")} <FaPlus />
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
),
|
||||||
|
|
||||||
|
key: "actions",
|
||||||
|
align: "end",
|
||||||
|
width: "25vw",
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canDeleteStudentPackage}
|
||||||
|
canEdit={canEditStudentPackage}
|
||||||
|
canShow={canShowStudentPackage}
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
onShow={() => handelShow(record)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { TCrudRoute, TMenuItem } from "./types/App";
|
import { TCrudRoute, TMenuItem } from "./types/App";
|
||||||
import { FaHome, FaMoneyBill } from "react-icons/fa";
|
import { FaHome, FaKey, FaMoneyBill, FaSellcast, FaUserGraduate } from "react-icons/fa";
|
||||||
import { LuPackage } from "react-icons/lu";
|
import { LuPackage } from "react-icons/lu";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
|
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
|
||||||
|
|
@ -10,6 +10,10 @@ const Tags = React.lazy(() => import("./Pages/Tags/Page"));
|
||||||
const Grade = React.lazy(() => import("./Pages/Grade/Page"));
|
const Grade = React.lazy(() => import("./Pages/Grade/Page"));
|
||||||
const Package = React.lazy(() => import("./Pages/Package/Page"));
|
const Package = React.lazy(() => import("./Pages/Package/Page"));
|
||||||
const Curriculum = React.lazy(() => import("./Pages/Curriculum/Page"));
|
const Curriculum = React.lazy(() => import("./Pages/Curriculum/Page"));
|
||||||
|
const PackageItemPage = React.lazy(() => import("./Pages/Package/PackageItem/Page"));
|
||||||
|
const ReSeller = React.lazy(() => import("./Pages/ReSeller/Page"));
|
||||||
|
const StudentPackage = React.lazy(() => import("./Pages/studentPackage/Page"));
|
||||||
|
const Student = React.lazy(() => import("./Pages/Student/Page"));
|
||||||
|
|
||||||
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
|
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
|
||||||
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
|
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
|
||||||
|
|
@ -19,9 +23,15 @@ const EditQuestionPage = React.lazy(() => import("./Pages/question/EditPage"));
|
||||||
const AddPackagePage = React.lazy(() => import("./Pages/Package/Model/AddModel"));
|
const AddPackagePage = React.lazy(() => import("./Pages/Package/Model/AddModel"));
|
||||||
const EditPackagePage = React.lazy(() => import("./Pages/Package/Model/EditModel"));
|
const EditPackagePage = React.lazy(() => import("./Pages/Package/Model/EditModel"));
|
||||||
|
|
||||||
|
|
||||||
|
const AddPackageItemPage = React.lazy(() => import("./Pages/Package/PackageItem/Model/AddModel"));
|
||||||
|
const EditPackageItemPage = React.lazy(() => import("./Pages/Package/PackageItem/Model/EditModel"));
|
||||||
|
|
||||||
import { hasAbility } from "./utils/hasAbility";
|
import { hasAbility } from "./utils/hasAbility";
|
||||||
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities";
|
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities";
|
||||||
import { ParamsEnum } from "./enums/params";
|
import { ParamsEnum } from "./enums/params";
|
||||||
|
import { BsPeople } from "react-icons/bs";
|
||||||
|
import { UserTypeEnum } from "./enums/UserType";
|
||||||
|
|
||||||
export const menuItems: TMenuItem[] = [
|
export const menuItems: TMenuItem[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -33,12 +43,13 @@ export const menuItems: TMenuItem[] = [
|
||||||
abilities: ABILITIES_ENUM?.PASS,
|
abilities: ABILITIES_ENUM?.PASS,
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
|
type:UserTypeEnum?.PASS
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "page_header.grade",
|
header: "page_header.grade",
|
||||||
element: <Grade />,
|
element: <Grade />,
|
||||||
icon: <FaMoneyBill />,
|
icon: <FaUserGraduate />,
|
||||||
text: "sidebar.grade",
|
text: "sidebar.grade",
|
||||||
path: `/${ABILITIES_ENUM?.GRADE}`,
|
path: `/${ABILITIES_ENUM?.GRADE}`,
|
||||||
abilities: ABILITIES_ENUM?.GRADE,
|
abilities: ABILITIES_ENUM?.GRADE,
|
||||||
|
|
@ -68,13 +79,45 @@ export const menuItems: TMenuItem[] = [
|
||||||
{
|
{
|
||||||
header: "page_header.tags",
|
header: "page_header.tags",
|
||||||
element: <Tags />,
|
element: <Tags />,
|
||||||
icon: <FaMoneyBill />,
|
icon: <FaKey />,
|
||||||
text: "sidebar.tags",
|
text: "sidebar.tags",
|
||||||
path: `/${ABILITIES_ENUM?.TAG}`,
|
path: `/${ABILITIES_ENUM?.TAG}`,
|
||||||
abilities: ABILITIES_ENUM?.TAG,
|
abilities: ABILITIES_ENUM?.TAG,
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: "page_header.reSeller",
|
||||||
|
element: <ReSeller />,
|
||||||
|
icon: <FaSellcast />,
|
||||||
|
text: "sidebar.reSeller",
|
||||||
|
path: `/${ABILITIES_ENUM?.RE_SELLER}`,
|
||||||
|
abilities: ABILITIES_ENUM?.RE_SELLER,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
header: "page_header.student",
|
||||||
|
element: <Student />,
|
||||||
|
icon: <FaSellcast />,
|
||||||
|
text: "sidebar.student",
|
||||||
|
path: `/${ABILITIES_ENUM?.STUDENT}`,
|
||||||
|
abilities: ABILITIES_ENUM?.STUDENT,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "page_header.studentPackage",
|
||||||
|
element: <StudentPackage />,
|
||||||
|
icon: <BsPeople />,
|
||||||
|
text: "sidebar.studentPackage",
|
||||||
|
path: `/${ABILITIES_ENUM?.STUDENT_PACKAGE}`,
|
||||||
|
abilities: ABILITIES_ENUM?.STUDENT_PACKAGE,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 0,
|
||||||
|
type:UserTypeEnum.RE_SELLER
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const CrudRoute: TCrudRoute[] = [
|
export const CrudRoute: TCrudRoute[] = [
|
||||||
|
|
@ -143,16 +186,44 @@ export const CrudRoute: TCrudRoute[] = [
|
||||||
path: `/${ABILITIES_ENUM?.Package}/add`,
|
path: `/${ABILITIES_ENUM?.Package}/add`,
|
||||||
abilities: ABILITIES_ENUM?.Package,
|
abilities: ABILITIES_ENUM?.Package,
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "page_header.edit_package",
|
header: "page_header.edit_package",
|
||||||
element: <EditPackagePage />,
|
element: <EditPackagePage />,
|
||||||
path: `/${ABILITIES_ENUM?.Package}/add`,
|
path: `/${ABILITIES_ENUM?.Package}/:${ParamsEnum?.PACKAGE_ID}`,
|
||||||
abilities: ABILITIES_ENUM?.Package,
|
abilities: ABILITIES_ENUM?.Package,
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 1,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
header: "page_header.package_item",
|
||||||
|
element: <PackageItemPage />,
|
||||||
|
path: `/${ABILITIES_ENUM?.Package}/:${ParamsEnum?.PACKAGE_ID}/${ABILITIES_ENUM?.PACKAGE_ITEM}`,
|
||||||
|
abilities: ABILITIES_ENUM?.PACKAGE_ITEM,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
header: "page_header.add_package_item",
|
||||||
|
element: <AddPackageItemPage />,
|
||||||
|
path: `/${ABILITIES_ENUM?.Package}/:${ParamsEnum?.PACKAGE_ID}/${ABILITIES_ENUM?.PACKAGE_ITEM}/add`,
|
||||||
|
abilities: ABILITIES_ENUM?.PACKAGE_ITEM,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "page_header.edit_package_item",
|
||||||
|
element: <EditPackageItemPage />,
|
||||||
|
path: `/${ABILITIES_ENUM?.Package}/:${ParamsEnum?.PACKAGE_ID}/${ABILITIES_ENUM?.PACKAGE_ITEM}/:${ParamsEnum?.PACKAGE_ITEM_ID}`,
|
||||||
|
abilities: ABILITIES_ENUM?.PACKAGE_ITEM,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 1,
|
||||||
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const AppRoutes: Record<string, string> = Object.fromEntries(
|
export const AppRoutes: Record<string, string> = Object.fromEntries(
|
||||||
|
|
|
||||||
9
src/Styles/Pages/Map.scss
Normal file
9
src/Styles/Pages/Map.scss
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.MapInputs{
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.leaflet-right{
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
.exercise_add_main {
|
.exercise_add_main {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
padding: 2vw;
|
padding: 2vw;
|
||||||
}
|
};
|
||||||
.exercise_add_buttons {
|
.exercise_add_buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2%;
|
gap: 2%;
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
|
|
||||||
.add_new_button {
|
.add_new_button {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
color: var(--primary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tags {
|
.tags {
|
||||||
|
|
@ -125,3 +126,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.add_new_button{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
svg{
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,3 +10,4 @@
|
||||||
@import "./subject.scss";
|
@import "./subject.scss";
|
||||||
@import "./Marks.scss";
|
@import "./Marks.scss";
|
||||||
@import "./exercise.scss";
|
@import "./exercise.scss";
|
||||||
|
@import './Map.scss';
|
||||||
21
src/api/ReSeller.ts
Normal file
21
src/api/ReSeller.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import useAddMutation from "./helper/useAddMutation";
|
||||||
|
import useDeleteMutation from "./helper/useDeleteMutation";
|
||||||
|
import useGetQuery from "./helper/useGetQuery";
|
||||||
|
import useUpdateMutation from "./helper/useUpdateMutation";
|
||||||
|
|
||||||
|
const API = {
|
||||||
|
GET: "/reseller",
|
||||||
|
ADD: "/reseller",
|
||||||
|
DELETE: "/reseller",
|
||||||
|
UPDATE: "/reseller",
|
||||||
|
};
|
||||||
|
|
||||||
|
const KEY = "ReSeller";
|
||||||
|
|
||||||
|
export const useGetAllReSeller = (params?: any, options?: any) =>
|
||||||
|
useGetQuery(KEY, API.GET, params, options);
|
||||||
|
export const useAddReSeller = () => useAddMutation(KEY, API.ADD);
|
||||||
|
export const useUpdateReSeller = (params?: any) =>
|
||||||
|
useUpdateMutation(KEY, API.GET);
|
||||||
|
export const useDeleteReSeller = (params?: any) =>
|
||||||
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
21
src/api/StudentPackage.ts
Normal file
21
src/api/StudentPackage.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import useAddMutation from "./helper/useAddMutation";
|
||||||
|
import useDeleteMutation from "./helper/useDeleteMutation";
|
||||||
|
import useGetQuery from "./helper/useGetQuery";
|
||||||
|
import useUpdateMutation from "./helper/useUpdateMutation";
|
||||||
|
|
||||||
|
const API = {
|
||||||
|
GET: "/resellers/studentPackage",
|
||||||
|
ADD: "/resellers/studentPackage",
|
||||||
|
DELETE: "/resellers/studentPackage",
|
||||||
|
UPDATE: "/resellers/studentPackage",
|
||||||
|
};
|
||||||
|
|
||||||
|
const KEY = "StudentPackage";
|
||||||
|
|
||||||
|
export const useGetAllStudentPackage = (params?: any, options?: any) =>
|
||||||
|
useGetQuery(KEY, API.GET, params, options);
|
||||||
|
export const useAddStudentPackage = () => useAddMutation(KEY, API.ADD);
|
||||||
|
export const useUpdateStudentPackage = (params?: any) =>
|
||||||
|
useUpdateMutation(KEY, API.GET);
|
||||||
|
export const useDeleteStudentPackage = (params?: any) =>
|
||||||
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export const BaseURL = "http://127.0.0.1:8000/api/";
|
export const BaseURL = "https://nerd-back.point-dev.net/api/";
|
||||||
// export const BaseURL = "http://127.0.0.1:8000/api/";
|
// export const BaseURL = "http://127.0.0.1:8000/api/";
|
||||||
|
|
||||||
// export const BaseURL = "http://192.168.1.120:8000/api/";
|
// export const BaseURL = "http://192.168.1.120:8000/api/";
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ function useAddMutation(
|
||||||
key: string,
|
key: string,
|
||||||
url: string,
|
url: string,
|
||||||
toast: boolean = true,
|
toast: boolean = true,
|
||||||
|
params: any = {},
|
||||||
|
options: any = {},
|
||||||
): UseMutationResult<AxiosResponse, unknown, any, unknown> {
|
): UseMutationResult<AxiosResponse, unknown, any, unknown> {
|
||||||
const axios = useAxios();
|
const axios = useAxios();
|
||||||
return useMutation<AxiosResponse, unknown, any, unknown>(
|
return useMutation<AxiosResponse, unknown, any, unknown>(
|
||||||
|
|
@ -20,9 +22,12 @@ function useAddMutation(
|
||||||
["X-Custom-Message"]: toast,
|
["X-Custom-Message"]: toast,
|
||||||
[HEADER_KEY]: key,
|
[HEADER_KEY]: key,
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
options,
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const API = {
|
||||||
ADD: "/lesson",
|
ADD: "/lesson",
|
||||||
DELETE: "/lesson",
|
DELETE: "/lesson",
|
||||||
UPDATE: "/lesson",
|
UPDATE: "/lesson",
|
||||||
|
ORDER: "/lesson/order",
|
||||||
};
|
};
|
||||||
|
|
||||||
const KEY = "lesson";
|
const KEY = "lesson";
|
||||||
|
|
@ -19,3 +20,5 @@ export const useUpdateLesson = (params?: any) =>
|
||||||
useUpdateMutation(KEY, API.GET);
|
useUpdateMutation(KEY, API.GET);
|
||||||
export const useDeleteLesson = (params?: any) =>
|
export const useDeleteLesson = (params?: any) =>
|
||||||
useDeleteMutation(KEY, API.DELETE);
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
|
|
||||||
|
export const useUpdateLessonOrder = (params?: any) => useAddMutation("karim", API.ORDER);
|
||||||
|
|
|
||||||
20
src/api/packageItem.ts
Normal file
20
src/api/packageItem.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import useAddMutation from "./helper/useAddMutation";
|
||||||
|
import useDeleteMutation from "./helper/useDeleteMutation";
|
||||||
|
import useGetQuery from "./helper/useGetQuery";
|
||||||
|
import useUpdateMutation from "./helper/useUpdateMutation";
|
||||||
|
|
||||||
|
const API = {
|
||||||
|
GET: "/packageItem",
|
||||||
|
ADD: "/packageItem",
|
||||||
|
DELETE: "/packageItem",
|
||||||
|
UPDATE: "/packageItem",
|
||||||
|
};
|
||||||
|
|
||||||
|
const KEY = "PackageItem";
|
||||||
|
|
||||||
|
export const useGetAllPackageItem = (params?: any, options?: any) =>
|
||||||
|
useGetQuery(KEY, API.GET, params, options);
|
||||||
|
export const useAddPackageItem = () => useAddMutation(KEY, API.ADD);
|
||||||
|
export const useUpdatePackageItem = (params?: any) => useUpdateMutation(KEY, API.GET);
|
||||||
|
export const useDeletePackageItem = (params?: any) =>
|
||||||
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
|
|
@ -8,6 +8,7 @@ const API = {
|
||||||
ADD: "/unit",
|
ADD: "/unit",
|
||||||
DELETE: "/unit",
|
DELETE: "/unit",
|
||||||
UPDATE: "/unit",
|
UPDATE: "/unit",
|
||||||
|
ORDER: "/unit/order",
|
||||||
};
|
};
|
||||||
|
|
||||||
const KEY = "unit";
|
const KEY = "unit";
|
||||||
|
|
@ -15,5 +16,6 @@ export const useGetAllUnit = (params?: any, options?: any) =>
|
||||||
useGetQuery(KEY, API.GET, params, options);
|
useGetQuery(KEY, API.GET, params, options);
|
||||||
export const useAddUnit = () => useAddMutation(KEY, API.ADD);
|
export const useAddUnit = () => useAddMutation(KEY, API.ADD);
|
||||||
export const useUpdateUnit = (params?: any) => useUpdateMutation(KEY, API.GET);
|
export const useUpdateUnit = (params?: any) => useUpdateMutation(KEY, API.GET);
|
||||||
|
export const useUpdateUnitOrder = (params?: any,option?: any,) => useAddMutation("karim", API.ORDER,true,params,option);
|
||||||
export const useDeleteUnit = (params?: any) =>
|
export const useDeleteUnit = (params?: any) =>
|
||||||
useDeleteMutation(KEY, API.DELETE);
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export enum DateEnum {
|
export enum DateEnum {
|
||||||
FORMATE = "YYYY-MM-DD",
|
FORMATE = "YYYY-MM-DD",
|
||||||
|
SEND_DATE_FORMAT = "YYYY-MM-DD",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,17 @@ export enum ModalEnum {
|
||||||
|
|
||||||
///package
|
///package
|
||||||
|
|
||||||
Package_EDIT = "Package.edit",
|
PACKAGE_EDIT = "Package.edit",
|
||||||
Package_ADD = "Package.add",
|
PACKAGE_ADD = "Package.add",
|
||||||
Package_DELETE = "Package.delete",
|
PACKAGE_DELETE = "Package.delete",
|
||||||
|
|
||||||
|
/// ReSeller
|
||||||
|
RE_SELLER_EDIT = "ReSeller.edit",
|
||||||
|
RE_SELLER_ADD = "ReSeller.add",
|
||||||
|
RE_SELLER_DELETE = "ReSeller.delete",
|
||||||
|
|
||||||
|
/// studentPackage
|
||||||
|
STUDENT_PACKAGE_EDIT = "studentPackage.edit",
|
||||||
|
STUDENT_PACKAGE_ADD = "studentPackage.add",
|
||||||
|
STUDENT_PACKAGE_DELETE = "studentPackage.delete",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
export enum UserTypeEnum {
|
export enum UserTypeEnum {
|
||||||
ADMIN = "ADMIN",
|
ADMIN = "admin",
|
||||||
RE_SELLER = "RE_SELLER",
|
RE_SELLER = "reseller",
|
||||||
|
PASS="pass"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ export enum ABILITIES_ENUM {
|
||||||
EARLY_DEPARTURE = "earlyDeparture",
|
EARLY_DEPARTURE = "earlyDeparture",
|
||||||
EDUCATION_CLASS = "eduClass",
|
EDUCATION_CLASS = "eduClass",
|
||||||
GRADE = "grade",
|
GRADE = "grade",
|
||||||
Package = "package",
|
Package = "packages",
|
||||||
HOMEWORK_ATTACHMENT = "homeworkAttachment",
|
HOMEWORK_ATTACHMENT = "homeworkAttachment",
|
||||||
HOMEWORK = "homework",
|
HOMEWORK = "homework",
|
||||||
LATE_ARRIVAL = "lateArrival",
|
LATE_ARRIVAL = "lateArrival",
|
||||||
|
|
@ -43,6 +43,9 @@ export enum ABILITIES_ENUM {
|
||||||
QUESTION = "Question",
|
QUESTION = "Question",
|
||||||
ADMIN = "admin",
|
ADMIN = "admin",
|
||||||
CURRICULUM = "curriculum",
|
CURRICULUM = "curriculum",
|
||||||
|
PACKAGE_ITEM = "package_item",
|
||||||
|
RE_SELLER = "ReSeller",
|
||||||
|
STUDENT_PACKAGE='studentPackage'
|
||||||
////
|
////
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user