diff --git a/client/src/assets/styles/components/Button.scss b/client/src/assets/styles/components/Button.scss
index 2dde81c4..1ae7aa31 100644
--- a/client/src/assets/styles/components/Button.scss
+++ b/client/src/assets/styles/components/Button.scss
@@ -51,6 +51,11 @@
color: var(--grey-900);
}
+ &--success-light {
+ background: var(--Green-200, #bcf0da);
+ color: #000;
+ }
+
&--danger {
background-color: var(--red-500);
color: var(--grey-900);
diff --git a/client/src/assets/styles/components/Inputs.scss b/client/src/assets/styles/components/Inputs.scss
index 1cabe062..49241bdc 100644
--- a/client/src/assets/styles/components/Inputs.scss
+++ b/client/src/assets/styles/components/Inputs.scss
@@ -37,3 +37,50 @@
direction: rtl;
}
}
+
+input[type="checkbox"] {
+ --size: 1.5em;
+ --mark-size: 0.8em;
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: var(--grey-800);
+ margin: 0;
+ font: inherit;
+ color: currentColor;
+ width: var(--size);
+ height: var(--size);
+ border: 0.15em solid var(--grey-700);
+ border-radius: 0.15em;
+ transform: translateY(-0.075em);
+ display: grid;
+ place-content: center;
+
+ &::before {
+ content: "";
+ width: var(--mark-size);
+ height: var(--mark-size);
+ transform: scale(0);
+ transition: 120ms transform ease-in-out;
+ box-shadow: inset 1em 1em var(--grey-100);
+ transform-origin: bottom left;
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
+ }
+ &:checked {
+ background-color: var(--primary-600);
+ border-color: var(--primary-600);
+ outline-color: var(--primary-600);
+ }
+ &:checked::before {
+ transform: scale(1);
+ }
+ &:focus {
+ outline: max(2px, 0.15em) solid currentColor;
+ outline-offset: max(2px, 0.15em);
+ }
+ &:disabled {
+ color: var(--grey-700);
+ background-color: var(--grey-700);
+ outline-color: var(--grey-600);
+ cursor: not-allowed;
+ }
+}
diff --git a/client/src/components/captains-attendance/CaptainAttendance.jsx b/client/src/components/captains-attendance/CaptainAttendance.jsx
new file mode 100644
index 00000000..6e1cffa3
--- /dev/null
+++ b/client/src/components/captains-attendance/CaptainAttendance.jsx
@@ -0,0 +1,224 @@
+import { useEffect, useState } from "react";
+import CustomSelect from "../common/CustomSelect";
+import PageTitle from "../common/PageTitle";
+import "../scouts-attendance/ScoutsAttendance.scss";
+import InfoBox from "../common/InfoBox";
+import Button from "../common/Button";
+import { useGetAllWeeksQuery } from "../../redux/slices/termApiSlice";
+import { useSelector } from "react-redux";
+import { toast } from "react-toastify";
+import {
+ useGetUnitAttendanceQuery,
+ useUpsertUnitAttendanceMutation,
+} from "../../redux/slices/attendanceApiSlice";
+
+export default function CaptainsAttendance() {
+ const [attendance, setAttendance] = useState([]);
+ const [chosenWeek, setChosenWeek] = useState("");
+
+ let {
+ data: weeks,
+ isLoading: isLoadingWeeks,
+ isFetching: isFetchingWeeks,
+ isSuccess: isSuccessWeeks,
+ } = useGetAllWeeksQuery();
+
+ const { userInfo } = useSelector((state) => state.auth);
+
+ const [upsertAttendance, { isLoading: isLoadingUpsertAttendance }] =
+ useUpsertUnitAttendanceMutation();
+
+ if (isSuccessWeeks && !isLoadingWeeks && !isFetchingWeeks) {
+ weeks = weeks?.body;
+ weeks = weeks.map((week) => ({
+ ...week,
+ display:
+ week?.weekNumber +
+ " - " +
+ new Date(week?.startDate).toLocaleDateString(),
+ }));
+
+ // console.log(weeks);
+ }
+
+ let {
+ data: scouts,
+ isLoading: isLoadingScouts,
+ isFetching: isFetchingScouts,
+ isSuccess: isSuccessScouts,
+ refetch: refetchScouts,
+ } = useGetUnitAttendanceQuery({
+ weekNumber: parseInt(chosenWeek),
+ termNumber: weeks?.find((week) => week.weekNumber === parseInt(chosenWeek))
+ ?.termNumber,
+ baseName: userInfo?.rSectorBaseName,
+ suffixName: userInfo?.rSectorSuffixName,
+ });
+
+ if (isSuccessScouts && !isLoadingScouts && !isFetchingScouts) {
+ scouts = scouts?.body;
+ scouts = scouts.map((scout) => ({
+ ...scout,
+ present: scout?.attendanceStatus === "attended",
+ excused: scout?.attendanceStatus === "execused",
+ id: scout.scoutId,
+ name: scout.firstName + " " + scout.middleName + " " + scout.lastName,
+ }));
+ // console.log({ scouts });
+ }
+
+ useEffect(() => {
+ if (scouts) {
+ setAttendance(scouts);
+ }
+ }, [isSuccessScouts]);
+
+ const handleCheckboxChange = (scoutId, checkboxType) => {
+ setAttendance((prevState) => {
+ return prevState.map((scout) => {
+ return scoutId === scout.id
+ ? { ...scout, [checkboxType]: !scout[checkboxType] }
+ : scout;
+ });
+ });
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ const attendanceReqBody = attendance.map((scout) => ({
+ ...scout,
+ attendanceStatus: scout.present
+ ? "attended"
+ : scout.excused
+ ? "execused"
+ : "absent",
+ weekNumber: parseInt(chosenWeek),
+ termNumber: weeks.find((week) => week.weekNumber === parseInt(chosenWeek))
+ ?.termNumber,
+ sectorBaseName: userInfo?.rSectorBaseName,
+ sectorSuffixName: userInfo?.rSectorSuffixName,
+ }));
+
+ console.log({ attendanceReqBody });
+
+ try {
+ const res = await upsertAttendance({
+ attendanceRecords: attendanceReqBody,
+ }).unwrap();
+ // if (!res.ok)
+ // throw new Error("Something went wrong while inserting attendance");
+ toast.success("تم تسجيل الغياب بنجاح");
+ console.log(res.body);
+ } catch (err) {
+ toast.error("حدث خطأ أثناء تسجيل الغياب");
+ console.log(JSON.stringify(err));
+ toast.error(JSON.stringify(err));
+ }
+ };
+
+ // if (!userInfo?.rSectorBaseName || !userInfo?.rSectorSuffixName) {
+ // return (
+ //
+ //
لا يمكنك تسجيل الغياب
+ //
يرجى تعيين القطاع الخاص بك للقيام بذلك
+ //
+ // );
+ // }
+
+ return (
+
+ );
+}
diff --git a/client/src/components/common/Inputs.jsx b/client/src/components/common/Inputs.jsx
index 3be83896..bee38ed4 100644
--- a/client/src/components/common/Inputs.jsx
+++ b/client/src/components/common/Inputs.jsx
@@ -29,7 +29,7 @@ TextInput.propTypes = {
label: PropTypes.string.isRequired,
type: PropTypes.string,
name: PropTypes.string,
- value: PropTypes.string,
+ value: PropTypes.string || PropTypes.number,
onChange: PropTypes.func,
placeholder: PropTypes.string,
required: PropTypes.bool,
@@ -48,7 +48,7 @@ function RadioInput({ label, name, required, valuesArr, onChange }) {
onChange={onChange}
required={required}
/>
- {value}
+ {value}
))}
diff --git a/client/src/components/common/UserActions.jsx b/client/src/components/common/UserActions.jsx
index d0385910..1e7f94b4 100644
--- a/client/src/components/common/UserActions.jsx
+++ b/client/src/components/common/UserActions.jsx
@@ -15,7 +15,7 @@ const ActionRoutes = {
Sessions: "/sessions",
"Start New Term": "/start-new-term",
Sectors: "/sectors",
- "Record Captain Absence": "/record-captain-absence",
+ "Record Captain Absence": "/record-captains-absence",
"Record Scouts Absence": "/record-scouts-absence",
Scores: "/scores",
Sector: "/sector",
@@ -173,7 +173,6 @@ export default function UserActions() {
القطاعات