add_setting

This commit is contained in:
karimaldeen 2024-06-03 17:29:06 +03:00
parent 09022c9aef
commit 5f67441d9d
113 changed files with 2005 additions and 2075 deletions

View File

@ -1,6 +1,7 @@
{ {
"cSpell.words": [ "cSpell.words": [
"aldeen", "aldeen",
"antd",
"Datepicker", "Datepicker",
"formik", "formik",
"Karim", "Karim",

View File

@ -10,6 +10,7 @@
<title>E-Menu - App</title> <title>E-Menu - App</title>
</head> </head>
<script type="module" src="/src/index.tsx"></script>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@ -4,85 +4,48 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.8.3", "@ant-design/icons": "^4.8.3",
"@emotion/styled": "^11.11.0", "@types/node": "^16.18.97",
"@mui/icons-material": "^5.14.19", "@types/react": "^18.3.3",
"@mui/x-charts": "^6.19.4", "@types/react-dom": "^18.3.0",
"@react-google-maps/api": "^2.19.2", "antd": "^5.17.4",
"@szhsin/react-menu": "github:szhsin/react-menu", "apexcharts": "^3.49.1",
"@testing-library/jest-dom": "^5.17.0", "axios": "^1.7.2",
"@testing-library/react": "^13.4.0", "bootstrap": "^5.3.3",
"@testing-library/user-event": "^13.5.0", "chart.js": "^4.4.3",
"@tinymce/tinymce-react": "^4.3.2", "dayjs": "^1.11.11",
"@types/jest": "^27.5.2", "formik": "^2.4.6",
"@types/node": "^16.18.60", "i18next": "^23.11.5",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"@types/socket.io-client": "^3.0.0",
"@wojtekmaj/react-daterange-picker": "^5.4.4",
"antd": "^5.12.1",
"apexcharts": "^3.44.2",
"axios": "^1.6.0",
"bootstrap": "^5.3.2",
"chart.js": "^4.4.0",
"dayjs": "^1.11.10",
"formik": "^2.4.5",
"google-map-react": "^2.2.1",
"history": "^5.3.0",
"i18next": "^23.6.0",
"i18next-browser-languagedetector": "^7.1.0",
"json-server": "^0.17.4",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"moment": "^2.30.1", "react": "^18.3.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1", "react-apexcharts": "^1.4.1",
"react-bootstrap": "^2.9.1", "react-bootstrap": "^2.10.2",
"react-bootstrap-sweetalert": "^5.2.0", "react-bootstrap-sweetalert": "^5.2.0",
"react-chartjs-2": "^5.2.0",
"react-confirm-alert": "^3.0.6", "react-confirm-alert": "^3.0.6",
"react-data-table-component": "^7.5.4", "react-data-table-component": "^7.6.2",
"react-dom": "^18.2.0", "react-dom": "^18.3.1",
"react-feather": "^2.0.10", "react-i18next": "^13.5.0",
"react-i18next": "^13.3.1", "react-icons": "^4.12.0",
"react-icons": "^4.11.0",
"react-input-range": "^1.3.0",
"react-leaflet": "^4.2.1", "react-leaflet": "^4.2.1",
"react-number-format": "^5.3.4", "react-number-format": "^5.4.0",
"react-player": "^2.16.0", "react-player": "^2.16.0",
"react-query": "^3.39.3", "react-query": "^3.39.3",
"react-redux": "^8.1.3", "react-router-dom": "^6.23.1",
"react-router-dom": "^6.18.0", "react-select": "^5.8.0",
"react-scripts": "5.0.1",
"react-select": "^5.7.7",
"react-simple-star-rating": "^5.1.7",
"react-switch": "^7.0.0",
"react-tabs": "^6.0.2", "react-tabs": "^6.0.2",
"react-toastify": "^9.1.3", "react-toastify": "^9.1.3",
"react-toggle": "^4.1.3", "reactstrap": "^9.2.2",
"reactstrap": "^9.2.0", "sass": "^1.77.4",
"redux": "^4.2.1",
"sass": "^1.69.5",
"socket.io-client": "^4.7.2",
"styled-components": "5.3.3",
"ts-xlsx": "^0.0.11",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"xlsx": "^0.18.5", "xlsx": "^0.18.5",
"yup": "^1.3.2", "yup": "^1.4.0",
"zustand": "^4.4.5" "zustand": "^4.5.2"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "vite",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject", "eject": "react-scripts eject"
"g:api": "node src/Extensions/FileGenerator/generateApi.js",
"g:column": "node src/Extensions/FileGenerator/generateColumn.js",
"g:formutil": "node src/Extensions/FileGenerator/generateformUtils.js",
"g:page": "node src/Extensions/FileGenerator/generatePage.js",
"g:dashboard": "node src/Extensions/FileGenerator/generateDashboard.js ",
"g:modal:add": "node src/Extensions/FileGenerator/generateEditModal.js ",
"g:model:edit": "node src/Extensions/FileGenerator/generateEditModal.js "
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [

BIN
public/Layout/images.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -20,7 +20,7 @@ const BlockModel: React.FC<BlockModelProps> = ({Mutation ,type}) => {
const handleSubmit = () => { const handleSubmit = () => {
const blockInput = document.getElementById('block_input') as HTMLInputElement; const blockInput = document.getElementById('block_input') as HTMLInputElement;
if (blockInput) { if (blockInput) {
Mutation.mutate({ [key_to_api]: objectID, block_timer: blockInput.value }); Mutation.mutate({ [key_to_api]: objectID, block_timer: blockvalue });
} }
}; };

View File

@ -24,8 +24,8 @@ const GiftModal: React.FC<GiftModalProps> = ({Mutation ,type }) => {
const handleGift = () => { const handleGift = () => {
const enterCodesInput = document.getElementById('enter_codes') as HTMLInputElement; const enterCodesInput = document.getElementById('enter_codes') as HTMLInputElement;
if (enterCodesInput && enterCodesInput.value) { if (enterCodesInput && enterCodesvalue) {
Mutation.mutate({ type, id: objectID, value: enterCodesInput.value }); Mutation.mutate({ type, id: objectID, value: enterCodesvalue });
} }
}; };

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from "react";
import { Spin } from 'antd'; import { Spin } from "antd";
interface Props { interface Props {
loading: boolean; loading: boolean;
@ -10,7 +10,13 @@ interface Props {
const KarimSpinner: React.FC<Props> = ({ loading, className, children }) => { const KarimSpinner: React.FC<Props> = ({ loading, className, children }) => {
return ( return (
<div className={className ?? ""}> <div className={className ?? ""}>
{loading ? <div className='text-center'><Spin /></div> : children} {loading ? (
<div className="text-center">
<Spin />
</div>
) : (
children
)}
</div> </div>
); );
}; };

View File

@ -6,7 +6,6 @@
position: relative; position: relative;
max-width: 350px; max-width: 350px;
width: 350px; width: 350px;
} }
.input { .input {
@ -21,17 +20,13 @@
color: var(--text); color: var(--text);
border: none; border: none;
box-shadow: 2px 2px 7px 0 var(--bg); box-shadow: 2px 2px 7px 0 var(--bg);
} }
.input::placeholder { .input::placeholder {
color: var(--subtext); color: var(--subtext);
opacity: .4; opacity: 0.4;
} }
.icon { .icon {
position: absolute; position: absolute;
left: 1rem; left: 1rem;
@ -39,10 +34,4 @@
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
} }
} }

View File

@ -1,9 +1,9 @@
import React, { useState } from 'react' import React, { useState } from "react";
import './SearchBar.scss' import "./SearchBar.scss";
import { useNavigate, useSearchParams } from 'react-router-dom'; import { useNavigate, useSearchParams } from "react-router-dom";
const SearchBar = () => { const SearchBar = () => {
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState("");
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams();
const navigate = useNavigate(); const navigate = useNavigate();
const handleChange = (event: any) => { const handleChange = (event: any) => {
@ -13,23 +13,33 @@ const SearchBar = () => {
}; };
const updateUrlParams = (value: any) => { const updateUrlParams = (value: any) => {
navigate(`?search=${value}`); navigate(`?search=${value}`, { replace: true });
}; };
return ( return (
<div className='SearchBar'> <div className="SearchBar">
<div className="group"> <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> <svg
<input placeholder="Search Product...." type="search" 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" className="input"
value={searchQuery} value={searchQuery}
onChange={handleChange} onChange={handleChange}
/> />
</div> </div>
</div> </div>
) );
} };
export default SearchBar export default SearchBar;

View File

@ -1,78 +0,0 @@
.ValidationField{
>*{
width: 100%;
}
.text,.ant-form-item{
margin-bottom:7px !important;
}
>span{
margin-bottom: 0px !important;
&:focus-within{
border-color: var(--primary) ;
box-shadow: 0 0 0 1px var(--primary);
cursor: pointer;
}
&:has(.is-invalid){
border-color: red !important;
}
input{
color: var(--text);
background: var(--bg);
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active{
-webkit-box-shadow: 0 0 0 30px white inset !important;
}
}
}
.ant-upload-select{
width: 100%;
}
.Checkboxs{
padding: 4%;
}
.SearchField{
button{
background: var(--primary);
}
}
.text{
color: var(--text);
}
input:disabled{
color: var(--text) !important;
}
.isError{
outline: red 1px solid;
color: red;
}
.Error_color{
color: red;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
/* Remove autofill background color on hover */
input:-webkit-autofill:hover {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
.ant-upload-list .ant-upload-list-item{
height:78px !important;
}

View File

@ -1,34 +1,46 @@
import React from "react"; import React from "react";
import "./ValidationField.scss"; import "./utils/ValidationField.scss";
import { Date, Time, File, DataRange, SelectField, Default, CheckboxField ,TextAreaField} from './View'; import {
import { ValidationFieldProps } from "./types"; Date,
import MaltyFile from "./View/MaltyFile"; Time,
import SearchField from "./View/SearchField"; File,
DataRange,
SelectField,
Default,
CheckboxField,
MaltyFile,
SearchField,
TextField,
DropFile,
} from "./View";
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
import LocalSearchField from "./View/LocalSearch";
import NumberFormate from "./View/NumberFormate";
const ValidationField: React.FC<ValidationFieldProps> = ({type , ...otherProps}) => { const components: { [key: string]: React.FC<any> } = {
Select: SelectField,
switch (type) { Search: SearchField,
case 'Select': LocalSearch: LocalSearchField,
return <SelectField {...otherProps} />; DataRange: DataRange,
case 'Search': TextArea: TextField,
return <SearchField {...otherProps} />; Date: Date,
case "DataRange": Time: Time,
return <DataRange {...otherProps} />; File: File,
case "Date": DropFile: DropFile,
return <Date {...otherProps} />; MaltyFile: MaltyFile,
case "Time": Checkbox: CheckboxField,
return <Time {...otherProps} />; NumberFormate: NumberFormate,
case "File":
return <File {...otherProps} />;
case "MaltyFile":
return <MaltyFile {...otherProps} />;
case "Checkbox":
return <CheckboxField {...otherProps} />;
case "TextArea":
return <TextAreaField {...otherProps} />;
default:
return <Default {...otherProps} type={type}/>;
}
}; };
export default React.memo(ValidationField); const ValidationField: React.FC<ValidationFieldProps> = React.memo(
({ type, ...otherProps }) => {
const Component = components[type as ValidationFieldType];
if (!Component) {
return <Default {...otherProps} />;
}
return <Component {...otherProps} />;
},
);
export default ValidationField;

View File

@ -1,36 +1,40 @@
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, Form } from "antd";
const CheckboxField = ({ name, label, isDisabled, onChange,Group,className, props }: any) => { const CheckboxField = ({
name,
const { t, formik,isError,errorMsg} = useFormField(name, props) label,
isDisabled,
onChange,
Group,
className,
props,
no_label,
label_icon,
}: any) => {
const { t, formik, isError, errorMsg } = useFormField(name, props);
const CheckboxhandleChange = (value: any) => { const CheckboxhandleChange = (value: any) => {
formik.setFieldValue(name, value?.target?.checked) formik.setFieldValue(name, value?.target?.checked);
}; };
return ( return (
<div className={Group ? "d-inline mt-3 Checkboxs" : ``}> <div className={Group ? "d-inline mt-3 Checkboxs" : ``}>
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? 'error' : ''} validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ''} help={isError ? errorMsg : ""}
> >
<Checkbox <Checkbox
onChange={onChange || CheckboxhandleChange} onChange={onChange || CheckboxhandleChange}
disabled={isDisabled} disabled={isDisabled}
checked={formik.values[name] ?? false} checked={formik.values[name] ?? false}
className={className} className={className}
> >
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</Checkbox> </Checkbox>
</Form.Item> </Form.Item>
</div> </div>
) );
} };
export default CheckboxField export default CheckboxField;

View File

@ -1,24 +1,46 @@
import { Form, DatePicker } from 'antd' 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";
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const DataRange = ({ name, label, Format, props, onChange, isDisabled, placeholder, className }: any) => { const DataRange = ({
name,
const { errorMsg, isError, t, formik } = useFormField(name, props) label,
Format,
props,
onChange,
isDisabled,
placeholder,
className,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const onCalendarChange = (value: any) => { const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
formik.setFieldValue(name, value)
}; };
return ( return (
<div className="ValidationField w-100 ">
<div className='ValidationField'> {no_label ? (
<label htmlFor={name} className="text">
<span>empty</span>
</label>
) : label_icon ? (
<div className="LabelWithIcon">
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? "error" : ""} validateStatus={isError ? "error" : ""}
@ -34,11 +56,9 @@ const DataRange = ({ name, label, Format, props, onChange, isDisabled, placehold
disabled={isDisabled} disabled={isDisabled}
defaultValue={formik.values[name]} defaultValue={formik.values[name]}
/> />
</Form.Item> </Form.Item>
</div> </div>
) );
} };
export default DataRange export default DataRange;

View File

@ -1,32 +1,49 @@
import { Form, DatePicker } from 'antd'; import { Form, DatePicker } from "antd";
import React from 'react'; import React from "react";
import useFormField from '../../../Hooks/useFormField'; import useFormField from "../../../Hooks/useFormField";
import dayjs from 'dayjs'; import { MdOutlineEdit } from "react-icons/md";
import dayjs from "dayjs";
const DateField = ({ name, label, picker = "date", isDisabled, props, onChange, placeholder, className, Format }: any) => {
const Date = ({
name,
label,
picker = "date",
isDisabled,
props,
onChange,
placeholder,
className,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props); const { errorMsg, isError, t, formik } = useFormField(name, props);
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 ");
}; };
// Function to check if a date is valid const Formater = "YYYY/MM/DD";
const isValidDate = (date: any) => {
return date && !isNaN(date.valueOf()) && dayjs(date).isValid();
};
// Set a default invalid date if the provided defaultValue is invalid
const getDefaultDate = () => {
const defaultValue = formik.values[name];
return isValidDate(defaultValue) ? defaultValue : null; // Set to null or any other default invalid date
};
return ( return (
<div className='ValidationField'> <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"> <label htmlFor={name} className="text">
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? "error" : ""} validateStatus={isError ? "error" : ""}
@ -34,18 +51,19 @@ const DateField = ({ name, label, picker = "date", isDisabled, props, onChange,
> >
<DatePicker <DatePicker
picker={picker} picker={picker}
placeholder={placeholder ? t(placeholder) : t(name)} placeholder={t(`${placeholder}`)}
allowClear allowClear
className={`${className} w-100`} className={`${className} w-100`}
defaultValue={getDefaultDate()} value={FormikValue ? FormikValue : null}
size="large" size="large"
onChange={onChange || onCalendarChange} onChange={onChange || onCalendarChange}
disabled={isDisabled} disabled={isDisabled}
format={Format} format={Formater}
/> />
{/* <DatePicker onChange={onChange} /> */}
</Form.Item> </Form.Item>
</div> </div>
); );
} };
export default DateField; export default Date;

View File

@ -1,31 +1,58 @@
import { Form, Input } from 'antd' import { Form, 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";
const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => { import { Field } from "formik";
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
const Default = ({
name,
label,
placeholder,
isDisabled,
onChange,
type,
no_label,
label_icon,
...props
}: any) => {
const { errorMsg, isError, t } = useFormField(name, props);
return ( return (
<div className="ValidationField w-100"> <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"> <label htmlFor={name} className="text">
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : placeholder ? placeholder : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? 'error' : ''} validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ''} help={isError ? errorMsg : ""}
> >
<Field <Field
as={Input} as={Input}
type={type ?? "text"} type={type ?? "text"}
placeholder={t(`${placeholder ?placeholder : name}`)} placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
name={name} name={name}
disabled={isDisabled} disabled={isDisabled}
size="large" size="large"
{...props}
// onChange={onChange ? onChange : handleChange} // onChange={onChange ? onChange : handleChange}
{...(type === "number" && { min: 0 })}
/> />
</Form.Item> </Form.Item>
</div> </div>
@ -33,4 +60,3 @@ const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }:
}; };
export default React.memo(Default); export default React.memo(Default);
;

View File

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

View File

@ -1,34 +1,53 @@
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 { ImageBaseURL } from '../../../api/config';
const File = ({
name,
label,
onChange,
isDisabled,
placholder,
className,
acceptedFileType,
props,
}: any) => {
const { formik, t, isError } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null;
const File = ({ name, label, onChange, isDisabled,placholder,className,acceptedFileType, props }: any) => { const fileList: UploadFile[] = imageUrl
const { formik, t ,isError} = useFormField(name, props) ? [
let FormikName = formik.values[name]; typeof imageUrl === "string"
const imageUrl = formik.values[name] ? ImageBaseURL + FormikName : ''; ? {
uid: "-1",
const fileList: UploadFile[] = [ name: "",
status: "done",
{ url: imageUrl,
uid: '-1', thumbUrl: imageUrl,
name: '',
status: 'done',
url: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage"),
thumbUrl: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage")
} }
]; : {
uid: imageUrl.uid || "-1",
name: imageUrl.name || "",
status: "done",
originFileObj: imageUrl,
},
]
: [];
// console.log(1);
const FilehandleChange = (value: any) => { const FilehandleChange = (value: any) => {
// console.log(value,"filevalue");
formik.setFieldValue(name, value.file.originFileObj) if (value.fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(name, value?.file?.originFileObj);
}
}; };
const customRequest = async ({ onSuccess}: any) => { const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
onSuccess(); onSuccess();
}; };
return ( return (
<div className="ValidationField"> <div className="ValidationField upload_image_button ">
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{t(`${label || name}`)} {t(`${label || name}`)}
</label> </label>
@ -36,28 +55,24 @@ const File = ({ name, label, onChange, isDisabled,placholder,className,acceptedF
<Upload <Upload
disabled={isDisabled} disabled={isDisabled}
listType="picture" listType="picture"
maxCount={1} maxCount={1}
defaultFileList={[...fileList]} fileList={[...fileList]}
onChange={onChange || FilehandleChange} onChange={onChange || FilehandleChange}
customRequest={customRequest} customRequest={customRequest}
className={`${className} w-100`} className={`${className} w-100`}
accept={acceptedFileType ? acceptedFileType : undefined} accept={acceptedFileType ? acceptedFileType : undefined}
> >
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}> <Button
{placholder ?? t("upload_image") } className={isError ? "isError w-100 " : " w-100"}
icon={<UploadOutlined />}
>
{placholder ?? t("Click_to_upload_the_image")}
</Button> </Button>
<div className='Error_color'> {isError ? "required" : ""}</div> <div className="Error_color"> {isError ? "required" : ""}</div>
</Upload> </Upload>
</div> </div>
) );
} };
export default File export default File;

View File

@ -0,0 +1,93 @@
import { Form, Select } from "antd";
import React, { useState } from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import { translateOptions } from "../utils/translatedOptions";
const LocalSelectField = ({
name,
label,
placeholder,
isDisabled,
option,
isMulti,
onChange,
className,
props,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
// State to manage the search input value
const [searchValue, setSearchValue] = useState("");
const handleSearch = (
input: string,
option: { value: string; label: React.ReactNode | undefined },
) =>
option?.label?.toString().toLowerCase().includes(toLowerCase()) ||
option?.value?.toString().toLowerCase().includes(toLowerCase());
const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
formik.setFieldValue(name, value);
};
const handleSelectChange = (value: any) => {
formik.setFieldValue(name, value);
if (onChange) onChange(value);
};
const handleSearchChange = (input: string) => {
setSearchValue(input); // Update the search input value
};
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(`${label ? label : name}`)}
</label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Select
placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
disabled={isDisabled}
options={translateOptions(option, t)}
size="large"
className={`${className} ${isError ? "Select_error" : ""} w-100`}
value={formik.values[name]}
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={handleSelectChange}
showSearch
filterOption={handleSearch} // Custom filter function
searchValue={searchValue} // Control the search input value
onSearch={handleSearchChange} // Update search input value on change
/>
</Form.Item>
</div>
);
};
export default React.memo(LocalSelectField);

View File

@ -1,31 +1,61 @@
import { Button, Upload } from 'antd'; import { Button, Upload } from "antd";
import { UploadOutlined } from '@ant-design/icons'; import { UploadOutlined } from "@ant-design/icons";
import { ImageBaseURL } from '../../../api/config';
import { useTranslation } from 'react-i18next';
import useFormField from '../../../Hooks/useFormField';
const MaltyFile = ({ name, label, onChange, isDisabled, placholder, className, props }: any) => { import useFormField from "../../../Hooks/useFormField";
const MaltyFile = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}: any) => {
const { formik, t, isError } = useFormField(name, props); const { formik, t, isError } = useFormField(name, props);
const imageUrl = formik?.values[name] ? ImageBaseURL + formik.values[name] : ''; let imageUrl = formik?.values?.[name] ?? null;
const fileList = formik?.values[name] ? formik?.values[name]?.map((file: any, index: number) => ({
// Mapping formik values to fileList format
const fileList = imageUrl
? imageUrl.map((file: any, index: number) => {
// console.log(file,"file");
return file instanceof File
? {
uid: index, uid: index,
name: file.name, name: file?.name,
status: 'done', status: "done",
url: file.url || '', originFileObj: file,
thumbUrl: file.url || '', }
})) : []; : {
uid: index,
const FilehandleChange = ({ file, fileList }: any) => { id: file?.id,
formik.setFieldValue(name, fileList.map((file: any) => file.originFileObj)); name: file?.name,
status: "done",
url: file?.url || "",
thumbUrl: file?.url || "",
}; };
})
: [];
const FilehandleChange = ({ fileList }: any) => {
if (fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(
name,
fileList.map((file: any) => file?.originFileObj ?? file),
);
}
};
// Custom request function
const customRequest = async ({ onSuccess }: any) => { const customRequest = async ({ onSuccess }: any) => {
// Perform any necessary actions before onSuccess is called // Perform any necessary actions before onSuccess is called
onSuccess(); onSuccess();
}; };
return ( return (
<div className="ValidationField"> <div className="ValidationField upload_image_button">
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{t(`${label || name}`)} {t(`${label || name}`)}
</label> </label>
@ -33,17 +63,20 @@ const MaltyFile = ({ name, label, onChange, isDisabled, placholder, className, p
<Upload <Upload
disabled={isDisabled} disabled={isDisabled}
listType="picture" listType="picture"
defaultFileList={[...fileList]} fileList={fileList} // Using fileList instead of defaultFileList
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
>
<Button
className={isError ? "isError w-100" : " w-100"}
icon={<UploadOutlined />}
> >
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}> {t(placeholder ?? t("upload_image") )}
{placholder ?? t("upload_image")}
</Button> </Button>
<div className='Error_color'> {isError ? "required" : ""}</div> <div className="Error_color"> {isError ? "required" : ""}</div>
</Upload> </Upload>
</div> </div>
); );

View File

@ -0,0 +1,75 @@
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";
const NumberFormate = ({
name,
label,
placeholder,
isDisabled,
props,
type,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
formik.setFieldValue(name, value);
};
return (
<div className="ValidationField w-100">
{no_label ? (
<label htmlFor={name} className="text">
<span>empty</span>
</label>
) : label_icon ? (
<div className="LabelWithIcon">
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : placeholder ? placeholder : name}`)}
</label>
)}
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Field
as={InputNumber}
formatter={(value: any) =>
`${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
parser={(value: any) =>
value?.replace(/\$\s?|(,*)/g, "") as unknown as number
}
min="0"
type={type ?? "text"}
value={formik.values[name]}
onChange={SelectableChange}
placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
name={name}
disabled={isDisabled}
size="large"
// onChange={onChange ? onChange : handleChange}
/>
</Form.Item>
</div>
);
};
export default React.memo(NumberFormate);

View File

@ -1,65 +1,83 @@
import { Form, Select } from 'antd'; import { Form, Select } 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 { useLocation, useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
import { MdOutlineEdit } from "react-icons/md";
const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, loading,props }: any) => { const SearchField = ({
name,
label,
placeholder,
isDisabled,
searchBy,
option,
isMulti,
onChange,
className,
props,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props); const { errorMsg, isError, t, formik } = useFormField(name, props);
const [searchQuery, setSearchQuery] = useState<string>(''); const [searchQuery, setSearchQuery] = useState<string>("");
const location = useLocation() const navigate = useNavigate();
const navigate = useNavigate()
useEffect(() => { useEffect(() => {
const searchParams = new URLSearchParams(location?.search); const searchParams = new URLSearchParams(window?.location?.search);
setSearchQuery(searchParams?.get('search') || ''); setSearchQuery(searchParams?.get("search") || "");
console.log(searchParams); }, []);
}, [location]); const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
formik?.setFieldValue(name, value); formik?.setFieldValue(name, value);
console.log(value);
}; };
const SearchHandleChange = (value: any) => { const SearchHandleChange = (value: any) => {
if (value || value !== "") { navigate(`${window?.location?.pathname}?${searchBy}=${value}`, {
navigate(`${window?.location?.pathname}?${searchBy}=${value}`); replace: true,
} else { });
const params = new URLSearchParams(location.search);
params.delete(searchBy ?? "search");
navigate(`${window?.location.pathname}?${params.toString()}`);
}
}; };
return ( return (
<div className='ValidationField'> <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"> <label htmlFor={name} className="text">
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? "error" : ""} validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""} help={isError ? errorMsg : ""}
> >
<Select <Select
placeholder={t(`${placeholder ? placeholder : name}`)} placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
disabled={isDisabled} disabled={isDisabled}
options={option} options={option}
size="large" size="large"
className={`${className} w-100`} className={`${className} w-100`}
value={formik.values[name]} value={formik.values[name]}
// defaultValue={formik.values[name]} loading={option?.length < 1}
allowClear allowClear
{...(isMulti && { mode: "multiple" })} {...(isMulti && { mode: "multiple" })}
onChange={onChange || SelecthandleChange} onChange={onChange || SelectableChange}
showSearch showSearch
optionFilterProp="label" optionFilterProp="label"
onSearch={SearchHandleChange} onSearch={SearchHandleChange}
loading={loading}
/> />
</Form.Item> </Form.Item>
</div> </div>

View File

@ -1,41 +1,72 @@
import { Form, Select } from 'antd' import { Form, 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";
const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onChange,className, props}: any) => { import { translateOptions } from "../utils/translatedOptions";
const { errorMsg, isError, t ,formik} = useFormField(name, props)
const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
formik.setFieldValue(name, value)
const SelectField = ({
name,
label,
placeholder,
isDisabled,
option,
isMulti,
onChange,
className,
props,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const SelectableChange = (value: {
value: string;
label: React.ReactNode;
}) => {
formik.setFieldValue(name, value);
}; };
// console.log(name,"Select");
return ( return (
<div className='ValidationField'> <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"> <label htmlFor={name} className="text">
{t(`${label ? label : name}`)} {t(`${label ? label : name}`)}
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? "error" : ""} validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""} help={isError ? errorMsg : ""}
> >
<Select <Select
placeholder={t(`${placeholder ?placeholder : name}`)} placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
disabled={isDisabled} disabled={isDisabled}
options={option} options={translateOptions(option, t)}
loading={option?.length < 1}
size="large" size="large"
className={`${className} w-100`} className={`${className} ${isError ? "Select_error" : ""} w-100`}
value={formik.values[name]} value={formik.values[name]}
allowClear allowClear
{...(isMulti && { mode: "multiple" })} {...(isMulti && { mode: "multiple" })}
onChange={onChange || SelecthandleChange} onChange={onChange || SelectableChange}
/> />
</Form.Item> </Form.Item>
</div> </div>
) );
} };
export default React.memo(SelectField); export default React.memo(SelectField);

View File

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

View File

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

View File

@ -0,0 +1,65 @@
import { Form, Input } from "antd";
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { MdOutlineEdit } from "react-icons/md";
import { Field } from "formik";
const { TextArea } = Input;
const TextField = ({
name,
label,
placeholder,
isDisabled,
onChange,
props,
no_label,
label_icon,
}: any) => {
const { formik, isError, errorMsg, t } = useFormField(name, props);
const TextFieldhandleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
// console.log('Change:', e.target.value);
formik.setFieldValue(name, e.target.value);
};
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(`${label ? label : name}`)}
</label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Field
as={TextArea}
placeholder={t(`${placeholder ? placeholder : name}`)}
name={name}
disabled={isDisabled}
size="large"
// showCount
maxLength={1000}
onChange={onChange || TextFieldhandleChange}
style={{ height: 100, resize: "none" }}
/>
</Form.Item>
</div>
);
};
export default React.memo(TextField);

View File

@ -1,21 +1,47 @@
import { Form, TimePicker } from 'antd' import { Form, TimePicker } 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 dayjs from "dayjs";
const Time = ({ name, label,className,isDisabled,onChange,props }: any) => { const Time = ({
name,
const { errorMsg, isError, t, formik } = useFormField(name, props) label,
className,
isDisabled,
onChange,
props,
placeholder,
no_label,
label_icon,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const onCalendarChange = (value: any) => { const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
formik.setFieldValue(name, value)
}; };
return (
<div className='ValidationField'> const Formater = "H:mm";
const FormikValue = formik.values[name];
return (
<div className="ValidationField w-100 ">
{no_label ? (
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{t(`${label}`)} <span>empty</span>
</label> </label>
) : label_icon ? (
<div className="LabelWithIcon">
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div>
) : (
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
)}
<Form.Item <Form.Item
hasFeedback hasFeedback
validateStatus={isError ? "error" : ""} validateStatus={isError ? "error" : ""}
@ -25,17 +51,18 @@ const Time = ({ name, label,className,isDisabled,onChange,props }: any) => {
allowClear allowClear
className={`${className} w-100`} className={`${className} w-100`}
size="large" size="large"
defaultValue={formik.values[name]} value={FormikValue ? dayjs(FormikValue, Formater) : null}
onChange={onChange || onCalendarChange} onChange={onChange || onCalendarChange}
disabled={isDisabled} disabled={isDisabled}
placeholder={t(
`${placeholder ? placeholder : label ? label : name}`,
)}
format={Formater}
needConfirm={false}
/> />
</Form.Item> </Form.Item>
</div> </div>
) );
} };
export default Time export default Time;

View File

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

View File

@ -1,21 +1,16 @@
import { useState } from 'react'; 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 Select from 'react-select'; import { convert_data_to_select } from "../../Layout/app/Const";
import { convert_data_to_select } from '../../Layout/app/Const';
export { export {
useState, useState,
ErrorMessage, useField, Field, useFormikContext, ErrorMessage,
useField,
Field,
useFormikContext,
useTranslation, useTranslation,
FaExclamationCircle, FaExclamationCircle,
Select,
convert_data_to_select, convert_data_to_select,
};
}

View File

@ -1,133 +0,0 @@
// export interface ValidationFieldProps {
// name: string;
// type?: "text" | "Select" | "DataRange" | "Date" | "Time" | "File" | "number" | "Checkbox" | "password";
// placeholder?: string;
// label?: string;
// className?: string;
// option?: any[];
// isMulti?: boolean;
// isDisabled?: boolean;
// picker?: "data" | "week" | "month" | "quarter" | "year";
// Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM";
// onChange?: (value: any) => void;
// Group?: boolean
// dir?:'ltr' | "rtl"
// }
export interface ValidationFieldPropsText {
name: string;
type: "text";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsSelect {
name: string;
type: "Select";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?:any;
dir?:'ltr' | "rtl";
option: any[];
isMulti?: boolean;
}
export interface ValidationFieldPropsSearch{
name: string;
type: "Search";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl";
option: any[];
isMulti?: boolean;
searchBy:string;
loading?:boolean;
}
export interface ValidationFieldPropsDataRange {
name: string;
type: "DataRange";
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";
}
export interface ValidationFieldPropsDate {
name: string;
type: "Date";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
picker?: "data" | "week" | "month" | "quarter" | "year";
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS" | "YYYY-MM-DD HH:MM:SS";
}
export interface ValidationFieldPropsTime {
name: string;
type: "Time";
label?: string;
placeholder?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsFile {
name: string;
type: "File" | "MaltyFile";
acceptedFileType?:string;
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsCheckbox {
name: string;
type: "Checkbox";
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
Group?: boolean
}
export interface ValidationFieldPropstext {
name: string;
type?: "text" | "number" | "password" | "TextArea";
label?: string;
className?: string;
placeholder?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
Group?: boolean
}
export type ValidationFieldProps = ValidationFieldPropsText| ValidationFieldPropsSelect| ValidationFieldPropsDataRange| ValidationFieldPropsDate| ValidationFieldPropsTime| ValidationFieldPropsFile| ValidationFieldPropsCheckbox| ValidationFieldPropstext | ValidationFieldPropsSearch;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,171 @@
export type ValidationFieldType =
| "text"
| "Select"
| "LocalSearch"
| "Search"
| "DataRange"
| "Date"
| "Time"
| "File"
| "MaltyFile"
| "DropFile"
| "Checkbox"
| "number"
| "password"
| "email"
| "TextArea";
export interface ValidationFieldPropsText {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "text";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
}
export interface ValidationFieldPropsSelect {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "Select";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: any;
dir?: "ltr" | "rtl";
option: any[];
isMulti?: boolean;
}
export interface ValidationFieldPropsLocalSearch {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "LocalSearch";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
option: any[];
isMulti?: boolean;
}
export interface ValidationFieldPropsSearch {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "Search";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
option: any[];
isMulti?: boolean;
searchBy: string;
}
export interface ValidationFieldPropsDataRange {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "DataRange";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
}
export interface ValidationFieldPropsDate {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "Date";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
picker?: "data" | "week" | "month" | "quarter" | "year";
}
export interface ValidationFieldPropsTime {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "Time";
label?: string;
placeholder?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
}
export interface ValidationFieldPropsFile {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "File" | "MaltyFile" | "DropFile";
acceptedFileType?:string;
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
}
export interface ValidationFieldPropsCheckbox {
name: string;
no_label?: boolean;
label_icon?: boolean;
type: "Checkbox";
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
Group?: boolean;
}
export interface ValidationFieldPropstext {
name: string;
no_label?: boolean;
label_icon?: boolean;
type?:
| "text"
| "number"
| "password"
| "email"
| "TextArea"
| "NumberFormate";
label?: string;
className?: string;
placeholder?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?: "ltr" | "rtl";
Group?: boolean;
[key: string]: any; // Index signature to allow any additional props
}
export type ValidationFieldProps =
| ValidationFieldPropsText
| ValidationFieldPropsSelect
| ValidationFieldPropsLocalSearch
| ValidationFieldPropsDataRange
| ValidationFieldPropsDate
| ValidationFieldPropsTime
| ValidationFieldPropsFile
| ValidationFieldPropsCheckbox
| ValidationFieldPropstext
| ValidationFieldPropsSearch;

View File

@ -1,42 +0,0 @@
import React, { FC } from "react";
import { Editor } from '@tinymce/tinymce-react';
import { useFormikContext } from "formik";
interface HtmlEditorProps {
langCode: number;
name: string;
editorState: string;
}
const HtmlEditor: FC<HtmlEditorProps> = ({ langCode, name, editorState, ...props }) => {
const formik = useFormikContext();
const ar: boolean = langCode === 2;
return (
<Editor
apiKey='6xf0byrgd7m2j28p9dfjittsq884x9j0d3e6dsterqrvtvez'
value={editorState}
init={{
height: 500,
menubar: false,
directionality: ar ? "rtl" : "ltr",
plugins: [
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen',
'insertdatetime media table paste code help wordcount'
],
toolbar: 'undo redo | formatselect | ' +
'bold italic backcolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
onEditorChange={(newValue, editor) => {
formik.setFieldValue(name, newValue)
}}
/>
);
}
export { HtmlEditor };

View File

@ -1,43 +0,0 @@
import React, { FC } from "react";
// import PropTypes from "";
import { HtmlEditor } from "./HtmlEditor";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
interface SingleLangEditorProps {
langCode: number;
property: string;
}
const PROPERTY_TYPES: string[] = [
"privacy_description",
"conditions_description",
"about_us_description",
"product_description",
"auction_description"
];
const SingleLangEditor: FC<SingleLangEditorProps> = ({ langCode, property }) => {
const formik:any = useFormikContext();
const {t} = useTranslation();
const label = `${t(property)} (${t(`lang_${langCode}`)})`;
const fieldName = `translated_fields[${langCode}][${property}]`;
return (
<>
<h5 className="Information_title">{label}</h5>
<HtmlEditor
langCode={langCode}
name={fieldName}
editorState={formik.values.translated_fields[langCode][property]}
/>
</>
);
};
// SingleLangEditor.propTypes = {
// langCode: PropTypes.oneOf([1, 2]).isRequired,
// property: PropTypes.oneOf(PROPERTY_TYPES).isRequired,
// };
export default SingleLangEditor;

View File

@ -1,23 +0,0 @@
import React, { FC } from "react";
import { Card, CardBody, Spinner } from "reactstrap";
interface StatusCardProps {
isLoading: boolean;
isError: boolean;
}
const StatusCard= ({ isLoading, isError }:StatusCardProps) => {
return (
<Card>
<CardBody
className="d-flex align-items-center justify-content-center"
style={{ height: "15rem" }}
>
{isLoading && <Spinner size="lg" color="primary" />}
{isError && <h4>Failed !</h4>}
</CardBody>
</Card>
);
};
export default StatusCard;

View File

@ -1,65 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
import { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
function Add${capitalizeFirstLetter(fileName)}Modal() {
const [t] = useTranslation()
const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
const handelSubmit = (values:any )=>{
const dataToSend = getDataToSend(values)
mutate(dataToSend)
// Submit Value
}
return (
<LayoutModal
isAddModal={true}
getInitialValues={getInitialValues()}
handleSubmit={handelSubmit}
status={status as QueryStatusEnum}
headerText={t('Add') +t('${(fileName)}')}
getValidationSchema={getValidationSchema()}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Add${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,40 +0,0 @@
const fs = require('fs');
const fileName = process.argv[2]
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation"
import useGetQuery from "./helper/useGetQuery"
import useUpdateMutation from "./helper/useUpdateMutation"
const API = {
GET: "/api/admin/${fileName}",
ADD: "/api/admin/${fileName}/create",
UPDATE: "/api/admin/${fileName}/update",
DELETE: "/api/admin/${fileName}/delete",
};
const KEY = "${fileName.toUpperCase()}";
export const useGet${capitalizeFirstLetter(fileName)} = (params?:any) => useGetQuery(KEY, API.GET, params);
export const useAdd${capitalizeFirstLetter(fileName)} = () => useAddMutation(KEY, API.ADD);
export const useUpdate${capitalizeFirstLetter(fileName)} = () => useUpdateMutation(KEY, API.UPDATE);
export const useDelete${capitalizeFirstLetter(fileName)} = () =>useDeleteMutation(KEY, API.DELETE);
`
fs.writeFileSync('src/api/'+fileName+".ts",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,63 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import Actions from "../../Components/Ui/tables/Actions";
function fnDelete(props :any ){}
const useTableColumns :any = () => {
const [t] = useTranslation();
return useMemo(
() => [
{
name: t("email"),
sortable: false,
center: "true",
cell: (row:any) => row?.email
},
{
name: "#",
sortable: false,
center: "true",
cell: (row) => (
<Actions
// importnat to return the row in on Edit Function to store in objectToEdit That Upper in Edit Modal
onEdit={() => row}
onView={()=>{}}
objectToEdit={row}
showEdit={true}
// showDelete={false}
onDelete={() => fnDelete({ id: row.id })}
/>
),
},
],
[t]
);
};
export default useTableColumns;
`
fs.writeFileSync('src/Pages/'+fileName+"/useTableColumns"+".tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);

View File

@ -1,30 +0,0 @@
const { exec } = require('child_process');
const fileName = process.argv[2]
const CreateApi = `node src/Extensions/FileGenerator/generateApi.js ${fileName}`
const CreatePage = `node src/Extensions/FileGenerator/generatePage.js ${fileName}`
const CreateColumn = `node src/Extensions/FileGenerator/generateColumn.js ${fileName}`
const CreateformUtil= `node src/Extensions/FileGenerator/generateformUtils.js ${fileName}`
const CreateAddModal= `node src/Extensions/FileGenerator/generateAddModal.js ${fileName}`
const CreateEditModal= `node src/Extensions/FileGenerator/generateEditModal.js ${fileName}`
const CreateForm= `node src/Extensions/FileGenerator/generateForm.js ${fileName}`
const RunCommand = async()=>{
exec(CreatePage)
exec(CreateApi)
setTimeout(()=>{},100)
exec(CreateColumn)
exec(CreateformUtil)
exec(CreateAddModal)
exec(CreateEditModal)
exec(CreateForm)
}
RunCommand()

View File

@ -1,47 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { getInitialValues, getValidationSchema } from './formUtil'
import { usePageState } from '../../lib/state mangment/LayoutPagestate'
function Edit${capitalizeFirstLetter(fileName)}Modal() {
const {objectToEdit} = usePageState()
return (
<LayoutModal
isAddModal={false}
getInitialValues={getInitialValues(objectToEdit)}
handleSubmit={() => { }}
headerText='Edit Modal'
getValidationSchema={getValidationSchema(objectToEdit)}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Edit${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Edit"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,66 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import { Col, Row } from 'reactstrap';
import ValidationField from '../../Components/ValidationField/ValidationField';
import { FakeSelectData } from '../../Layout/app/Const';
import { useFormikContext } from 'formik';
import { DatePicker } from 'antd';
function Form${capitalizeFirstLetter(fileName)}() {
const formik = useFormikContext<any>();
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
// name from form utils
<ValidationField name="name" type="text"label='name' placeholder='placeholder' />
<ValidationField name="number" type="number" label='number' placeholder='placeholder' />
<ValidationField name="select" type="select"label='select' option={FakeSelectData} isMulti={true} placeholder='placeholder' />
<ValidationField name="Multiselect" type="select"label='Multiselect' option={FakeSelectData} Disabled={true} placeholder='placeholder'/>
</Col>
<Col>
<ValidationField name="date" type="date" label='date' placeholder='placeholder' />
<ValidationField name="time" type="text"label='time' placeholder='placeholder' />
<ValidationField name="CheckBox" name2='CheckBox2' type="checkbox" label='CheckBox' placeholder='placeholder' group={true} />
<ValidationField name="DateFrom" name2="DateTo" type="DataRange" />
</Col>
</Row>
)
}
export default Form${capitalizeFirstLetter(fileName)}
`
fs.writeFileSync('src/Pages/'+fileName+'/Form'+ capitalizeFirstLetter(fileName)+".tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,64 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
import { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
function Add${capitalizeFirstLetter(fileName)}Modal() {
const [t] = useTranslation()
const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
const handelSubmit = (values:any )=>{
const dataToSend = getDataToSend(values)
mutate(dataToSend)
// Submit Value
}
return (
<LayoutModal
isAddModal={true}
getInitialValues={getInitialValues()}
handleSubmit={handelSubmit}
status={status as QueryStatusEnum}
headerText={t('Add') +t('${(fileName)}')}
getValidationSchema={getValidationSchema()}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Add${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,67 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
const folderPath = 'src/Pages/'+fileName;
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath, { recursive: true });
}
let FileContiner = `
import React from 'react'
import DashBody from '../../Layout/Dashboard/DashBody'
import DashHeader from '../../Layout/Dashboard/DashHeader'
import LyTable from '../../Layout/Dashboard/LyTable'
import useTableColumns from './useTableColumns'
import { useGet${capitalizeFirstLetter(fileName)}} from '../../api/${fileName}'
import { QueryStatusEnum } from '../../config/QueryStatus'
import Edit${capitalizeFirstLetter(fileName)}Modal from './Edit${capitalizeFirstLetter(fileName)}Modal'
import Add${capitalizeFirstLetter(fileName)}Modal from './Add${capitalizeFirstLetter(fileName)}Modal'
function ${capitalizeFirstLetter(fileName)}Page() {
const column =useTableColumns()
const {data ,status } = useGet${capitalizeFirstLetter(fileName)}()
return (
// Pass Status to Layout
<DashBody status={status as QueryStatusEnum} >
<DashHeader title={'${capitalizeFirstLetter(fileName)}'}></DashHeader>
<LyTable
data={data}
isLoading={false}
columns={column}
/>
<Edit${capitalizeFirstLetter(fileName)}Modal />
<Add${capitalizeFirstLetter(fileName)}Modal />
</DashBody>
)
}
export default ${capitalizeFirstLetter(fileName)}Page
`
fs.writeFileSync('src/Pages/'+fileName+"/"+capitalizeFirstLetter(fileName)+"Page.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -1,73 +0,0 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import * as Yup from "yup";
import { buildFormData } from "../../api/helper/buildFormData";
interface formUtilCommon {
name:string,
email:string
}
interface ObjectToEdit extends formUtilCommon {
id?:number,
}
interface InitialValues extends ObjectToEdit {
}
interface ValidateSchema extends formUtilCommon{
}
export const getInitialValues = (objectToEdit: ObjectToEdit | null = null): InitialValues => {
return {
id:objectToEdit?.id?? 0 ,
name:objectToEdit?.name ?? "",
email:objectToEdit?.email?? ""
}
};
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<ValidateSchema> => {
// validate input
return Yup.object().shape({
name:Yup.string().required('required'),
email:Yup.string().required("required")
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
const formData = new FormData();
buildFormData(formData, data);
return formData;
};
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"formUtil.ts",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -7,15 +7,19 @@ import { Rate, Spin } from 'antd';
import { usePageState } from '../../../lib/statemangment/LayoutPagestate'; import { usePageState } from '../../../lib/statemangment/LayoutPagestate';
import LoadingPage from '../../../Layout/app/LoadingPage'; import LoadingPage from '../../../Layout/app/LoadingPage';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetOneCategories, useUpdateCategories } from '../../../api/Categories'; import { useGetCategories, useUpdateCategories } from '../../../api/Categories';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess'; import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import Form from './EditForm'; import Form from './EditForm';
import { useParams } from 'react-router-dom';
const EditPage = () => { const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation(); const { t } = useTranslation();
const { data,isRefetching } = useGetOneCategories() const {id} = useParams()
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateCategories("put") const { data,isRefetching } = useGetCategories({
show:id
})
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateCategories()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
if( typeof values?.image === "string" ){ if( typeof values?.image === "string" ){
delete values["image"] delete values["image"]

10
src/Pages/Home/Page.tsx Normal file
View File

@ -0,0 +1,10 @@
import React from 'react'
const Page = () => {
return (
<div>Page</div>
)
}
export default Page

View File

@ -7,15 +7,19 @@ import { Rate, Spin } from 'antd';
import { usePageState } from '../../../lib/statemangment/LayoutPagestate'; import { usePageState } from '../../../lib/statemangment/LayoutPagestate';
import LoadingPage from '../../../Layout/app/LoadingPage'; import LoadingPage from '../../../Layout/app/LoadingPage';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetOneMeal, useUpdateMeal } from '../../../api/Meal'; import { useGetMeal, useUpdateMeal } from '../../../api/Meal';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess'; import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import Form from './EditForm'; import Form from './EditForm';
import { useParams } from 'react-router-dom';
const EditPage = () => { const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation(); const { t } = useTranslation();
const { data,isRefetching } = useGetOneMeal() const {id} = useParams()
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal("put") const { data,isRefetching } = useGetMeal({
show:id
})
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
if( typeof values?.image === "string" ){ if( typeof values?.image === "string" ){

View File

@ -7,15 +7,19 @@ import { Rate, Spin } from 'antd';
import { usePageState } from '../../../lib/statemangment/LayoutPagestate'; import { usePageState } from '../../../lib/statemangment/LayoutPagestate';
import LoadingPage from '../../../Layout/app/LoadingPage'; import LoadingPage from '../../../Layout/app/LoadingPage';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetOneOffer, useUpdateOffer } from '../../../api/Offer'; import { useGetOffer, useUpdateOffer } from '../../../api/Offer';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess'; import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import Form from './EditForm'; import Form from './EditForm';
import { useParams } from 'react-router-dom';
const EditPage = () => { const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation(); const { t } = useTranslation();
const { data,isRefetching } = useGetOneOffer() const {id} = useParams()
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateOffer("put") const { data,isRefetching } = useGetOffer({
show:id
})
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateOffer()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
if( typeof values?.image === "string" ){ if( typeof values?.image === "string" ){
delete values["image"] delete values["image"]

View 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(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("key")}
onChange={(e) => handleChangeKey(e, index)}
value={group.key}
size="large"
style={{ width: "100%" }}
allowClear
disabled={only_value}
/>
<Input
placeholder={t("value")}
onChange={(e) => handleChangeValue(e, index)}
value={group.value}
size="large"
style={{ width: "100%" }}
allowClear
/>
</div>
))}
{!isStatic &&
<div className="d-flex gap-2">
<Button
type="dashed"
onClick={addFieldGroup}
>
{t("add_new")}
</Button>
<Button
type="dashed"
onClick={deleteFieldGroup}
>
{t("delete_last")}
</Button>
</div>
}
</>
);
};
export default FieldGroup;

View File

@ -1,7 +1,7 @@
import { Image, Spin } from "antd"; import { Image, Spin } from "antd";
import React from "react"; import React from "react";
import SimpleMap from "./Map"; import SimpleMap from "./Map";
import { useGetOneSetting, useGetSetting } from "../../api/GuestApi"; import { useGetSetting } from "../../api/GuestApi";
import { TOKEN_KEY } from "../../api/config"; import { TOKEN_KEY } from "../../api/config";
import useAuthState from "../../lib/statemangment/AuthState"; import useAuthState from "../../lib/statemangment/AuthState";
import ReactPlayer from 'react-player' import ReactPlayer from 'react-player'
@ -9,8 +9,6 @@ import { FaEdit } from "react-icons/fa";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
const Page = () => { const Page = () => {
const { token } = useAuthState();
console.log(token, "token");
const navigate= useNavigate() const navigate= useNavigate()
const fake = "900310ff-610f-11ee-9fbc-00505649cf62"; const fake = "900310ff-610f-11ee-9fbc-00505649cf62";
const { data, isLoading } = useGetSetting({ const { data, isLoading } = useGetSetting({
@ -29,10 +27,13 @@ const Page = () => {
id id
} = data?.data ?? []; } = data?.data ?? [];
console.log(attributes, "attribute"); const fakeIMage = [1,1,1,1,1,1]
const handel_navigate = (id:number)=>{
console.log(id);
console.log(video,"video");
navigate(`/Setting/${id}`)
}
if(isLoading){ if(isLoading){
return <Spin/> return <Spin/>
} }
@ -43,6 +44,7 @@ const Page = () => {
width={200} width={200}
src={logo} src={logo}
className="Personal_Image" className="Personal_Image"
fallback="/Layout/images.png"
/> />
<div> <div>
<h1>{name}</h1> <h1>{name}</h1>
@ -86,8 +88,8 @@ const Page = () => {
} }
<div className="EditButton" onClick={()=> navigate(id)} > <div className="EditButton" >
<FaEdit size={30}/> <FaEdit onClick={()=> handel_navigate(id)} size={30}/>
</div> </div>
</div> </div>
); );

View File

@ -4,7 +4,7 @@ import { Col, Row } from 'reactstrap';
import ValidationField from '../../../Components/ValidationField/ValidationField'; import ValidationField from '../../../Components/ValidationField/ValidationField';
import { useGetCategories } from '../../../api/Categories'; import { useGetCategories } from '../../../api/Categories';
import useFormatToSelect from '../../../Hooks/useFormatToSelect'; import useFormatToSelect from '../../../Hooks/useFormatToSelect';
import FieldGroup from '../Groups/FieldGroup';
function Form() { function Form() {
const {data:Categories} = useGetCategories() const {data:Categories} = useGetCategories()
const SelectCategoriesData = useFormatToSelect(Categories?.data) const SelectCategoriesData = useFormatToSelect(Categories?.data)
@ -15,12 +15,17 @@ function Form() {
<Col> <Col>
<ValidationField name="name" /> <ValidationField name="name" />
<ValidationField name="address" /> <ValidationField name="address" />
<ValidationField name="categories_id" type='Select' option={SelectCategoriesData} /> <ValidationField name="categories" type='Select' option={SelectCategoriesData} isMulti />
<ValidationField name="description" type='TextArea' /> {/* <ValidationField name="description" type='TextArea' /> */}
<ValidationField name="phone_number" />
<ValidationField name="email" />
<FieldGroup array_name='slogan' title='slogan' />
</Col> </Col>
<Col> <Col>
<ValidationField type='File' name='logo' />
<ValidationField type='MaltyFile' name='images' /> <ValidationField type='MaltyFile' name='images' />
<ValidationField type='File' name='video' acceptedFileType='.mp4' /> <ValidationField type='File' name='video' acceptedFileType='.mp4' />

View File

@ -7,25 +7,42 @@ import { Rate, Spin } from 'antd';
import { usePageState } from '../../../lib/statemangment/LayoutPagestate'; import { usePageState } from '../../../lib/statemangment/LayoutPagestate';
import LoadingPage from '../../../Layout/app/LoadingPage'; import LoadingPage from '../../../Layout/app/LoadingPage';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetOneMeal, useUpdateMeal } from '../../../api/Meal'; import { useGetSetting, useUpdateSetting } from '../../../api/setting';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess'; import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import Form from './EditForm'; import Form from './EditForm';
import { useParams } from 'react-router-dom';
import { convertArrayToJsonString } from '../../../utils/Array/convertArrayToJsonString';
const EditPage = () => { const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation(); const { t } = useTranslation();
const { data,isRefetching } = useGetOneMeal() const {id} = useParams()
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal("put")
const { data,isRefetching } = useGetSetting({
show:id
})
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateSetting()
const handleSubmit = (values:any) => { const handleSubmit = (values:any) => {
const dataToSend = {...values};
const slogan = convertArrayToJsonString(values?.slogan);
const phone_number = values?.phone_number;
const email = values?.email;
const contact_info = convertArrayToJsonString([{key: 'phone_number', value:phone_number},{key: 'email', value:email}])
dataToSend["slogan"] = slogan;
dataToSend["contact_info"] = contact_info;
// mutate({...values, _method : "put"});
console.log(dataToSend,"dataToSend");
if( typeof values?.image === "string" ){
delete values["video"]
}
mutate({...values, _method : "put"});
} }
useNavigateOnSuccess(isSuccess, '/Meal') useNavigateOnSuccess(isSuccess, '/Setting')
useEffect(() => { useEffect(() => {
@ -43,7 +60,6 @@ const EditPage = () => {
} }
const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton }; const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };

View File

@ -1,15 +1,29 @@
import * as Yup from "yup"; import * as Yup from "yup";
import { KeyAndValue, objectToArray } from "../../utils/object/objectToArray";
import { Restaurant } from "../../types/item";
export const getInitialValues = (objectToEdit: any | null = null): any => { export const getInitialValues = (objectToEdit: Restaurant ): any => {
console.log(objectToEdit,"objectToEdit");
const slogan: KeyAndValue[] = objectToArray(objectToEdit?.slogan);
const contact_info: KeyAndValue[] = objectToArray(objectToEdit?.contact_info);
const categories = objectToEdit?.categories?.map((item:any)=>(item.id)) || null;
console.log(categories,"categories");
return { return {
id: objectToEdit?.id ?? null, id: objectToEdit?.id ?? null,
name: objectToEdit?.name ?? null, name: objectToEdit?.name ?? null,
images: objectToEdit?.images ?? null, images: objectToEdit?.images ?? null,
logo: objectToEdit?.logo ?? null,
address: objectToEdit?.address ?? null, address: objectToEdit?.address ?? null,
contact_info: objectToEdit?.contact_info ?? null, phone_number:contact_info?.[0]?.value ?? null,
slogan: objectToEdit?.slogan ?? null, email:contact_info?.[1]?.value ?? null,
categories:categories,
slogan: slogan ?? null,
video: objectToEdit?.video ?? null, video: objectToEdit?.video ?? null,
attributes: objectToEdit?.attributes ?? null, attributes: objectToEdit?.attributes ?? null,
}; };

View File

@ -2,13 +2,11 @@ import React, { ReactNode } from 'react'
import QueryProvider from './lib/ReactQueryProvider' import QueryProvider from './lib/ReactQueryProvider'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
import ToastProvider from './lib/ToastProvider' import ToastProvider from './lib/ToastProvider'
import { createBrowserHistory } from 'history'
type ProviderContainerProps = { type ProviderContainerProps = {
children:ReactNode children:ReactNode
} }
export let history = createBrowserHistory()
function ProviderContainer({children}:ProviderContainerProps) { function ProviderContainer({children}:ProviderContainerProps) {
return ( return (
<BrowserRouter basename='/'> <BrowserRouter basename='/'>

View File

@ -29,7 +29,7 @@ import { SettingFilled } from "@ant-design/icons";
import { GiMeal } from "react-icons/gi"; import { GiMeal } from "react-icons/gi";
import Home from './Pages/Home/Page'
@ -48,7 +48,7 @@ export const RoutesLinks: RoutesLinksType[] = [
{ {
name: "Home", name: "Home",
element: <>Home Page</>, element: <Home/>,
icon: <FaHome />, icon: <FaHome />,
href: "/", href: "/",
}, },

View File

@ -1,5 +1,5 @@
:root { :root {
--primary:#E57DB1 ; --primary:black ;
--secondary : #2D9CDB; --secondary : #2D9CDB;
--text: #565656; --text: #565656;
--bg: #ffffff; --bg: #ffffff;

View File

@ -1,9 +1,8 @@
import useGetQueryPagination from "./helper/ueGetPagination"; import useGetQuery from "./helper/useGetQuery";
import useAddMutation from "./helper/useAddMutation" import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation" import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useUpdateMutation from "./helper/useUpdateMutation";
import useUpdateMutationPost from "./helper/useUpdateMutationPut";
const API = { const API = {
ADD: `category`, ADD: `category`,
@ -15,10 +14,9 @@ const API = {
const KEY = "categories" const KEY = "categories"
export const useGetCategories = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params); export const useGetCategories = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
export const useGetOneCategories = () => useGetOneQuery(KEY, API.GET_ALL);
export const useAddCategories = () => useAddMutation(KEY, API.ADD); export const useAddCategories = () => useAddMutation(KEY, API.ADD);
export const useUpdateCategories = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method); export const useUpdateCategories = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteCategories = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteCategories = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -1,10 +1,8 @@
import useGetQuery from "./helper/useGetQuery"; import useGetQuery from "./helper/useGetQuery";
import useGetQueryPagination from "./helper/ueGetPagination";
import useAddMutation from "./helper/useAddMutation" import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation" import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useUpdateMutation from "./helper/useUpdateMutation";
import useUpdateMutationPost from "./helper/useUpdateMutationPut";
const API = { const API = {
ADD: `guest/restaurant`, ADD: `guest/restaurant`,
@ -16,10 +14,9 @@ const API = {
const KEY = "setting" const KEY = "setting"
export const useGetSetting = (params?:any) => useGetQuery(KEY, API.GET_ALL,params); export const useGetSetting = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
export const useGetOneSetting = () => useGetOneQuery(KEY, API.GET_ALL);
export const useAddSetting = () => useAddMutation(KEY, API.ADD); export const useAddSetting = () => useAddMutation(KEY, API.ADD);
export const useUpdateSetting = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method); export const useUpdateSetting = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteSetting = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteSetting = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -1,9 +1,8 @@
import useGetQueryPagination from "./helper/ueGetPagination";
import useAddMutation from "./helper/useAddMutation" import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation" import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useGetQuery from "./helper/useGetQuery";
import useUpdateMutationPost from "./helper/useUpdateMutationPut"; import useUpdateMutation from "./helper/useUpdateMutation";
const API = { const API = {
ADD: `meal`, ADD: `meal`,
@ -15,10 +14,9 @@ const API = {
const KEY = "Meal" const KEY = "Meal"
export const useGetMeal = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params); export const useGetMeal = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params,option);
export const useGetOneMeal = () => useGetOneQuery(KEY, API.GET_ALL);
export const useAddMeal = () => useAddMutation(KEY, API.ADD); export const useAddMeal = () => useAddMutation(KEY, API.ADD);
export const useUpdateMeal = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method); export const useUpdateMeal = () => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteMeal = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteMeal = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -1,9 +1,8 @@
import useGetQueryPagination from "./helper/ueGetPagination"; import useGetQuery from "./helper/useGetQuery";
import useAddMutation from "./helper/useAddMutation" import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation" import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useUpdateMutation from "./helper/useUpdateMutation";
import useUpdateMutationPost from "./helper/useUpdateMutationPut";
const API = { const API = {
ADD: `offer`, ADD: `offer`,
@ -15,10 +14,9 @@ const API = {
const KEY = "Offer" const KEY = "Offer"
export const useGetOffer = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params); export const useGetOffer = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
export const useGetOneOffer = () => useGetOneQuery(KEY, API.GET_ALL);
export const useAddOffer = () => useAddMutation(KEY, API.ADD); export const useAddOffer = () => useAddMutation(KEY, API.ADD);
export const useUpdateOffer = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method); export const useUpdateOffer = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteOffer = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteOffer = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -1,9 +1,8 @@
import useGetQueryPagination from "./helper/ueGetPagination"; import useGetQuery from "./helper/useGetQuery";
import useAddMutation from "./helper/useAddMutation" import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation" import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useUpdateMutation from "./helper/useUpdateMutation";
import useUpdateMutationPost from "./helper/useUpdateMutationPut";
const API = { const API = {
ADD: `restaurant`, ADD: `restaurant`,
@ -15,10 +14,9 @@ const API = {
const KEY = "Restaurant" const KEY = "Restaurant"
export const useGetRestaurant = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params); export const useGetRestaurant = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
export const useGetOneRestaurant = () => useGetOneQuery(KEY, API.GET_ALL);
export const useAddRestaurant = () => useAddMutation(KEY, API.ADD); export const useAddRestaurant = () => useAddMutation(KEY, API.ADD);
export const useUpdateRestaurant = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method); export const useUpdateRestaurant = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteRestaurant = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteRestaurant = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -15,3 +15,5 @@ export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
export const USER_KEY = PROJECT_NAME + "_USER" export const USER_KEY = PROJECT_NAME + "_USER"
export const HEADER_KEY = "X-Custom-Query-Key";

View File

@ -1,21 +1,19 @@
import axios, { AxiosInstance, AxiosRequestConfig ,ResponseType } from 'axios'; import axios, { AxiosInstance, AxiosRequestConfig, ResponseType } from "axios";
class AxiosBuilder { class AxiosBuilder {
private baseURL: string = ''; private baseURL: string = "";
private headers: Record<string, string> = {}; private headers: Record<any, any> = {};
private timeout: number = 60000; // Request failed with 60 second private timeout: number = 60000; // Request failed with 60 second
private withCreds: boolean = false; private withCreds: boolean = false;
private responseType: ResponseType = 'json'; private responseType: ResponseType = "json";
// Custom Another Props with Your Position // Custom Another Props with Your Position
withBaseURL(baseURL: string): AxiosBuilder { withBaseURL(baseURL: string): AxiosBuilder {
this.baseURL = baseURL; this.baseURL = baseURL;
return this; return this;
} }
withHeaders(headers: Record<string, string>): AxiosBuilder { withHeaders(headers: Record<any, any>): AxiosBuilder {
this.headers = headers; this.headers = headers;
return this; return this;
} }
@ -25,25 +23,21 @@ class AxiosBuilder {
return this; return this;
} }
withResponseType(responseType: ResponseType): AxiosBuilder { withResponseType(responseType: ResponseType): AxiosBuilder {
this.responseType = responseType; this.responseType = responseType;
return this; return this;
} }
build(): AxiosInstance { build(): AxiosInstance {
const config: AxiosRequestConfig = { const config: AxiosRequestConfig = {
baseURL: this.baseURL, baseURL: this.baseURL,
headers: this.headers, headers: this.headers,
timeout: this.timeout, timeout: this.timeout,
responseType:this.responseType responseType: this.responseType,
}; };
return axios.create(config); return axios.create(config);
} }
} }
export default AxiosBuilder;
export default AxiosBuilder

View File

@ -1,27 +0,0 @@
export const buildFormData = (
formData: FormData,
data: any,
parentKey?: string
): void => {
if (
data &&
typeof data === "object" &&
!(data instanceof Date) &&
!(data instanceof File)
) {
Object.keys(data).forEach((key) => {
buildFormData(
formData,
data[key],
parentKey ? `${parentKey}[${key}]` : key
);
});
} else {
const value = data == null ? "" : data;
formData.append(parentKey as string, value);
}
};

View File

@ -1,44 +0,0 @@
import { useQuery } from 'react-query';
import useAxios from './useAxios';
import { useLocation, useNavigate } from 'react-router-dom';
import useAuthState from '../../lib/state mangment/AuthState';
export default function useGetQueryPagination(KEY: string | string[], Api: string, params: any = {}, options: any = {}, dontSearchBy?: string) {
const axios = useAxios();
const location = useLocation();
let pagination = location?.search || '';
const language = localStorage.getItem("language") ?? "en"
const { logout } = useAuthState();
const navigate = useNavigate();
if (dontSearchBy && pagination.includes(dontSearchBy)) {
const searchParams = new URLSearchParams(pagination);
searchParams.delete(dontSearchBy);
pagination = searchParams.toString();
}
if (pagination && !pagination.startsWith('?')) {
pagination = '?' + pagination;
}
// Check if pagination exists and append it to the API endpoint
const paginationParams = pagination ? pagination + '&orderById=desc' : '?orderById=desc';
const apiUrl = Api + paginationParams;
return useQuery(
[Array.isArray(KEY) ? KEY.join(',') : KEY, pagination,language], async () => {
const response = await axios.get(apiUrl, { params });
return response.data;
},
{
onError: (error: any) => {
if (error?.response?.status === 401 || error?.response?.status === 403) {
logout();
navigate("/auth");
}
},
refetchOnWindowFocus: false,
...options
}
);
}

View File

@ -1,38 +1,28 @@
import { useMutation, useQueryClient, UseMutationResult } from 'react-query'; import { useMutation, UseMutationResult } from "react-query";
import { toast } from 'react-toastify'; import useAxios from "./useAxios";
import useAxios from './useAxios'; import { HEADER_KEY } from "../config";
import { useTranslation } from 'react-i18next'; import { AxiosResponse } from "../../types/Axios";
type AxiosResponse = { function useAddMutation(
message: string; key: string,
data:any , url: string,
success:true message?: string,
};
function useAddMutation(key: string, url: string,message?:string): UseMutationResult<AxiosResponse, unknown, any, unknown> { ): UseMutationResult<AxiosResponse, unknown, any, unknown> {
const axios = useAxios(); const axios = useAxios();
const [t] = useTranslation();
const queryClient = useQueryClient();
return useMutation<AxiosResponse, unknown, any, unknown>( return useMutation<AxiosResponse, unknown, any, unknown>(
async (dataToSend) => { async (dataToSend) => {
const { data } = await axios.post(url, dataToSend, { const { data } = await axios.post(url, dataToSend, {
headers: { headers: {
'Content-Type': 'multipart/form-data' "Content-Type": "multipart/form-data",
} [HEADER_KEY]: key,
},
}); });
return data; return data;
}, },
{
onSuccess: (data) => {
queryClient.invalidateQueries([key]);
toast.success(data.message || t(message??"") || t("added_successful"));
},
onError: (error:any) => {
const message = error?.response?.data?.message || t("failed_to_add_data");
toast.error(message);
}
}
); );
} }

View File

@ -1,35 +0,0 @@
import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
import { toast } from 'react-toastify';
import useAxios from './useAxios';
import { useTranslation } from 'react-i18next';
type AxiosResponse = {
message: string;
data:any ,
success:true
};
function useAddMutationJson(key: string, url: string): UseMutationResult<AxiosResponse, unknown, any, unknown> {
const axios = useAxios();
const [t] = useTranslation();
const queryClient = useQueryClient();
return useMutation<AxiosResponse, unknown, any, unknown>(
async (dataToSend) => {
const { data } = await axios.post(url, dataToSend);
return data;
},
{
onSuccess: (data) => {
queryClient.invalidateQueries([key]);
toast.success(data.message || t("added_successful"));
},
onError: (error:any) => {
const message = error?.response?.data?.message || t("failed_to_add_data");
toast.error(message);
}
}
);
}
export default useAddMutationJson;

View File

@ -1,25 +1,78 @@
import { BaseURL } from '../config'
import useAuthState from '../../lib/state mangment/AuthState' import { BaseURL, HEADER_KEY } from "../config";
import AxiosBuilder from './AxiosBuilder' import AxiosBuilder from "./AxiosBuilder";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import { useQueryClient } from "react-query";
import { useNavigate } from "react-router-dom";
import useAuthState from "../../lib/statemangment/AuthState";
import { useValidationState } from "../../Components/ValidationField/utils/ValidationState";
import { AxiosQueryEnum, AxiosStatusEnum } from "../../enums/Axios";
function useAxios() { function useAxios() {
const {isAuthenticated , token}= useAuthState() const { isAuthenticated, token } = useAuthState();
const buildAxios = new AxiosBuilder(). const { setValidation } = useValidationState((state) => state);
withBaseURL(BaseURL) const [t] = useTranslation();
.withResponseType('json') const queryClient = useQueryClient();
.withTimeout(120000)
.withHeaders({"Content-Type" :"application/json"})
const { logout } = useAuthState();
const navigate = useNavigate();
const buildAxios = new AxiosBuilder()
.withBaseURL(BaseURL)
.withResponseType("json")
.withTimeout(120000);
if (isAuthenticated) { if (isAuthenticated) {
buildAxios.withHeaders({
buildAxios.withHeaders({ Authorization: 'Bearer '+ token }) Authorization: "Bearer " + token,
});
} }
return ( const build_Axios = buildAxios.build();
buildAxios.build()
) build_Axios.interceptors.response.use(
function (response: any) {
const responseMsg = response?.data?.message;
const method = response.config.method;
const key = response.config.headers[HEADER_KEY];
const ResponseMessage =
responseMsg || t("validation.the_possess_done_successful");
if (method !== AxiosQueryEnum?.GET) {
queryClient.invalidateQueries(key);
toast.success(ResponseMessage);
setValidation([{}]);
}
return response;
},
function (error) {
const status = error?.request?.status;
const errorMsg = error?.response?.data?.message;
const errorField = error?.response?.data;
const method = error.config.method;
if (status === AxiosStatusEnum.VALIDATION) {
setValidation(errorMsg ?? errorField);
const errorMessage = errorMsg || t("validation.some_thing_went_wrong");
toast.error(errorMessage);
}
if (status === AxiosStatusEnum.AUTHENTICATED) {
logout();
navigate("/auth");
} }
export default useAxios if (method !== AxiosQueryEnum?.GET) {
const errorMessage = errorMsg || t("validation.some_thing_went_wrong");
toast.error(errorMessage);
return Promise.reject(error);
}
},
);
return build_Axios;
// return buildAxios.build();
}
export default useAxios;

View File

@ -1,34 +1,27 @@
import { useMutation, useQueryClient, UseMutationResult } from 'react-query'; import { useMutation, UseMutationResult } from "react-query";
import { toast } from 'react-toastify'; import useAxios from "./useAxios";
import useAxios from './useAxios'; import { HEADER_KEY } from "../config";
import { useTranslation } from 'react-i18next'; import { AxiosResponse } from "../../types/Axios";
type AxiosResponse = { type DataToSend = {
message: string; id: number | string;
// Add other properties as needed
}; };
function useDeleteMutation(key:any , url: string): UseMutationResult<AxiosResponse, unknown, any, unknown> { function useDeleteMutation(
key: any,
url: string,
message?: string,
): UseMutationResult<AxiosResponse, unknown, DataToSend, unknown> {
const axios = useAxios(); const axios = useAxios();
const queryClient = useQueryClient(); return useMutation<AxiosResponse, unknown, DataToSend, unknown>(
const {t} = useTranslation(); async (dataToSend) => {
const { data } = await axios.delete(url + `/` + dataToSend?.id, {
return useMutation<AxiosResponse, unknown, any, unknown>( headers: {
async ({dataToSend,id}:any) => { [HEADER_KEY]: key,
const { data } = await axios.delete(url+"/"+id );
return {...data, id,dataToSend};
}, },
{ });
onSuccess: (data) => { return data;
queryClient.invalidateQueries(key);
toast.success(t('deleted_successfully'));
}, },
onError: (error:any) => {
const message = error?.response?.data?.message || t("failed_to_add_data");
toast.error(message);
}
},
); );
} }

View File

@ -1,39 +0,0 @@
import { useQuery } from 'react-query';
import useAxios from './useAxios';
import useAuthState from '../../lib/state mangment/AuthState';
import { useNavigate, useParams } from 'react-router-dom';
function useGetOneQuery(key: string, url: string , params:any={},options:any={}) {
const axios = useAxios();
const {logout} = useAuthState()
const language = localStorage.getItem("language") ?? "en"
const navigate = useNavigate()
const {id} = useParams()
return useQuery(
[id, key,language],
async () => {
const response = await axios.get(url+"/"+ id+`?lang=${language}`);
return response.data;
},
{
onError: (error:any) => {
if(error.response.status == 401 || error.response.status == 403){
logout()
navigate("/auth")
}
},
cacheTime: 0, // Set cacheTime to 0 to disable caching
refetchOnWindowFocus: false,
...options
}
);
}
export default useGetOneQuery;

View File

@ -1,24 +1,39 @@
import { useQuery } from 'react-query'; import { useQuery } from "react-query";
import useAxios from './useAxios'; import useAxios from "./useAxios";
import { useLocation } from "react-router-dom";
import { PaginationParams } from "../utils/PaginationParams";
import { filterParams } from "../utils/filterParams";
function useGetQuery(KEY: string | string[], url: string, params: any = {}, options: any = {}) { function useGetQuery(
KEY: string | string[],
url: string,
params: any = {},
options: any = {},
) {
const axios = useAxios(); const axios = useAxios();
const show = params.show ? "/" + params.show : '';
const filteredParams = Object.fromEntries( const { show, pagination, ...remainingParams } = params;
Object.entries(params).filter(([_, value]) => value !== '')
);
return useQuery([KEY, filteredParams], async () => { const location = useLocation();
const response = await axios.get(url + show, { params: filteredParams });
return response.data; const { page, per_page } = PaginationParams(location);
}, {
onError: (error) => { const param_to_send = pagination
console.error('An error occurred:', error); ? { ...remainingParams, page: page, per_page: per_page }
}, : { ...remainingParams };
refetchOnWindowFocus: false,
...options const filteredParams = filterParams(param_to_send);
return useQuery(
[KEY, filteredParams, show],
async () => {
const response = await axios.get(url + (show ? `/${show}` : ""), {
params: filteredParams,
}); });
return response?.data ?? [];
},
options,
);
} }
export default useGetQuery; export default useGetQuery;

View File

@ -1,38 +0,0 @@
import { useQuery } from 'react-query';
import useAxios from './useAxios';
import useAuthState from '../../lib/state mangment/AuthState';
import { useNavigate, useParams } from 'react-router-dom';
function useGetSingleQuery(key: string, url: string , params:any={},options:any={}) {
const axios = useAxios();
const {logout} = useAuthState()
const language = localStorage.getItem("language") ?? "en"
const navigate = useNavigate()
const {id} = useParams()
return useQuery(
[id, key,params?.id],
async () => {
const response = await axios.get(url+"?"+params?.name+"="+params?.id+`?lang=${language}`);
return response.data;
},
{
onError: (error:any) => {
if(error.response.status == 401 || error.response.status == 403){
logout()
navigate("/auth")
}
},
refetchOnWindowFocus: false,
...options
}
);
}
export default useGetSingleQuery;

View File

@ -1,22 +0,0 @@
import { useQuery } from 'react-query';
import useAxios from './useAxios';
export default function useGetQueryPagination(KEY: string | string[], Api: string, options: any = {}) {
const axios = useAxios();
const pagination = options;
return useQuery(
[ KEY], async () => {
const response = await axios.get(Api + pagination );
return response.data;
},
{
onError: (error:any) => {
},
}
);
}

View File

@ -1,32 +0,0 @@
import { useQueryClient, useMutation } from "react-query";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import useAxios from "./useAxios";
export const useToggleStatus = (key:any, url:any, object_id:any) => {
const axios = useAxios();
const queryClient = useQueryClient();
const [t] = useTranslation();
return useMutation(
async ({ id, new_status }:any) => {
const { data } = await axios.post(url, {
[object_id]: id,
new_status,
});
return { ...data, id, new_status };
},
{
onSuccess: ({ message, id, new_status }) => {
toast.success(message || t("toggle_success"));
queryClient.invalidateQueries([key]);
},
onError: (err:any) => {
const message = err?.response?.data?.message || t("toggle_failed");
toast.error(message);
// validateSession(err.response);
},
}
);
};

View File

@ -1,58 +1,36 @@
import { useQueryClient, useMutation, UseMutationResult } from "react-query"; import { useMutation, UseMutationResult } from "react-query";
import { toast } from "react-toastify";
import useAxios from "./useAxios"; import useAxios from "./useAxios";
import { useTranslation } from "react-i18next"; import { HEADER_KEY } from "../config";
import { useParams } from "react-router-dom"; import { AxiosResponse } from "../../types/Axios";
type AxiosResponse = {
message: string;
// Add other properties as needed
};
const useUpdateMutation = ( const useUpdateMutation = (
key: string, key: string,
url: string, url: string,
toastMessage: boolean = false, message?: string,
method?:string ): UseMutationResult<AxiosResponse, any, any, any> => {
): UseMutationResult<AxiosResponse, unknown, unknown> => {
const axios = useAxios(); const axios = useAxios();
const queryClient = useQueryClient();
const [t] = useTranslation();
const {id}= useParams()
return useMutation<AxiosResponse, unknown, unknown>( return useMutation<AxiosResponse, any, any>(async (dataToSend) => {
async (dataToSend) => { let request = null;
if(method === "put"){ let id = null;
const { data } = await axios.put(url+"/"+id, dataToSend );
return data; if (dataToSend instanceof FormData) {
dataToSend.append("_method", "PUT");
request = dataToSend;
id = dataToSend.get("id");
} else { } else {
const { data } = await axios.post(url+"/"+id, dataToSend,{ request = { ...dataToSend, _method: "PUT" };
headers: { id = dataToSend?.id;
'Content-Type': 'multipart/form-data'
} }
const { data } = await axios.post(url + `/` + id, request, {
headers: {
"Content-Type": "multipart/form-data",
[HEADER_KEY]: key,
},
}); });
return data; return data;
} });
},
{
onSuccess: (data) => {
if (toastMessage) {
toast.success(data.message || t("updated_successfully"));
}
queryClient.invalidateQueries([key]);
},
onError: (err:any) => {
const message = err?.response?.data?.message || t("failed_to_update_data");
toast.error(message);
// validateSession(err.response);
},
}
);
}; };
export default useUpdateMutation; export default useUpdateMutation;

View File

@ -1,57 +0,0 @@
import { useQueryClient, useMutation, UseMutationResult } from "react-query";
import { toast } from "react-toastify";
import useAxios from "./useAxios";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
type AxiosResponse = {
message: string;
// Add other properties as needed
};
const useUpdateMutationById = (
key: string,
url: string,
toastMessage: boolean = false,
method?:string
): UseMutationResult<AxiosResponse, unknown, unknown> => {
const axios = useAxios();
const queryClient = useQueryClient();
const [t] = useTranslation();
return useMutation<AxiosResponse, unknown, unknown>(
async (dataToSend:any) => {
if(method === "put"){
const { data } = await axios.put(url+"/"+dataToSend?.id, dataToSend );
return data;
}else{
const { data } = await axios.post(url+"/"+dataToSend?.id, dataToSend,{
headers: {
'Content-Type': 'multipart/form-data'
}
});
return data;
}
},
{
onSuccess: (data) => {
if (toastMessage) {
toast.success(data.message || t("updated_successfully"));
}
queryClient.invalidateQueries([key]);
},
onError: (err:any) => {
const message = err?.response?.data?.message || t("failed_to_update_data");
toast.error(message);
// validateSession(err.response);
},
}
);
};
export default useUpdateMutationById;

View File

@ -1,52 +0,0 @@
import { useQueryClient, useMutation, UseMutationResult } from "react-query";
import { toast } from "react-toastify";
import useAxios from "./useAxios";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
type AxiosResponse = {
message: string;
// Add other properties as needed
};
const useUpdateMutationPost = (
key: string,
url: string,
toastMessage: boolean = true,
method?:string
): UseMutationResult<AxiosResponse, unknown, unknown> => {
const axios = useAxios();
const queryClient = useQueryClient();
const [t] = useTranslation();
const {id}= useParams()
return useMutation<AxiosResponse, unknown, unknown>(
async (dataToSend) => {
const { data } = await axios.post(url+"/"+id, dataToSend,{
headers: {
'Content-Type': 'multipart/form-data'
}
});
return data;
},
{
onSuccess: (data) => {
if (toastMessage) {
toast.success(data.message || t("updated_successfully"));
}
queryClient.invalidateQueries([key]);
},
onError: (err:any) => {
const message = err?.response?.data?.message || t("failed_to_update_data");
toast.error(message);
// validateSession(err.response);
},
}
);
};
export default useUpdateMutationPost;

View File

@ -1,75 +0,0 @@
import { useState } from "react";
import { useQueryClient, useMutation, MutationFunction } from "react-query";
import { toast } from "react-toastify";
import useAxios from "./useAxios";
import { AxiosResponse } from "axios";
import { useTranslation } from "react-i18next";
import { QueryStatusEnum } from "../../config/QueryStatus";
// import { validateSession } from "./validateSession";
interface UploadWithProgressReturnType {
percentCompleted: number;
mutate: MutationFunction;
isLoading: boolean;
isError: boolean;
error: unknown;
isSuccess:boolean,
value:any,
status : QueryStatusEnum
}
export const useUploadWithProgress = (
key: string,
url: string
): UploadWithProgressReturnType => {
const axios = useAxios();
const queryClient = useQueryClient();
const [percentCompleted, setPercentCompleted] = useState<number>(0.0);
const {t} = useTranslation();
const mutation = useMutation<
AxiosResponse<any>,
unknown,
any,
{
onSuccess: (data: AxiosResponse<any>) => void;
onError: (error: unknown) => void;
}
>(
async (dataToSend) => {
setPercentCompleted(0.0);
const { data } = await axios.post(url, dataToSend, {
onUploadProgress: (event:any) => {
console.log();
if (event?.event?.lengthComputable) {
setPercentCompleted(Math.round((event.loaded * 100) / event.total));
}
},
});
return data;
},
{
onSuccess: ({ data }) => {
toast.success(data.message || t("_messages.success.upload"));
queryClient.invalidateQueries([key]);
},
onError: (err:any) => {
const message =
err?.response?.data?.message || t("_messages.error.upload");
toast.error(message);
// validateSession(err.response);
},
}
);
return {
percentCompleted,
value:percentCompleted,
mutate: mutation.mutate as MutationFunction,
isLoading: mutation.isLoading,
isError: mutation.isError,
error: mutation.error,
isSuccess :mutation.isSuccess,
status : mutation.status as QueryStatusEnum
};
};

22
src/api/setting.ts Normal file
View File

@ -0,0 +1,22 @@
import useGetQuery from "./helper/useGetQuery";
import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation"
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
ADD: `restaurant`,
GET_ALL: `restaurant`,
DELETE: `restaurant`,
UPDATE: `restaurant`,
};
const KEY = "restaurant"
export const useGetSetting = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
export const useAddSetting = () => useAddMutation(KEY, API.ADD);
export const useUpdateSetting = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
export const useDeleteSetting = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -0,0 +1,7 @@
export function PaginationParams(location: any) {
const searchParams = new URLSearchParams(location?.search);
return {
page: searchParams.get("page") || "",
per_page: searchParams.get("per_page") || "",
};
}

View File

@ -0,0 +1,5 @@
export function filterParams(params: any) {
return Object.fromEntries(
Object.entries(params ?? {}).filter(([_, value]) => value !== ""),
);
}

View File

@ -0,0 +1,16 @@
import { useState, useEffect } from "react";
import { useLocation } from "react-router-dom";
function useSearchQuery(paramName: string): [string, (value: string) => void] {
const location = useLocation();
const [queryValue, setQueryValue] = useState<string>("");
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
setQueryValue(searchParams.get(paramName) || "");
}, [location, paramName]);
return [queryValue, setQueryValue];
}
export default useSearchQuery;

10
src/enums/Axios.ts Normal file
View File

@ -0,0 +1,10 @@
export enum AxiosQueryEnum {
GET = "get",
POST = "post",
DELETE = "delete",
}
export enum AxiosStatusEnum {
VALIDATION = 422,
AUTHENTICATED = 401,
}

5
src/enums/QueryStatus.ts Normal file
View File

@ -0,0 +1,5 @@
export enum QueryStatusEnum {
LOADING = "loading",
ERROR = "error",
SUCCESS = "success",
}

7
src/enums/Validation.ts Normal file
View File

@ -0,0 +1,7 @@
export enum Payments {
MAX_VALUE = 900000,
}
export enum Exam {
MAX_VALUE = 10000,
}

8
src/enums/params.ts Normal file
View File

@ -0,0 +1,8 @@
export enum ParamsEnum {
STUDENT_ID = "student_id",
COURSE_ID = "course_id",
EDUCATION_CLASS_ID = "edu_class_id",
SUBJECT_ID = "subject_id",
BRANCH_ID = "branch_id",
CYCLE_ID = "cycle_id",
}

View File

@ -1,7 +1,6 @@
import App from './App'; import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import './Styles/AppStyle/Import.scss' import './Styles/AppStyle/Import.scss'
import 'react-tabs/style/react-tabs.css';
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import ProviderContainer from './ProviderContainer'; import ProviderContainer from './ProviderContainer';

View File

@ -1,17 +1,18 @@
import React from 'react' import React from "react";
import { QueryClient, QueryClientProvider } from 'react-query' import { QueryClient, QueryClientProvider } from "react-query";
function QueryProvider({ children }: any) { function QueryProvider({ children }: any) {
const queryClient = new QueryClient() const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
});
return ( return (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
{children} );
</QueryClientProvider>
)
} }
export default QueryProvider export default QueryProvider;

View File

@ -1,37 +0,0 @@
import { Socket, io } from 'socket.io-client';
import { TOKEN_KEY_SOCKET } from '../config/AppKey';
export const BASE_URL_SOCKET = 'http://192.168.1.14:8001/';
var socket :Socket | null = null ;
function InitSocket(){
if (!socket){
socket = io(BASE_URL_SOCKET , {
transports:['websocket'],
autoConnect:true,
query:{
token:localStorage.getItem(TOKEN_KEY_SOCKET),
}
});
}
}
export const disconnectSocket = ()=>{
socket?.disconnect();
socket = null;
}
export const getScoket = ()=>{
InitSocket();
return socket;
}

3
src/types/Axios.ts Normal file
View File

@ -0,0 +1,3 @@
export type AxiosResponse = {
message?: string;
};

49
src/types/item.ts Normal file
View File

@ -0,0 +1,49 @@
export interface Restaurant {
id: number;
name: string;
address: string;
logo: string;
slogan: {
text: string;
};
contact_info: {
phone_number: string;
email: string;
};
attributes: {
attribute: string;
};
video: string;
design_system: {
primary_color: string;
secondry_color: string;
};
location: {
location: string;
};
images: any[]; // Assuming the images array contains objects, replace 'any' with appropriate type if known
categories: Category[];
offers: Offer[];
uuid: string;
created_at: string;
updated_at: string;
}
interface Category {
id: number;
name: string;
image: string;
restaurant_id: number;
meals_count: number;
uuid: string;
}
interface Offer {
id: number;
name: string;
description: string;
image: string;
price: number;
restaurant_id: number;
uuid: string;
}

View File

@ -0,0 +1,13 @@
interface KeyValue {
key: string;
value: any;
}
export function convertArrayToJsonString(array: KeyValue[]): string {
const jsonObject: { [key: string]: any } = {};
array.forEach(item => {
jsonObject[item.key] = item.value;
});
return JSON.stringify(jsonObject);
}

View File

@ -0,0 +1,8 @@
export interface KeyAndValue {
key: string;
value: any;
}
export function objectToArray(obj: Record<string, any>): KeyAndValue[] {
return Object.keys(obj).map((key: string) => ({ key, value: obj[key] }));
}

11
vite.config.js Normal file
View File

@ -0,0 +1,11 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig(() => {
return {
build: {
outDir: 'build',
},
plugins: [react()],
};
});