Compare commits

..

3 Commits

Author SHA1 Message Date
Moaz Dawalibi
7fc7258a24 fixes 2024-09-26 13:13:32 +03:00
Moaz Dawalibi
9b3c1fb49b fix react query bug 2024-09-26 10:47:22 +03:00
Moaz Dawalibi
81eb55e2e0 reseller : sales page and collection page
admin: collection and some fixes
2024-09-26 09:40:58 +03:00
54 changed files with 895 additions and 314 deletions

View File

@ -38,7 +38,7 @@ const NavBarRightSide = () => {
icon={<CiCirclePlus size={25} />} icon={<CiCirclePlus size={25} />}
/> />
<TooltipComp <TooltipComp
onClick={()=>(Navigate('/notifications'))} // onClick={()=>(Navigate('/notifications'))}
className="NotificationsIcon" className="NotificationsIcon"
note="notification" note="notification"
color="#E0E0E0" color="#E0E0E0"
@ -55,7 +55,9 @@ const NavBarRightSide = () => {
<h6>{userData?.username}</h6> <h6>{userData?.username}</h6>
<p>{userData?.type}</p> <p>{userData?.type}</p>
</span> */} </span> */}
<Image onClick={()=>(Navigate('/profile'))} src="/Image/faker_user.png" alt="Profile" /> <Image
// onClick={()=>(Navigate('/profile'))}
src="/Image/faker_user.png" alt="Profile" />
</div> </div>
</article> </article>
); );

View File

