fix product

This commit is contained in:
karimalden 2024-07-28 15:23:22 +03:00
parent ecf5b1c9b6
commit b91fc7e7cf
35 changed files with 533 additions and 207 deletions

View File

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

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

View File

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

View File

@ -1,52 +1,97 @@
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";
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 { formik, t, isError } = useFormField(name, props);
const imageUrl = formik?.values[name] ? ImageBaseURL + formik.values[name] : ''; const FormikName = getNestedValue(formik.values, name);
const fileList = formik?.values[name] ? formik?.values[name]?.map((file: any, index: number) => ({ let imageUrl = FormikName ?? null;
uid: index,
name: file.name, // Mapping formik values to fileList format
status: 'done', console.table(imageUrl)
url: file.url || '', const fileList = imageUrl
thumbUrl: file.url || '', ? imageUrl.map((file: any, index: number) => {
})) : []; const imageUrl = (file?.path || file?.url) ? fixImageUrl(ImageBaseURL + file?.path ?? file?.url): '';
console.log(file);
const FilehandleChange = ({ file, fileList }: any) => { console.log(imageUrl);
formik.setFieldValue(name, fileList.map((file: any) => file.originFileObj));
return file instanceof File
? {
uid: index,
name: file?.name,
status: "done",
originFileObj: file,
}
: {
uid: index,
id: file?.id,
name: file?.name,
status: "done",
url: imageUrl || "",
thumbUrl: imageUrl || "",
};
})
: [];
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 ( return (
<div className="ValidationField"> <div className="ValidationField upload_image_button">
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{t(`${label || name}`)} {t(`input.${label || name}`)}
</label> </label>
<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
id={name}
> >
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}> <Button
{placholder ?? t("upload_image")} className={isError ? "isError w-100" : " w-100"}
icon={<UploadOutlined />}
>
{t(`input.` + placeholder) ?? t("input.upload_image")}
</Button> </Button>
<div className='Error_color'> {isError ? "required" : ""}</div> <div className="Error_color"> {isError ? "required" : ""}</div>
</Upload> </Upload>
</div> </div>
); );
}; };
export default MaltyFile; 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, getDataToSend:any,
handleSubmit:any, handleSubmit:any,
// BarStatus: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 {objectToEdit} = usePageState()
const {t} = useTranslation(); const {t} = useTranslation();
@ -66,7 +66,7 @@ const ViewPage: React.FC<TViewPage>= ({children,getInitialValues, getValidation
<LoadingButton <LoadingButton
type="submit" type="submit"
color="primary" color="primary"
isLoading={IsloadingButton} isLoading={IsLoadingButton}
> >
{t("save")} {t("save")}
</LoadingButton> </LoadingButton>

View File

@ -19,7 +19,7 @@ const AddcategoriesPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const {mutate,isLoading:IsloadingButton ,isSuccess,data } = useAddCategories() const {mutate,isLoading:IsLoadingButton ,isSuccess,data } = useAddCategories()
const {mutateAsync} = useAddAttribute() const {mutateAsync} = useAddAttribute()
const {mutate:AddAttributeValue } = useAddAttributeValue() 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 ( return (
@ -227,9 +227,9 @@ const AddcategoriesPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>

View File

@ -26,7 +26,7 @@ const EditPage = () => {
const { id } = useParams() const { id } = useParams()
const { data: Atrribute, isLoading: isLoadingAtrribute, isRefetching: AttributeisRefetching } = useGetSingleAttribute({ name: "category_id", id: id }, {}) 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 { mutateAsync } = useAddAttribute()
const { mutate: mutateAttributeValue } = useAddAttributeValue() const { mutate: mutateAttributeValue } = useAddAttributeValue()
const { mutate: UpdateAttribute } = useUpdateAttribute("put") 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))) { if (AttributeisRefetching || isRefetching || isLoadingAtrribute || isLoading || !objectToEdit || (Array.isArray(objectToEdit) && objectToEdit.some(item => item === undefined))) {
return <Spin /> return <Spin />
@ -506,8 +506,8 @@ const EditPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>

View File

@ -12,7 +12,7 @@ import Form from './AddForm';
const AddCouponPage = () => { const AddCouponPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddCoupon() const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddCoupon()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
const transformedValues = { ...values }; // Create a new object 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 ( return (
@ -55,7 +55,7 @@ const AddCouponPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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 EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const { t } = useTranslation(); const { t } = useTranslation();
const { data,isLoading:IsloadingButton,isRefetching } = useGetOneCoupon() const { data,isLoading:IsLoadingButton,isRefetching } = useGetOneCoupon()
const { mutate, isSuccess } = useUpdateCoupon("put") const { mutate, isSuccess } = useUpdateCoupon("put")
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
const products = values?.product_attr?.map((item: any) => { const products = values?.product_attr?.map((item: any) => {
@ -70,13 +70,13 @@ const EditPage = () => {
const getValidationSchema = () => { const getValidationSchema = () => {
return null return null
}; };
if ( IsloadingButton || !objectToEdit || isRefetching) { if ( IsLoadingButton || !objectToEdit || isRefetching) {
return <Spin /> return <Spin />
} }
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton }; const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return ( return (
@ -85,7 +85,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>
<TabBody > <TabBody >

View File

@ -14,7 +14,7 @@ import { useAddNotification } from '../../../api/notification';
const AddPage = () => { const AddPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddNotification() const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddNotification()
const {id} = useParams() const {id} = useParams()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
const hasAsterisk = values?.user_ids.some((item:any) => typeof item === 'string' && item.includes('*')); 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 ( return (
@ -64,7 +64,7 @@ const AddPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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 AddProductPage = () => {
const { mutate, isLoading:IsloadingButton, data, isSuccess } = useAddProduct() const { mutate, isLoading:IsLoadingButton, data, isSuccess } = useAddProduct()
const { mutate: AddVariation } = useAddProductVariation() const { mutate: AddVariation } = useAddProductVariation()
const [IsValed, setIsValed] = useState(false) 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 ( return (
@ -83,9 +83,9 @@ const AddProductPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>

View File

@ -24,7 +24,7 @@ const ViewProduct = () => {
const { data, isLoading, isRefetching } = useGetOneProduct({ id: id }) const { data, isLoading, isRefetching } = useGetOneProduct({ id: id })
const [OldData, setOldData] = useState(data?.data?.products) 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: UpdateVariation } = useUpdateProductVariation()
const { mutate: AddVariation } = useAddProductVariation() const { mutate: AddVariation } = useAddProductVariation()
@ -343,7 +343,7 @@ console.log(mappedAttributes, "mappedAttributes");
return <Spin /> return <Spin />
} }
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit, IsloadingButton }; const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit, IsLoadingButton };
return ( return (
@ -352,9 +352,9 @@ console.log(mappedAttributes, "mappedAttributes");
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>

View File

@ -139,7 +139,7 @@ export const TabsContainer: React.FC = () => {
onEdit={(targetKey: any, action) => (action === 'add' ? handleAdd() : handleRemove(targetKey))} onEdit={(targetKey: any, action) => (action === 'add' ? handleAdd() : handleRemove(targetKey))}
tabPosition={tabPosition} tabPosition={tabPosition}
removeIcon={<MdOutlineDeleteOutline size={20}/>} removeIcon={<MdOutlineDeleteOutline size={20}/>}
items={ items={
items.map((item: any) => ({ items.map((item: any) => ({
label: <Space>{t(`${item.label}`)} <CopyOutlined onClick={() => handleDuplicate(item.key)} /></Space>, label: <Space>{t(`${item.label}`)} <CopyOutlined onClick={() => handleDuplicate(item.key)} /></Space>,

View File

@ -13,7 +13,7 @@ import Form from './AddForm';
const AddSliderPage = () => { const AddSliderPage = () => {
const {mutate , isLoading:IsloadingButton , isSuccess} = useAddSlider() const {mutate , isLoading:IsLoadingButton , isSuccess} = useAddSlider()
const handleSubmit = (values:any)=>{ const handleSubmit = (values:any)=>{
mutate(values) mutate(values)
@ -26,7 +26,7 @@ const AddSliderPage = () => {
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton }; const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return ( return (
@ -35,7 +35,7 @@ const AddSliderPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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 { setObjectToEdit, objectToEdit } = usePageState()
const {t} = useTranslation(); const {t} = useTranslation();
const { data } = useGetOneSlider() const { data } = useGetOneSlider()
const {mutate ,isSuccess,isLoading:IsloadingButton} = useUpdateSlider() const {mutate ,isSuccess,isLoading:IsLoadingButton} = useUpdateSlider()
const FormatedData = data?.data ; const FormatedData = data?.data ;
const handleSubmit = (values:any)=>{ 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 ( return (
@ -60,7 +60,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>
<TabBody > <TabBody >

View File

@ -11,7 +11,7 @@ import Form from './AddForm';
const AddSupportMessagesPage = () => { const AddSupportMessagesPage = () => {
const {mutate , isLoading:IsloadingButton , isSuccess} = useAddSupportMessages() const {mutate , isLoading:IsLoadingButton , isSuccess} = useAddSupportMessages()
const handleSubmit = (values:any)=>{ const handleSubmit = (values:any)=>{
console.log(values,"values"); 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 ( return (
@ -34,7 +34,7 @@ const AddSupportMessagesPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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 AddPage = () => {
const { mutate, isLoading:IsloadingButton, isSuccess } = useAddNotification() const { mutate, isLoading:IsLoadingButton, isSuccess } = useAddNotification()
const {id} = useParams() const {id} = useParams()
const handleSubmit = (values: any) => { 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 ( return (
@ -57,7 +57,7 @@ const AddPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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 { setObjectToEdit, objectToEdit } = usePageState()
const {t} = useTranslation(); const {t} = useTranslation();
const { data } = useGetOneUser() const { data } = useGetOneUser()
const {mutate ,isSuccess,isLoading:IsloadingButton} = useUpdateAdmin() const {mutate ,isSuccess,isLoading:IsLoadingButton} = useUpdateAdmin()
const handleSubmit = (values:any)=>{ const handleSubmit = (values:any)=>{
return mutate(values); return mutate(values);
@ -37,7 +37,7 @@ const EditPage = () => {
}; };
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton }; const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsLoadingButton };
return ( return (
@ -46,7 +46,7 @@ const EditPage = () => {
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <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> </TabList>
<TabBody > <TabBody >

View File

@ -36,7 +36,7 @@ function ProductsPage() {
<SelectField selectBy="category" submiteBy="category_id" lebel="category" option={SelectData} /> <SelectField selectBy="category" submiteBy="category_id" lebel="category" option={SelectData} />
<SearchField searchBy="name"/> <SearchField searchBy="name"/>
<AddButton onClick={()=>navigate('/products/add')}></AddButton> <AddButton onClick={()=>navigate('add')}></AddButton>
</div> </div>
</DashHeader> </DashHeader>

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

@ -1,104 +1,61 @@
import * as Yup from "yup"; import * as Yup from "yup";
import { ImageBaseURL } from "../../api/config";
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)[]
}
export const getInitialValues = (objectToEdit: any) => { interface Category {
if (!objectToEdit || !objectToEdit?.products) { id: string;
return {}; }
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"
} }
const products = objectToEdit?.products?.map((item: any) => { ],
// console.log(item,"item"); }
export const getInitialValues = (objectToEdit: ObjectToEditProductType): InitialValuesProductType => {
const variant = objectToEdit?.variant;
const formattedData = item?.info ? Object.entries(item?.info).map(([key, value], index) => ({
[`Description`]: key,
[`key`]: value,
})) : [];
// console.log(formattedData,"formattedData");
const images_product = item?.images?.map((item:any)=>{
return item?.path
})
console.log(images_product,"images_product");
return ({
name_ar: item?.name["ar"],
name_en: item?.name["en"],
name_de: item?.name["de"],
description_ar: item?.description["ar"],
description_en: item?.description["en"],
description_de: item?.description["de"],
images: images_product,
main_photo: item?.main_photo,
price: item?.price,
// quantity: item?.quantity,
// products_attributes: item?.products_attributes,
id:item?.id,
info:formattedData
})
})
const productsInfo = objectToEdit?.products?.info || {};
const formattedData = Object.entries(productsInfo).map(([key, value], index) => ({
[`${index}.Description`]: key,
[`${index}.key`]: value,
}));
console.log(products,"products");
return { return {
id:objectToEdit?.id, id: objectToEdit?.id,
name: objectToEdit?.name ?? "", name: objectToEdit?.name ?? { en: '', de: '', ar: '' },
name_ar: objectToEdit?.name?.ar ?? '', category_id: objectToEdit?.category?.id ?? '',
name_en: objectToEdit?.name?.en ?? '', variant: variant ?? [emptyVariant]
name_de: objectToEdit?.name?.de ?? '', };
description_ar: objectToEdit?.description?.ar ?? '',
description_en: objectToEdit?.description?.en ?? '',
description_de: objectToEdit?.description?.de ?? '',
// attribute: objectToEdit?.attribute ?? "",
category_id: objectToEdit?.category?.id ?? "",
price: objectToEdit?.price ?? "",
variable: [{}, ...products],
// info: [undefined, ...formattedData] ?? [],
removedVariant:[],
}
};
export const getInitialValuesAdd = (objectToEdit: any | null = null) => {
return {
id: "",
name: "",
name_ar:'',
name_en: '',
name_de: '',
description_ar:'',
description_en: '',
description_de: '',
price: "",
category_id: "",
variable: [],
info: [],
}
}; };
export const getValidationSchema = (editMode: boolean = false) => { export const getValidationSchema = (editMode: boolean = false) => {
// validate input
return Yup.object().shape({ return Yup.object().shape({
name_ar: Yup.string().required('Required'),
name_en: Yup.string().required('Required'),
name_de: Yup.string().required('Required'),
category_id: Yup.string().required('Required'),
}); });
}; };

View File

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

View File

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

View File

@ -545,4 +545,16 @@ padding: 10px 40px;
direction: ltr !important; direction: ltr !important;
} }
}
.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; display: flex;justify-content: start;align-items: center;
.Tab_Info{ .Tab_Info{
font-size: 1.4vw; font-size: 1.4vw;
padding-left: .5vw; padding-left: .5vw;
margin-bottom: 0; margin-bottom: 0;
} }
.SignleDriverInfoIcon{ .TabIcon{
svg{ svg{
width: 90%; width: 90%;
} }