This commit is contained in:
KarimAldeen 2024-03-19 09:08:33 +03:00
parent 6ec649308d
commit 8c6c1fd6cb
55 changed files with 1457 additions and 902 deletions

View File

@ -7,5 +7,5 @@
```bash ```bash
git clone https://repos.point-dev.net/Karimaldeen/hijabi-dashboard.git git clone https://repos.point-dev.net/Karimaldeen/hijabi-dashboard.git
cd hijabi-dashboard cd hijabi-dashboard
npm install pnpm install
npm start pnpm start

View File

@ -33,6 +33,7 @@ const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,sh
}} className="cursor-pointer m-2" size={20} />} }} className="cursor-pointer m-2" size={20} />}
{showView && <FaEye onClick={onView} className="cursor-pointer m-2" size={25} />} {showView && <FaEye onClick={onView} className="cursor-pointer m-2" size={25} />}
{showDelete && ( {showDelete && (
<FaTrash <FaTrash
onClick={() => onClick={() =>

View File

@ -7,7 +7,7 @@ const Date = ({ name, label,picker="date" ,isDisabled,props,onChange,placeholder
const { errorMsg, isError, t, formik } = useFormField(name, props) const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => { const onCalendarChange = (value: any) => {
console.log(value,"value");
formik.setFieldValue(name, value) formik.setFieldValue(name, value)
}; };
@ -31,7 +31,7 @@ const Date = ({ name, label,picker="date" ,isDisabled,props,onChange,placeholder
size="large" size="large"
onChange={onChange || onCalendarChange} onChange={onChange || onCalendarChange}
disabled={isDisabled} disabled={isDisabled}
format={Format ?? ""} format={Format}
/> />

View File

@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
import useFormField from '../../../Hooks/useFormField'; import useFormField from '../../../Hooks/useFormField';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, props }: any) => { const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, loading,props }: 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 location = useLocation()
@ -55,6 +55,7 @@ const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, i
showSearch showSearch
optionFilterProp="label" optionFilterProp="label"
onSearch={SearchHandleChange} onSearch={SearchHandleChange}
loading={loading}
/> />
</Form.Item> </Form.Item>

View File

@ -25,7 +25,7 @@ const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onCha
options={option} options={option}
size="large" size="large"
className={`${className} w-100`} className={`${className} w-100`}
defaultValue={formik.values?.name} defaultValue={formik.values[name]}
allowClear allowClear
{...(isMulti && { mode: "multiple" })} {...(isMulti && { mode: "multiple" })}
onChange={onChange || SelecthandleChange} onChange={onChange || SelecthandleChange}

View File

@ -52,6 +52,7 @@
option: any[]; option: any[];
isMulti?: boolean; isMulti?: boolean;
searchBy:string; searchBy:string;
loading?:boolean;
} }
export interface ValidationFieldPropsDataRange { export interface ValidationFieldPropsDataRange {

View File

@ -0,0 +1,67 @@
import { Formik, Form } from 'formik';
import React, { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from "reactstrap";
import * as Yup from 'yup';
interface FormValues {
[key: string]: any;
}
interface FormikFormProps {
handleSubmit: (values: any) => void
initialValues: FormValues;
validationSchema: any;
title?: string;
children: ReactNode;
ButtonName?:string
}
const FormikForm: React.FC<FormikFormProps> = ({ children, handleSubmit, initialValues, validationSchema, title = "Add New Item" ,ButtonName="إضافة"}) => {
const [t]= useTranslation()
return (
<>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{formik => (
<Form >
<div className="Card">
{children}
</div>
</Form>
)}
</Formik>
</>
);
};
export default FormikForm;
{/* <FormikForm
handleSubmit={() => {
}}
initialValues={() => {
return {
id: null,
name: "",
}
}}
validationSchema={() => {
return Yup.object().shape({
name: Yup.string().required('required'),
});
}}
>
</FormikForm> */}

View File

@ -26,9 +26,9 @@ const Header = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const navigate = useNavigate() const navigate = useNavigate()
// const { logout , user} = useAuthState() const { logout , user} = useAuthState()
const handelClick = () => { const handelClick = () => {
// logout() logout()
navigate('/auth', { replace: true }) navigate('/auth', { replace: true })
} }

View File

@ -30,7 +30,7 @@ const OnSuccess = ()=>{
return ( return (
<div className='LoginForm'> <div className='LoginForm'>
<img className='Logo' src="/Layout/etaxlogo.svg" alt="Logo" /> <img className='Logo' src="/Logo.png" alt="Logo" />
<nav className='Login_Nav'> <nav className='Login_Nav'>
<h5> {t("Login")} </h5> <h5> {t("Login")} </h5>

View File

@ -69,7 +69,7 @@ export const TabsContainer= ({parentKey}:any) => {
setActiveKey(newKey); setActiveKey(newKey);
const originalValues = values?.Attribute[parentKey].AttributeValue[targetKey]; const originalValues = values?.Attribute[parentKey].AttributeValue[targetKey];
setFieldValue(`Attribute[${parentKey}].AttributeValue[${newKey}]`, originalValues); setFieldValue(`Attribute[${parentKey}].AttributeValue[${newKey}]`, {...originalValues,id:null});
} }
}; };

View File

@ -0,0 +1,87 @@
import { toast } from 'react-toastify';
export const isvalidation = (attributes: any[] | undefined, t: any) => {
const validationResults: boolean[] = [];
let previousNames: { [key: string]: string } = {};
attributes?.slice(1)?.forEach((item: any, index: number) => {
if (item && Object.keys(item).length > 0) {
const itemName = t('name');
const itemNumber = index + 1;
const currentItemNames = {
name_ar: item.name_ar,
name_en: item.name_en,
name_de: item.name_de,
};
if (
previousNames.name_ar === currentItemNames.name_ar ||
previousNames.name_en === currentItemNames.name_en ||
previousNames.name_de === currentItemNames.name_de
) {
toast.error(`${itemName} ${t('unique_error_names')}`);
validationResults.push(false);
}
previousNames = currentItemNames;
// Check for other validation rules
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(`${t('required_name')} ${itemNumber}`);
validationResults.push(false);
} else if (!item?.type) {
toast.error(`${t('required_type')} ${itemNumber}`);
validationResults.push(false);
} else if (item?.type === "image") {
if (Array.isArray(item.AttributeValue)) {
item.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem.image === null) {
toast.error(`${t('required_image')} ${index + 1}`);
validationResults.push(false);
} else if (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de) {
toast.error(`${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "color") {
if (Array.isArray(item.AttributeValue)) {
item.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
const hexColorRegex = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
if (attrItem && !hexColorRegex.test(attrItem?.value_en)) {
toast.error(`${t('required_color')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "text") {
if (Array.isArray(item.AttributeValue)) {
item.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem && (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de)) {
toast.error(` ${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else {
validationResults.push(true);
}
}
});
return validationResults;
};

View File

@ -11,21 +11,20 @@ import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
import { useAddAttribute } from '../../../api/attribute'; import { useAddAttribute } from '../../../api/attribute';
import { TabsContainer } from './Add/AttributeTab/TabsContainer'; import { TabsContainer } from './Add/AttributeTab/TabsContainer';
import { useAddAttributeValue } from '../../../api/attributeValue'; import { useAddAttributeValue } from '../../../api/attributeValue';
import { useFormikContext } from 'formik';
import { toast } from 'react-toastify';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess'; import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import { isvalidation } from './Add/fn/isvalidation';
const AddcategoriesPage = () => { const AddcategoriesPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
const {mutate , isLoading,isSuccess,data } = useAddCategories() const {mutate ,isSuccess,data } = useAddCategories()
const {isSuccess : isSuccessAttribute,data:AttributeData, mutateAsync} = useAddAttribute() const {mutateAsync} = useAddAttribute()
const {mutate:AddAttributeValue,isSuccess : isSuccessAttributeValue} = useAddAttributeValue() const {mutate:AddAttributeValue } = useAddAttributeValue()
const [Attribute , setAttribute] = useState<any[]>([]) const [Attribute , setAttribute] = useState<any[]>([])
const [AttributeValues , setAttributeValues] = useState<any[]>([]) const [AttributeValues , setAttributeValues] = useState<any[]>([])
const formik = useFormikContext()
const handleSubmit = (values:any)=>{ const handleSubmit = (values:any)=>{
@ -38,7 +37,6 @@ const AddcategoriesPage = () => {
}); });
setAttributeValues(values?.Attribute?.slice(1)?.map((item:any)=>{ setAttributeValues(values?.Attribute?.slice(1)?.map((item:any)=>{
if (item && Object.keys(item).length > 0){ if (item && Object.keys(item).length > 0){
return item?.AttributeValue return item?.AttributeValue
@ -55,87 +53,7 @@ const AddcategoriesPage = () => {
} }
mutate(CategoriesValues) mutate(CategoriesValues)
} }
const validationResults: boolean[] = []; const validationResults = isvalidation(values?.Attribute, t);
let previousNames: any = {};
values?.Attribute?.slice(1)?.forEach((item: any, index: any) => {
if (item && Object.keys(item).length > 0) {
const itemName = t('name');
const itemNumber = index + 1;
// Check if the names are unique across items
const currentItemNames = {
name_ar: item?.name_ar,
name_en: item?.name_en,
name_de: item?.name_de,
};
if (
previousNames.name_ar === currentItemNames.name_ar ||
previousNames.name_en === currentItemNames.name_en ||
previousNames.name_de === currentItemNames.name_de
) {
toast.error(`${itemName} ${t('unique_error_names')}`);
validationResults.push(false);
}
previousNames = currentItemNames;
// Check for other validation rules
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(`${t('required_name')} ${itemNumber}`);
validationResults.push(false);
} else if (!item?.type) {
toast.error(`${t('required_type')} ${itemNumber}`);
validationResults.push(false);
} else if (item?.type === "image") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem.image === null) {
toast.error(`${t('required_image')} ${index + 1}`);
validationResults.push(false);
} else if (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de) {
toast.error(`${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "color") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
const hexColorRegex = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
if (attrItem && !hexColorRegex.test(attrItem?.value_en)) {
toast.error(`${t('required_color')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "text") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem && (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de)) {
toast.error(` ${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else {
validationResults.push(true);
}
}
});
if (validationResults.every((result) => result)) { if (validationResults.every((result) => result)) {
isValid(); isValid();
@ -196,31 +114,6 @@ const AddcategoriesPage = () => {
},[isSuccess]) },[isSuccess])
// useEffect(()=>{
// if(isSuccessAttribute){
// const AttributeId = (AttributeData as any )?.id ;
// AttributeValues?.slice(1)?.map((dataToSend:any , index:number)=>{
// console.log(dataToSend,"dataToSend");
// const AttributeValues = dataToSend
// const NewAttributeValues = {
// value:{
// en:AttributeValues?.value_en,
// ar:AttributeValues?.value_ar,
// de:AttributeValues?.value_de
// },
// image:AttributeValues?.main_photo,
// attribute_id:AttributeId,
// }
// AddAttributeValue(NewAttributeValues)
// })
// }
// },[isSuccessAttribute])
const {t} = useTranslation(); const {t} = useTranslation();
useNavigateOnSuccess(isSuccess , '/categories' ) useNavigateOnSuccess(isSuccess , '/categories' )
@ -266,18 +159,3 @@ const AddcategoriesPage = () => {
export default AddcategoriesPage export default AddcategoriesPage
function changeShapeInfo(originalObject: any) {
const transformedObject: any = {};
for (const key in originalObject) {
if (originalObject.hasOwnProperty(key)) {
const index = key.split('.')[0]; // Extract index from key
const attribute = key.split('.')[1]; // Extract attribute from key
transformedObject[originalObject[`${index}.key`]] = originalObject[`${index}.Description`];
}
}
return transformedObject
}

View File

@ -74,6 +74,7 @@ const initialItemShape: any = {
const originalValues = values?.Attribute?.[parentKey]?.AttributeValue?.[targetKey]; const originalValues = values?.Attribute?.[parentKey]?.AttributeValue?.[targetKey];
setFieldValue(`Attribute.${parentKey}.AttributeValue.${newKey}`, {...originalValues,id:null}); setFieldValue(`Attribute.${parentKey}.AttributeValue.${newKey}`, {...originalValues,id:null});
console.log({...originalValues,id:null},"{...originalValues,id:null}");
} }
}; };

View File

@ -15,8 +15,9 @@ import { TabsContainer } from './Edit/AttributeTab/TabsContainer';
import { useAddAttribute, useGetSingleAttribute } from '../../../api/attribute'; import { useAddAttribute, useGetSingleAttribute } from '../../../api/attribute';
import { useDeleteAttribute, useUpdateAttribute } from '../../../api/attribute'; import { useDeleteAttribute, useUpdateAttribute } from '../../../api/attribute';
import { useAddAttributeValue, useDeleteAttributeValue, useUpdateAttributeValue } from '../../../api/attributeValue'; import { useAddAttributeValue, useDeleteAttributeValue, useUpdateAttributeValue } from '../../../api/attributeValue';
import { toast } from 'react-toastify';
import Form from './Add/AddForm'; import Form from './Add/AddForm';
import filterUndefinedAndEmpty from '../../../utils/Array/filterUndefinedAndEmpty';
import { isvalidation } from './Add/fn/isvalidation';
const EditPage = () => { const EditPage = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
@ -48,16 +49,19 @@ const EditPage = () => {
const [OldDataValues, setOldDataValues] = useState([]) const [OldDataValues, setOldDataValues] = useState([])
const handleSubmit = (values: any) => { const handleSubmit = (values: any
console.log(values,"values"); ) => {
function isValid(){
function isValid() {
const attributes = values?.Attribute?.slice(1); const attributes = values?.Attribute?.slice(1);
setremovedAttribute(values?.removedAttribute) setremovedAttribute(values?.removedAttribute)
setremovedAttributeValue(values?.removedAttributeValue) setremovedAttributeValue(values?.removedAttributeValue)
console.log(attributes, "attributes");
if (attributes) { if (attributes) {
attributes.forEach((item: any, index: number) => { attributes.forEach((item: any, index: number) => {
if (item.id && item.id !== null) { if (item?.id && item?.id !== null) {
setEditAttribute((prevEditAttribute) => [...prevEditAttribute, item]); setEditAttribute((prevEditAttribute) => [...prevEditAttribute, item]);
console.log(item, "item"); console.log(item, "item");
if (item?.AttributeValue) { if (item?.AttributeValue) {
@ -70,8 +74,10 @@ const EditPage = () => {
} else { } else {
setAddAttribute((prevAddAttribute) => [...prevAddAttribute, item]); setAddAttribute((prevAddAttribute) => [...prevAddAttribute, item]);
if (item?.AttributeValue) { if (item?.AttributeValue) {
item.AttributeValue.slice(1).forEach((attrValueItem: any) => { item?.AttributeValue?.slice(1)?.forEach((attrValueItem: any) => {
if (attrValueItem && Object.keys(attrValueItem).length > 0) { // Check if attrValueItem is defined and not empty console.log(attrValueItem, "attrValueItemadd");
if (attrValueItem && Object.keys(attrValueItem)?.length > 0) { // Check if attrValueItem is defined and not empty
setAddAttributeValue((prevEditAttributeValue) => [...prevEditAttributeValue, [index, attrValueItem]]); setAddAttributeValue((prevEditAttributeValue) => [...prevEditAttributeValue, [index, attrValueItem]]);
} }
}); });
@ -80,8 +86,6 @@ const EditPage = () => {
}); });
} }
const EditedCategory = { const EditedCategory = {
name: { name: {
en: values?.name_en, en: values?.name_en,
@ -90,7 +94,7 @@ const EditPage = () => {
}, },
photo: values?.photo, photo: values?.photo,
parent_id: values?.parent_id, parent_id: values?.parent_id,
_method:"PUT" _method: "PUT"
} }
const Imagetype = typeof values?.photo const Imagetype = typeof values?.photo
@ -98,89 +102,11 @@ const EditPage = () => {
delete EditedCategory['photo'] delete EditedCategory['photo']
} }
console.log(EditedCategory, "EditedCategory");
mutate(EditedCategory) mutate(EditedCategory)
} }
const validationResults: boolean[] = []; const validationResults = isvalidation(values?.Attribute, t);
let previousNames: any = {};
values?.Attribute?.slice(1)?.forEach((item: any, index: any) => {
if (item && Object.keys(item).length > 0) {
const itemName = t('name');
const itemNumber = index + 1;
const currentItemNames = {
name_ar: item?.name_ar,
name_en: item?.name_en,
name_de: item?.name_de,
};
if (
previousNames.name_ar === currentItemNames.name_ar ||
previousNames.name_en === currentItemNames.name_en ||
previousNames.name_de === currentItemNames.name_de
) {
toast.error(`${itemName} ${t('unique_error_names')}`);
validationResults.push(false);
}
previousNames = currentItemNames;
// Check for other validation rules
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(`${t('required_name')} ${itemNumber}`);
validationResults.push(false);
} else if (!item?.type) {
toast.error(`${t('required_type')} ${itemNumber}`);
validationResults.push(false);
} else if (item?.type === "image") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem.image === null) {
toast.error(`${t('required_image')} ${index + 1}`);
validationResults.push(false);
} else if (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de) {
toast.error(`${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "color") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
const hexColorRegex = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
if (attrItem && !hexColorRegex.test(attrItem?.value_en)) {
toast.error(`${t('required_color')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else if (item?.type === "text") {
if (Array.isArray(item.AttributeValue)) {
item?.AttributeValue.slice(1)?.forEach((attrItem: any, index: number) => {
if (attrItem && Object.keys(attrItem).length > 0) {
if (attrItem && (!attrItem?.value_ar || !attrItem?.value_en || !attrItem?.value_de)) {
toast.error(` ${t('required_text')} ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
}
} else {
validationResults.push(true);
}
}
});
if (validationResults.every((result) => result)) { if (validationResults.every((result) => result)) {
isValid(); isValid();
@ -199,13 +125,16 @@ const EditPage = () => {
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
console.log(isSuccess, "isSuccess");
const categoryId = id; const categoryId = id;
console.log(EditAttribute,"EditAttribute"); console.log(EditAttribute, "EditAttribute");
const filteredEditAttribute = filterUndefinedAndEmpty(EditAttribute);
EditAttribute?.map((dataToSend: any, index: number) => { filteredEditAttribute?.map((dataToSend: any, index: number) => {
console.log(index,"index"); console.log(index, "index");
const EditAttribute = dataToSend const EditAttribute = dataToSend
const foundObject = OldData.find((item: any) => item.id === EditAttribute?.id) as any; const foundObject = OldData.find((item: any) => item.id === EditAttribute?.id) as any;
@ -259,15 +188,16 @@ const EditPage = () => {
} }
const result: [number, any][] = filterByIndex(index, EditAttributeValue); const result: [number, any][] = filterByIndex(index, EditAttributeValue);
console.log(result,"result"); console.log(result, "result");
const filteredresult = filterUndefinedAndEmpty(result);
result?.map((dataToSend: any) => { filteredresult?.map((dataToSend: any) => {
if(dataToSend?.id && dataToSend.id !== null){ if (dataToSend?.id && dataToSend.id !== null) {
console.log(OldDataValues,"OldDataValues"); console.log(OldDataValues, "OldDataValues");
const foundObjectValue = (OldDataValues[index] as any).find((item: any) => item.id === dataToSend?.id) as any; const foundObjectValue = (OldDataValues[index] as any).find((item: any) => item.id === dataToSend?.id) as any;
console.log(foundObjectValue,"foundObjectValue"); console.log(foundObjectValue, "foundObjectValue");
console.log(OldDataValues[index],"OldDataValues[index]"); console.log(OldDataValues[index], "OldDataValues[index]");
const EditAttributeValue = dataToSend const EditAttributeValue = dataToSend
console.log(EditAttributeValue); console.log(EditAttributeValue);
@ -295,8 +225,8 @@ const EditPage = () => {
delete NewEditAttributeValue['image'] delete NewEditAttributeValue['image']
} }
if(foundObjectValue){ if (foundObjectValue) {
console.log(foundObjectValue,"foundObjectValue"); console.log(foundObjectValue, "foundObjectValue");
Object.keys(NewEditAttributeValue).forEach((propName: any) => { Object.keys(NewEditAttributeValue).forEach((propName: any) => {
if (foundObjectValue.hasOwnProperty(propName)) { if (foundObjectValue.hasOwnProperty(propName)) {
@ -323,8 +253,8 @@ const EditPage = () => {
//@ts-ignore //@ts-ignore
delete NewEditAttributeValue.value; delete NewEditAttributeValue.value;
} }
console.log(foundObjectValue.value,"foundObjectValue.value"); console.log(foundObjectValue.value, "foundObjectValue.value");
console.log(NewEditAttributeValue.value,"NewEditAttributeValue.value"); console.log(NewEditAttributeValue.value, "NewEditAttributeValue.value");
if (Object.keys(NewEditAttributeValue).length > 0) { if (Object.keys(NewEditAttributeValue).length > 0) {
@ -343,10 +273,16 @@ const EditPage = () => {
} }
else{ else {
console.log("mutateAttributeValue"); console.log("mutateAttributeValue");
const EditAttributeValue = dataToSend const EditAttributeValue = dataToSend
const IMages = EditAttributeValue?.id !== null ? {
main_photo: EditAttributeValue?.main_photo,
image: EditAttributeValue?.image,
} : {
copied_assets: { image: EditAttributeValue?.image },
}
const NewEditAttributeValue = { const NewEditAttributeValue = {
value: { value: {
@ -354,7 +290,8 @@ const EditPage = () => {
ar: EditAttributeValue?.value_ar, ar: EditAttributeValue?.value_ar,
de: EditAttributeValue?.value_de de: EditAttributeValue?.value_de
}, },
image: EditAttributeValue?.main_photo, // image: EditAttributeValue?.main_photo,
...IMages,
// attribute_id:EditAttribute?.id, // attribute_id:EditAttribute?.id,
attribute_id: EditAttribute?.id, attribute_id: EditAttribute?.id,
} }
@ -375,12 +312,15 @@ const EditPage = () => {
} }
) )
console.log(removedAttribute,"removedAttribute"); console.log(removedAttribute, "removedAttribute");
removedAttribute?.map((item:any)=>{ removedAttribute?.map((item: any) => {
DeleteAttribute({ id: item }) DeleteAttribute({ id: item })
}) })
AddAttribute?.map((dataToSend: any, index: number) => { console.log(AddAttribute, "AddAttribute");
const filteredAddAttribute = filterUndefinedAndEmpty(AddAttribute);
filteredAddAttribute?.map((dataToSend: any, index: number) => {
const AddAttribute = dataToSend const AddAttribute = dataToSend
@ -417,9 +357,9 @@ const EditPage = () => {
}) })
}) })
console.log(removedAttributeValue,"removedAttributeValue"); console.log(removedAttributeValue, "removedAttributeValue");
removedAttributeValue?.map((item:any)=>{ removedAttributeValue?.map((item: any) => {
console.log(item,"item"); console.log(item, "item");
return DeleteAttributeValue({ id: item }) return DeleteAttributeValue({ id: item })
}) })
@ -435,7 +375,7 @@ const EditPage = () => {
// useNavigateOnSuccess(isSuccess, '/categories') useNavigateOnSuccess(isSuccess, '/categories')
@ -453,12 +393,12 @@ const EditPage = () => {
setObjectToEdit([data?.category, Atrribute?.data]); setObjectToEdit([data?.category, Atrribute?.data]);
setOldData(Atrribute?.data) setOldData(Atrribute?.data)
setOldDataValues(Atrribute?.data?.map((item:any)=>{ setOldDataValues(Atrribute?.data?.map((item: any) => {
return item?.attribute_value return item?.attribute_value
})) }))
console.log(OldDataValues,"OldDataValues"); console.log(OldDataValues, "OldDataValues");
}, [data?.category, Atrribute?.data]); }, [data?.category, Atrribute?.data, isRefetching, AttributeisRefetching]);
const getValidationSchema = () => { const getValidationSchema = () => {

View File

@ -18,8 +18,8 @@ function Form() {
const coupon_type_discount_flat = [{ lable: "general", value: "general" }] const coupon_type_discount_flat = [{ lable: "general", value: "general" }]
const discount_type = [{ lable: "percentage", value: "percentage" },{ lable: "flat", value: "flat" }] const discount_type = [{ lable: "percentage", value: "percentage" },{ lable: "flat", value: "flat" }]
const { data: CategoriesData} = useGetCategories() const { data: CategoriesData,isLoading:CategoriesLoading} = useGetCategories()
const { data: ProductData } = useGetProduct() const { data: ProductData ,isLoading:ProductLoading} = useGetProduct()
const SelectCategoriesData = useFormatToSelect(CategoriesData?.categories) const SelectCategoriesData = useFormatToSelect(CategoriesData?.categories)
const SelectProductData = useFormatToSelect(ProductData?.BaseProducts) const SelectProductData = useFormatToSelect(ProductData?.BaseProducts)
@ -51,8 +51,8 @@ function Form() {
<ValidationField name="discount_type" type="Select" option={discount_type} /> <ValidationField name="discount_type" type="Select" option={discount_type} />
<ValidationField name="coupon_type" type="Select" option={values?.discount_type !== 'flat' ? coupon_type :coupon_type_discount_flat } /> <ValidationField name="coupon_type" type="Select" option={values?.discount_type !== 'flat' ? coupon_type :coupon_type_discount_flat } />
{/* <ValidationField name="itemable_type" label='coupon_item_type' type="Select" option={itemable_type} isDisabled={values?.coupon_type !== "specified"} isMulti/> */} {/* <ValidationField name="itemable_type" label='coupon_item_type' type="Select" option={itemable_type} isDisabled={values?.coupon_type !== "specified"} isMulti/> */}
<ValidationField name="product_attr" label='product_item' type="Search" option={SelectProductData} searchBy={"name"} isDisabled={values?.coupon_type !== "specified"}isMulti /> <ValidationField name="product_attr" label='product_item' type="Search" option={SelectProductData} searchBy={"name"} isDisabled={values?.coupon_type !== "specified"}isMulti loading={ProductLoading} />
<ValidationField name="category_attr" label='categories_item_name' type="Search" option={SelectCategoriesData} searchBy={"name"} isDisabled={values?.coupon_type !== "specified"}isMulti /> <ValidationField name="category_attr" label='categories_item_name' type="Search" option={SelectCategoriesData} searchBy={"name"} isDisabled={values?.coupon_type !== "specified"}isMulti loading={CategoriesLoading} />
<ValidationField name="status" type='Checkbox' label='status' /> <ValidationField name="status" type='Checkbox' label='status' />

View File

@ -85,7 +85,6 @@ export const getValidationSchema = (editMode: boolean = false): Yup.Schema<any>
name: Yup.string().required('Required'), name: Yup.string().required('Required'),
code: Yup.string().required('Required'), code: Yup.string().required('Required'),
coupon_value: Yup.string().required('Required'), coupon_value: Yup.string().required('Required'),
status: Yup.string().required('Required'),
active: Yup.mixed().required('Required'), active: Yup.mixed().required('Required'),
discount_type: Yup.string().required('Required'), discount_type: Yup.string().required('Required'),
coupon_type: Yup.string().required('Required'), coupon_type: Yup.string().required('Required'),

View File

@ -5,6 +5,8 @@ import Actions from "../../Components/Ui/tables/Actions";
import ColumnsImage from "../../Components/Columns/ColumnsImage"; import ColumnsImage from "../../Components/Columns/ColumnsImage";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useDeleteCoupon } from "../../api/Coupon"; import { useDeleteCoupon } from "../../api/Coupon";
import { MdEmail } from "react-icons/md";
import { useModalState } from "../../zustand/Modal";
function fnDelete(props :any ){} function fnDelete(props :any ){}
@ -12,8 +14,7 @@ const useTableColumns :any = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const deleteMutation = useDeleteCoupon() const deleteMutation = useDeleteCoupon()
const navigate = useNavigate() const navigate = useNavigate()
const language = localStorage.getItem("language") ?? "en" const {setIsOpen} = useModalState(state=>state)
return useMemo( return useMemo(
() => [ () => [
@ -58,7 +59,8 @@ const useTableColumns :any = () => {
onEdit={()=> navigate(`/coupon/${row.id}`) } onEdit={()=> navigate(`/coupon/${row.id}`) }
showView={false} showView={false}
onDelete={() => deleteMutation.mutate({ id: row.id })} onDelete={() => deleteMutation.mutate({ id: row.id })}
/> >
</Actions>
), ),
}, },

View File

@ -1,36 +0,0 @@
import React from 'react'
import DataTable, { TableColumn } from "react-data-table-component";
import { Card, CardBody, CardHeader } from 'reactstrap';
import useTableColumns from './useTableColumn';
import { useTranslation } from 'react-i18next';
import { LoadingButton } from '../../../../Components/Ui/LoadingButton';
import { useNavigate } from 'react-router-dom';
export default function LastOrderTable({ latest_Orders }:any) {
const columns = useTableColumns();
const {t} = useTranslation();
const navigate = useNavigate()
return (
<Card>
<div className="primary" style={{display:"flex" , justifyContent:"space-between" , padding:"20px", marginTop:"10px"}}>
{t("latest_orders")}
<LoadingButton color="primary" onClick={() => navigate("/order",{replace:true})}>
{t("show_all_orders")}
</LoadingButton>
</div>
<CardBody>
<DataTable
columns={columns as any}
data={latest_Orders}
noDataComponent={<h6 className="my-4">{t("no_records")}</h6>}
noHeader
/>
</CardBody>
</Card>
)
}

View File

@ -1,60 +0,0 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { GrView } from "react-icons/gr";
import { useNavigate } from "react-router-dom";
const useTableColumns = () => {
const {t} = useTranslation();
const navigate = useNavigate()
return useMemo(
() => [
{
name: t("order_code"),
sortable: false,
center: true,
cell:(row:any)=>{
console.log(row);
return (row?.order_code)
}
},
{
name: t("order_total"),
sortable: true,
center: true,
cell:(row)=>row["order_total"]
},
{
name: t("order_status"),
sortable: false,
center: true,
cell:(row:any)=><span style={{
padding:8, color:'black',borderRadius:10,fontSize:10}}>{t(row.order_status)}</span>
},
{
name: "#",
selector: "action",
sortable: false,
center: true,
cell: (row:any) => (
<GrView
onClick={() => navigate(`/order/${row?.id}`, {replace:true})}
size={22}
style={{ cursor: "pointer" }}
/>
),
},
],
[t]
);
};
export default useTableColumns;

View File

@ -1,40 +0,0 @@
import React from 'react'
import DataTable from 'react-data-table-component';
import { Card, CardBody, CardHeader } from 'reactstrap';
import useTableColumns from './useTableColumn';
import { useTranslation } from 'react-i18next';
import { LoadingButton } from '../../../../Components/Ui/LoadingButton';
import { useNavigate } from 'react-router-dom';
export default function LastUserTable({ most_driver_rate }:any) {
const columns = useTableColumns();
const {t} = useTranslation();
const navigate = useNavigate()
// console.log(most_driver_rate);
return (
<Card>
<div className='primary' style={{display:"flex" , justifyContent:"space-between" , padding:"20px", marginTop:"10px"}}>
{t("last_users")}
{/* <LoadingButton color="primary" onClick={() => navigate("/user" , {replace:true})}>
{t("show_all_users")}
</LoadingButton> */}
</div>
<CardBody>
<DataTable
columns={columns as any }
data={most_driver_rate}
noDataComponent={<h6 className="my-4">{t("no_records")}</h6>}
noHeader
/>
</CardBody>
</Card>
)
}

View File

@ -1,59 +0,0 @@
import React from "react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { GrView } from "react-icons/gr";
import { useNavigate } from "react-router-dom";
import { Rating } from "react-simple-star-rating";
interface RowData {
name:string ,
phone:string ,
email:string ,
id:number
}
const useTableColumns = () => {
const navigate = useNavigate()
const {t} = useTranslation();
return useMemo(() => {
const columns = [
{
name: t("full_name"),
sortable: false,
center: true,
cell: (row: RowData) => row?.name,
},
{
name: t("email"),
sortable: false,
center: true,
cell: (row: RowData) => row?.email,
},
{
name: t("phone"),
sortable: false,
center: true,
cell: (row: RowData) => row?.phone,
},
// {
// name: "#",
// selector: "action",
// sortable: false,
// center: true,
// cell: (row: RowData) => (
// <GrView
// onClick={() => navigate(`/user/${row?.id}`, {replace:true})}
// size={22}
// style={{ cursor: "pointer" }}
// />
// ),
// },
];
return columns;
}, [t]);
};
export default useTableColumns;

View File

@ -0,0 +1,46 @@
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 { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
import SearchField from '../../Layout/Dashboard/SearchField'
import { useGetNotification } from '../../api/notification'
function Page() {
const column =useTableColumns()
const {data ,status } = useGetNotification()
const [t] = useTranslation()
const navigate = useNavigate()
const totalRows = data?.meta?.total;
return (
// Pass Status to Layout
<DashBody status={status as QueryStatusEnum} >
<DashHeader showAddButton={false} title={'notification'}>
<div className='RightSide d-flex gap-2 align-center '>
<SearchField searchBy={"name"} />
<AddButton onClick={()=>navigate('/notification/add')}></AddButton>
</div>
</DashHeader>
<LyTable
data={data?.data}
isLoading={false}
columns={column}
total={totalRows}
is_pagination={true}
/>
</DashBody>
)
}
export default Page

View File

@ -0,0 +1,42 @@
import { Col, Row } from 'reactstrap';
import ValidationField from '../../../Components/ValidationField/ValidationField';
function Form() {
const type = [{ lable: "other", value: "other" },{ lable: "product", value: "product"},{ lable: "order", value: "order" }]
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
<ValidationField name="body_en" />
<ValidationField name="body_ar" />
<ValidationField name="body_de" />
{/* <ValidationField name="meta" /> */}
</Col>
<Col>
<ValidationField name="title_en" />
<ValidationField name="title_ar" />
<ValidationField name="title_de" />
{/* <ValidationField name="type" type="Select" option={type} /> */}
</Col>
</Row>
)
}
export default Form

View File

@ -0,0 +1,80 @@
import React, { useEffect, useState } from 'react'
import { getInitialValuesForAdd as 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 { useTranslation } from 'react-i18next';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import { useAddUsers } from '../../../api/users';
import Form from './AddForm';
import { useParams } from 'react-router-dom';
import { useAddNotification } from '../../../api/notification';
const AddPage = () => {
const { mutate, isLoading, isSuccess } = useAddNotification()
const {id} = useParams()
const handleSubmit = (values: any) => {
const body = {
en: values.body_en,
ar: values.body_ar,
du: values.body_de
}
const meta = {}
const title = {
en: values.title_en,
ar: values.title_ar,
du: values.title_de
}
const dataToSend = {
body: JSON.stringify(body),
meta: JSON.stringify(meta),
title:JSON.stringify(title),
user_ids: [id],
type: "other",
};
mutate(dataToSend);
};
const { t } = useTranslation();
useNavigateOnSuccess(isSuccess, '/users')
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit };
return (
<div className='ViewPage'>
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='SingleDriverInfo'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >
<div className=" mt-4"><Form /></div>
</TabBody>
</Tabs>
</ViewPage>
</div>
)
}
export default AddPage

View File

@ -0,0 +1,72 @@
import * as Yup from "yup";
import { buildFormData } from "../../../api/helper/buildFormData";
import moment from 'moment';
import * as dayjs from 'dayjs'
export const getInitialValues = (objectToEdit: any | null = null): any => {
//@ts-ignore
return {
id: objectToEdit?.id ,
name: objectToEdit?.name ,
email: objectToEdit?.email ,
type: objectToEdit?.type ,
avatar: objectToEdit?.avatar ,
};
};
export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
return {
body_en: "" ,
body_ar: "" ,
body_de: "" ,
meta: "" ,
title_en: "" ,
title_ar: "" ,
title_de: "" ,
user_ids:[],
type: "" ,
};
};
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<any> => {
// Validate input
return Yup.object().shape({
body_en: Yup.string().required('Required'),
body_ar: Yup.string().required('Required'),
body_de: Yup.string().required('Required'),
// meta: Yup.string().required('Required'),
title_en: Yup.string().required('Required'),
title_ar: Yup.string().required('Required'),
title_de: Yup.string().required('Required'),
// type: Yup.string().required('Required'),
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
const formData = new FormData();
buildFormData(formData, data);
return formData;
};
export const ChangeDataToPrint = (data: any) => {
let new_array = data
for (let i = 0; i < data.length; i++) {
new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
delete new_array[i]['deleted_at']
}
return new_array
}

View File

@ -0,0 +1,67 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import Actions from "../../Components/Ui/tables/Actions";
import ColumnsImage from "../../Components/Columns/ColumnsImage";
import { useNavigate } from "react-router-dom";
import { useDeleteNotification } from "../../api/notification";
import { Switch } from "antd";
import { MdEmail } from "react-icons/md";
import { useModalState } from "../../zustand/Modal";
const useTableColumns: any = () => {
const [t] = useTranslation();
const deleteMutation = useDeleteNotification()
const navigate = useNavigate()
const { setIsOpen } = useModalState(state => state)
const language = localStorage.getItem("language") ?? "en"
return useMemo(
() => [
{
name: t("name"),
sortable: false,
center: "true",
cell: (row: any) => row?.user?.name
},
{
name: t("title"),
sortable: false,
center: "true",
cell: (row: any) => row?.title[language]
},
{
name: t("body"),
sortable: false,
center: "true",
cell: (row: any) => row?.body[language]
},
// {
// name: "#",
// sortable: false,
// center: true,
// cell: (row: any) => (
// <Actions
// objectToEdit={row}
// showEdit={false}
// onEdit={() => navigate(`/notification/${row.id}`)}
// showView={false}
// onDelete={() => deleteMutation.mutate({ id: row.id })}
// >
// </Actions>
// ),
// },
],
[t]
);
};
export default useTableColumns;

View File

@ -11,7 +11,8 @@ import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import { useAddProduct, useAddProductVariation } from '../../../api/product'; import { useAddProduct, useAddProductVariation } from '../../../api/product';
import { usePageState } from '../../../lib/state mangment/LayoutPagestate'; import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
import { TabsContainer } from './FormikTab/TabsContainer'; import { TabsContainer } from './FormikTab/TabsContainer';
import { toast } from 'react-toastify'; import { isvalidation } from './Addfn/isvalidation';
import { AddNewVariation } from './Addfn/AddNewVariation';
// import AttributeInfo from './AttributeInfo'; // import AttributeInfo from './AttributeInfo';
const AddProductPage = () => { const AddProductPage = () => {
@ -21,7 +22,6 @@ const AddProductPage = () => {
const { mutate: AddVariation, isSuccess: SuccessVariation } = useAddProductVariation() const { mutate: AddVariation, isSuccess: SuccessVariation } = useAddProductVariation()
const [IsValed, setIsValed] = useState(false) const [IsValed, setIsValed] = useState(false)
const [infotaps, setInfoTaps] = useState<any[]>([])
const [Varibletaps, setVaribleTaps] = useState<any[]>([]) const [Varibletaps, setVaribleTaps] = useState<any[]>([])
@ -29,108 +29,35 @@ const AddProductPage = () => {
function isValid() { function isValid() {
setInfoTaps(values?.info?.slice(1)?.map((taps: any) => {
return (changeShapeInfo(taps));
}));
setVaribleTaps(values?.variable?.slice(1)) setVaribleTaps(values?.variable?.slice(1))
mutate({
const new_category = {
name: { name: {
en: values?.name_en, en: values?.name_en,
ar: values?.name_ar, ar: values?.name_ar,
de: values?.name_de de: values?.name_de
}, },
category_id: 1 category_id: 1
}) }
mutate(new_category)
} }
const validationResults: boolean[] = []; const validationResults = isvalidation(values.variable, t);
values?.variable?.slice(1)?.forEach((item: any, index: any) => {
if (item && Object.keys(item).length > 0) { // Check if attrValueItem is defined and not empty
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(t('required_name') + ` ${index + 1}`);
validationResults.push(false);
}
else if (!item?.description_ar || !item?.description_en || !item?.description_de) {
toast.error(t('required_description') + ` ${index + 1}`);
validationResults.push(false);
} else if (item.main_photo === null || !item?.main_photo ) {
toast.error(t('required_main_photo') + ` ${index + 1}`);
validationResults.push(false);
}
else if (item.price === null || !item?.price) {
toast.error(t('required_price') + ` ${index + 1}`);
validationResults.push(false);
}
else {
validationResults.push(true);
}
}
});
if (validationResults.every((result) => result)) { if (validationResults.every((result) => result)) {
isValid(); isValid();
} }
} }
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
const baseProductId = (data as any)?.id; AddNewVariation(Varibletaps, data, AddVariation);
console.log(infotaps);
console.log(Varibletaps);
Varibletaps?.map((dataToSend: any, index: number) => {
const varible = dataToSend
const info = varible?.info
const convertedArray = info.reduce((acc:any, obj:any) => {
acc[obj.Description] = obj.key;
return acc;
}, {});
const jsonString = JSON.stringify(convertedArray);
const Newproduct = {
name: {
en: varible?.name_en,
ar: varible?.name_ar,
de: varible?.name_de
},
description: {
en: varible?.description_en,
ar: varible?.description_ar,
de: varible?.description_de
},
quantity: varible?.quantity,
main_photo: varible?.main_photo,
images: varible?.images,
info: jsonString,
price : varible?.price,
product_attributes: varible?.attribute?.map((item: any, index: any) => {
return { attribute_value_id: item?.value, attribute_id: item?.id }
}),
base_product_id: baseProductId
}
console.log(Newproduct);
AddVariation(Newproduct)
})
} }
}, [isSuccess]) }, [isSuccess])
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit } = usePageState()
useEffect(() => { useEffect(() => {
setObjectToEdit([]); setObjectToEdit([]);
@ -155,8 +82,6 @@ const AddProductPage = () => {
<Tab ><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><BsInfoCircle size={20} /></span> <h6 className='SingleInfo'>{t("VarianInfo")}</h6></div></Tab> <Tab ><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><BsInfoCircle size={20} /></span> <h6 className='SingleInfo'>{t("VarianInfo")}</h6></div></Tab>
{/* <Tab ><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><BsInfoCircle size={20} /></span> <h6 className='SingleInfo'>{t("AttributeInfo")}</h6></div></Tab> */}
</TabList> </TabList>
<TabBody > <TabBody >
@ -165,9 +90,6 @@ const AddProductPage = () => {
<TabBody > <TabBody >
<div className=" mt-4"><TabsContainer /></div> <div className=" mt-4"><TabsContainer /></div>
</TabBody> </TabBody>
<TabBody >
{/* <div className=" mt-4"><AttributeInfo /></div> */}
</TabBody>
</Tabs> </Tabs>
</ViewPage> </ViewPage>
@ -180,18 +102,3 @@ const AddProductPage = () => {
export default AddProductPage export default AddProductPage
function changeShapeInfo(originalObject: any) {
const transformedObject: any = {};
for (const key in originalObject) {
if (originalObject.hasOwnProperty(key)) {
const index = key.split('.')[0]; // Extract index from key
const attribute = key.split('.')[1]; // Extract attribute from key
transformedObject[originalObject[`${index}.key`]] = originalObject[`${index}.Description`];
}
}
return transformedObject
}

View File

@ -0,0 +1,43 @@
// Function to process variable taps when success is true
export function AddNewVariation(Varibletaps: any[], data: any, AddVariation: any) {
const baseProductId = data?.id;
Varibletaps?.forEach((dataToSend: any) => {
const varible = dataToSend;
const info = varible?.info;
const convertedArray = info?.reduce((acc: any, obj: any) => {
acc[obj.Description] = obj.key;
return acc;
}, {});
const jsonString = JSON.stringify(convertedArray);
const IMages = varible?.id !== null ? {
main_photo: varible?.main_photo,
images: varible?.images,
} : {
copied_assets: { main_photo: varible?.main_photo, images: varible?.images },
}
const Newproduct = {
name: {
en: varible?.name_en,
ar: varible?.name_ar,
de: varible?.name_de
},
description: {
en: varible?.description_en,
ar: varible?.description_ar,
de: varible?.description_de
},
// quantity: varible?.quantity,
...IMages,
info: jsonString,
price: varible?.price,
product_attributes: varible?.attribute?.map((item: any, index: any) => {
return { attribute_value_id: item?.value, attribute_id: item?.id };
}),
base_product_id: baseProductId
};
console.log(Newproduct);
AddVariation(Newproduct);
});
}

View File

@ -0,0 +1,27 @@
import { toast } from "react-toastify";
// Function to validate variable items
export function isvalidation(variableItems: any[], t: any) {
const validationResults: boolean[] = [];
variableItems.slice(1).forEach((item: any, index: any) => {
if (item && Object.keys(item).length > 0) { // Check if item is defined and not empty
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(t('required_name') + ` ${index + 1}`);
validationResults.push(false);
} else if (!item?.description_ar || !item?.description_en || !item?.description_de) {
toast.error(t('required_description') + ` ${index + 1}`);
validationResults.push(false);
} else if (item.main_photo === null || !item?.main_photo) {
toast.error(t('required_main_photo') + ` ${index + 1}`);
validationResults.push(false);
} else if (item.price === null || !item?.price) {
toast.error(t('required_price') + ` ${index + 1}`);
validationResults.push(false);
} else {
validationResults.push(true);
}
}
});
return validationResults;
}

View File

@ -10,11 +10,12 @@ import LoadingPage from '../../../Layout/app/LoadingPage';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { BsInfoCircle } from 'react-icons/bs'; import { BsInfoCircle } from 'react-icons/bs';
import { useAddProductVariation, useDeleteProductVariation, useGetOneProduct, useUpdateProduct, useUpdateProductVariation } from '../../../api/product'; import { useAddProductVariation, useDeleteProductVariation, useGetOneProduct, useUpdateProduct, useUpdateProductVariation } from '../../../api/product';
import { changeShapeInfo } from '../../../utils/Array/changeShapeInfo';
import { Spin } from 'antd'; import { Spin } from 'antd';
import BasicInfo from './BasicInfo'; import BasicInfo from './BasicInfo';
import { TabsContainer } from './FormikTab/TabsContainer'; import { TabsContainer } from './FormikTab/TabsContainer';
import { toast } from 'react-toastify'; import { isvalidation } from './Addfn/isvalidation';
import filterUndefinedAndEmpty from '../../../utils/Array/filterUndefinedAndEmpty';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
const ViewProduct = () => { const ViewProduct = () => {
const { setObjectToEdit, objectToEdit } = usePageState() const { setObjectToEdit, objectToEdit } = usePageState()
@ -34,13 +35,10 @@ const ViewProduct = () => {
const [Variant, setVariant] = useState<any>([]) const [Variant, setVariant] = useState<any>([])
const [InfoTaps, setInfoTaps] = useState<any>([])
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
// Update removedVarianteValues state // Update removedVarianteValues state
console.log(values, "values"); console.log(values?.removedVariant, "values?.removedVariant");
function isValid() { function isValid() {
setremovedVariant(values?.removedVariant); setremovedVariant(values?.removedVariant);
const variables = values?.variable?.slice(1); const variables = values?.variable?.slice(1);
@ -58,41 +56,9 @@ const ViewProduct = () => {
category_id: values?.category_id category_id: values?.category_id
}; };
// Uncomment this line to perform the mutation
mutate(newData); mutate(newData);
} }
const validationResults = isvalidation(values.variable, t);
const validationResults: boolean[] = [];
values?.variable?.slice(1)?.forEach((item: any, index: any) => {
if (item && Object.keys(item).length > 0) { // Check if attrValueItem is defined and not empty
if (!item?.name_ar || !item?.name_en || !item?.name_de) {
toast.error(t('required_name') + ` ${index + 1}`);
validationResults.push(false);
}
else if (!item?.description_ar || !item?.description_en || !item?.description_de) {
toast.error(t('required_description') + ` ${index + 1}`);
validationResults.push(false);
} else if (item.main_photo === null || !item?.main_photo ) {
toast.error(t('required_main_photo') + ` ${index + 1}`);
validationResults.push(false);
}
else if (item.price === null || !item?.price) {
toast.error(t('required_price') + ` ${index + 1}`);
validationResults.push(false);
}
else {
validationResults.push(true);
}
}
});
if (validationResults.every((result) => result)) { if (validationResults.every((result) => result)) {
isValid(); isValid();
} }
@ -108,18 +74,17 @@ const ViewProduct = () => {
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
const baseProductId = id; const baseProductId = id;
const filtered_Variant = filterUndefinedAndEmpty(Variant);
Variant?.map((dataToSend: any, index: number) => { filtered_Variant?.map((dataToSend: any, index: number) => {
console.log(dataToSend, "dataToSend"); console.log(dataToSend, "dataToSend");
const varible = dataToSend const varible = dataToSend
if (varible?.id && varible?.id !== null) { if (varible?.id && varible?.id !== null) {
const foundObject = OldData.find((item: any) => item.id === varible?.id) as any; const foundObject = OldData.find((item: any) => item.id === varible?.id) as any;
const info = varible?.info const info = varible?.info
console.log(info, "info"); console.log(info, "info");
const convertedArray = info.reduce((acc:any, obj:any) => { const convertedArray = info.reduce((acc: any, obj: any) => {
acc[obj.Description] = obj.key; acc[obj.Description] = obj.key;
return acc; return acc;
}, {}); }, {});
@ -138,7 +103,7 @@ const ViewProduct = () => {
ar: varible?.description_ar, ar: varible?.description_ar,
de: varible?.description_de de: varible?.description_de
}, },
quantity: varible?.quantity, // quantity: varible?.quantity,
main_photo: varible?.main_photo, main_photo: varible?.main_photo,
images: varible?.images, images: varible?.images,
info: jsonString, info: jsonString,
@ -192,16 +157,17 @@ const ViewProduct = () => {
if (convertedArray && foundObject.info) { if (convertedArray && foundObject.info) {
const editedInfoKeys = Object.keys(convertedArray); const editedInfoKeys = Object.keys(convertedArray);
const foundInfoKeys = Object.keys(foundObject.info); const foundInfoKeys = Object.keys(foundObject.info);
console.log(editedInfoKeys,"editedInfoKeys"); console.log(editedInfoKeys, "editedInfoKeys");
console.log(foundInfoKeys,"foundInfoKeys"); console.log(foundInfoKeys, "foundInfoKeys");
// Check if the number of keys is the same // Check if the number of keys is the same
if (editedInfoKeys.length === foundInfoKeys.length) { if (editedInfoKeys.length === foundInfoKeys.length) {
// Check if all keys and their corresponding values are the same // Check if all keys and their corresponding values are the same
const keysAreEqual = editedInfoKeys.every((key: any) => { const keysAreEqual = editedInfoKeys.every((key: any) => {
//@ts-ignore //@ts-ignore
console.log(convertedArray[key] ,"convertedArray[key] "); console.log(convertedArray[key], "convertedArray[key] ");
console.log(foundObject.info[key],"foundObject.info[key]"); console.log(foundObject.info[key], "foundObject.info[key]");
return convertedArray[key] === foundObject.info[key]; return convertedArray[key] === foundObject.info[key];
}); });
@ -212,6 +178,10 @@ const ViewProduct = () => {
delete Editedproduct.info; delete Editedproduct.info;
} }
} }
if (Object.keys(Editedproduct.info).length === 0) {
//@ts-ignore
delete Editedproduct.info;
}
} }
if (Object.keys(Editedproduct).length > 0) { if (Object.keys(Editedproduct).length > 0) {
//@ts-ignore //@ts-ignore
@ -228,12 +198,19 @@ const ViewProduct = () => {
} else { } else {
const info = varible?.info const info = varible?.info
const convertedArray = info?.reduce((acc:any, obj:any) => { const convertedArray = info?.reduce((acc: any, obj: any) => {
acc[obj.Description] = obj.key; acc[obj.Description] = obj.key;
return acc; return acc;
}, {}); }, {});
const jsonString = JSON.stringify(convertedArray); const jsonString = JSON.stringify(convertedArray);
const IMages = varible?.id !== null ? {
main_photo: varible?.main_photo,
images: varible?.images,
} : {
copied_assets: { main_photo: varible?.main_photo, images: varible?.images },
}
const Newproduct = { const Newproduct = {
name: { name: {
en: varible?.name_en, en: varible?.name_en,
@ -245,13 +222,15 @@ const ViewProduct = () => {
ar: varible?.description_ar, ar: varible?.description_ar,
de: varible?.description_de de: varible?.description_de
}, },
quantity: varible?.quantity, // quantity: varible?.quantity,
main_photo: varible?.main_photo,
images: varible?.images,
info: jsonString, info: jsonString,
price: varible?.price, price: varible?.price,
base_product_id: id, base_product_id: id,
...IMages,
product_attributes: varible?.attribute?.map((item: any, index: any) => { product_attributes: varible?.attribute?.map((item: any, index: any) => {
return { attribute_value_id: item?.value, attribute_id: item?.id } return { attribute_value_id: item?.value, attribute_id: item?.id }
@ -265,7 +244,9 @@ const ViewProduct = () => {
}) })
console.log(removedVariant); console.log(removedVariant);
removedVariant?.map((item: any) => { const filtered_removedVariant = filterUndefinedAndEmpty(removedVariant);
filtered_removedVariant?.map((item: any) => {
return DeleteVariation({ id: item }) return DeleteVariation({ id: item })
}) })
} }
@ -273,14 +254,14 @@ const ViewProduct = () => {
// useNavigateOnSuccess(UpdetedSuccessVariation || AddedSuccessVariation, '/products') useNavigateOnSuccess(isSuccess , '/products')
useEffect(() => { useEffect(() => {
// refetch() // refetch()
setObjectToEdit(data?.data); setObjectToEdit(data?.data);
setOldData(data?.data?.products) setOldData(data?.data?.products)
}, [data, id, isRefetching]); }, [data, data?.data, id, isRefetching]);
const getValidationSchema = () => { const getValidationSchema = () => {
return null return null
@ -294,7 +275,7 @@ const ViewProduct = () => {
return ( return (
<div className='ViewPage'> <div className='ViewPage'>
{objectToEdit && data ? {objectToEdit && data?.data && objectToEdit ?
<ViewPage {...ViewProps}> <ViewPage {...ViewProps}>
<Tabs> <Tabs>
<TabList> <TabList>
@ -308,7 +289,7 @@ const ViewProduct = () => {
<div className=" mt-4"><BasicInfo /></div> <div className=" mt-4"><BasicInfo /></div>
</TabBody> </TabBody>
<TabBody > <TabBody >
<div className=" mt-4"> {isLoading ? <Spin /> : <TabsContainer />} </div> <div className=" mt-4"> {isLoading && objectToEdit ? <Spin /> : <TabsContainer />} </div>
</TabBody> </TabBody>
</Tabs> </Tabs>

View File

@ -50,11 +50,17 @@ export const VariableTabs: React.FC<VariableTabsProps> = ({ tabKey }) => {
onChange={handleFieldChange('name_de')} onChange={handleFieldChange('name_de')}
/> />
<FormItem {/* <FormItem
label={t(`quantity`)} label={t(`quantity`)}
value={FormikName("quantity")} value={FormikName("quantity")}
onChange={handleFieldChange('quantity')} onChange={handleFieldChange('quantity')}
type="number" type="number"
/> */}
<FormItem
label={t(`price`)}
value={FormikName("price")}
onChange={handleFieldChange('price')}
type="number"
/> />
{values?.category_id && {values?.category_id &&
@ -79,12 +85,7 @@ export const VariableTabs: React.FC<VariableTabsProps> = ({ tabKey }) => {
value={FormikName("description_de")} value={FormikName("description_de")}
onChange={handleFieldChange('description_de')} onChange={handleFieldChange('description_de')}
/> />
<FormItem
label={t(`price`)}
value={FormikName("price")}
onChange={handleFieldChange('price')}
type="number"
/>
<File tabKey={tabKey} /> <File tabKey={tabKey} />
<MaltyFile tabKey={tabKey} /> <MaltyFile tabKey={tabKey} />
</Col> </Col>

View File

@ -5,17 +5,18 @@ import { ImageBaseURL } from "../../api/config";
export const getInitialValues = (objectToEdit: any) => { export const getInitialValues = (objectToEdit: any) => {
if (!objectToEdit || !objectToEdit.products) { if (!objectToEdit || !objectToEdit?.products) {
return {}; return {};
} }
const products = objectToEdit?.products.map((item: any) => { const products = objectToEdit?.products?.map((item: any) => {
if (!item || !item.info) { console.log(item,"item");
return {};
}
const formattedData = Object.entries(item?.info).map(([key, value]) => ({ const formattedData = item?.info ? Object.entries(item?.info).map(([key, value], index) => ({
[`Description`]: key, [`${index}.Description`]: key,
[`key`]: value, [`${index}.key`]: value,
})); })) : [];
return ({ return ({
@ -41,6 +42,9 @@ export const getInitialValues = (objectToEdit: any) => {
[`${index}.Description`]: key, [`${index}.Description`]: key,
[`${index}.key`]: value, [`${index}.key`]: value,
})); }));
console.log(products,"products");
console.log(objectToEdit,"objectToEdit");
return { return {
id:objectToEdit?.id, id:objectToEdit?.id,

46
src/Pages/Users/Page.tsx Normal file
View File

@ -0,0 +1,46 @@
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 { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
import { useGetUsers } from '../../api/users'
import SearchField from '../../Layout/Dashboard/SearchField'
function Page() {
const column =useTableColumns()
const {data ,status } = useGetUsers()
const [t] = useTranslation()
const navigate = useNavigate()
const totalRows = data?.meta?.total;
return (
// Pass Status to Layout
<DashBody status={status as QueryStatusEnum} >
<DashHeader showAddButton={false} title={'users'}>
<div className='RightSide d-flex gap-2 align-center '>
<SearchField searchBy={"name"} />
{/* <AddButton onClick={()=>navigate('/users/add')}></AddButton> */}
</div>
</DashHeader>
<LyTable
data={data?.data}
isLoading={false}
columns={column}
total={totalRows}
is_pagination={true}
/>
</DashBody>
)
}
export default Page

View File

@ -0,0 +1,42 @@
import { Col, Row } from 'reactstrap';
import ValidationField from '../../../../Components/ValidationField/ValidationField';
function Form() {
const type = [{ lable: "other", value: "other" },{ lable: "product", value: "product"},{ lable: "order", value: "order" }]
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
<ValidationField name="body_en" />
<ValidationField name="body_ar" />
<ValidationField name="body_de" />
{/* <ValidationField name="meta" /> */}
</Col>
<Col>
<ValidationField name="title_en" />
<ValidationField name="title_ar" />
<ValidationField name="title_de" />
{/* <ValidationField name="type" type="Select" option={type} /> */}
</Col>
</Row>
)
}
export default Form

View File

@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react'
import { getInitialValuesForAdd as 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 { useTranslation } from 'react-i18next';
import useNavigateOnSuccess from '../../../../Hooks/useNavigateOnSuccess';
import { useAddUsers } from '../../../../api/users';
import Form from './AddForm';
import { useParams } from 'react-router-dom';
import { useAddNotification } from '../../../../api/notification';
const AddPage = () => {
const { mutate, isLoading, isSuccess } = useAddNotification()
const {id} = useParams()
const handleSubmit = (values: any) => {
const body = {
en: values.body_en,
ar: values.body_ar,
du: values.body_de
}
const meta = {}
const title = {
en: values.title_en,
ar: values.title_ar,
du: values.title_de
}
const dataToSend = {
body: JSON.stringify(body),
meta: JSON.stringify(meta),
title:JSON.stringify(title),
user_ids: [id],
type: "other",
};
mutate(dataToSend);
};
const { t } = useTranslation();
useNavigateOnSuccess(isSuccess, '/users')
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit };
return (
<div className='ViewPage'>
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='SingleDriverInfo'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >
<div className=" mt-4"><Form /></div>
</TabBody>
</Tabs>
</ViewPage>
</div>
)
}
export default AddPage

View File

@ -0,0 +1,73 @@
import * as Yup from "yup";
import { buildFormData } from "../../../api/helper/buildFormData";
import moment from 'moment';
import * as dayjs from 'dayjs'
export const getInitialValues = (objectToEdit: any | null = null): any => {
//@ts-ignore
return {
id: objectToEdit?.id ,
name: objectToEdit?.name ,
email: objectToEdit?.email ,
type: objectToEdit?.type ,
avatar: objectToEdit?.avatar ,
};
};
export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
return {
body_en: "" ,
body_ar: "" ,
body_de: "" ,
// meta: "" ,
title_en: "" ,
title_ar: "" ,
title_de: "" ,
user_ids:[],
// type: "" ,
};
};
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<any> => {
// Validate input
return Yup.object().shape({
body_en: Yup.string().required('Required'),
body_ar: Yup.string().required('Required'),
body_de: Yup.string().required('Required'),
// meta: Yup.string().required('Required'),
title_en: Yup.string().required('Required'),
title_ar: Yup.string().required('Required'),
title_de: Yup.string().required('Required'),
// type: Yup.string().required('Required'),
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
const formData = new FormData();
buildFormData(formData, data);
return formData;
};
export const ChangeDataToPrint = (data: any) => {
let new_array = data
for (let i = 0; i < data.length; i++) {
new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
delete new_array[i]['deleted_at']
}
return new_array
}

View File

@ -0,0 +1,31 @@
import { Col, Row } from 'reactstrap';
import ValidationField from '../../../Components/ValidationField/ValidationField';
function Form() {
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
<ValidationField name="name" />
<ValidationField name="avatar" type="File" />
</Col>
<Col>
<ValidationField name="type" />
<ValidationField name="email" />
</Col>
</Row>
)
}
export default Form

View File

@ -0,0 +1,57 @@
import React, { useEffect, useState } from 'react'
import { getInitialValuesForAdd as 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 { useTranslation } from 'react-i18next';
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
import { useAddUsers } from '../../../api/users';
import Form from './AddForm';
const AddPage = () => {
const { mutate, isLoading, isSuccess } = useAddUsers()
const handleSubmit = (values: any) => {
mutate(values)
};
const { t } = useTranslation();
useNavigateOnSuccess(isSuccess, '/users')
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit };
return (
<div className='ViewPage'>
<ViewPage {...ViewProps}>
<Tabs>
<TabList>
<Tab><div className='SignleDriverContainer'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='SingleDriverInfo'>{t("BasicInfo")}</h6></div></Tab>
</TabList>
<TabBody >
<div className=" mt-4"><Form /></div>
</TabBody>
</Tabs>
</ViewPage>
</div>
)
}
export default AddPage

View File

@ -0,0 +1,60 @@
import * as Yup from "yup";
import { buildFormData } from "../../api/helper/buildFormData";
import moment from 'moment';
import * as dayjs from 'dayjs'
export const getInitialValues = (objectToEdit: any | null = null): any => {
//@ts-ignore
return {
id: objectToEdit?.id ,
name: objectToEdit?.name ,
email: objectToEdit?.email ,
type: objectToEdit?.type ,
avatar: objectToEdit?.avatar ,
};
};
export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
return {
name: null ,
email: null ,
type: null ,
avatar: null ,
};
};
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<any> => {
// Validate input
return Yup.object().shape({
name: Yup.string().required('Required'),
email: Yup.string().required('Required'),
type: Yup.string().required('Required'),
avatar: Yup.string().required('Required'),
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
const formData = new FormData();
buildFormData(formData, data);
return formData;
};
export const ChangeDataToPrint = (data: any) => {
let new_array = data
for (let i = 0; i < data.length; i++) {
new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
delete new_array[i]['deleted_at']
}
return new_array
}

View File

@ -0,0 +1,99 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import Actions from "../../Components/Ui/tables/Actions";
import ColumnsImage from "../../Components/Columns/ColumnsImage";
import { useNavigate } from "react-router-dom";
import { useDeleteUsers, useUpdateUsers } from "../../api/users";
import { Switch } from "antd";
import { MdEmail } from "react-icons/md";
import { useModalState } from "../../zustand/Modal";
const useTableColumns: any = () => {
const [t] = useTranslation();
const deleteMutation = useDeleteUsers()
const navigate = useNavigate()
const { mutate: update_status } = useUpdateUsers("put")
const onChange = (checked: boolean, row: any) => {
console.log(`switch to ${checked}`);
update_status({
id: row.id,
status: checked ? "active" : "suspended"
})
};
return useMemo(
() => [
{
name: t("avatar"),
sortable: false,
center: "true",
cell: (row: any) => {
let str = row?.avatar;
str = str?.replace(`public`, "/storage") ?? "";
return <ColumnsImage src={str} />
}
},
{
name: t("name"),
sortable: false,
center: "true",
cell: (row: any) => row?.name
},
{
name: t("email"),
sortable: false,
center: "true",
cell: (row: any) => row?.email
},
{
name: t("type"),
sortable: false,
center: "true",
cell: (row: any) => row?.type
},
{
name: t("status"),
sortable: false,
center: "true",
cell: (row: any) => {
let status = row?.status;
return <Switch checked={status === "active"} onChange={(value: any) => onChange(value, row)} />;
}
},
{
name: "#",
sortable: false,
center: true,
cell: (row: any) => (
<Actions
objectToEdit={row}
showEdit={false}
onEdit={() => navigate(`/users/${row.id}`)}
showView={false}
// onDelete={() => deleteMutation.mutate({ id: row.id })}
showDelete={false}
>
<MdEmail onClick={() => navigate(`/users/${row.id}`)} className="cursor-pointer m-2" size={25} />
</Actions>
),
},
],
[t]
);
};
export default useTableColumns;

View File

@ -28,7 +28,7 @@ function Form() {
</Col> </Col>
<Col> <Col>
<ValidationField name="admin_note" /> <ValidationField name="admin_note" />
<ValidationField name="deliviration_estimated_time" Format="YYYY-MM-DD HH:MM:SS" type='Date' /> <ValidationField name="deliviration_estimated_time" Format="YYYY/MM/DD" type='Date' />
</Col> </Col>

View File

@ -25,7 +25,12 @@ const EditPage = () => {
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)=>{
return mutate(values);
console.log(values?.deliviration_estimated_time?.format('YYYY-MM-DD HH:mm:ss'));
return mutate({
...values,
deliviration_estimated_time:values?.deliviration_estimated_time?.format('YYYY-MM-DD HH:mm:ss')
});
} }
useNavigateOnSuccess(isSuccess , '/order') useNavigateOnSuccess(isSuccess , '/order')

View File

@ -1,7 +1,7 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
// Icons Import // Icons Import
import { FaCartArrowDown, FaHome, FaProductHunt, FaRegImages } from "react-icons/fa" import { FaCartArrowDown, FaHome, FaProductHunt, FaRegImages, FaUser } from "react-icons/fa"
import { BiSolidCategory } from "react-icons/bi"; import { BiSolidCategory } from "react-icons/bi";
import { BiSolidCoupon } from "react-icons/bi"; import { BiSolidCoupon } from "react-icons/bi";
@ -30,6 +30,15 @@ import SliderPage from "./Pages/Slider/Page";
import AddSliderPage from "./Pages/Slider/View/AddPage"; import AddSliderPage from "./Pages/Slider/View/AddPage";
import EditSlider from "./Pages/Slider/View/EditPage"; import EditSlider from "./Pages/Slider/View/EditPage";
import UsersPage from "./Pages/Users/Page";
import AddUsersPage from "./Pages/Users/View/AddPage";
import AddUsersNotifactionPage from "./Pages/Users/SendNotifcation/View/AddPage";
import NotificationPage from "./Pages/Notifcation/Page";
import AddNotificationPage from "./Pages/Notifcation/View/AddPage";
import { MdEmail } from "react-icons/md";
interface RoutesLinksType { interface RoutesLinksType {
@ -143,7 +152,35 @@ export const RoutesLinks: RoutesLinksType[] = [
hidden:true hidden:true
}, },
{
name: "users",
element: <UsersPage />,
icon: <FaUser />,
href: "/users",
},
{
href: "/users/add",
element: <AddUsersPage />,
hidden:true
},
{
href: "/users/:id",
element: <AddUsersNotifactionPage />,
hidden:true
}
, {
name: "notification",
element: <NotificationPage />,
icon: <MdEmail />,
href: "/notification",
},
{
href: "/notification/add",
element: <AddNotificationPage />,
hidden:true
},
] ]

View File

@ -26,7 +26,7 @@ function useAddMutation(key: string, url: string): UseMutationResult<AxiosRespon
{ {
onSuccess: (data) => { onSuccess: (data) => {
queryClient.invalidateQueries([key]); queryClient.invalidateQueries([key]);
toast.success(data.message || t("Add Successful")); toast.success(data.message || t("added_uccessful"));
}, },
onError: (error:any) => { onError: (error:any) => {
const message = error?.response?.data?.message || t("failed_to_add_data"); const message = error?.response?.data?.message || t("failed_to_add_data");

23
src/api/notification.ts Normal file
View File

@ -0,0 +1,23 @@
import useGetQueryPagination from "./helper/ueGetPagination";
import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery";
const API = {
ADD: `notification`,
GET_ALL: `notification`,
DELETE: `notification`,
};
const KEY = "notification"
export const useGetNotification = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
export const useGetOnenotification = (params?:any) => useGetOneQuery(KEY, API.GET_ALL,params);
export const useAddNotification = () => useAddMutation(KEY, API.ADD);
export const useDeleteNotification = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -5,12 +5,13 @@ import useDeleteMutation from "./helper/useDeleteMutation"
import useGetOneQuery from "./helper/useGetOneQuery"; import useGetOneQuery from "./helper/useGetOneQuery";
import useGetQuery from "./helper/useGetQuery" import useGetQuery from "./helper/useGetQuery"
import useUpdateMutation from "./helper/useUpdateMutation"; import useUpdateMutation from "./helper/useUpdateMutation";
import useUpdateMutationById from "./helper/useUpdateMutationById";
const API = { const API = {
ADD: `user`, ADD: `user`,
GET_ALL: `user`, GET_ALL: `user?notOfType=admin`,
DELETE: `user`, DELETE: `user`,
UPDATE: `user`, UPDATE: `user/updateStatus`,
}; };
const KEY = "User" const KEY = "User"
@ -20,6 +21,8 @@ export const useGetUsers = (params?:any) => useGetQueryPagination(KEY, API.GET_A
export const useGetOneUser = (params?:any) => useGetOneQuery(KEY, API.GET_ALL,params); export const useGetOneUser = (params?:any) => useGetOneQuery(KEY, API.GET_ALL,params);
export const useAddUsers = () => useAddMutation(KEY, API.ADD); export const useAddUsers = () => useAddMutation(KEY, API.ADD);
export const useUpdateUsers = () => useUpdateMutation(KEY, API.UPDATE); export const useUpdateUsers = (method?:string) => useUpdateMutationById(KEY, API.UPDATE,true,method);
export const useDeleteUsers = () =>useDeleteMutation(KEY, API.DELETE); export const useDeleteUsers = () =>useDeleteMutation(KEY, API.DELETE);

View File

@ -1,69 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var zustand_1 = require("zustand");
var AppKey_1 = require("../../config/AppKey");
var useAuthState = zustand_1.create(function (set) {
var storedUser = localStorage.getItem(AppKey_1.USER_KEY);
var storedToken = localStorage.getItem(AppKey_1.TOKEN_KEY);
var initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
return {
user: initialUser,
isAuthenticated: !!storedToken,
token: storedToken,
login: function (userData) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
console.log(userData);
localStorage.setItem(AppKey_1.TOKEN_KEY, userData.token);
localStorage.setItem(AppKey_1.USER_KEY, JSON.stringify(userData.admin));
set(function (state) { return ({ user: userData.admin, isAuthenticated: true, token: userData.token }); });
return [2 /*return*/];
});
}); },
logout: function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
localStorage.removeItem(AppKey_1.TOKEN_KEY);
localStorage.removeItem(AppKey_1.TOKEN_KEY_SOCKET);
localStorage.removeItem(AppKey_1.USER_KEY);
set(function (state) { return ({ user: null, isAuthenticated: false, token: null }); });
return [2 /*return*/];
});
}); }
};
});
exports["default"] = useAuthState;

View File

@ -1,23 +0,0 @@
"use strict";
exports.__esModule = true;
exports.usePageState = void 0;
var zustand_1 = require("zustand");
exports.usePageState = zustand_1.create(function (set) { return ({
isOpenAddModel: false,
isOpenEditModel: false,
objectToEdit: null,
isThemChanged: false,
setThemChange: function () {
return set(function (state) { return ({ isThemChanged: !state.isThemChanged }); });
},
setIsOpenAddModel: function () {
return set(function (state) { return ({ isOpenAddModel: !state.isOpenAddModel }); });
},
setIsOpenEditModel: function () {
return set(function (state) { return ({ isOpenEditModel: !state.isOpenEditModel }); });
},
CloseAllModal: function () {
return set(function (state) { return ({ isOpenAddModel: false, isOpenEditModel: false }); });
},
setObjectToEdit: function (data) { return set(function () { return ({ objectToEdit: data }); }); }
}); });

View File

@ -1,22 +0,0 @@
"use strict";
exports.__esModule = true;
exports.useCommonModelState = void 0;
var zustand_1 = require("zustand");
exports.useCommonModelState = zustand_1.create(function (set) { return ({
isOpenBlock: false,
isOpenGift: false,
isOpenUnBlock: false,
setIsopenBlock: function () {
return set(function (state) { return ({ isOpenBlock: !state.isOpenBlock }); });
},
setIsopenUnBlock: function () {
return set(function (state) { return ({ isOpenUnBlock: !state.isOpenUnBlock }); });
},
setIsopenGift: function () {
return set(function (state) { return ({ isOpenGift: !state.isOpenGift }); });
},
setObjectId: function (data) {
return set(function (state) { return ({ objectID: data }); });
},
objectID: 0
}); });

View File

@ -128,9 +128,22 @@
"unique_error_names": "اسم فريد لكل سمة مطلوب", "unique_error_names": "اسم فريد لكل سمة مطلوب",
"deliviration_estimated_time": "الوقت المقدر للتسليم", "deliviration_estimated_time": "الوقت المقدر للتسليم",
"delivery_link": "رابط التسليم", "delivery_link": "رابط التسليم",
"failed_to_add_data": "فشل في إضافة البيانات",
"delete_are_you_sure": "هل أنت متأكد أنك تريد الحذف؟", "delete_are_you_sure": "هل أنت متأكد أنك تريد الحذف؟",
"yes_delete_it": "نعم، احذفه" "yes_delete_it": "نعم، احذفه",
"notification": "إشعار",
"users": "المستخدمون",
"body": "جسم",
"body_en": "الجسم (الإنجليزية)",
"body_ar": "الجسم (العربية)",
"body_de": "الجسم (الألمانية)",
"title_en": "العنوان (الإنجليزية)",
"title_ar": "العنوان (العربية)",
"title_de": "العنوان (الألمانية)",
"avatar": "الصورة الرمزية",
"added_successful": "تمت الإضافة بنجاح",
"failed_to_add_data": "فشلت عملية الإضافة",
"deleted_successfully": "تم الحذف بنجاح",
"updated_successfully": "تم التحديث بنجاح"

View File

@ -124,10 +124,23 @@
"unique_error_names": "Einzigartiger Name für jede Eigenschaft ist erforderlich", "unique_error_names": "Einzigartiger Name für jede Eigenschaft ist erforderlich",
"deliviration_estimated_time": "Voraussichtliche Lieferzeit", "deliviration_estimated_time": "Voraussichtliche Lieferzeit",
"delivery_link": "Lieferlink", "delivery_link": "Lieferlink",
"failed_to_add_data": "Fehler beim Hinzufügen von Daten",
"delete_are_you_sure": "Möchten Sie wirklich löschen?", "delete_are_you_sure": "Möchten Sie wirklich löschen?",
"yes_delete_it": "Ja, löschen", "yes_delete_it": "Ja, löschen",
"cancel": "Abbrechen" "cancel": "Abbrechen",
"notification": "Benachrichtigung",
"users": "Benutzer",
"body": "Körper",
"body_en": "Körper (Englisch)",
"body_ar": "Körper (Arabisch)",
"body_de": "Körper (Deutsch)",
"title_en": "Titel (Englisch)",
"title_ar": "Titel (Arabisch)",
"title_de": "Titel (Deutsch)",
"avatar": "Avatar",
"added_successful": "Erfolgreich hinzugefügt",
"failed_to_add_data": "Daten konnten nicht hinzugefügt werden",
"deleted_successfully": "Erfolgreich gelöscht",
"updated_successfully": "Erfolgreich aktualisiert"

View File

@ -124,11 +124,24 @@
"unique_error_names": "Unique name for each attribute is required", "unique_error_names": "Unique name for each attribute is required",
"deliviration_estimated_time": "Delivery Estimated Time", "deliviration_estimated_time": "Delivery Estimated Time",
"delivery_link": "Delivery Link", "delivery_link": "Delivery Link",
"failed_to_add_data": "Failed to add data",
"delete_are_you_sure": "Are you sure you want to delete?", "delete_are_you_sure": "Are you sure you want to delete?",
"yes_delete_it": "Yes, delete it", "yes_delete_it": "Yes, delete it",
"cancel": "Cancel", "cancel": "Cancel",
"required_error":"required_error" "required_error":"required_error",
"notification": "Notification",
"users": "Users",
"body": "Body",
"body_en": "Body (English)",
"body_ar": "Body (Arabic)",
"body_de": "Body (German)",
"title_en": "Title (English)",
"title_ar": "Title (Arabic)",
"title_de": "Title (German)",
"avatar": "Avatar",
"added_successful": "added successful",
"failed_to_add_data": "Failed to add data",
"deleted_successfully": "deleted successfully",
"updated_successfully": "updated successfully"
} }

View File

@ -1,3 +1,6 @@
BasicInfo {
attributes added_uccessful
Add New Attribute failed_to_add_data
deleted_successfully
updated_successfully
}

View File

@ -0,0 +1,5 @@
const filterUndefinedAndEmpty = (array:any) => {
return array.filter((data:any) => data !== undefined && Object.keys(data).length !== 0);
};
export default filterUndefinedAndEmpty;

15
src/zustand/Modal.ts Normal file
View File

@ -0,0 +1,15 @@
import {create} from 'zustand'
interface ModalState {
isOpen: boolean;
setIsOpen: (value:boolean) => void;
}
export const useModalState = create<ModalState>((set) => ({
isOpen: false,
setIsOpen: () =>
set((state) => ({ isOpen: !state.isOpen })),
}));