#81 feature on Reseller Dashboard

This commit is contained in:
Majd_dk 2025-09-30 12:57:17 +03:00
parent 3a5ed72481
commit ff63cb0bec
13 changed files with 157 additions and 43 deletions

View File

@ -0,0 +1,37 @@
import { useFormikContext } from "formik"
import { useEffect, useState } from "react"
import { useObjectToEdit } from "../zustand/ObjectToEditState";
import { useModalState } from "../zustand/Modal";
import { useQueryClient } from "react-query";
export const useStepsModalReseller = () =>{
const { setObjectToEdit } = useObjectToEdit();
const formik = useFormikContext<any>();
const { setIsOpen } = useModalState((state) => state);
const queryClient = useQueryClient();
const [biggestModalIndex,setBiggestModalIndex] = useState(0)
const currentModalIndex = formik?.values?.currentModalIndex
useEffect(()=>{
const modalIndex = formik?.values?.currentModalIndex
modalIndex > biggestModalIndex && setBiggestModalIndex(modalIndex)
},[formik?.values?.currentModalIndex])
const handleCloseModel = () => {
formik?.resetForm();
setIsOpen("");
formik?.setFieldValue("currentModalIndex", 0);
setObjectToEdit({});
queryClient.resetQueries();
setBiggestModalIndex(0)
};
const handleClickOnStep = (index:number) =>{
if(index > biggestModalIndex)return
formik?.setFieldValue("currentModalIndex", index);
}
return {handleCloseModel , handleClickOnStep , currentModalIndex}
}

View File