@ -158,14 +158,14 @@ const useFilter = () => {
return ( return (
<div className="filter-submit-buttons buttons"> <div className="filter-submit-buttons buttons">
<Button <Button
className="back_button filter_modal_add_button" className="back_button filter_modal_cancel_button"
type="default" type="default"
htmlType="reset" htmlType="reset"
> >
{t("practical.reset")} {t("practical.reset")}
</Button> </Button>
<Button <Button
className="add_button pointer filter_modal_add_button" className="pointer filter_modal_add_button"
type="primary" type="primary"
{...buttonProps} {...buttonProps}
htmlType="submit" htmlType="submit"

View File

@ -25,6 +25,7 @@ const Date = ({
const onCalendarChange = (value: any) => { const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value); formik.setFieldValue(name, value);
}; };
console.log(FormikValue);
const Formatter = [DateEnum?.FORMATE]; const Formatter = [DateEnum?.FORMATE];
return ( return (

View File

@ -37,6 +37,7 @@ const Default = ({
name={name} name={name}
id={name} id={name}
disabled={isDisabled} disabled={isDisabled}
value={formik?.values?.[name]}
size="large" size="large"
{...(type === "number" && { min: 0 })} {...(type === "number" && { min: 0 })}
{...props} {...props}

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { Divider, Modal, Spin } from "antd"; import { Button, Divider, Modal, Spin } from "antd";
import { useModalState } from "../../zustand/Modal"; import { useModalState } from "../../zustand/Modal";
import FormikForm from "./FormikFormModel"; import FormikForm from "./FormikFormModel";
import { useObjectToEdit } from "../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../zustand/ObjectToEditState";
@ -76,7 +76,6 @@ const LayoutModel = ({
initialValues={getInitialValues} initialValues={getInitialValues}
validationSchema={getValidationSchema} validationSchema={getValidationSchema}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{(formik) => { {(formik) => {
useEffect(() => { useEffect(() => {
@ -101,13 +100,13 @@ const LayoutModel = ({
<Divider /> <Divider />
<div className="buttons"> <div className="buttons">
<div className="back_button pointer" onClick={handleCancel}> <Button className="back_button pointer" onClick={handleCancel}>
{t("practical.cancel")} {t("practical.cancel")}
</div> </Button>
<button <Button
className="add_button" className="add_button"
disabled={status === QueryStatusEnum.LOADING || !formik.dirty} disabled={status === QueryStatusEnum.LOADING || !formik.dirty}
type="submit" htmlType="submit"
> >
{ {
initialButtonName ? t(`practical.${isAddModal ? "add" : "edit"}`) initialButtonName ? t(`practical.${isAddModal ? "add" : "edit"}`)
@ -118,7 +117,7 @@ const LayoutModel = ({
<Spin /> <Spin />
</span> </span>
)} )}
</button> </Button>
</div> </div>
</main> </main>

View File

@ -66,7 +66,9 @@ const SideBar = ({
</div> </div>
<div className="side_bar_setting"> <div className="side_bar_setting">
<p>{t("sidebar.setting")}</p> <p>{t("sidebar.setting")}</p>
<div onClick={() => {navigate("/setting")}}> <div
// onClick={() => {navigate("/setting")}}
>
<CiSettings /> <CiSettings />
<span>{t("sidebar.setting")}</span> <span>{t("sidebar.setting")}</span>
</div> </div>

View File

@ -0,0 +1,39 @@
import React from "react";
import { getInitialValues, getValidationSchema } from "./formUtil";
import { ModalEnum } from "../../../../enums/Model";
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { useAddTag } from "../../../../api/tags";
import ModelForm from "./ModelForm";
import { useAddFinancialCollection } from "../../../../api/financial_collection";
import { formatDate } from "../../../../utils/formatDate";
import dayjs from "dayjs";
const AddModel: React.FC = () => {
const { mutate, status } = useAddFinancialCollection();
const handleSubmit = (values: any) => {
console.log(values);
mutate({
...values,
date: dayjs(values?.date).format('YYYY-MM-DD'),
});
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.Financial_Collection_ADD}
modelTitle="financial_collection"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})}
getValidationSchema={getValidationSchema}
>
<ModelForm />
</LayoutModel>
</>
);
};
export default AddModel;

View File

@ -0,0 +1,40 @@
import React from "react";
import { getInitialValues, getValidationSchema, getValidationSchemaEdit } from "./formUtil";
import { ModalEnum } from "../../../../enums/Model";
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
import ModelForm from "./ModelForm";
import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useUpdateTag } from "../../../../api/tags";
import { useUpdateFinancialCollection } from "../../../../api/financial_collection";
import dayjs from "dayjs";
const EditModel: React.FC = () => {
const { mutate, status } = useUpdateFinancialCollection();
const { objectToEdit } = useObjectToEdit((state) => state);
console.log(objectToEdit);
const handleSubmit = (values: any) => {
mutate({
...values,
date: dayjs(values?.date).format('YYYY-MM-DD'),
});
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.Financial_Collection_EDIT}
modelTitle="financial_collection_details"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchemaEdit}
isAddModal={false}
>
<ModelForm isEdit={true}/>
</LayoutModel>
</>
);
};
export default EditModel;

View File

@ -0,0 +1,35 @@
import React from "react";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { Col, Row } from "reactstrap";
import { useGetAllReseller } from "../../../../api/reseller";
const FilterForm = () => {
const {data} = useGetAllReseller()
return (
<div>
<Row>
<Col>
<ValidationField placeholder="description" label="description" name="description" />
<ValidationField placeholder="amount" label="amount" name="amount" />
<ValidationField
placeholder="reseller"
label="reseller"
name="reseller_id"
type="Select"
option={data?.data?.map((e: any) => ({
...e,
fullName: `${e.first_name} ${e.last_name}`
}))}
fieldNames={{
label: "fullName",
value: "id"
}}
/>
</Col>
</Row>
</div>
);
};
export default FilterForm;

View File

@ -0,0 +1,38 @@
import { Col, Row } from "reactstrap";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { useGetAllReseller } from "../../../../api/reseller";
const Form = ({isEdit= false}:{isEdit?:boolean}) => {
const {data} = useGetAllReseller()
return (
<Row className="w-100">
<Col>
<ValidationField placeholder="description" label="description" name="description" />
<ValidationField placeholder="amount" label="amount" name="amount" />
</Col>
<Col>
<ValidationField placeholder="date" label="date" name="date" type="Date"/>
{isEdit ? " " :
<ValidationField
placeholder="reseller"
label="reseller"
name="reseller_id"
type="Select"
option={data?.data?.map((e: any) => ({
...e,
fullName: `${e.first_name} ${e.last_name}`
}))}
fieldNames={{
label: "fullName",
value: "id"
}}
/>
}
</Col>
</Row>
);
};
export default Form;

View File

@ -0,0 +1,30 @@
import * as Yup from "yup";
import dayjs from "dayjs";
export const getInitialValues = (objectToEdit: any): any => {
console.log(objectToEdit);
return {
id: objectToEdit?.id ?? null,
description: objectToEdit?.description ?? null,
amount: objectToEdit?.amount ?? null,
date: objectToEdit?.date ? dayjs(objectToEdit?.date) : null,
reseller_id: objectToEdit?.reseller_id ?? null,
};
};
export const getValidationSchema = () => {
return Yup.object().shape({
description: Yup.string().required("validation.required"),
amount: Yup.mixed().required("validation.required"),
date: Yup.mixed().required("validation.required"),
reseller_id: Yup.mixed().required("validation.required"),
});
};
export const getValidationSchemaEdit = () => {
return Yup.object().shape({
description: Yup.string().required("validation.required"),
amount: Yup.mixed().required("validation.required"),
date: Yup.mixed().required("validation.required"),
});
};

View File

@ -0,0 +1,54 @@
import { FaPlus } from "react-icons/fa";
import useModalHandler from "../../../utils/useModalHandler";
import { ModalEnum } from "../../../enums/Model";
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import { canAddFinancial_Collection, canAddTags } from "../../../utils/hasAbilityFn";
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
import { useDeleteTag } from "../../../api/tags";
import PageHeader from "../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../Layout/Dashboard/FilterLayout";
import FilterForm from "./Model/FilterForm";
import { useDeleteFinancialCollection } from "../../../api/financial_collection";
const Table = lazy(() => import("./Table"));
const AddModalForm = lazy(() => import("./Model/AddModel"));
const EditModalForm = lazy(() => import("./Model/EditModel"));
const DeleteModalForm = lazy(
() => import("../../../Layout/Dashboard/DeleteModels"),
);
const TableHeader = () => {
const [t] = useTranslation();
useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.financial_collection`)}`, path:"financial_collection"}
]);
const deleteMutation = useDeleteFinancialCollection();
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<PageHeader
pageTitle="financial_collection"
ModelAbility={ModalEnum?.Financial_Collection_ADD}
canAdd={canAddFinancial_Collection}
/>
<FilterLayout
sub_children={<FilterForm />}
filterTitle="sidebar.financial_collection"
/>
<Table />
<DeleteModalForm
deleteMutation={deleteMutation}
ModelEnum={ModalEnum?.Financial_Collection_DELETE}
/>
<AddModalForm />
<EditModalForm />
</Suspense>
</div>
);
};
export default TableHeader;

View File

@ -0,0 +1,24 @@
import React from "react";
import DataTable from "../../../Layout/Dashboard/Table/DataTable";
import { useColumns } from "./useTableColumns";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../zustand/Filter";
import { useGetAllFinancialCollection } from "../../../api/financial_collection";
const App: React.FC = () => {
const { filterState } = useFilterState();
const { Filter } = useFilterStateState();
const name = Filter?.name ;
const sort_by = Filter?.sort_by ;
const response = useGetAllFinancialCollection({
pagination: true,
name,
sort_by,
...filterState,
});
return <DataTable response={response} useColumns={useColumns} />;
};
export default App;

View File

@ -0,0 +1,17 @@
import { useColumns } from "./useTableColumns";
import Table from "./Table";
import { FaPlus } from "react-icons/fa";
import AddModalForm from "./Model/AddModel";
import EditModalForm from "./Model/EditModel";
// import DeleteModalForm from "../../";
export {
Table,
useColumns,
AddModalForm,
EditModalForm,
// DeleteModalForm,
FaPlus,
};

View File

@ -0,0 +1,73 @@
import { TableColumnsType } from "antd";
import { tags } from "../../../types/Item";
import { ModalEnum } from "../../../enums/Model";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useModalState } from "../../../zustand/Modal";
import { useTranslation } from "react-i18next";
import { canDeleteFinancial_Collection, canDeleteTags, canEditFinancial_Collection, canEditTags } from "../../../utils/hasAbilityFn";
import ActionButtons from "../../../Components/Table/ActionButtons";
export const useColumns = () => {
const [t] = useTranslation();
const { setIsOpen } = useModalState((state) => state);
const { setObjectToEdit } = useObjectToEdit((state) => state);
const handelDelete = (record: any) => {
setObjectToEdit(record);
setIsOpen(ModalEnum?.Financial_Collection_DELETE);
};
const handleEdit = (record: any) => {
setObjectToEdit(record);
setIsOpen(ModalEnum?.Financial_Collection_EDIT);
};
const columns: TableColumnsType<any> = [
{
title: t("columns.id"),
dataIndex: "id",
key: "id",
align: "center",
},
{
title: t("columns.amount"),
dataIndex: "amount",
key: "amount",
align: "center",
ellipsis:true
},
{
title: t("columns.date"),
dataIndex: "date",
key: "date",
align: "center",
ellipsis:true
},
{
title: t("columns.description"),
dataIndex: "description",
key: "description",
align: "center",
ellipsis:true
},
{
title: t("columns.procedure"),
key: "actions",
align: "center",
width: "25vw",
render: (_text, record, index) => {
return (
<ActionButtons
canDelete={canEditFinancial_Collection}
canEdit={canDeleteFinancial_Collection}
index={index}
onDelete={() => handelDelete(record)}
onEdit={() => handleEdit(record)}
/>
);
},
},
];
return columns;
};

View File

@ -16,6 +16,7 @@ const App: React.FC = () => {
name, name,
sort_by sort_by
}); });
// console.log(response);
return <DataTable response={response} useColumns={useColumns} />; return <DataTable response={response} useColumns={useColumns} />;
}; };

View File

@ -1,12 +1,13 @@
import { Spin } from "antd";
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
const CollectionInfoCard = ({label,value}:{label:string,value:string}) => { const CollectionInfoCard = ({label,value,isLoading}:{label:string,value:string,isLoading?:boolean}) => {
const {t} = useTranslation(); const {t} = useTranslation();
return ( return (
<div className='collection_info_card'> <div className='collection_info_card'>
<h5>{t(`card.${label}`)}</h5> <h5>{t(`card.${label}`)}</h5>
<p>{t(value)}</p> <p> {isLoading ?<Spin/>: t(value)}</p>
</div> </div>
) )
} }

View File

@ -1,30 +1,39 @@
import React from 'react' import React from 'react'
import CollectionInfoCard from './CollectionInfoCard' import CollectionInfoCard from './CollectionInfoCard'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useGetSummery } from '../../../../api/sales';
import { Spin } from 'antd';
const CollectionsCards = ({data}:{data?:any}) => { const CollectionsCards = () => {
const {t} = useTranslation(); const {t} = useTranslation();
const { data ,isLoading} = useGetSummery();
return ( return (
<> <>
<CollectionInfoCard <CollectionInfoCard
label={t('total_sells')} label={t('total_sells')}
value={"210"} isLoading={isLoading}
value={data?.data?.total_sells}
/> />
<CollectionInfoCard <CollectionInfoCard
label={t('reseller_profit')} label={t('reseller_profit')}
value={"210"} isLoading={isLoading}
value={data?.data?.reseller_profit}
/> />
<CollectionInfoCard <CollectionInfoCard
label={t('company_profit')} label={t('company_profit')}
value={"210"} isLoading={isLoading}
value={data?.data?.dues}
/> />
<CollectionInfoCard <CollectionInfoCard
label={t('collected')} label={t('collected')}
value={"210"} isLoading={isLoading}
value={data?.data?.collected_amount}
/> />
<CollectionInfoCard <CollectionInfoCard
label={t('residual')} label={t('residual')}
value={"210"} isLoading={isLoading}
value={data?.data?.remaining_amount}
/> />
</> </>
) )

View File

@ -1,18 +1,17 @@
import React from "react";
import ValidationField from "../../../../Components/ValidationField/ValidationField"; import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { Col, Row } from "reactstrap"; import { Col, Row } from "reactstrap";
import { useGetAllReseller } from "../../../../api/reseller";
const FilterForm = () => { const FilterForm = () => {
const {data} = useGetAllReseller()
console.log(data);
return ( return (
<div> <div>
<Row> <Row>
<Col> <Col>
<ValidationField <ValidationField placeholder="description" label="description" name="description" />
placeholder="activation_date" <ValidationField placeholder="amount" label="amount" name="amount" />
label="activation_date"
name="activation_date"
/>
{/* <ValidationField placeholder="name" label="name" name="name" /> */}
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@ -0,0 +1,22 @@
import React from "react";
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { Col, Row } from "reactstrap";
const FilterForm = () => {
return (
<div>
<Row>
<Col>
<ValidationField
placeholder="activation_date"
label="activation_date"
name="activation_date"
/>
{/* <ValidationField placeholder="name" label="name" name="name" /> */}
</Col>
</Row>
</div>
);
};
export default FilterForm;

View File

@ -0,0 +1,35 @@
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import useSetPageTitle from "../../../../Hooks/useSetPageTitle";
import PageHeader from "../../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../../Layout/Dashboard/FilterLayout";
import FilterForm from "./Model/FilterForm";
const Table = lazy(() => import("./Table"));
const TableHeader = () => {
const [t] = useTranslation();
useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.collections`)}`, path:"collections"},
{name:`${t(`page_header.show_collection`)}`, path:"show_collection"},
]);
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<PageHeader
pageTitle="show_collection"
/>
<FilterLayout
sub_children={<FilterForm />}
filterTitle="table.show_collection"
/>
<Table />
</Suspense>
</div>
);
};
export default TableHeader;

View File

@ -0,0 +1,25 @@
import React from "react";
import DataTable from "../../../../Layout/Dashboard/Table/DataTable";
import { useColumns } from "./useTableColumns";
import useSearchQuery from "../../../../api/utils/useSearchQuery";
import { useFilterState } from "../../../../Components/Utils/Filter/FilterState";
import { useGetCollection } from "../../../../api/collections";
import { useParams } from "react-router-dom";
const App: React.FC = () => {
const [searchQuery] = useSearchQuery("name");
const { filterState } = useFilterState();
const {collection_id}= useParams()
console.log(collection_id);
const response = useGetCollection({
name: searchQuery,
pagination: true,
...filterState,
show:collection_id
});
return <DataTable response={response} useColumns={useColumns} dataSource={[]} />;
};
export default App;

View File

@ -0,0 +1,35 @@
import { TableColumnsType } from "antd";
import { Collection } from "../../../../types/Item";
import { useTranslation } from "react-i18next";
export const useColumns = () => {
const [t] = useTranslation();
const columns: TableColumnsType<Collection> = [
{
title: t("columns.ID"),
dataIndex: "id",
key: "id",
align: "center",
},
{
title: t("columns.amount"),
dataIndex: "amount",
key: "amount",
align: "center",
},
{
title: t("columns.date"),
dataIndex: "date",
key: "date",
align: "center",
},
{
title: t("columns.description"),
dataIndex: "description",
key: "description",
align: "center",
},
];
return columns;
};

View File

@ -20,9 +20,9 @@ export const useColumns = () => {
align: "center", align: "center",
}, },
{ {
title: t("columns.date_of_receipt"), title: t("columns.date"),
dataIndex: "date_of_receipt", dataIndex: "date",
key: "date_of_receipt", key: "date",
align: "center", align: "center",
}, },
{ {
@ -31,12 +31,6 @@ export const useColumns = () => {
key: "description", key: "description",
align: "center", align: "center",
}, },
{
title: t("columns.residual"),
dataIndex: "residual",
key: "residual",
align: "center",
},
]; ];
return columns; return columns;

View File

@ -5,54 +5,33 @@ import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import ValidationModelForm from "./ValidationModelForm"; import ValidationModelForm from "./ValidationModelForm";
import SalesModelForm from "./SalesModelForm"; import SalesModelForm from "./SalesModelForm";
import SubmitModelForm from "./SubmitModelForm"; import SubmitModelForm from "./SubmitModelForm";
import { useAddSales } from "../../../../api/sales";
import LayoutModel from "./LayoutModel"; import LayoutModel from "./LayoutModel";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { salesModelEnum } from "../../../../enums/salesForms";
const AddModel: React.FC = () => { const AddModel: React.FC = () => {
const { mutate, status } = useAddSales();
const handleSubmit = (values: any) => {
// mutate({
// ...values,
// });
};
enum modal {
Number= 0,
Package= 1,
Sure= 2
}
const { objectToEdit } = useObjectToEdit();
const handleSubmit = () => {};
const Forms = { const Forms = {
[modal.Number]: <ValidationModelForm /> , [salesModelEnum.Number]: <ValidationModelForm /> ,
[modal.Package] : <SalesModelForm /> , [salesModelEnum.Package] : <SalesModelForm /> ,
[modal.Sure]: <SubmitModelForm /> [salesModelEnum.Submit]: <SubmitModelForm />
} }
// const modelTitle = Forms.[modal.Number] ? "sale" : Forms.Package ? "adcs" : "Ascas";
const { objectToEdit,setObjectToEdit } = useObjectToEdit();
console.log(objectToEdit); console.log(objectToEdit);
return ( return (
<> <>
<LayoutModel <LayoutModel
status={status as QueryStatusEnum} status={objectToEdit?.status as QueryStatusEnum}
ModelEnum={ModalEnum.Sales_ADD} ModelEnum={ModalEnum.Sales_ADD}
modelTitle={"modelTitle"}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})} getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
initialButtonName={false}
buttonTitle="search"
> >
{/* {Forms["Number"]} */} {Forms[salesModelEnum.Number]}
<> {Forms[salesModelEnum.Package]}
<ValidationModelForm/> {Forms[salesModelEnum.Submit]}
<SalesModelForm/>
<SubmitModelForm/>
</>
</LayoutModel> </LayoutModel>
</> </>
); );

View File

@ -1,4 +1,3 @@
import React from "react";
import ValidationField from "../../../../Components/ValidationField/ValidationField"; import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { Col, Row } from "reactstrap"; import { Col, Row } from "reactstrap";
@ -11,8 +10,14 @@ const FilterForm = () => {
placeholder="activation_date" placeholder="activation_date"
label="activation_date" label="activation_date"
name="activation_date" name="activation_date"
type="Date"
/>
<ValidationField
placeholder="expiration_date"
label="expiration_date"
name="expiration_date"
type="Date"
/> />
{/* <ValidationField placeholder="name" label="name" name="name" /> */}
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@ -6,56 +6,55 @@ import { useTranslation } from "react-i18next";
import { QueryStatusEnum } from "../../../../enums/QueryStatus"; import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import SpinContainer from "../../../../Components/Layout/SpinContainer"; import SpinContainer from "../../../../Components/Layout/SpinContainer";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { Form, Formik } from "formik"; import { Form, Formik, useFormikContext } from "formik";
interface LayoutModalProps { interface LayoutModalProps {
isAddModal?: boolean; isAddModal?: boolean;
modelTitle: string;
handleSubmit: (values: any) => void; handleSubmit: (values: any) => void;
handleReset?: (values: any) => void;
getInitialValues: any; getInitialValues: any;
getValidationSchema: any; getValidationSchema: any;
children: React.ReactNode; children: React.ReactNode;
status: QueryStatusEnum; status?: QueryStatusEnum;
ModelEnum: any; ModelEnum: any;
ModelClassName?: string; ModelClassName?: string;
width?: string; width?: string;
isLoading?: boolean; isLoading?: boolean;
buttonTitle?:string;
initialButtonName?:boolean
} }
const LayoutModel = ({ const LayoutModel = ({
isAddModal = true, isAddModal = true,
children, children,
handleSubmit = () => {}, handleSubmit = () => {},
handleReset = () => {},
getInitialValues, getInitialValues,
getValidationSchema, getValidationSchema,
status, status,
modelTitle,
ModelEnum, ModelEnum,
ModelClassName, ModelClassName,
width = "800px", width = "800px",
isLoading = false, isLoading = false,
buttonTitle,
initialButtonName = true,
}: LayoutModalProps) => { }: LayoutModalProps) => {
const { isOpen, setIsOpen } = useModalState((state) => state); const { isOpen, setIsOpen } = useModalState((state) => state);
const { setObjectToEdit } = useObjectToEdit(); const { setObjectToEdit } = useObjectToEdit();
const formik = useFormikContext();
useEffect(() => { useEffect(() => {
if (isAddModal && status === QueryStatusEnum.SUCCESS) { if (isAddModal && status === QueryStatusEnum.SUCCESS) {
setIsOpen("isSuccess"); setIsOpen("isSuccess");
setObjectToEdit({}); setObjectToEdit({});
formik.resetForm();
return; return;
} }
if (status === QueryStatusEnum.SUCCESS) { if (status === QueryStatusEnum.SUCCESS) {
setIsOpen(""); setIsOpen("");
setObjectToEdit({});
} }
}, [setIsOpen, status]); }, [setIsOpen, status]);
const handleCancel = () => { const handleCancel = () => {
setIsOpen(""); setIsOpen("");
setObjectToEdit({}); setObjectToEdit({});
formik.resetForm();
}; };
const [t] = useTranslation(); const [t] = useTranslation();
@ -75,7 +74,7 @@ const LayoutModel = ({
initialValues={getInitialValues} initialValues={getInitialValues}
validationSchema={getValidationSchema} validationSchema={getValidationSchema}
onSubmit={handleSubmit} onSubmit={handleSubmit}
onReset={handleReset}
> >
{(formik) => { {(formik) => {
useEffect(() => { useEffect(() => {

View File

@ -1,43 +1,41 @@
import { Col, Row } from "reactstrap";
import ValidationField from "../../../../Components/ValidationField/ValidationField"; import ValidationField from "../../../../Components/ValidationField/ValidationField";
import useFormatDataToSelect from "../../../../utils/useFormatDataToSelect";
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import { useModalState } from "../../../../zustand/Modal"; import { useModalState } from "../../../../zustand/Modal";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { QueryStatusEnum } from "../../../../enums/QueryStatus"; import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { Divider, Spin } from "antd"; import { Button, Divider, Spin } from "antd";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
const Form = ({status}:{status?:any}) => { const Form = () => {
const {values,setFieldValue} = useFormikContext<any>()
console.log(values?.currentModalIndex);
const { isOpen, setIsOpen } = useModalState((state) => state);
const { objectToEdit,setObjectToEdit } = useObjectToEdit(); const { objectToEdit,setObjectToEdit } = useObjectToEdit();
const { setIsOpen } = useModalState((state) => state);
const {t} = useTranslation(); const {t} = useTranslation();
const formik = useFormikContext(); const formik = useFormikContext();
const { values, setFieldValue } = useFormikContext<any>()
const handleNext = ()=>{ const handleNext = ()=>{
setFieldValue( "currentModalIndex" , values?.currentModalIndex + 1 ) setFieldValue( "currentModalIndex" , values?.currentModalIndex + 1 )
} }
const handleCancel = () => { const handleCancel = () => {
setIsOpen(""); setIsOpen("");
setObjectToEdit({}); formik.resetForm();
}; };
console.log(objectToEdit);
const student_info = objectToEdit?.data?.data const student_info = objectToEdit?.data?.data
const PackagesInfo = student_info?.packages.map((info:any) => ({ const PackagesInfo = student_info?.packages.map((info:any) => ({
id: info?.id, id: info?.id,
name: info.name + " " + `( ${info?.original_price} )` name: info.name + " " + `( ${info?.original_price} )`
})); }));
console.log(PackagesInfo);
return ( return (
values?.currentModalIndex == 1 && values?.currentModalIndex == 1 &&
<div className="w-100"> <div className="w-100">
<header className="modal_title"> <header className="modal_title">
<span> <span>
{t(`models.add_sales`)}{" "} {t(`models.add_sales`)}{" "}
@ -50,7 +48,7 @@ console.log(PackagesInfo);
<img src="/Image/faker_user.png" alt="" /> <img src="/Image/faker_user.png" alt="" />
<span> <span>
<h5>{student_info?.first_name +" " + student_info?.last_name}</h5> <h5>{student_info?.first_name +" " + student_info?.last_name}</h5>
<h5>الصف: <p> {student_info?.grade_name}</p></h5> <h5>{t("models.course")}: <p> {student_info?.grade_name}</p></h5>
</span> </span>
</div> </div>
<ValidationField <ValidationField
@ -61,12 +59,11 @@ console.log(PackagesInfo);
option={PackagesInfo} option={PackagesInfo}
/> />
</div> </div>
{/* {values?.currentModalIndex} */}
<div className="buttons"> <div className="buttons">
<div className="back_button pointer" onClick={handleCancel}> <Button className="back_button pointer" onClick={handleCancel}>
{t("practical.cancel")} {t("practical.cancel")}
</div> </Button>
<button <Button
className="add_button" className="add_button"
disabled={status === QueryStatusEnum.LOADING || !formik.dirty || !values?.package_id} disabled={status === QueryStatusEnum.LOADING || !formik.dirty || !values?.package_id}
onClick={handleNext} onClick={handleNext}
@ -77,7 +74,7 @@ console.log(PackagesInfo);
<Spin /> <Spin />
</span> </span>
)} )}
</button> </Button>
</div> </div>
</div> </div>
); );

View File

@ -1,33 +1,24 @@
import { Col, Row } from "reactstrap";
import ValidationField from "../../../../Components/ValidationField/ValidationField"; import ValidationField from "../../../../Components/ValidationField/ValidationField";
import useFormatDataToSelect from "../../../../utils/useFormatDataToSelect";
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import { useModalState } from "../../../../zustand/Modal"; import { useModalState } from "../../../../zustand/Modal";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { QueryStatusEnum } from "../../../../enums/QueryStatus"; import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { Divider, Spin } from "antd"; import { Button, Divider, Spin } from "antd";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { useAddSales } from "../../../../api/sales";
import { useEffect } from "react";
import { toast } from "react-toastify";
const Form = ({status}:{status?:any}) => { const Form = () => {
const {values,setFieldValue} = useFormikContext<any>()
console.log(values?.currentModalIndex);
const { isOpen, setIsOpen } = useModalState((state) => state);
const { setObjectToEdit,objectToEdit } = useObjectToEdit(); const { setObjectToEdit,objectToEdit } = useObjectToEdit();
const { resetForm, values, setFieldValue } = useFormikContext<any>();
const { setIsOpen } = useModalState((state) => state);
const {t} = useTranslation(); const {t} = useTranslation();
const formik = useFormikContext();
const handleNext = ()=>{
setFieldValue( "currentModalIndex" , values?.currentModalIndex - 2 )
setIsOpen("");
}
const handleCancel = () => {
setIsOpen("");
setObjectToEdit({});
};
const {mutate,status,error}:any = useAddSales();
const coupon_id_object = objectToEdit?.data?.data?.packages.find((e:any)=>(e.id === values?.package_id))
const student_info = objectToEdit?.data?.data const student_info = objectToEdit?.data?.data
const PackagesInfo = student_info?.packages.map((info:any) => ({ const PackagesInfo = student_info?.packages.map((info:any) => ({
id: info?.id, id: info?.id,
@ -35,6 +26,35 @@ const Form = ({status}:{status?:any}) => {
})); }));
const handleNext = ()=>{
mutate({
package_id:values?.package_id,
student_id:objectToEdit?.data?.data?.student_id,
coupon_id:coupon_id_object?.coupon_id
});
}
const handleCancel = () => {
resetForm();
setIsOpen("");
setFieldValue( "currentModalIndex" , 0 )
};
useEffect(() => {
if(status === QueryStatusEnum.SUCCESS){
setIsOpen("");
setObjectToEdit({});
setFieldValue( "currentModalIndex" , values?.currentModalIndex - 2 )
}else if(status === QueryStatusEnum.ERROR){
toast.error(t(`toast.${error?.response?.data?.message}` || `toast.error_while_trying_please_try_again`))
}
if(values?.currentModalIndex >= 3){
setIsOpen("")
setObjectToEdit({})
setFieldValue( "currentModalIndex" , 0 )
}
}, [values?.currentModalIndex,status])
return ( return (
values?.currentModalIndex == 2 && values?.currentModalIndex == 2 &&
@ -50,8 +70,8 @@ const Form = ({status}:{status?:any}) => {
<div className="info"> <div className="info">
<img src="/Image/faker_user.png" alt="" /> <img src="/Image/faker_user.png" alt="" />
<span> <span>
<h5>أنس محمد ياسر القلعجي</h5> <h5>{student_info?.first_name +" " + student_info?.last_name}</h5>
<h5>الصف: <p> بكالوريا / علمي</p></h5> <h5>{t("models.course")}: <p> {student_info?.grade_name}</p></h5>
</span> </span>
</div> </div>
<ValidationField <ValidationField
@ -64,12 +84,11 @@ const Form = ({status}:{status?:any}) => {
allowClear={false} allowClear={false}
/> />
</div> </div>
{/* {values?.currentModalIndex} */}
<div className="buttons"> <div className="buttons">
<div className="back_button pointer" onClick={handleCancel}> <Button className="back_button pointer" onClick={handleCancel}>
{t("practical.cancel")} {t("practical.cancel")}
</div> </Button>
<button <Button
className="add_button" className="add_button"
disabled={status === QueryStatusEnum.LOADING} disabled={status === QueryStatusEnum.LOADING}
onClick={handleNext} onClick={handleNext}
@ -80,7 +99,7 @@ const Form = ({status}:{status?:any}) => {
<Spin /> <Spin />
</span> </span>
)} )}
</button> </Button>
</div> </div>
</div> </div>
); );

View File

@ -1,27 +1,29 @@
import { Col, Row } from "reactstrap"; import { Col, Row } from "reactstrap";
import ValidationField from "../../../../Components/ValidationField/ValidationField"; import ValidationField from "../../../../Components/ValidationField/ValidationField";
import useFormatDataToSelect from "../../../../utils/useFormatDataToSelect";
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import { useModalState } from "../../../../zustand/Modal"; import { useModalState } from "../../../../zustand/Modal";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { QueryStatusEnum } from "../../../../enums/QueryStatus"; import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { Divider, Spin } from "antd"; import { Button, Divider, Spin } from "antd";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useGetStudentByPhone } from "../../../../api/sales"; import { useGetStudentByPhone } from "../../../../api/sales";
import { toast } from "react-toastify";
const Form = () => { const Form = () => {
const {values,setFieldValue} = useFormikContext<any>()
const [triggerApi, setTriggerApi] = useState(false)
const phoneNumber : number = values?.phone_number
const { isOpen, setIsOpen } = useModalState((state) => state);
const { objectToEdit,setObjectToEdit } = useObjectToEdit();
const {t} = useTranslation();
const formik = useFormikContext();
const {data,isError,isSuccess,status} = useGetStudentByPhone({ const [triggerApi, setTriggerApi] = useState(false)
phone_number:phoneNumber const { setIsOpen } = useModalState((state) => state);
const { setObjectToEdit } = useObjectToEdit();
const {t} = useTranslation();
const formik = useFormikContext();
const {values,setFieldValue} = useFormikContext<any>()
const phoneNumber : number = values?.phone_number
const { data,isError,status } = useGetStudentByPhone({
phone_number:phoneNumber,
},{ },{
enabled: triggerApi enabled: triggerApi
}); });
@ -31,35 +33,31 @@ const Form = () => {
setTriggerApi(true) setTriggerApi(true)
} }
} }
console.log(status);
console.log(isSuccess);
const handleCancel = () => { const handleCancel = () => {
setIsOpen(""); setIsOpen("");
setObjectToEdit({}); formik.resetForm();
}; };
console.log(data?.data);
useEffect(() => { useEffect(() => {
if(!!data?.data?.phone_number){ if(!!data?.data?.phone_number){
setFieldValue( "currentModalIndex" , values?.currentModalIndex + 1 ) setFieldValue( "currentModalIndex" , values?.currentModalIndex + 1 )
setObjectToEdit({data}) setObjectToEdit({data})
setTriggerApi(false) setTriggerApi(false)
} }
else { else if(!data?.data){
setTriggerApi(false) setTriggerApi(false)
} }
if(isError){
}, [data?.data]) toast.error(t('toast.phone_number_not_found'))
}
}, [data?.data,triggerApi,isError])
return ( return (
values?.currentModalIndex == 0 && values?.currentModalIndex == 0 &&
<div className="w-100"> <div className="w-100">
<header className="modal_title"> <header className="modal_title">
<span> <span>
{t(`models.add_sales`)}{" "} {t(`models.add_sales`)}{" "}
@ -78,23 +76,24 @@ const Form = () => {
<Divider className="margin_auto"/> <Divider className="margin_auto"/>
</Col> </Col>
<div className="buttons"> <div className="buttons">
<div className="back_button pointer" onClick={handleCancel}> <Button className="back_button pointer" onClick={handleCancel}>
{t("practical.cancel")} {t("practical.cancel")}
</div> </Button>
<button <Button
className="add_button" className="add_button"
disabled={status === QueryStatusEnum.LOADING || !formik.dirty} disabled={status === QueryStatusEnum.LOADING || !formik.dirty || !values?.phone_number}
onClick={handleNext} onClick={handleNext}
> >
{t(`practical.search`)} {t(`practical.sale`)}
{status === QueryStatusEnum.LOADING && ( {status === QueryStatusEnum.LOADING && (
<span className="Spinier_Div"> <span className="Spinier_Div">
<Spin /> <Spin />
</span> </span>
)} )}
</button> </Button>
</div> </div>
</Row> </Row>
</div> </div>
); );
}; };

View File

@ -1,26 +1,26 @@
import * as Yup from "yup"; import * as Yup from "yup";
// Function to get the initial values
export const getInitialValues = (objectToEdit: any): any => { export const getInitialValues = (objectToEdit: any): any => {
console.log(objectToEdit);
return { return {
id: objectToEdit?.id ?? null, id: objectToEdit?.id ?? null,
phone_number: objectToEdit?.phone_number ?? null, phone_number: objectToEdit?.phone_number ?? null,
currentModalIndex: 0, currentModalIndex: 0,
package_id:objectToEdit?.package_id ?? null package_id: objectToEdit?.package_id ?? null,
student_id: objectToEdit?.student_id ?? null,
coupon_id: objectToEdit?.coupon_id ?? null,
}; };
}; };
// Validation schema with Yup
export const getValidationSchema = () => { export const getValidationSchema = () => {
return Yup.object().shape({ return Yup.object().shape({
phone_number: Yup.string() phone_number: Yup.string()
.required("Phone number is required") .required("Phone number is required")
.length(10, "Phone number must be exactly 10 numbers") .length(10, "Phone number must be exactly 10 digits")
.matches(/^\d{10}$/, "Phone number must be a valid 10-number number"), .matches(/^\d{10}$/, "Phone number must be a valid 10-digit number"),
currentModalIndex: Yup.number().max(2) currentModalIndex: Yup.number().max(2),
});
};
export const getValidationSchemaForSale = () => {
return Yup.object().shape({
package_id: Yup.string().required("package_id is required")
}); });
}; };

View File

@ -11,11 +11,14 @@ const Table = lazy(() => import("./Table"));
const AddModalForm = lazy(() => import("./Model/AddModel")); const AddModalForm = lazy(() => import("./Model/AddModel"));
const TableHeader = () => { const TableHeader = () => {
const [t] = useTranslation(); const [t] = useTranslation();
useSetPageTitle([ useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"}, {name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.sales`)}`, path:"sales"} {name:`${t(`page_header.sales`)}`, path:"sales"}
]); return ( ]);
return (
<div className="TableWithHeader"> <div className="TableWithHeader">
<Suspense fallback={<Spin />}> <Suspense fallback={<Spin />}>
<PageHeader <PageHeader

View File

@ -4,14 +4,19 @@ import { useColumns } from "./useTableColumns";
import useSearchQuery from "../../../api/utils/useSearchQuery"; import useSearchQuery from "../../../api/utils/useSearchQuery";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState"; import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
import { useGetAllSales } from "../../../api/sales"; import { useGetAllSales } from "../../../api/sales";
import { formatDate } from "../../../utils/formatDate";
const App: React.FC = () => { const App: React.FC = () => {
const [searchQuery] = useSearchQuery("name"); const [searchQuery] = useSearchQuery("name");
const { filterState } = useFilterState(); const { filterState }:any = useFilterState();
const response = useGetAllSales({ const response = useGetAllSales({
name: searchQuery, name: searchQuery,
pagination: true, pagination: true,
...filterState, ...filterState,
activation_date:formatDate(filterState?.activation_date),
expiration_date:formatDate(filterState?.expiration_date),
}); });
return <DataTable response={response} useColumns={useColumns} />; return <DataTable response={response} useColumns={useColumns} />;

View File

@ -4,14 +4,10 @@ import Table from "./Table";
import { FaPlus } from "react-icons/fa"; import { FaPlus } from "react-icons/fa";
import AddModalForm from "./Model/AddModel"; import AddModalForm from "./Model/AddModel";
import EditModalForm from "./Model/EditModel";
// import DeleteModalForm from "../../";
export { export {
Table, Table,
useColumns, useColumns,
AddModalForm, AddModalForm,
EditModalForm,
// DeleteModalForm,
FaPlus, FaPlus,
}; };

View File

@ -5,7 +5,6 @@ import { useTranslation } from "react-i18next";
export const useColumns = () => { export const useColumns = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const columns: TableColumnsType<Sales> = [ const columns: TableColumnsType<Sales> = [
{ {
title: t("columns.id"), title: t("columns.id"),
@ -15,32 +14,38 @@ export const useColumns = () => {
}, },
{ {
title: t("columns.student_full_name"), title: t("columns.student_full_name"),
key: "student_full_name",
align: "center",
render: (row) => {
return row?.student?.first_name +" "+ row?.student?.last_name;
},
},
{
title: t("columns.grade"),
render: (row) => {
return row?.package?.name;
},
key: "package",
align: "center",
},
{
title: t("columns.paid_price"),
render: (row) => {
return row?.package?.price;
},
key: "price",
align: "center",
},
{
title: t("columns.activation_date"),
dataIndex: "activation_date", dataIndex: "activation_date",
key: "activation_date", key: "activation_date",
align: "center", align: "center",
}, },
{ {
title: t("columns.grade"), title: t("columns.expiration_date"),
dataIndex: "grade", dataIndex: "expiration_date",
key: "grade", key: "expiration_date",
align: "center",
},
{
title: t("columns.package"),
dataIndex: "package",
key: "package",
align: "center",
},
{
title: t("columns.amount_paid"),
dataIndex: "amount_paid",
key: "amount_paid",
align: "center",
},
{
title: t("columns.sale_date"),
dataIndex: "sale_date",
key: "sale_date",
align: "center", align: "center",
}, },
]; ];

View File

@ -65,24 +65,6 @@ export const useColumns = () => {
return row?.student?.sex; return row?.student?.sex;
}, },
}, },
// {
// title: t("columns.procedure"),
// key: "actions",
// align: "center",
// width: "25vw",
// render: (_text, record, index) => {
// return (
// <ActionButtons
// // canDelete={canEditUser}
// canEdit={canDeleteUser}
// index={index}
// onDelete={() => handelDelete(record)}
// onEdit={() => handleEdit(record)}
// />
// );
// },
// },
]; ];
return columns; return columns;

View File

@ -31,6 +31,8 @@ const Manager = React.lazy(() => import("./Pages/Admin/Manager/Page"));
const AddManager = React.lazy(() => import("./Pages/Admin/Manager/Add/Page")); const AddManager = React.lazy(() => import("./Pages/Admin/Manager/Add/Page"));
const EditManager = React.lazy(() => import("./Pages/Admin/Manager/Edit/Page")); const EditManager = React.lazy(() => import("./Pages/Admin/Manager/Edit/Page"));
const FinancialCollection = React.lazy(() => import("./Pages/Admin/FinancialCollection/Page"));
const ReSeller = React.lazy(() => import("./Pages/Admin/Reseller/Page")); const ReSeller = React.lazy(() => import("./Pages/Admin/Reseller/Page"));
const ShowReSeller = React.lazy(() => import("./Pages/Admin/Reseller/show/Page")); const ShowReSeller = React.lazy(() => import("./Pages/Admin/Reseller/show/Page"));
@ -52,6 +54,7 @@ const Param = React.lazy(() => import("./Pages/Admin/Param/Page"));
/// RESELLER /// /// RESELLER ///
const Sales = React.lazy(() => import("./Pages/ReSeller/Sales/Page")); const Sales = React.lazy(() => import("./Pages/ReSeller/Sales/Page"));
const Collections = React.lazy(() => import("./Pages/ReSeller/Collections/Page")); const Collections = React.lazy(() => import("./Pages/ReSeller/Collections/Page"));
const ShowCollection = React.lazy(() => import("./Pages/ReSeller/Collections/Show/Page"));
const NotificationReSeller = React.lazy(() => import("./Pages/ReSeller/Notifications/Page")); const NotificationReSeller = React.lazy(() => import("./Pages/ReSeller/Notifications/Page"));
const ProfileReSeller = React.lazy(() => import("./Pages/ReSeller/Profile/Page")); const ProfileReSeller = React.lazy(() => import("./Pages/ReSeller/Profile/Page"));
@ -192,7 +195,16 @@ export const menuItems: TMenuItem[] = [
abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0, prevPath: 0,
}, },
{
header: "page_header.financial_collection",
element: <FinancialCollection />,
icon: <FaMoneyBill />,
text: "sidebar.financial_collection",
path: `/${ABILITIES_ENUM?.Financial_Collection}`,
abilities: ABILITIES_ENUM?.Financial_Collection,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
},
/// RESELLER ///// /// RESELLER /////
{ {
@ -217,17 +229,17 @@ export const menuItems: TMenuItem[] = [
prevPath: 0, prevPath: 0,
type: UserTypeEnum.RE_SELLER, type: UserTypeEnum.RE_SELLER,
}, },
{ // {
header: "page_header.profile", // header: "page_header.profile",
element: <ProfileReSeller />, // element: <ProfileReSeller />,
icon: <CgProfile />, // icon: <CgProfile />,
text: "sidebar.profile", // text: "sidebar.profile",
path: `/${ABILITIES_ENUM?.PROFILE}`, // path: `/${ABILITIES_ENUM?.PROFILE}`,
abilities: ABILITIES_ENUM?.Profile_RE_SELLER, // abilities: ABILITIES_ENUM?.Profile_RE_SELLER,
abilities_value: ABILITIES_VALUES_ENUM.INDEX, // abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0, // prevPath: 0,
type: UserTypeEnum.RE_SELLER, // type: UserTypeEnum.RE_SELLER,
}, // },
]; ];
@ -380,7 +392,16 @@ export const CrudRoute: TCrudRoute[] = [
abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 1, prevPath: 1,
}, },
{
header: "page_header.collection",
element: <ShowCollection />,
path: `/${ABILITIES_ENUM?.Collections}/:${ParamsEnum?.Collection_ID}`,
abilities: ABILITIES_ENUM?.Collections,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
type:UserTypeEnum.RE_SELLER
},
]; ];
export const AppRoutes: Record<string, string> = Object.fromEntries( export const AppRoutes: Record<string, string> = Object.fromEntries(

View File

@ -43,7 +43,9 @@
font-size: 20px; font-size: 20px;
} }
} }
.main_modal{
}
.add_button { .add_button {
outline: none; outline: none;
border: none; border: none;
@ -64,8 +66,12 @@
} }
transition: .4s ease-in-out; transition: .4s ease-in-out;
&:focus{
// display: none !important;
}
&:hover{ &:hover{
scale: 1.1; scale: 1.04;
background: var(--primary) !important;
color: var(--white) !important;
} }
} }

View File

@ -93,6 +93,10 @@
padding: 20px 10px !important; padding: 20px 10px !important;
} }
.filter_modal_add_button{
padding: 20.8px 10px !important;
}
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
.filter_modal_add_button, .filter_modal_add_button,

View File

@ -94,7 +94,6 @@
color: var(--borderColor); color: var(--borderColor);
} }
svg { svg {
// width: 20px;
border-radius: 5px; border-radius: 5px;
padding: 4px; padding: 4px;
color: var(--borderColor); color: var(--borderColor);
@ -121,7 +120,6 @@
justify-content: start; justify-content: start;
background: inherit; background: inherit;
font-size: 20px; font-size: 20px;
// height: 2.5vw;
width: 80%; width: 80%;
font-weight: bold; font-weight: bold;
margin-inline: auto; margin-inline: auto;
@ -152,7 +150,6 @@
} }
} }
.active { .active {
// transform: translateX(-1vw);
color: var(--text) !important; color: var(--text) !important;
background-color: var(--bg); background-color: var(--bg);
font-weight: bold; font-weight: bold;
@ -162,8 +159,6 @@
} }
i { i {
// width: 1.5vw;
// height: 1.5vw;
border-radius: 5px; border-radius: 5px;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -209,6 +204,11 @@
.side_bar_links { .side_bar_links {
display: flex; display: flex;
align-items: center; align-items: center;
.DropDownLink{
.DropDownIcon{
transform: translate(-1.4vw,10px);
}
}
.active { .active {
background: inherit !important; background: inherit !important;
} }
@ -240,7 +240,7 @@
div { div {
@include Flex; @include Flex;
width: 100%; width: 100%;
margin-block: 12px; margin-block: 0px;
svg { svg {
height: 36px; height: 36px;
padding: 7px; padding: 7px;

View File

@ -4,7 +4,6 @@
gap: 5px; gap: 5px;
.collection_info_card { .collection_info_card {
display: flex; display: flex;
justify-content: center;
flex-direction: column; flex-direction: column;
width: 15vw; width: 15vw;
padding: 1.2vw 1.2vw; padding: 1.2vw 1.2vw;

View File

@ -1,7 +1,7 @@
import useGetQuery from "./helper/useGetQuery"; import useGetQuery from "./helper/useGetQuery";
const API = { const API = {
GET: "/collections", GET: "/resellers/financialCollection",
}; };
const KEY = "collections"; const KEY = "collections";

View File

@ -0,0 +1,20 @@
import useAddMutation from "./helper/useAddMutation";
import useDeleteMutation from "./helper/useDeleteMutation";
import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/financialCollection",
ADD: "/financialCollection",
DELETE: "/financialCollection",
UPDATE: "/financialCollection",
};
const KEY = "financialCollection";
export const useGetAllFinancialCollection = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddFinancialCollection = () => useAddMutation(KEY, API.ADD);
export const useUpdateFinancialCollection = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteFinancialCollection = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -50,9 +50,12 @@ function useAxios() {
return response; return response;
}, },
function (error) { function (error) {
console.log(error?.response); // Reject errors with non-2xx status codes
const status = error?.response?.status;
if (status >= 400) {
return Promise.reject(error);
}
const status = error?.request?.status;
const errorMsg = error?.response?.data?.error; const errorMsg = error?.response?.data?.error;
const errorField = error?.response?.data; const errorField = error?.response?.data;
const method = error.config.method; const method = error.config.method;
@ -65,8 +68,6 @@ function useAxios() {
? errorMsg ? errorMsg
: errorMsg?.[ErrorKey]?.[0] ?? : errorMsg?.[ErrorKey]?.[0] ??
t("validation.some_thing_went_wrong"); t("validation.some_thing_went_wrong");
console.log(isString);
toast.error(t(`${isString}`)); toast.error(t(`${isString}`));
return; return;
} }
@ -80,8 +81,11 @@ function useAxios() {
toast.error(errorMessage); toast.error(errorMessage);
return Promise.reject(error); return Promise.reject(error);
} }
},
return Promise.reject(error); // Important to reject the promise
}
); );
return build_Axios; return build_Axios;
// return buildAxios.build(); // return buildAxios.build();

View File

@ -3,15 +3,18 @@ import useGetQuery from "./helper/useGetQuery";
const API = { const API = {
GET: "/resellers/studentPackage", GET: "/resellers/studentPackage",
ADD: "/resellers/studentPackage", ADD: "/resellers/studentPackage/purchase",
GET_BY_PHONE: "/resellers/studentPackage/student", GET_BY_PHONE: "/resellers/studentPackage/student",
GET_SUMMERY: "/resellers/studentPackage/summery", GET_SUMMERY: "/resellers/studentPackage/summery",
}; };
const KEY = "sales"; const KEY = "sales";
const KEY2 = "Sale_Student_Data";
const KEY3 = "collection_summery";
export const useGetAllSales = (params?: any, options?: any) =>useGetQuery(KEY, API.GET, params, options); export const useGetAllSales = (params?: any, options?: any) =>useGetQuery(KEY, API.GET, params, options);
export const useAddSales = () => useAddMutation(KEY, API.ADD); export const useAddSales = () => useAddMutation(KEY, API.ADD);
export const useGetStudentByPhone = (params?: any, options?: any) => useGetQuery(KEY, API.GET_BY_PHONE, params, options); export const useGetStudentByPhone = (params?: any, options?: any) => useGetQuery(KEY2, API.GET_BY_PHONE, params, options);
export const useGetSummery = () => useGetQuery(KEY, API.GET_SUMMERY); export const useGetSummery = () => useGetQuery(KEY3, API.GET_SUMMERY);

View File

@ -237,4 +237,10 @@ export enum ModalEnum {
/// email /// email
Email_EDIT = "Email.edit", Email_EDIT = "Email.edit",
///financial_collection
Financial_Collection_EDIT = "Financial_Collection.edit",
Financial_Collection_ADD = "Financial_Collection.add",
Financial_Collection_DELETE = "Financial_Collection.delete",
} }

View File

@ -60,7 +60,8 @@ export enum ABILITIES_ENUM {
Email = "email", Email = "email",
Phone = "phone", Phone = "phone",
CITY = "city", CITY = "city",
AREA = "area" AREA = "area",
Financial_Collection = "financial_collection"
//// ////
} }

View File

@ -14,4 +14,5 @@ export enum ParamsEnum {
RE_SELLER_ID = "re_seller_id", RE_SELLER_ID = "re_seller_id",
ROLE_ID = "role_id", ROLE_ID = "role_id",
CITY_ID = "city_id", CITY_ID = "city_id",
Collection_ID = "collection_id"
} }

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

@ -0,0 +1,5 @@
export enum salesModelEnum {
Number= 0,
Package= 1,
Submit= 2
}

View File

@ -149,7 +149,8 @@
"past_your_MMl_text":"ضع نص MMl الخاص بك", "past_your_MMl_text":"ضع نص MMl الخاص بك",
"add_MML":"إضافة MML", "add_MML":"إضافة MML",
"show_preview":"عرض المعاينة", "show_preview":"عرض المعاينة",
"show_MMl":" MML عرض" "show_MMl":" MML عرض",
"financial_collection":"التحصيلات"
}, },
"columns": { "columns": {
"id": "الرقم التعريفي", "id": "الرقم التعريفي",
@ -233,7 +234,8 @@
"delete":"حذف", "delete":"حذف",
"read":"قراءة", "read":"قراءة",
"managers":"مدراء", "managers":"مدراء",
"show":"عرض" "show":"عرض",
"paid_price":"المبلغ المدفوع"
}, },
"practical": { "practical": {
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال", "to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
@ -313,7 +315,9 @@
"Map":"الخريطة", "Map":"الخريطة",
"Show":"عرض", "Show":"عرض",
"Hide":"اخفاء", "Hide":"اخفاء",
"sale":"بيع" "sale":"بيع",
"financial_collection":"التحصيلات",
"show_collection":"حصيلة"
}, },
"Table": { "Table": {
"header": "", "header": "",
@ -404,7 +408,9 @@
"Area":"المنطقة", "Area":"المنطقة",
"City":"مدينة", "City":"مدينة",
"add_sales":"إضافة عملية بيع", "add_sales":"إضافة عملية بيع",
"are_you_sure_about_sale":"هل أنت متأكد من عملية البيع ؟" "are_you_sure_about_sale":"هل أنت متأكد من عملية البيع ؟",
"financial_collection":"التحصيلات",
"show_collection":"حصيلة"
}, },
"education_class_actions": { "education_class_actions": {
"Student_Records": "سجلات الطلاب", "Student_Records": "سجلات الطلاب",
@ -538,7 +544,11 @@
"contact_number2":"رقم الهاتف الإضافي", "contact_number2":"رقم الهاتف الإضافي",
"lat":"الطول", "lat":"الطول",
"lng":"العرض", "lng":"العرض",
"choose":"حدد" "choose":"حدد",
"amount":"مبلغ",
"reseller":"البائعين",
"activation_date":"تاريخ التنشيط",
"expiration_date":"تاريخ الالغاء"
}, },
"select": { "select": {
"enums": { "enums": {
@ -875,7 +885,8 @@
"sales":"المبيعات", "sales":"المبيعات",
"collections": "التحصيلات", "collections": "التحصيلات",
"Area":"المنطقة", "Area":"المنطقة",
"city":"مدينة" "city":"مدينة",
"financial_collection":"التحصيلات"
}, },
"message": { "message": {
"some_thing_went_wrong": "حدث خطأ ما", "some_thing_went_wrong": "حدث خطأ ما",
@ -924,7 +935,9 @@
"City":"مدينة", "City":"مدينة",
"Area":"المنطقة", "Area":"المنطقة",
"setting":"الإعدادات", "setting":"الإعدادات",
"edit_reseller":"تعديل البائع" "edit_reseller":"تعديل البائع",
"financial_collection":"التحصيلات",
"show_collection":"حصيلة"
}, },
"page_header": { "page_header": {
"home": "لوحة القيادة", "home": "لوحة القيادة",
@ -973,7 +986,9 @@
"sales":"المبيعات", "sales":"المبيعات",
"setting":"الإعدادات", "setting":"الإعدادات",
"City":"مدينة", "City":"مدينة",
"Area":"المنطقة" "Area":"المنطقة",
"financial_collection":"التحصيلات",
"show_collection":"حصيلة"
}, },
"table": { "table": {
"student": "قائمة الطلاب", "student": "قائمة الطلاب",
@ -992,7 +1007,9 @@
"City":"مدينة", "City":"مدينة",
"notification":"الاشعارات", "notification":"الاشعارات",
"upload_your_photo_and_personal_data_here":"قم بتحميل صورتك وبياناتك الشخصية هنا", "upload_your_photo_and_personal_data_here":"قم بتحميل صورتك وبياناتك الشخصية هنا",
"get_notified_of_whats_happening_now_you_can_turn_it_off_at_any_time":"احصل على إشعار بما يحدث الآن ، يمكنك إيقاف تشغيله في أي وقت" "get_notified_of_whats_happening_now_you_can_turn_it_off_at_any_time":"احصل على إشعار بما يحدث الآن ، يمكنك إيقاف تشغيله في أي وقت",
"financial_collection":"التحصيلات",
"show_collection":"حصيلة"
}, },
"card" : { "card" : {
"residual":"المتبقي", "residual":"المتبقي",
@ -1001,6 +1018,12 @@
"reseller_profit":"نسبة الأرباح (10%)", "reseller_profit":"نسبة الأرباح (10%)",
"total_sells":"إجمالي المبيعات" "total_sells":"إجمالي المبيعات"
}, },
"toast" : {
"phone_number_not_found":"رقم الهاتف غير موجود",
"error_while_trying_please_try_again":"حدث خطأ أثناء المحاولة، يرجى المحاولة مرة أخرى",
"Student Already Have this Package":"الطالب لديه هذه الحزمة بالفعل",
"The combination of student_id and package_id already exists.":"مجموعة الطالب والحزمة موجودة بالفعل."
},
"alphabet": { "alphabet": {
"A": "A", "A": "A",
"B": "B", "B": "B",

View File

@ -367,7 +367,7 @@ export type Sales = {
export type Collection = { export type Collection = {
id: number; id: number;
student: student; amount: student;
expiration_date: string; date: string;
activation_date: string; description: string;
}; };

View File

@ -767,7 +767,7 @@ export const canShowQuestionBank = hasAbility(
); );
/// User /// sales
export const canAddSales = hasAbility( export const canAddSales = hasAbility(
ABILITIES_ENUM.Sales, ABILITIES_ENUM.Sales,
@ -797,3 +797,26 @@ export const canEditEmail = hasAbility(
ABILITIES_ENUM.Email, ABILITIES_ENUM.Email,
ABILITIES_VALUES_ENUM.UPDATE, ABILITIES_VALUES_ENUM.UPDATE,
); );
/// financial_collection
export const canAddFinancial_Collection = hasAbility(
ABILITIES_ENUM.Financial_Collection,
ABILITIES_VALUES_ENUM.STORE,
);
export const canEditFinancial_Collection = hasAbility(
ABILITIES_ENUM.Financial_Collection,
ABILITIES_VALUES_ENUM.UPDATE,
);
export const canDeleteFinancial_Collection = hasAbility(
ABILITIES_ENUM.Financial_Collection,
ABILITIES_VALUES_ENUM.DELETE,
);
// collection reseller
export const canShowCollection = hasAbility(
ABILITIES_ENUM.Collections,
ABILITIES_VALUES_ENUM.SHOW,
);