main
حسین معصومی پور 2024-02-22 12:13:03 +03:30
parent 6f137b548e
commit 96835cf13f
9 changed files with 553 additions and 185 deletions

6
.env
View File

@ -1,8 +1,8 @@
NODE_ENV="development" NODE_ENV="development"
NEXT_PUBLIC_SERVER_URL=http://192.168.88.12:32769 NEXT_PUBLIC_SERVER_URL=http://192.168.189.123:32769
NEXT_PUBLIC_PUBLIC_URL=http://192.168.88.12:32769 NEXT_PUBLIC_PUBLIC_URL=http://192.168.189.123:32769
NEXT_PUBLIC_API_URL=http://192.168.88.12:32769/api NEXT_PUBLIC_API_URL=http://192.168.189.123:32769/api
# SECURE_LOCAL_STORAGE_HASH_KEY=f1da2b2c7a4c446934267fea631102ec389b5b99 # SECURE_LOCAL_STORAGE_HASH_KEY=f1da2b2c7a4c446934267fea631102ec389b5b99
# NEXT_PUBLIC_API_URL_IMAGE=https://192.168.88.12:49154/Files/ReportImages # NEXT_PUBLIC_API_URL_IMAGE=https://192.168.88.12:49154/Files/ReportImages

View File

@ -63,12 +63,6 @@ const LoginStep = (props) => {
}`} }`}
> >
<div> <div>
{/* <input
type="checkbox"
className="w-[40px] h-[40px] !rounded-xl mx-2 custom-checkbox mt-1"
value={}
/> */}
<input <input
type="checkbox" type="checkbox"
checked={roleCheckBox ? true : false} checked={roleCheckBox ? true : false}

View File

@ -0,0 +1,62 @@
"use client";
import React, { useContext, useEffect, useRef, useState } from "react";
import { BottomSheet } from "react-spring-bottom-sheet";
import Input from "plugins/Input/page";
import AppContext from "@ctx/AppContext";
import SimpleReactValidator from "simple-react-validator";
import CheckBoxBriz from "plugins/CheckBoxBriz/page";
import Buttonbriz from "plugins/Buttonbriz/page";
import { toast } from "react-toastify";
const BottomSheetReport = (props) => {
const CTX = useContext(AppContext);
const reportDetail = CTX.state.reportDetail;
const handleSendReport_SHIFTPLAN = () => {
CTX.ReportShiftPlan(reportDetail?.shiftId);
CTX.setBottomSheetReportOpen(false);
};
const handleSendReport_TASK = () => {
CTX.ReportTask();
CTX.setBottomSheetReportOpen(false);
};
return (
<BottomSheet
open={CTX.state.BottomSheetReportOpen}
onDismiss={() => CTX.setBottomSheetReportOpen(false)}
blocking={false}
>
<div className="text-center py-2 bg-primary-300 ">
<p className="mb-0 text-white relative top-[-5px]">گزارشات</p>
</div>
<div className="px-3 pt-10 ">
<p className="mb-0 text-center text-sm font-light">
شما در حال گرفتن گزارش برای
<small className="text-sm font-medium"> {reportDetail?.title} </small>
هستید
</p>
</div>
<div className=" p-4">
<Buttonbriz
title="گرفتن گزارش"
color="INFO"
icon="CHECK"
buttonEvent={() => {
if (reportDetail.typeReport == "TASK") {
handleSendReport_TASK();
} else if (reportDetail.typeReport == "SHIFTPLAN") {
handleSendReport_SHIFTPLAN();
}
}}
/>
</div>
</BottomSheet>
);
};
export default BottomSheetReport;

View File

