Compare commits

..

3 Commits

Author SHA1 Message Date
karimalden
b91fc7e7cf fix product 2024-07-28 15:23:22 +03:00
karimalden
ecf5b1c9b6 fixtabs 2024-07-22 12:52:21 +03:00
karimalden
e6eedf13fe convert to vite 2024-07-22 12:49:00 +03:00
40 changed files with 714 additions and 123 deletions

View File

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

View File

@ -7,7 +7,7 @@
name="description"
content="Web site created using create-react-app"
/>
<script type="module" src="/src/index.tsx"></script>
<title>Hijab - App</title>
</head>
<body>

View File

@ -68,8 +68,8 @@
"zustand": "^4.4.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"start": "vite --port=3000",
"build": "vite build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"g:api": "node src/Extensions/FileGenerator/generateApi.js",

View File

@ -0,0 +1,10 @@
export const getNestedValue = (obj: any, path: string): any => {
return path.split('.').reduce((acc, part) => {
const arrayMatch = part.match(/(\w+)\[(\d+)\]/);
if (arrayMatch) {
const [, key, index] = arrayMatch;
return acc && acc[key] && acc[key][index];
}
return acc && acc[part];
}, obj);
};

View File

@ -6,6 +6,7 @@ const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }:
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
console.log(name);
return (
<div className="ValidationField w-100" >

View File

@ -1,32 +1,37 @@
import { Button, Upload, UploadFile } from 'antd'
import { Button, Upload, UploadFile } from 'antd';
import useFormField from '../../../Hooks/useFormField';
import { UploadOutlined } from '@ant-design/icons';
import { getNestedValue } from '../../Utils/getNestedValue';
import { ImageBaseURL } from '../../../api/config';
import { fixImageUrl } from '../utils/fixImageUrl';
import { customRequest } from '../utils/customRequest';
const File = ({ name, label, onChange, isDisabled,placholder,className, props }: any) => {
const { formik, t ,isError} = useFormField(name, props)
let FormikName = formik.values[name];
const imageUrl = formik.values[name] ? ImageBaseURL + FormikName : '';
const File: React.FC<any> = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}) => {
const { formik, t, isError } = useFormField(name, props);
const FormikName = getNestedValue(formik.values, name);
const imageUrl = FormikName? fixImageUrl(ImageBaseURL + FormikName): '';
const fileList: UploadFile[] = [
{
uid: '-1',
name: '',
status: 'done',
url: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage"),
thumbUrl: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage")
}
url: imageUrl,
thumbUrl: imageUrl,
},
];
const FilehandleChange = (value:any) => {
formik.setFieldValue(name, value.file.originFileObj)
;
};
const customRequest = async ({ onSuccess}: any) => {
onSuccess();
};
return (
<div className="ValidationField">
<label htmlFor={name} className="text">
@ -38,25 +43,22 @@ const File = ({ name, label, onChange, isDisabled,placholder,className, props }:
listType="picture"
maxCount={1}
defaultFileList={[...fileList]}
onChange={onChange || FilehandleChange}
onChange={onChange}
customRequest={customRequest}
className={`${className} w-100`}
>
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}>
{placholder ?? t("upload_image") }
<Button
className={isError ? 'isError w-100' : ' w-100'}
icon={<UploadOutlined />}
>
{placeholder ?? t('upload_image')}
</Button>
<div className='Error_color'> {isError ? "required" : ""}</div>
{isError && (
<div className="Error_color">required</div>
)}
</Upload>
</div>
)
}
);
};
export default File
export default File;

View File