@ -19,6 +19,7 @@ const AddModel: React.FC = () => {
getInitialValues={getInitialValues(objectToEdit)} getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
canClearObjectToEdit = {false} canClearObjectToEdit = {false}
width="70%"
> >
<ModelBody /> <ModelBody />
</LayoutModel> </LayoutModel>

View File

@ -53,7 +53,6 @@ const LayoutModel = ({
}, [setIsOpen, status]); }, [setIsOpen, status]);
const handleCancel = () => { const handleCancel = () => {
console.log(true)
setIsOpen(""); setIsOpen("");
canClearObjectToEdit && setObjectToEdit({}); canClearObjectToEdit && setObjectToEdit({});
formik.resetForm(); formik.resetForm();
@ -68,7 +67,7 @@ const LayoutModel = ({
width={width} width={width}
footer={null} footer={null}
open={isOpen === ModelEnum} open={isOpen === ModelEnum}
onCancel={handleCancel} // onCancel={handleCancel}
> >
<Formik <Formik
enableReinitialize={true} enableReinitialize={true}

View File

@ -1,25 +1,11 @@
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 { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { salesModelEnum } from "../../../../enums/salesForms"; import { salesModelEnum } from "../../../../enums/salesForms";
import { useFormikContext } from "formik"; import { useStepsModalReseller } from "../../../../Hooks/useStepsModalReseller";
import { useModalState } from "../../../../zustand/Modal";
import { useQueryClient } from "react-query";
const ModelBody = () => { const ModelBody = () => {
const { setObjectToEdit } = useObjectToEdit(); const { handleCloseModel , handleClickOnStep , currentModalIndex} = useStepsModalReseller()
const formik = useFormikContext<any>();
const { setIsOpen } = useModalState((state) => state);
const queryClient = useQueryClient();
const handleCloseModel = () => {
formik?.resetForm();
setIsOpen("");
formik?.setFieldValue("currentModalIndex", 0);
setObjectToEdit({});
queryClient.resetQueries();
};
const Forms = { const Forms = {
[salesModelEnum.Number]: ( [salesModelEnum.Number]: (
@ -38,6 +24,9 @@ const ModelBody = () => {
{Forms[salesModelEnum.Number]} {Forms[salesModelEnum.Number]}
{Forms[salesModelEnum.Package]} {Forms[salesModelEnum.Package]}
{Forms[salesModelEnum.Submit]} {Forms[salesModelEnum.Submit]}
<div className="circle_parent">
{[...Array(3)].map((_:null,index:number) =><div onClick={() => handleClickOnStep(index)} className={`circle ${currentModalIndex == index ? "active_circle" :""}`}>{index + 1}</div>)}
</div>
</> </>
); );
}; };

View File

@ -6,6 +6,7 @@ import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import { Button, Divider, Spin } from "antd"; import { Button, Divider, Spin } from "antd";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { ModalBodyProps } from "../../../../types/Sales"; import { ModalBodyProps } from "../../../../types/Sales";
import { onEnterDown } from "../../../../utils/onKeyDown";
const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => { const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
const { objectToEdit } = useObjectToEdit(); const { objectToEdit } = useObjectToEdit();
@ -29,7 +30,10 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
</div> </div>
) )
})); }));
const isDisabled = status === QueryStatusEnum.LOADING || !formik.dirty || !values?.phone_number
const handleKeyDown = (e:any) =>{
onEnterDown(e,handleNext,isDisabled)
}
return ( return (
values?.currentModalIndex == 1 && ( values?.currentModalIndex == 1 && (
<div className="w-100"> <div className="w-100">
@ -41,7 +45,8 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
<Divider /> <Divider />
<div className="sales_info_modal"> <div className="sales_info_modal">
<div className="info">
<div className="info between">
{/* <img src="/Image/faker_user.png" alt="" /> */} {/* <img src="/Image/faker_user.png" alt="" /> */}
<span className="mr-20"> <span className="mr-20">
<h5> <h5>
@ -51,13 +56,23 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
{t("models.course")}: <p> {student_info?.grade_name}</p> {t("models.course")}: <p> {student_info?.grade_name}</p>
</h5> </h5>
</span> </span>
<span className="ml-20"
style={{marginLeft:"20px"}}
>
<h5>
{t("models.mobile_number")}: <p> {student_info?.phone_number}</p>
</h5>
</span>
</div> </div>
<ValidationField <ValidationField
placeholder="choose" placeholder="choose"
label="package" label="package"
name="package_id" name="package_id"
type="Select" type="Select"
className="package"
option={PackagesInfo} option={PackagesInfo}
onKeyDown={handleKeyDown}
/> />
</div> </div>
@ -67,11 +82,7 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
</Button> </Button>
<Button <Button
className="add_button" className="add_button"
disabled={ disabled={isDisabled}
status === QueryStatusEnum.LOADING ||
!formik.dirty ||
!values?.package_id
}
onClick={handleNext} onClick={handleNext}
> >
{t(`practical.sale`)} {t(`practical.sale`)}

View File

@ -11,6 +11,8 @@ import { useEffect } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { ModalBodyProps } from "../../../../types/Sales"; import { ModalBodyProps } from "../../../../types/Sales";
import { useQueryClient } from "react-query"; import { useQueryClient } from "react-query";
import { onEnterDown } from "../../../../utils/onKeyDown";
import { ModalEnum } from "../../../../enums/Model";
const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => { const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
const { setObjectToEdit, objectToEdit } = useObjectToEdit(); const { setObjectToEdit, objectToEdit } = useObjectToEdit();
@ -45,11 +47,7 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
}; };
useEffect(() => { useEffect(() => {
if (status === QueryStatusEnum.SUCCESS) { if (status === QueryStatusEnum.SUCCESS) {
setIsOpen("");
setObjectToEdit({});
setFieldValue("currentModalIndex", values?.currentModalIndex - 2);
reset(); reset();
formik?.resetForm();
} else if (status === QueryStatusEnum.ERROR) { } else if (status === QueryStatusEnum.ERROR) {
toast.error( toast.error(
t( t(
@ -59,6 +57,10 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
); );
} }
}, [ status]);
useEffect(() =>{
if (values?.currentModalIndex >= 3) { if (values?.currentModalIndex >= 3) {
setIsOpen(""); setIsOpen("");
setObjectToEdit({}); setObjectToEdit({});
@ -66,7 +68,17 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
queryClient.resetQueries(); queryClient.resetQueries();
reset(); reset();
} }
}, [values?.currentModalIndex, status]); })
const isDisabled = status === QueryStatusEnum.LOADING
const handleKeyDown = (e:any) =>{
onEnterDown(e,handleNext,isDisabled)
}
const handleAddAnotherPurchase = () =>{
handleCloseModel("")
setIsOpen(ModalEnum.Sales_ADD)
}
return ( return (
values?.currentModalIndex == 2 && ( values?.currentModalIndex == 2 && (
@ -77,17 +89,33 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
</header> </header>
<Divider /> <Divider />
<div className="buttons">
<Button
className="add_button"
// disabled={isDisabled}
onClick={handleAddAnotherPurchase}
>
{t(`practical.add_new`)}
</Button>
</div>
<div className="sales_info_modal"> <div className="sales_info_modal">
<div className="info"> <div className="info between">
{/* <img src="/Image/faker_user.png" alt="" /> */} {/* <img src="/Image/faker_user.png" alt="" /> */}
<span> <span className="mr"
style={{marginRight:"20px"}}>
<h5> <h5>
{student_info?.first_name + " " + student_info?.last_name} {student_info?.first_name + " " + student_info?.last_name}
</h5> </h5>
<h5> <h5>
{t("models.course")}: <p> {student_info?.grade_name}</p> {t("models.course")}: <p> {student_info?.grade_name}</p>
</h5> </h5>
</span>
<span className="ml-20"
style={{marginLeft:"20px"}}
>
<h5>
{t("models.mobile_number")}: <p> {student_info?.phone_number}</p>
</h5>
</span> </span>
</div> </div>
<ValidationField <ValidationField
@ -98,26 +126,29 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
option={PackagesInfo} option={PackagesInfo}
disabled disabled
allowClear={false} allowClear={false}
onKeyDown={handleKeyDown}
/> />
</div> </div>
<div className="buttons"> <div className="buttons">
<Button className="back_button pointer" onClick={handleCloseModel}> <Button className="back_button pointer" onClick={handleCloseModel}>
{t("practical.cancel")} {t("practical.cancel")}
</Button> </Button>
<Button <Button
className="add_button" className="add_button"
disabled={status === QueryStatusEnum.LOADING} disabled={isDisabled}
onClick={handleNext} onClick={handleNext}
> >
{t(`practical.yes`)} {t(`practical.yes`)}
{status === QueryStatusEnum.LOADING && ( {isDisabled && (
<span className="Spinier_Div"> <span className="Spinier_Div">
<Spin /> <Spin />
</span> </span>
)} )}
</Button> </Button>
</div> </div>
</div> </div>
) )
); );

View File

@ -9,6 +9,7 @@ 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 { ModalBodyProps } from "../../../../types/Sales"; import { ModalBodyProps } from "../../../../types/Sales";
import { onEnterDown } from "../../../../utils/onKeyDown";
const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => { const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
const [triggerApi, setTriggerApi] = useState(false); const [triggerApi, setTriggerApi] = useState(false);
@ -44,6 +45,13 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
} }
}, [isSuccess,isError,status]); }, [isSuccess,isError,status]);
const isDisabled = status === QueryStatusEnum.LOADING ||
!formik.dirty ||
!values?.phone_number
const handleKeyDown = (e:any) =>{
onEnterDown(e,handleNext,isDisabled)
}
return ( return (
values?.currentModalIndex == 0 && ( values?.currentModalIndex == 0 && (
<div className="w-100"> <div className="w-100">
@ -60,6 +68,7 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
placeholder="phone_number" placeholder="phone_number"
label="phone_number" label="phone_number"
name="phone_number" name="phone_number"
onKeyDown={handleKeyDown}
/> />
<Divider className="margin_auto" /> <Divider className="margin_auto" />
</Col> </Col>
@ -70,12 +79,9 @@ const Form = ({ handleCloseModel = () => {} }: ModalBodyProps) => {
</Button> </Button>
<Button <Button
className="add_button" className="add_button"
disabled={ disabled={isDisabled}
status === QueryStatusEnum.LOADING || onClick={handleNext} // eee
!formik.dirty ||
!values?.phone_number
}
onClick={handleNext}
> >
{t(`practical.sale`)} {t(`practical.sale`)}
{status === QueryStatusEnum.LOADING && ( {status === QueryStatusEnum.LOADING && (

View File

@ -0,0 +1,3 @@
.ant-select.package .ant-select-selector .ant-select-selection-item div{
color: red !important;
}

View File

@ -49,6 +49,7 @@
main { main {
.buttons { .buttons {
// background-color: rebeccapurple;
padding-inline: 0 10px; padding-inline: 0 10px;
display: flex; display: flex;
gap: 10px; gap: 10px;
@ -60,7 +61,7 @@
position: relative; position: relative;
outline: none; outline: none;
border: none; border: none;
width: 120px; min-width: 120px;
border-radius: 7px; border-radius: 7px;
padding: 7px; padding: 7px;
font-weight: bold; font-weight: bold;
@ -78,6 +79,10 @@
} }
} }
} }
.between{
display: flex;
justify-content: space-between;
}
} }
label { label {

View File

@ -4,3 +4,4 @@
@import "./Model.scss"; @import "./Model.scss";
@import "./Segmented.scss"; @import "./Segmented.scss";
@import "./Mix.scss"; @import "./Mix.scss";
@import "./Input.scss";

View File

@ -332,3 +332,26 @@ button:disabled {
color:rgba(0, 128, 0, 0.499); color:rgba(0, 128, 0, 0.499);
} }
} }
.circle{
width: 40px;
height: 40px;
border-radius: 50%;
background-color: var(--primary);
color: white;
display: flex;
justify-content: center;
align-items: center;
opacity: .5;
transition: .5;
cursor: pointer;
&.active_circle{
opacity: 1;
}
}
.circle_parent{
display: flex;
column-gap: 10px;
margin: auto;
padding-top: 20px;
}

View File

@ -292,6 +292,7 @@
"overview": "نظرة عامة", "overview": "نظرة عامة",
"presence": "الحضور", "presence": "الحضور",
"add_new_role": "اضافة صلاحية جديدة", "add_new_role": "اضافة صلاحية جديدة",
"add_new":"اضافة جديدة",
"yes": "نعم", "yes": "نعم",
"no": "لا", "no": "لا",
"Are you sure you want to go back and not save any changes?": "هل أنت متأكد أنك تريد العودة وعدم حفظ أي تغييرات؟", "Are you sure you want to go back and not save any changes?": "هل أنت متأكد أنك تريد العودة وعدم حفظ أي تغييرات؟",
@ -370,6 +371,7 @@
"earlyDeparture": "الأذن", "earlyDeparture": "الأذن",
"unit": "الوحدة", "unit": "الوحدة",
"lesson": "الدرس", "lesson": "الدرس",
"mobile_number":"رقم الموبايل",
"branch": "الفرع", "branch": "الفرع",
"cycle": "السنة دراسية", "cycle": "السنة دراسية",
"term": "الفصل", "term": "الفصل",

6
src/utils/onKeyDown.ts Normal file
View File

@ -0,0 +1,6 @@
export function onEnterDown(event:any,Fn:()=>void,dontRun:boolean=false) {
if(dontRun)return;
if(event.code === "Enter"){
Fn();
}
}