@ -86,7 +86,7 @@ const Buttonbriz = ({
> >
{icons.find((e) => e.iconName == icon)?.icon} {icons.find((e) => e.iconName == icon)?.icon}
</div> </div>
<span className="text-center mt-2">{title}</span> <span className="text-center mt-2 text-sm font-medium ">{title}</span>
<div className="w-[40px] h-[40px] rounded-xl "></div> <div className="w-[40px] h-[40px] rounded-xl "></div>
</button> </button>
</div> </div>
@ -102,7 +102,9 @@ const Buttonbriz = ({
> >
<p <p
className={`mb-0 tr03 ${ className={`mb-0 tr03 ${
subButtonAction ? "text-white font-semibold" : "text-red-500" subButtonAction
? "text-white font-medium text-sm"
: "text-red-500"
} `} } `}
> >
{subButtonTitle} {subButtonTitle}

View File

@ -19,6 +19,7 @@ import Chapar, { getToken } from "plugins/Chapar";
import TimePicker from "plugins/TimePicker/page"; import TimePicker from "plugins/TimePicker/page";
import axios from "axios"; import axios from "axios";
import "rc-slider/assets/index.css"; import "rc-slider/assets/index.css";
import BottomSheetReport from "plugins/BottomSheet/BottomSheetReport";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
@ -55,6 +56,8 @@ export default function RootLayout({ children }) {
const [BottomSheetChangeRoleOpen, setBottomSheetChangeRoleOpen] = const [BottomSheetChangeRoleOpen, setBottomSheetChangeRoleOpen] =
useState(false); useState(false);
const [BottomSheetReportOpen, setBottomSheetReportOpen] = useState(false);
// BigPlus // BigPlus
const [BigPlusOpen, setBigPlusOpen] = useState(false); const [BigPlusOpen, setBigPlusOpen] = useState(false);
const [BigPlusRotateIcon, setBigPlusRotateIcon] = useState(false); const [BigPlusRotateIcon, setBigPlusRotateIcon] = useState(false);
@ -117,6 +120,7 @@ export default function RootLayout({ children }) {
const [goToEditShift, setGoToEditShift] = useState(false); const [goToEditShift, setGoToEditShift] = useState(false);
const [idEditShift, setIdEditShift] = useState(null); const [idEditShift, setIdEditShift] = useState(null);
const [shiftPlanData, setShiftPlanData] = useState([]); const [shiftPlanData, setShiftPlanData] = useState([]);
const [shiftPlansData, setShifPlansData] = useState([]);
// task // task
const [routineForTaskChoose, setRoutineForTaskChoose] = useState([]); const [routineForTaskChoose, setRoutineForTaskChoose] = useState([]);
@ -145,6 +149,9 @@ export default function RootLayout({ children }) {
// closeShift // closeShift
const [completeActivities, setCompleteActivities] = useState([]); const [completeActivities, setCompleteActivities] = useState([]);
//report
const [reportDetail, setReportDetail] = useState(null);
const pathname = usePathname(); const pathname = usePathname();
const router = useRouter(); const router = useRouter();
const hiddenUrls = ["/login", "/pricing", "/about-us", "/"]; const hiddenUrls = ["/login", "/pricing", "/about-us", "/"];
@ -263,7 +270,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateRole = async (body) => { const CreateRole = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -388,7 +394,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateUser = async (body) => { const CreateUser = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -514,7 +519,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateShift = async (body) => { const CreateShift = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -600,57 +604,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const GetShiftPlan = async (id) => {
setLoading(true);
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/shift/plan/${id}`,
{
headers: {
Authorization: getToken(),
},
}
);
setShiftPlanData(data);
setLoading(false);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const UpdateShiftPlan = async (body, id) => {
setLoading(true);
try {
const data = await Chapar.put(
`${process.env.NEXT_PUBLIC_API_URL}/shift/plan`,
body,
{
headers: {
Authorization: getToken(),
},
}
);
toast.success(`شیفت ویرایش شد`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
setShiftPlanData(id);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const GetShift = async (id) => { const GetShift = async (id) => {
setLoading(true); setLoading(true);
try { try {
@ -697,7 +650,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateSection = async (body) => { const CreateSection = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -822,7 +774,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateRoutine = async (body) => { const CreateRoutine = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -927,7 +878,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const GetRoutineShiftPlan = async (id, time) => { const GetRoutineShiftPlan = async (id, time) => {
setLoading(true); setLoading(true);
try { try {
@ -951,6 +901,56 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const GetShiftPlan = async (id) => {
setLoading(true);
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/shift/plan/${id}`,
{
headers: {
Authorization: getToken(),
},
}
);
setShiftPlanData(data);
setLoading(false);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const UpdateShiftPlan = async (body, id) => {
setLoading(true);
try {
const data = await Chapar.put(
`${process.env.NEXT_PUBLIC_API_URL}/shift/plan`,
body,
{
headers: {
Authorization: getToken(),
},
}
);
toast.success(`شیفت ویرایش شد`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
setShiftPlanData(id);
router.push("/shifts");
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const CreateShifPlan = async (body) => { const CreateShifPlan = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -967,6 +967,8 @@ export default function RootLayout({ children }) {
position: "bottom-right", position: "bottom-right",
closeOnClick: true, closeOnClick: true,
}); });
router.push("/shifts");
} catch ({ error, status }) { } catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, { toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right", position: "bottom-right",
@ -975,7 +977,31 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const GetShifPlans = async (page) => {
setLoading(true);
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/shift/plan?page=${page}`,
{
headers: {
Authorization: getToken(),
},
}
);
console.log(data);
setShifPlansData(data);
setLoading(false);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const DeleteRoutine = async (id) => { const DeleteRoutine = async (id) => {
setLoading(true); setLoading(true);
try { try {
@ -1000,7 +1026,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreatePosition = async (body) => { const CreatePosition = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -1125,7 +1150,6 @@ export default function RootLayout({ children }) {
setLoading(false); setLoading(false);
} }
}; };
const CreateTask = async (body) => { const CreateTask = async (body) => {
setLoading(true); setLoading(true);
try { try {
@ -1427,6 +1451,76 @@ export default function RootLayout({ children }) {
} }
}; };
const ReportShiftPlan = async (shiftPlanId) => {
setLoading(true);
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/report/shift/plan/${shiftPlanId}`,
{
headers: {
Authorization: getToken(),
},
}
);
if (!response.ok) {
throw new Error("Failed to download report");
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "report.xlsx"; // Change the filename if needed
document.body.appendChild(a);
a.click();
a.remove();
setLoading(false);
} catch (error) {
toast.error(error.message, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const ReportTask = async () => {
setLoading(true);
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/report/task`,
{
headers: {
Authorization: getToken(),
},
}
);
if (!response.ok) {
throw new Error("Failed to download report");
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "report.xlsx"; // Change the filename if needed
document.body.appendChild(a);
a.click();
a.remove();
setLoading(false);
} catch (error) {
toast.error(error.message, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
useEffect(() => { useEffect(() => {
console.log(` console.log(`
bbbbbbbb bbbbbbbb
@ -1526,6 +1620,9 @@ export default function RootLayout({ children }) {
pageGetTasks, pageGetTasks,
stopGetActivities, stopGetActivities,
pageGetActivity, pageGetActivity,
shiftPlansData,
BottomSheetReportOpen,
reportDetail,
}, },
setBottomSheetCreateRoleOpen, setBottomSheetCreateRoleOpen,
setBottomSheetCreateEmployeesOpen, setBottomSheetCreateEmployeesOpen,
@ -1641,6 +1738,12 @@ export default function RootLayout({ children }) {
setPageGetTasks, setPageGetTasks,
setStopGetActivities, setStopGetActivities,
setPageGetActivity, setPageGetActivity,
setShifPlansData,
GetShifPlans,
setBottomSheetReportOpen,
setReportDetail,
ReportShiftPlan,
ReportTask,
}} }}
> >
<html lang="en"> <html lang="en">
@ -1649,6 +1752,7 @@ export default function RootLayout({ children }) {
{shouldRenderComponent && <NavBAr />} {shouldRenderComponent && <NavBAr />}
<ToastContainer position="bottom-right" closeOnClick={true} rtl /> <ToastContainer position="bottom-right" closeOnClick={true} rtl />
<Loading /> <Loading />
<BottomSheetReport />
{openTimePicker && <TimePicker />} {openTimePicker && <TimePicker />}
{BigPlusOpen ? ( {BigPlusOpen ? (

View File

@ -134,6 +134,15 @@ const CompleteShift = () => {
// ; // ;
}; };
const handleGoToReport = (title, shiftId) => {
CTX.setReportDetail({
title: title,
shiftId: shiftId,
typeReport: "SHIFTPLAN",
});
CTX.setBottomSheetReportOpen(true);
};
useEffect(() => { useEffect(() => {
handleDayCloseShift(1); handleDayCloseShift(1);
}, []); }, []);
@ -173,7 +182,7 @@ const CompleteShift = () => {
/> />
<div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-4 rtl"> <div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-4 rtl">
<div className="flex overflow-auto whitespace-nowrap"> <div className="flex overflow-auto whitespace-nowrap mb-7">
<div <div
className={`mx-1 rtl py-1 px-2 rounded-full font-bold inline-block tr03 ${ className={`mx-1 rtl py-1 px-2 rounded-full font-bold inline-block tr03 ${
selectDayForShift == 0 selectDayForShift == 0
@ -216,46 +225,62 @@ const CompleteShift = () => {
className={`bg-gray-200 p-2 rounded-full flex justify-between ${ className={`bg-gray-200 p-2 rounded-full flex justify-between ${
activeShifPlan == index ? "bg-gray-300 " : "bg-gray-200 " activeShifPlan == index ? "bg-gray-300 " : "bg-gray-200 "
} `} } `}
onClick={() =>
handleOpenShift(
e?.isCompleted,
e?.id,
index,
e?.hasCurrentShiftPlan
)
}
> >
<p className="mb-0">{e?.title} </p> <div
className="flex w-full justify-between"
<div className="flex"> onClick={() =>
<div className="bg-gray-400 rounded-full mr-1"> handleOpenShift(
<p className="mb-0 text-sm p-1 text-white "> e?.isCompleted,
{" "} e?.id,
<PersianNumber index,
number={e?.totalActivitiesCount} e?.hasCurrentShiftPlan
style="mx-1 text-base" )
/> }
فعالیت >
</p> <p className="mb-0">{e?.title} </p>
</div> <div className="flex">
<div
{e?.undoneActivitiesCount != 0 && ( className={`bg-gray-400 rounded-full mr-1 ${
<div className="bg-red-700 w-[30px] h-[30px] rounded-full mr-1"> e?.isCompleted
<p className="mb-0 text-sm p-1 text-white text-center mt-[2px]"> ? "w-[30px] h-[30px] text-center pt-[2px]"
: ""
}`}
>
<p className="mb-0 text-sm p-1 text-white ">
{" "} {" "}
<PersianNumber <PersianNumber
number={e?.undoneActivitiesCount} number={e?.totalActivitiesCount}
style="mx-1 text-base" style="mx-1 text-base"
/> />
{!e?.isCompleted && "فعالیت"}
</p> </p>
</div> </div>
)}
{e?.undoneActivitiesCount != 0 && (
<div className="bg-red-700 w-[30px] h-[30px] rounded-full mr-1">
<p className="mb-0 text-sm p-1 text-white text-center mt-[2px]">
{" "}
<PersianNumber
number={e?.undoneActivitiesCount}
style="mx-1 text-base"
/>
</p>
</div>
)}
</div>
</div>
<div className={` ${e?.isCompleted ? "w-[170px]" : ""}`}>
{e?.isCompleted && ( {e?.isCompleted && (
<div className="bg-yellow-500 w-fit px-2 h-[30px] rounded-full mr-1"> <div
className="bg-sky-600 w-fit px-2 h-[30px] rounded-full mr-1 !z-50 relative"
onClick={() =>
handleGoToReport(e.title, e.currentShiftPlanId)
}
>
<p className="mb-0 text-sm p-1 text-white text-center mt-[2px]"> <p className="mb-0 text-sm p-1 text-white text-center mt-[2px]">
{" "} {" "}
بسته شده گزارش شیفت{" "}
</p> </p>
</div> </div>
)} )}

View File

@ -33,6 +33,8 @@ const Calendar = () => {
const [shiftsPlan, setShiftsPlan] = useState([]); const [shiftsPlan, setShiftsPlan] = useState([]);
const [manageShiftEmployeesData, setManageShiftEmployeesData] = useState([]); const [manageShiftEmployeesData, setManageShiftEmployeesData] = useState([]);
const [editManageShift, setEditManageShift] = useState(false); const [editManageShift, setEditManageShift] = useState(false);
const [superId, setSuperId] = useState(null);
const [superData, setSuperData] = useState(false);
const [shiftPlanSteps, setShiftPlanSteps] = useState(0); const [shiftPlanSteps, setShiftPlanSteps] = useState(0);
@ -110,6 +112,7 @@ const Calendar = () => {
1000, 1000,
shiftId: shiftsPlan && shiftsPlan[selectShift]?.id, shiftId: shiftsPlan && shiftsPlan[selectShift]?.id,
routineId: routinesData && routinesData[selectRoutine]?.id, routineId: routinesData && routinesData[selectRoutine]?.id,
supervisionUserId: superId,
userAndPositionIds, userAndPositionIds,
}; };
@ -121,6 +124,7 @@ const Calendar = () => {
shiftId: shiftsPlan && shiftsPlan[selectShift]?.id, shiftId: shiftsPlan && shiftsPlan[selectShift]?.id,
routineId: routinesData && routinesData[selectRoutine]?.id, routineId: routinesData && routinesData[selectRoutine]?.id,
userAndPositionIds, userAndPositionIds,
supervisionUserId: superId,
id: currentShiftPlanId, id: currentShiftPlanId,
}; };
@ -143,10 +147,8 @@ const Calendar = () => {
const handleCreateShiftPlan = (update) => { const handleCreateShiftPlan = (update) => {
if (update == "UPDATE") { if (update == "UPDATE") {
CTX.UpdateShiftPlan(bodyUpdate); CTX.UpdateShiftPlan(bodyUpdate);
setShiftPlanSteps(1);
} else { } else {
CTX.CreateShifPlan(body); CTX.CreateShifPlan(body);
setShiftPlanSteps(1);
} }
}; };
@ -195,8 +197,25 @@ const Calendar = () => {
setUserAndPositionIds( setUserAndPositionIds(
shiftPlanData?.users?.map((e) => ({ key: e.positionId, value: e.userId })) shiftPlanData?.users?.map((e) => ({ key: e.positionId, value: e.userId }))
); );
setSuperId(shiftPlanData?.supervisorId);
}, [shiftPlanData]); }, [shiftPlanData]);
useEffect(() => {
const userJustSuper = usersData?.filter((obj) =>
obj.roleNames.includes("سوپروایزر")
);
setSuperData(
userJustSuper?.map((item) => ({
key: item.firstName + " " + item.lastName,
value: item.userId,
}))
);
}, [usersData]);
console.log(superData, usersData);
return ( return (
<div className="pb-20"> <div className="pb-20">
<AppHeader <AppHeader
@ -215,8 +234,8 @@ const Calendar = () => {
}} }}
/> />
<div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-4 rtl"> <div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden px-4 rtl ">
<div className="font-bold text-right"> <div className="font-medium text-right mt-5">
<p className="mb-0">روتین را انتخاب کنید</p> <p className="mb-0">روتین را انتخاب کنید</p>
</div> </div>
<div <div
@ -246,14 +265,16 @@ const Calendar = () => {
} }
}} }}
> >
<p className="mb-0">{e.name}</p> <p className="mb-0 text-sm">{e.name}</p>
</div> </div>
))} ))}
</div> </div>
</div>
{shiftPlanSteps >= 1 && ( {shiftPlanSteps >= 0 && (
<div className="bg-body-100 relative top-[-40px] rounded-t-3xl overflow-hidden px-4 rtl ">
<> <>
<div className="font-bold text-right mt-3"> <div className="font-medium text-right mt-3 pb-2">
<p className="mb-0">تاریخ را انتخاب کنید</p> <p className="mb-0">تاریخ را انتخاب کنید</p>
</div> </div>
<Swiper <Swiper
@ -271,7 +292,16 @@ const Calendar = () => {
: " opacity-70" : " opacity-70"
}`} }`}
key={index} key={index}
onClick={() => handleRoutineShiftPlanWithDay(index)} onClick={() => {
if (shiftPlanSteps >= 1) {
handleRoutineShiftPlanWithDay(index);
} else {
toast.error(`ابتدا روتین را انتخاب کنید`, {
position: "bottom-right",
closeOnClick: true,
});
}
}}
> >
<div className="py-2"> <div className="py-2">
<p className="mb-0 text-center "> <p className="mb-0 text-center ">
@ -309,14 +339,13 @@ const Calendar = () => {
))} ))}
</Swiper> </Swiper>
</> </>
)} </div>
</div> )}
{shiftPlanSteps >= 0 && (
{shiftPlanSteps >= 2 && (
<> <>
<div className="bg-body-100 relative top-[-40px] rounded-t-3xl overflow-hidden px-4 rtl"> <div className="bg-body-100 relative top-[-40px] rounded-t-3xl overflow-hidden px-4 rtl">
<> <>
<div className="font-bold text-right mt-3"> <div className="font-medium text-right mt-3">
<p className="mb-0">شیفت را انتخاب کنید</p> <p className="mb-0">شیفت را انتخاب کنید</p>
</div> </div>
{!!routineShiftPlan?.find( {!!routineShiftPlan?.find(
@ -338,7 +367,7 @@ const Calendar = () => {
setShiftPlanSteps(3); setShiftPlanSteps(3);
}} }}
> >
<p className="mb-0">{e?.title}</p> <p className="mb-0 text-sm">{e?.title}</p>
</div> </div>
))} ))}
</div> </div>
@ -357,8 +386,8 @@ const Calendar = () => {
)} )}
{shiftPlanSteps >= 3 && ( {shiftPlanSteps >= 3 && (
<div className="bg-white relative top-[15px] rounded-t-3xl p-4 rtl pt-6 sm:h-auto pb-20"> <div className="bg-white relative top-[15px] rounded-t-3xl p-4 rtl pt-3 sm:h-auto pb-20">
<div className="mx-3 flex justify-center mb-10"> <div className="mx-3 flex justify-center mb-5">
<div className=" bg-gray-100 rounded-xl w-fit mr-0 p-3"> <div className=" bg-gray-100 rounded-xl w-fit mr-0 p-3">
<p className="mb-0 text-right text-sm rtl opacity-80"> <p className="mb-0 text-right text-sm rtl opacity-80">
ویرایش برای{" "} ویرایش برای{" "}
@ -376,6 +405,9 @@ const Calendar = () => {
</div> </div>
</div> </div>
<div className=" text-right mt-3 mb-5">
<p className="mb-0 font-medium m">پرسنل را انتخاب کنید</p>
</div>
{positionsData.map((e) => ( {positionsData.map((e) => (
<div className=""> <div className="">
<div className="flex justify-between bg-gray-200 rounded-2xl"> <div className="flex justify-between bg-gray-200 rounded-2xl">
@ -397,84 +429,104 @@ const Calendar = () => {
</div> </div>
</div> </div>
{/* <div className=" m-1">
<Input
lable="جستجوی افراد"
id="SearchUser-id"
name="SearchUser"
type={"text"}
value={searchUserCurrntData}
inputEvent={(e) => {
setSearchUserCurrntData(e.target.value);
if (!!searchUserChoose.find((b) => b == e.target.value)) {
toast.error("نقش تکراری است", {
position: "bottom-right",
closeOnClick: true,
});
} else {
CTX.setSearchUserChoose((current) => [
...current,
e.target.value,
]);
}
}}
style="text-right"
select={true}
selectData={manageShiftEmployeesData}
theme={1}
defaultValue={"انتخاب کنید"}
/>
</div> */}
<div <div
className={`flex j flex-wrap mt-2 rtl ${ className={`flex j flex-wrap mt-2 rtl ${
userAndPositionIds?.length > 0 ? "" : "justify-center" userAndPositionIds?.length > 0 ? "" : "justify-center"
}`} }`}
> >
{userAndPositionIds?.length > 0 ? ( {userAndPositionIds?.length > 0
userAndPositionIds?.map((item) => ( ? userAndPositionIds?.map((item) => (
<> <>
{e.id == item.key && ( {e.id == item.key && (
<div className="flex bg-gray-100 p-1 rounded-full m-1 justify-start mb-7 "> <div className="flex bg-gray-100 p-1 rounded-full m-1 justify-start mb-7 ">
<div <div
className="w-[30px] h-[30px] rounded-full bg-gray-400 " className="w-[30px] h-[30px] rounded-full bg-gray-400 "
// onClick={() => deleteSearchUser(e)} // onClick={() => deleteSearchUser(e)}
> >
<Avatar <Avatar
size={30} size={30}
name={ name={
usersData.find((b) => b?.userId == item?.value) usersData.find(
?.firstName (b) => b?.userId == item?.value
} )?.firstName
variant="beam" }
colors={["#9d9f88", "#83af96", "#b2de93"]} variant="beam"
/> colors={["#9d9f88", "#83af96", "#b2de93"]}
</div> />
</div>
<div> <div>
<p className="mb-0 px-3 text-sm mt-1"> <p className="mb-0 px-3 text-sm mt-1">
{ {
usersData.find((b) => b.userId == item?.value) usersData.find((b) => b.userId == item?.value)
?.firstName ?.firstName
} }
</p> </p>
</div>
</div> </div>
</div> )}
)} </>
</> ))
)) : ""}
) : (
<div className="flex justify-center mb-3 ">
<div className="bg-gray-100 w-fit rounded-full p-2 px-4">
چیزی یافت نشد
</div>
</div>
)}
</div> </div>
</div> </div>
))} ))}
<div>
<div className="mt-8">
<div className=" text-right mt-3">
<p className="mb-0 font-medium">
سوپروایزر را انتخاب کنید
<small className="text-red-500 mx-1">(ضروری)</small>
</p>
<p className="mb-0 text-right text-[12px] text-primary-300">
شیفت توسط سوپروایزر بسته میشود لطفا برای هر شیفت آن را مشخص کنید
</p>
</div>
<div className="">
<Input
lable="سوپروایزر"
id="superId-id"
name="superId"
type={"text"}
value={superId}
inputEvent={(e) => {
setSuperId(e.target.value);
console.log(e.target.value);
}}
style="text-right"
select={true}
selectData={superData}
defaultValue={"انتخاب کنید"}
theme={1}
/>
</div>
</div>
<div className="mt-8">
<p className="mb-0 font-medium ">غیر فعال کردن شیفت </p>
<div
className={`flex rtl tr03 border-[2px] border-transparent py-2 ${
1 ? "animate-pulse-1 " : ""
}`}
>
<div>
<input
type="checkbox"
checked={1 ? true : false}
defaultValue={true}
className="w-[40px] h-[40px] !rounded-xl ml-2 custom-checkbox mt-1"
name="hasSchengenRelative"
// onClick={(e) => setRoleCheckBox(e.target.checked)}
/>
</div>
<p className="mb-0 text-right mt-1 text-[12px] text-red-600 font-medium">
با خاموش کردن شیفت فعالیت ها برای افراد داخل شیفت خاموش میشود{" "}
</p>
</div>
</div>
<div className="mt-5">
{editManageShift ? ( {editManageShift ? (
<Buttonbriz <Buttonbriz
title="ویرایش فعالیت" title="ویرایش فعالیت"

View File

@ -2,9 +2,11 @@
import AppHeader from "@comp/AppHeader/page"; import AppHeader from "@comp/AppHeader/page";
import AppContext from "@ctx/AppContext"; import AppContext from "@ctx/AppContext";
import moment from "jalali-moment";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import PersianNumber from "plugins/PersianNumber";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
@ -12,6 +14,55 @@ const Shifts = (props) => {
const CTX = useContext(AppContext); const CTX = useContext(AppContext);
const router = useRouter(); const router = useRouter();
const [shiftplans, setShiftplans] = useState([]);
const [shiftPlansSelect, setShiftPlansSelect] = useState(0);
const shiftplansData = CTX.state.shiftPlansData;
const groupObjectsByPlanFor = (responseData) => {
const groupedData = {};
// Iterate through the array
responseData.forEach((obj) => {
const { planFor } = obj;
// If the planFor value is not in the groupedData object, create a new array
if (!groupedData[planFor]) {
groupedData[planFor] = [obj];
} else {
// If the planFor value already exists, push the object into the existing array
groupedData[planFor].push(obj);
}
});
// Sort the objects within each group by the planFor date
Object.keys(groupedData).forEach((key) => {
groupedData[key].sort(
(a, b) => new Date(a.planFor) - new Date(b.planFor)
);
});
// Convert the groupedData object into an array of objects
const groupedArray = Object.keys(groupedData).map((key) => ({
planFor: key,
data: groupedData[key],
}));
// Sort the groupedArray by the planFor date
groupedArray.sort((a, b) => new Date(a.planFor) - new Date(b.planFor));
console.log(groupedArray);
setShiftplans(groupedArray);
};
useEffect(() => {
CTX.GetShifPlans(0);
}, []);
useEffect(() => {
groupObjectsByPlanFor(shiftplansData);
}, [shiftplansData]);
return ( return (
<> <>
<div className="pb-20"> <div className="pb-20">
@ -62,7 +113,62 @@ const Shifts = (props) => {
</Link> </Link>
</div> </div>
<div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-4 rtl mt-2"></div> <div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-4 rtl mt-2">
{shiftplans?.map((e, index) => (
<>
<div
className={` bg-gray-200 rounded-xl p-5 my-3 tr03 ${
shiftPlansSelect == index ? "h-fit " : "h-[65px]"
}`}
>
<div
className={`flex justify-between ${
shiftPlansSelect == index
? "border-b border-gray-300 pb-3"
: ""
}`}
onClick={() => setShiftPlansSelect(index)}
>
<div className="">
<PersianNumber
number={moment(e.planFor).format("jYYYY/jM/jD")}
/>
</div>
<div className="bg-gray-500 fit rounded-xl p-1 px-2 h-fit">
<p className="mb-0 text-sm text-white">
<PersianNumber number={e.data.length} style={"ml-1"} />
شیفت
</p>
</div>
</div>
{shiftPlansSelect == index && (
<div className="flex">
{e.data.map((e) => (
<div className="ml-2 bg-white rounded-xl mt-3 p-2">
<p className="text-sm mb-0 text-gray-700 font-medium">
{" "}
{e.shiftTitle}
</p>
<div className="flex justify-center">
<p className="mb-0 text-[12px] text-center w-fit bg-primary-100 px-1 rounded-xl mt-2 ">
<PersianNumber
number={e.totalActivitiesCount}
style={"ml-1 !text-[12px]"}
/>
فعالیت
</p>
</div>
</div>
))}
</div>
)}
</div>
</>
))}
</div>
</div> </div>
</> </>
); );

View File

@ -44,6 +44,7 @@ const page = () => {
CTX.setPageGetTasks((e) => e + 1); CTX.setPageGetTasks((e) => e + 1);
CTX.GetTasks(pageGetTasks + 1); CTX.GetTasks(pageGetTasks + 1);
}; };
const handleInfiniteNextFetchActivity = () => { const handleInfiniteNextFetchActivity = () => {
CTX.setPageGetActivity((e) => e + 1); CTX.setPageGetActivity((e) => e + 1);
CTX.GetActivity( CTX.GetActivity(
@ -53,6 +54,15 @@ const page = () => {
); );
}; };
const handleGoToReport = () => {
CTX.setReportDetail({
title: "فعالیت های مجموعه",
shiftId: "",
typeReport: "TASK",
});
CTX.setBottomSheetReportOpen(true);
};
console.log(activities.length); console.log(activities.length);
return ( return (
@ -75,7 +85,20 @@ const page = () => {
GoBack(); GoBack();
}} }}
/> />
<div className="bg-primary-300 flex whitespace-nowrap rtl p-3">
<div
className=" bg-white rounded-3xl p-5 inline-block w-fit relative top-[-32px] mx-2"
onClick={() => handleGoToReport()}
>
<div>
<h2> خروجی گرفتن از فعالیت ها </h2>
<div className="flex justify-end">
<div className="w-10 h-5 rounded-full bg-secondary-200 opacity-30"></div>
</div>
</div>
</div>
</div>
<div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-5 rtl "> <div className="bg-body-100 relative top-[-30px] rounded-t-3xl overflow-hidden p-5 rtl ">
{!!HasPermission("ManageTasks", permissions) && ( {!!HasPermission("ManageTasks", permissions) && (
<div className="flex mb-6 "> <div className="flex mb-6 ">