@ -1,52 +1,97 @@
import { Button, Upload } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { ImageBaseURL } from '../../../api/config';
import { useTranslation } from 'react-i18next';
import useFormField from '../../../Hooks/useFormField';
import { Button, Upload } from "antd";
import { UploadOutlined } from "@ant-design/icons";
const MaltyFile = ({ name, label, onChange, isDisabled, placholder, className, props }: any) => {
import useFormField from "../../../Hooks/useFormField";
import { customRequest } from "../utils/customRequest";
import { getNestedValue } from "../../Utils/getNestedValue";
import { fixImageUrl } from "../utils/fixImageUrl";
import { ImageBaseURL } from "../../../api/config";
import { Console } from "console";
const MaltyFile = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}: any) => {
const { formik, t, isError } = useFormField(name, props);
const imageUrl = formik?.values[name] ? ImageBaseURL + formik.values[name] : '';
const fileList = formik?.values[name] ? formik?.values[name]?.map((file: any, index: number) => ({
const FormikName = getNestedValue(formik.values, name);
let imageUrl = FormikName ?? null;
// Mapping formik values to fileList format
console.table(imageUrl)
const fileList = imageUrl
? imageUrl.map((file: any, index: number) => {
const imageUrl = (file?.path || file?.url) ? fixImageUrl(ImageBaseURL + file?.path ?? file?.url): '';
console.log(file);
console.log(imageUrl);
return file instanceof File
? {
uid: index,
name: file.name,
status: 'done',
url: file.url || '',
thumbUrl: file.url || '',
})) : [];
name: file?.name,
status: "done",
originFileObj: file,
}
: {
uid: index,
id: file?.id,
name: file?.name,
status: "done",
url: imageUrl || "",
thumbUrl: imageUrl || "",
};
})
: [];
const FilehandleChange = ({ file, fileList }: any) => {
formik.setFieldValue(name, fileList.map((file: any) => file.originFileObj));
const FilehandleChange = ({ fileList }: any) => {
if (fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(
name,
fileList.map((file: any) => {
console.log(file);
return(
file?.originFileObj ?? file
)
}),
);
}
};
const customRequest = async ({ onSuccess }: any) => {
// Perform any necessary actions before onSuccess is called
onSuccess();
};
return (
<div className="ValidationField">
<div className="ValidationField upload_image_button">
<label htmlFor={name} className="text">
{t(`${label || name}`)}
{t(`input.${label || name}`)}
</label>
<Upload
disabled={isDisabled}
listType="picture"
defaultFileList={[...fileList]}
fileList={fileList} // Using fileList instead of defaultFileList
onChange={onChange || FilehandleChange}
customRequest={customRequest}
className={`${className} w-100`}
multiple // Allow multiple files to be selected
id={name}
>
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}>
{placholder ?? t("upload_image")}
<Button
className={isError ? "isError w-100" : " w-100"}
icon={<UploadOutlined />}
>
{t(`input.` + placeholder) ?? t("input.upload_image")}
</Button>
<div className='Error_color'> {isError ? "required" : ""}</div>
<div className="Error_color"> {isError ? "required" : ""}</div>
</Upload>
</div>
);
};
export default MaltyFile;
78

View File

@ -0,0 +1,3 @@
export const customRequest = async ({ onSuccess}: any) => {
onSuccess();
}

View File

@ -0,0 +1,3 @@
export const fixImageUrl = (url: string | undefined): string => {
return url?.replace('public', '/storage') || '';
};

View File

@ -14,10 +14,10 @@ type TViewPage ={
getDataToSend:any,
handleSubmit:any,
// BarStatus:any,
IsloadingButton:boolean
IsLoadingButton:boolean
}
const ViewPage: React.FC<TViewPage>= ({children,getInitialValues, getValidationSchema,handleSubmit,IsloadingButton})=> {
const ViewPage: React.FC<TViewPage>= ({children,getInitialValues, getValidationSchema,handleSubmit,IsLoadingButton})=> {
const {objectToEdit} = usePageState()
const {t} = useTranslation();
@ -66,7 +66,7 @@ const ViewPage: React.FC<TViewPage>= ({children,getInitialValues, getValidation
<LoadingButton
type="submit"
color="primary"
isLoading={IsloadingButton}
isLoading={IsLoadingButton}
>
{t("save")}
</LoadingButton>

View File

@ -18,14 +18,10 @@ function Page() {
const navigate = useNavigate()
const totalRows = data?.meta?.total;
const { setObjectToEdit, objectToEdit } = usePageState()
console.log(objectToEdit,"objectToEdit");
useEffect(() => {
console.log(objectToEdit,"objectToEdit");
if(objectToEdit)
setObjectToEdit(null)
}, [setObjectToEdit,objectToEdit ,data,isRefetching])
return (

View File

@ -19,7 +19,7 @@ const AddcategoriesPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState()
const {mutate,isLoading:IsloadingButton ,isSuccess,data } = useAddCategories()
const {mutate,isLoading:IsLoadingButton ,isSuccess,data } = useAddCategories()
const {mutateAsync} = useAddAttribute()
const {mutate:AddAttributeValue } = useAddAttributeValue()
@ -218,7 +218,7 @@ const AddcategoriesPage = () => {
}, []);
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -227,9 +227,9 @@ const AddcategoriesPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("attributes")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("attributes")}</h6></div></Tab>
</TabList>

View File

@ -26,7 +26,7 @@ const EditPage = () => {
const { id } = useParams()
const { data: Atrribute, isLoading: isLoadingAtrribute, isRefetching: AttributeisRefetching } = useGetSingleAttribute({ name: "category_id", id: id }, {})
const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateCategories()
const { mutate, isSuccess,isLoading:IsLoadingButton } = useUpdateCategories()
const { mutateAsync } = useAddAttribute()
const { mutate: mutateAttributeValue } = useAddAttributeValue()
const { mutate: UpdateAttribute } = useUpdateAttribute("put")
@ -492,7 +492,7 @@ const EditPage = () => {
};
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
if (AttributeisRefetching || isRefetching || isLoadingAtrribute || isLoading || !objectToEdit || (Array.isArray(objectToEdit) && objectToEdit.some(item => item === undefined))) {
return <Spin />
@ -506,8 +506,8 @@ const EditPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("attributes")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("attributes")}</h6></div></Tab>
</TabList>

View File

@ -12,7 +12,7 @@ import Form from './AddForm';
const AddCouponPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddCoupon()
const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddCoupon()
const handleSubmit = (values: any) => {
const transformedValues = { ...values }; // Create a new object
@ -46,7 +46,7 @@ const AddCouponPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -55,7 +55,7 @@ const AddCouponPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>

View File

@ -18,7 +18,7 @@ import Form from './EditForm';
const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation();
const { data,isLoading:IsloadingButton,isRefetching } = useGetOneCoupon()
const { data,isLoading:IsLoadingButton,isRefetching } = useGetOneCoupon()
const { mutate, isSuccess } = useUpdateCoupon("put")
const handleSubmit = (values: any) => {
const products = values?.product_attr?.map((item: any) => {
@ -70,13 +70,13 @@ const EditPage = () => {
const getValidationSchema = () => {
return null
};
if ( IsloadingButton || !objectToEdit || isRefetching) {
if ( IsLoadingButton || !objectToEdit || isRefetching) {
return <Spin />
}
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -85,7 +85,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >

View File

@ -14,7 +14,7 @@ import { useAddNotification } from '../../../api/notification';
const AddPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddNotification()
const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddNotification()
const {id} = useParams()
const handleSubmit = (values: any) => {
const hasAsterisk = values?.user_ids.some((item:any) => typeof item === 'string' && item.includes('*'));
@ -55,7 +55,7 @@ const AddPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -64,7 +64,7 @@ const AddPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>

View File

@ -18,7 +18,7 @@ import { AddNewVariation } from './Addfn/AddNewVariation';
const AddProductPage = () => {
const { mutate, isLoading:IsloadingButton, data, isSuccess } = useAddProduct()
const { mutate, isLoading:IsLoadingButton, data, isSuccess } = useAddProduct()
const { mutate: AddVariation } = useAddProductVariation()
const [IsValed, setIsValed] = useState(false)
@ -74,7 +74,7 @@ const AddProductPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -83,9 +83,9 @@ const AddProductPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='SingleInfo'>{t("Base_info")} </h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='SingleInfo'>{t("Base_info")} </h6></div></Tab>
<Tab ><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><BsInfoCircle size={20} /></span> <h6 className='SingleInfo'>{t("VarianInfo")}</h6></div></Tab>
<Tab ><div className='TabContainer'><span className='TabIcon'><BsInfoCircle size={20} /></span> <h6 className='SingleInfo'>{t("VarianInfo")}</h6></div></Tab>
</TabList>

View File

@ -24,7 +24,7 @@ const ViewProduct = () => {
const { data, isLoading, isRefetching } = useGetOneProduct({ id: id })
const [OldData, setOldData] = useState(data?.data?.products)
const { mutate, isSuccess, isLoading: IsloadingButton } = useUpdateProduct('put')
const { mutate, isSuccess, isLoading: IsLoadingButton } = useUpdateProduct('put')
const { mutate: UpdateVariation } = useUpdateProductVariation()
const { mutate: AddVariation } = useAddProductVariation()
@ -343,7 +343,7 @@ console.log(mappedAttributes, "mappedAttributes");
return <Spin />
}
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit, IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit, IsLoadingButton };
return (
@ -352,9 +352,9 @@ console.log(mappedAttributes, "mappedAttributes");
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("Base_info")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("Base_info")}</h6></div></Tab>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><BsInfoCircle size={20} /></span> <h6 className='Tab_Info'>{t("VarianInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><BsInfoCircle size={20} /></span> <h6 className='Tab_Info'>{t("VarianInfo")}</h6></div></Tab>
</TabList>

View File

@ -13,7 +13,7 @@ import Form from './AddForm';
const AddSliderPage = () => {
const {mutate , isLoading:IsloadingButton , isSuccess} = useAddSlider()
const {mutate , isLoading:IsLoadingButton , isSuccess} = useAddSlider()
const handleSubmit = (values:any)=>{
mutate(values)
@ -26,7 +26,7 @@ const AddSliderPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -35,7 +35,7 @@ const AddSliderPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>

View File

@ -19,7 +19,7 @@ const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState()
const {t} = useTranslation();
const { data } = useGetOneSlider()
const {mutate ,isSuccess,isLoading:IsloadingButton} = useUpdateSlider()
const {mutate ,isSuccess,isLoading:IsLoadingButton} = useUpdateSlider()
const FormatedData = data?.data ;
const handleSubmit = (values:any)=>{
@ -51,7 +51,7 @@ const EditPage = () => {
};
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -60,7 +60,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >

View File

@ -11,7 +11,7 @@ import Form from './AddForm';
const AddSupportMessagesPage = () => {
const {mutate , isLoading:IsloadingButton , isSuccess} = useAddSupportMessages()
const {mutate , isLoading:IsLoadingButton , isSuccess} = useAddSupportMessages()
const handleSubmit = (values:any)=>{
console.log(values,"values");
@ -25,7 +25,7 @@ const AddSupportMessagesPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -34,7 +34,7 @@ const AddSupportMessagesPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>

View File

@ -14,7 +14,7 @@ import { useAddNotification } from '../../../../api/notification';
const AddPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddNotification()
const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddNotification()
const {id} = useParams()
const handleSubmit = (values: any) => {
@ -48,7 +48,7 @@ const AddPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -57,7 +57,7 @@ const AddPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>

View File

@ -15,7 +15,7 @@ const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState()
const {t} = useTranslation();
const { data } = useGetOneUser()
const {mutate ,isSuccess,isLoading:IsloadingButton} = useUpdateAdmin()
const {mutate ,isSuccess,isLoading:IsLoadingButton} = useUpdateAdmin()
const handleSubmit = (values:any)=>{
return mutate(values);
@ -37,7 +37,7 @@ const EditPage = () => {
};
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return (
@ -46,7 +46,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >

View File

@ -0,0 +1,58 @@
import DashBody from '../../Layout/Dashboard/DashBody'
import DashHeader from '../../Layout/Dashboard/DashHeader'
import LyTable from '../../Layout/Dashboard/LyTable'
import useTableColumns from './useTableColumns'
import { QueryStatusEnum } from '../../config/QueryStatus'
import { useGetProduct } from '../../api/product'
import { useNavigate } from 'react-router-dom'
import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
import SearchField from '../../Layout/Dashboard/SearchField'
import SelectField from '../../Layout/Dashboard/SelectWSearchField'
import { useGetCategories } from '../../api/Categories'
function ProductsPage() {
const column =useTableColumns()
const {data ,status } = useGetProduct()
const navigate = useNavigate()
const totalRows = data?.meta?.total;
const { data:Categories } = useGetCategories()
const language = localStorage.getItem("language") ?? "en"
const SelectData = Categories?.categories?.map((item:any)=>(
{
label : item?.name[language],
value : item?.id
}
))
return (
<DashBody status={status as QueryStatusEnum} >
<DashHeader showAddButton={false} title={'products'}>
<div className='RightSide d-flex gap-2 align-center '>
<SelectField selectBy="category" submiteBy="category_id" lebel="category" option={SelectData} />
<SearchField searchBy="name"/>
<AddButton onClick={()=>navigate('add')}></AddButton>
</div>
</DashHeader>
<LyTable
data={data?.BaseProducts}
isLoading={false}
columns={column}
total={totalRows }
is_pagination={true}
/>
</DashBody>
)
}
export default ProductsPage

View File

@ -0,0 +1,54 @@
import { getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
import 'react-tabs/style/react-tabs.css';
import { MdLanguage } from 'react-icons/md'
import ViewPage from '../../../Layout/Dashboard/ViewPage';
import BasicInfo from './BasicInfo';
import { useTranslation } from 'react-i18next';
import VariantInfo from './VariantInfo';
// import AttributeInfo from './AttributeInfo';
const AddProductPage = () => {
const handleSubmit = (values: any) => {
console.log(values,"values");
}
const { t } = useTranslation();
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton:false };
return (
<div className='ViewPage'>
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 >{t("Base_info")} </h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 >{t("variant")} </h6></div></Tab>
</TabList>
<TabBody >
<div className="mt-4"><BasicInfo /></div>
</TabBody>
<TabBody >
<div className="mt-4"><VariantInfo /></div>
</TabBody>
</Tabs>
</ViewPage>
</div>
)
}
export default AddProductPage

View File

@ -0,0 +1,59 @@
import React, { useEffect, useState } from 'react'
import { Col, Row } from 'reactstrap'
import ValidationField from '../../../Components/ValidationField/ValidationField'
import { useTranslation } from 'react-i18next';
import { useFormikContext } from 'formik';
import { toast } from 'react-toastify';
import { useGetCategories } from '../../../api/Categories';
import useFormatToSelect from '../../../Hooks/useFormatToSelect';
import { useParams } from 'react-router-dom';
const BasicInfo = ({ setIsValed, IsValed }: any) => {
const [t] = useTranslation();
const formikContext = useFormikContext();
const { values, isValid } = formikContext;
const { data } = useGetCategories()
const language = localStorage.getItem("language") ?? "en"
const {id}=useParams()
const SelectData = data?.categories?.map((item:any)=>(
{
label : item?.name[language],
value : item?.id
}
))
useEffect(() => {
const { name_ar, name_en, name_de, main_photo, category_id } = values as any;
if (name_ar && name_en && name_de && main_photo && category_id && IsValed === false) {
toast.success(t("view_information_filed_fill_sucsessfully"));
setIsValed(true)
} else {
// console.log(isValid, "isValid");
}
}, [values]);
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
<ValidationField name="name_ar" />
<ValidationField name="name_en" />
</Col>
<Col>
<ValidationField name="name_de" />
{/* <ValidationField name="main_photo" type='File' /> */}
{!id &&
<ValidationField name="category_id" type="Search" label='category' placeholder='category' option={SelectData} searchBy={"name"} />
}
</Col>
</Row>
)
}
export default BasicInfo

View File

@ -0,0 +1,35 @@
import React from 'react'
import { Variant } from '../../formUtil'
import { Col, Row } from 'reactstrap';
import ValidationField from '../../../../Components/ValidationField/ValidationField';
const TabContent = ({data,index}:{data:Variant,index:number}) => {
console.log(data);
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
<ValidationField name={`variant.${index}.name.ar`} label='name_ar' placeholder='name_ar' />
<ValidationField name={`variant.${index}.name.en`} label='name_en' placeholder='name_en' />
<ValidationField name={`variant.${index}.name.de`} label='name_de' placeholder='name_de' />
</Col>
<Col>
<ValidationField name={`variant.${index}.description.ar`} label='description_ar' placeholder='description_ar' />
<ValidationField name={`variant.${index}.description.en`} label='description_en' placeholder='description_en' />
<ValidationField name={`variant.${index}.description.de`} label='description_de' placeholder='description_de' />
<ValidationField name={`variant.${index}.price`} label='price' placeholder='price' />
<ValidationField type='File' name={`variant.${index}.main_photo`} label='main_photo' placeholder='main_photo' />
<ValidationField type='MaltyFile' name={`variant.${index}.images`} label='images' placeholder='images' />
</Col>
</Row>
)
}
export default TabContent

View File

@ -0,0 +1,40 @@
import React from 'react'
import { Variant } from '../../formUtil'
import { Tabs, TabsProps } from 'antd';
import { useTranslation } from 'react-i18next';
import TabContent from './TabContent';
import AddIcon from '../handle/AddIcon';
import DeleteIcon from '../handle/DeleteIcon';
import DuplicateIcon from '../handle/DuplicateIcon';
const TabsContainer = ({data}:{data:Variant[]}) => {
const [t] = useTranslation()
const width = 1400;
const label = "variant"
const tabPosition = width > 1000 ? 'left' : 'top';
const items : TabsProps['items'] = data?.map((item:Variant,index:number) =>{
const key = index + 1 ;
return {
key: String(key) ,
label: <div className='tabHeader'> <div>{t(label)} {key} </div> <DuplicateIcon index={index} /> <DeleteIcon index={index}/> </div>,
children:<TabContent index={index} data={item} />
}
})
return (
<Tabs
defaultActiveKey="1"
items={items}
tabPosition={tabPosition}
type="editable-card"
removeIcon
addIcon={<AddIcon/>}
/>
)
}
export default TabsContainer

View File

@ -0,0 +1,13 @@
import { useFormikContext } from 'formik'
import { InitialValuesProductType, Variant } from '../formUtil'
import TabsContainer from './Tabs/TabsContainer'
const VariantInfo = () => {
const {values} = useFormikContext<InitialValuesProductType>()
const variant = values?.variant
return (
<TabsContainer data={variant} />
)
}
export default VariantInfo

View File

@ -0,0 +1,24 @@
import { useFormikContext } from 'formik'
import { FaPlus } from 'react-icons/fa'
import { emptyVariant, InitialValuesProductType } from '../../formUtil'
const AddIcon = () => {
const {values,setFieldValue} = useFormikContext<InitialValuesProductType>()
const handleClick = ()=>{
setFieldValue("variant",
[...values?.variant,
emptyVariant
]
)
}
return (
<FaPlus size={20} onClick={()=> handleClick()}/>
)
}
export default AddIcon

View File

@ -0,0 +1,21 @@
import { useFormikContext } from 'formik'
import { InitialValuesProductType } from '../../formUtil'
import { MdOutlineDeleteOutline } from 'react-icons/md'
const DeleteIcon = ({index}:{index:number}) => {
const {values,setFieldValue} = useFormikContext<InitialValuesProductType>()
const handleClick = ()=>{
const newData = values?.variant?.filter((_, i: number) => i !== index);
setFieldValue("variant", newData)
}
return (
<MdOutlineDeleteOutline size={20} onClick={()=> handleClick()}/>
)
}
export default DeleteIcon

View File

@ -0,0 +1,29 @@
import { useFormikContext } from 'formik'
import { FaPlus } from 'react-icons/fa'
import { InitialValuesProductType } from '../../formUtil'
import { CopyOutlined } from '@ant-design/icons'
const DuplicateIcon = ({index}:{index:number}) => {
const {values,setFieldValue} = useFormikContext<InitialValuesProductType>()
const handleClick = ()=>{
const currentValue = values?.variant?.find((item:any,key:number)=>{
return index === key
})
setFieldValue("variant",
[
...values?.variant,
currentValue
]
)
}
return (
<CopyOutlined size={20} onClick={()=> handleClick()}/>
)
}
export default DuplicateIcon

View File

@ -0,0 +1,68 @@
import * as Yup from "yup";
interface translate {
ar: string;
en: string;
de: string;
}
export interface Variant {
name: translate;
description: translate;
price:number | null;
main_photo:File | string | null
images:(File | string | null | object)[]
}
interface Category {
id: string;
}
interface ObjectToEditProductType {
id: string;
name: translate;
category: Category;
variant?: Variant[];
}
export interface InitialValuesProductType {
id: string;
name: translate;
category_id: string;
variant: Variant[];
}
export const emptyVariant : Variant = {
name: { en: '', de: '', ar: '' },
description: { en: '', de: '', ar: '' },
price:null,
main_photo:null,
images:[
{ created_at: "2024-06-11T10:14:38.000000Z",
id: 35,
path : "public/product/images/XX5EcgZmtbNhBoaXwdjNTKjHYPrOsBqyQDHu2omI.png"
}
],
}
export const getInitialValues = (objectToEdit: ObjectToEditProductType): InitialValuesProductType => {
const variant = objectToEdit?.variant;
return {
id: objectToEdit?.id,
name: objectToEdit?.name ?? { en: '', de: '', ar: '' },
category_id: objectToEdit?.category?.id ?? '',
variant: variant ?? [emptyVariant]
};
};
export const getValidationSchema = (editMode: boolean = false) => {
return Yup.object().shape({
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
return data;
};

View File

@ -0,0 +1,89 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import Actions from "../../Components/Ui/tables/Actions";
import { HovarableImage } from "../../Components/Ui";
import { BaseURL } from "../../api/config";
import { ToggleStatus } from "../../Components/Ui/ToggleStatus";
import ColumnsImage from "../../Components/Columns/ColumnsImage";
import LoadingSpinner from "../../Components/Ui/LoadingSpinner";
import { Switch } from "antd";
import { mapTranslatedProperties } from "../../utils/language/mapTranslatedProperties";
// import { useDeleteProduct, useUpdateProductStatus } from "../../api/owner_products";
import { useNavigate } from "react-router-dom";
import { useDeleteProduct, useUpdateProductStatus } from "../../api/product";
const useTableColumns :any = () => {
const [t] = useTranslation();
const toggleMutation = useUpdateProductStatus();
const deleteMutation = useDeleteProduct();
const navigate = useNavigate()
const handleChange = (row:any)=> {
const status = row?.favorite ;
toggleMutation.mutate({id:row?.id,new_status:status})
}
const language = localStorage.getItem("language") ?? "en"
return useMemo(
() => [
{
name: t("id"),
sortable: true, // Enable sorting for id column
center: true,
selector: (row: any) => row.id, // Specify selector function for sorting
}, {
name: t("name"),
sortable: false,
center: true,
selector:(row:any) => row?.name?.[language],
},
{
name: t("product_count"),
sortable: false,
center: true,
selector:(row:any) => row?.product_count,
},
{
name: t("category"),
sortable: false,
center: true,
cell: (row:any) => (
row?.category?.name?.[language]
),
},
// {
// name: t("favorite"),
// sortable: false,
// center: true,
// cell: (row:any) => (
// <ToggleStatus handleSwitch={handleChange} object={row} toggleMutation={toggleMutation} />
// ),
// },
{
name: "#",
sortable: false,
center: "true",
cell: (row:any) => (
<Actions
onEdit={()=> navigate('/products/'+row.id)}
objectToEdit={row}
showEdit={true}
showView={false}
onDelete={() => deleteMutation.mutate({ id: row.id })}
/>
),
},
],
[t]
);
};
export default useTableColumns;

View File

@ -21,7 +21,7 @@ import ViewForm from './View/ViewForm';
const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState()
const {t} = useTranslation();
const {mutate ,isSuccess,isLoading:IsloadingButton} = useUpdateOrder("put")
const {mutate ,isSuccess,isLoading:IsLoadingButton} = useUpdateOrder("put")
const { id } = useParams();
const { data, isLoading } = useGetOneOrder({id: id })
const handleSubmit = (values:any) => {
@ -65,7 +65,7 @@ const EditPage = () => {
};
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
if ( isLoading || !objectToEdit) {
return <Spin />
}
@ -79,9 +79,9 @@ const EditPage = () => {
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><FaEdit size={20} /></span> <h6 className='Tab_Info'>{t("EditDetails")}</h6></div></Tab>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><FaFirstOrderAlt size={20} /></span> <h6 className='Tab_Info'>{t("OrderItems")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><FaEdit size={20} /></span> <h6 className='Tab_Info'>{t("EditDetails")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
<Tab><div className='TabContainer'><span className='TabIcon'><FaFirstOrderAlt size={20} /></span> <h6 className='Tab_Info'>{t("OrderItems")}</h6></div></Tab>
</TabList>
<TabBody >

View File

@ -17,6 +17,11 @@ import EditCategories from "./Pages/Categories/View/EditPage";
import ProductsPage from "./Pages/Products/ProductsPage";
import AddProductPage from "./Pages/Products/View/AddPage";
import EditProduct from "./Pages/Products/View/EditPage";
import NewProductsPage from "./Pages/newProduct/ProductsPage";
import AddNewProductPage from "./Pages/newProduct/View/AddPage";
import OrderPage from "./Pages/order/OrderPage";
import EditOrder from "./Pages/order/EditPage";
@ -200,5 +205,17 @@ export const RoutesLinks: RoutesLinksType[] = [
element: <AddSupportMessagesPage />,
hidden:true
},
{
name: "NewProducts",
element: <NewProductsPage />,
icon: <FaProductHunt /> ,
href: "/Newproducts",
},
{
name: "add_Newproducts",
element: <AddNewProductPage />,
href: "/Newproducts/add",
hidden:true
},
]

View File

@ -546,3 +546,15 @@ padding: 10px 40px;
}
}
.tabHeader{
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.ant-tabs .ant-tabs-tab .anticon:not(:last-child) {
margin-right: 0px;
}

View File

@ -1,12 +1,12 @@
.Tab_Info_Container{
.TabContainer{
display: flex;justify-content: start;align-items: center;
.Tab_Info{
font-size: 1.4vw;
padding-left: .5vw;
margin-bottom: 0;
}
.SignleDriverInfoIcon{
.TabIcon{
svg{
width: 90%;
}

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()],
};
});