diff --git a/client/src/assets/styles/components/Button.scss b/client/src/assets/styles/components/Button.scss index fcd812b2..0058dc5d 100644 --- a/client/src/assets/styles/components/Button.scss +++ b/client/src/assets/styles/components/Button.scss @@ -45,5 +45,10 @@ color: var(--grey-900); } + &--danger { + background-color: var(--red-500); + color: var(--grey-900); + } + // TODO: Add more button styles and maybe sizes } diff --git a/client/src/assets/styles/components/InfoSection.scss b/client/src/assets/styles/components/InfoSection.scss index e69de29b..2573a7f5 100644 --- a/client/src/assets/styles/components/InfoSection.scss +++ b/client/src/assets/styles/components/InfoSection.scss @@ -0,0 +1,30 @@ +.info-section { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 1rem; + direction: rtl; + margin-block: 2rem; + + .span-2-cols { + grid-column: 1 / span 2; + } + + > .info-box { + display: flex; + flex-direction: column; + direction: rtl; + align-items: flex-start; + justify-content: space-around; + padding: 1rem; + + h6:first-child { + font-size: 13px; + } + + // unset fixed width + &.narrow { + width: initial; + } + } +} diff --git a/client/src/assets/styles/components/infoBox.scss b/client/src/assets/styles/components/infoBox.scss index 03986681..69b21c21 100644 --- a/client/src/assets/styles/components/infoBox.scss +++ b/client/src/assets/styles/components/infoBox.scss @@ -1,35 +1,44 @@ .info-box { - height: 97px; - flex-shrink: 0; - border-radius: 12px; - - display: flex; - flex-direction: column; - justify-content: space-around; - align-items: end; - - padding-right: 2rem; - - &.narrow { - width: 40%; - } - - &.wide { - width: 90%; - } - - &.dark { - - background: var(--simnle-grid, linear-gradient(113deg, #1F2A37 6.36%, rgba(31, 42, 55, 0.00) 108.22%)); - } - - &.purple { - background: var(--pur-grid, linear-gradient(115deg, #B773E9 2.95%, #5B1092 95.69%)); - - } - - &.colorfull { - background: linear-gradient(96deg, #650DA6 -11.62%, #650DA6 -11.61%, #DF1846 119.72%); - box-shadow: 4px 5px 103.7px 0px var(--Primary-800, #2B0547); - } -} \ No newline at end of file + height: 97px; + flex-shrink: 0; + border-radius: 12px; + + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: end; + + padding-right: 2rem; + + &.narrow { + width: 40%; + } + + &.wide { + width: 90%; + } + + &.dark { + background: var( + --simnle-grid, + linear-gradient(113deg, #1f2a37 6.36%, rgba(31, 42, 55, 0) 108.22%) + ); + } + + &.purple { + background: var( + --pur-grid, + linear-gradient(115deg, #b773e9 2.95%, #5b1092 95.69%) + ); + } + + &.colorful { + background: linear-gradient( + 96deg, + #650da6 -11.62%, + #650da6 -11.61%, + #df1846 119.72% + ); + box-shadow: 4px 5px 103.7px 0px var(--Primary-800, #2b0547); + } +} diff --git a/client/src/components/common/InfoBox.jsx b/client/src/components/common/InfoBox.jsx index f0cc0e79..2ed43517 100644 --- a/client/src/components/common/InfoBox.jsx +++ b/client/src/components/common/InfoBox.jsx @@ -1,11 +1,21 @@ +import PropTypes from "prop-types"; import "../../assets/styles/components/infoBox.scss"; -const InfoBox = ({ title, value, width = "narrow", color = "dark" }) => { + +const InfoBox = ({ title, value, width = "narrow", color = "dark", spans }) => { + const spanClass = spans ? "span-2-cols" : ""; return ( -
- {title} - {value} +
+
{title}
+
{value}
); }; +InfoBox.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.any, + width: PropTypes.string, + color: PropTypes.string, +}; + export default InfoBox; diff --git a/client/src/components/common/InfoSection.jsx b/client/src/components/common/InfoSection.jsx index a03eff0e..35e91006 100644 --- a/client/src/components/common/InfoSection.jsx +++ b/client/src/components/common/InfoSection.jsx @@ -1,5 +1,169 @@ import "../../assets/styles/components/InfoSection.scss"; +import { useSelector } from "react-redux"; +import InfoBox from "./InfoBox"; +import { useGetCaptainsQuery } from "../../redux/slices/captainsApiSlice"; +import { useGetAbsenceRateQuery } from "../../redux/slices/statsApiSlice"; +import { useGetAllScoutsCountQuery } from "../../redux/slices/scoutApiSlice"; +import { useGetBudgetQuery } from "../../redux/slices/financeApiSlice"; export default function InfoSection() { - return
InfoSection
; + const { userInfo } = useSelector((state) => state.auth); + const { type } = userInfo; + + const GeneralCaptainInfo = () => { + const { data: captains, isFetching } = useGetCaptainsQuery(); + const captainCount = captains?.body.length; + + const { data: absenceRate, isFetching: isFetchingAbsence } = + useGetAbsenceRateQuery(); + + const { data: scoutsCount, isFetching: isFetchingScoutsCount } = + useGetAllScoutsCountQuery(); + + const { data: budget, isFetching: isFetchingBudget } = useGetBudgetQuery(); + + return ( + <> + + + + + + ); + }; + + const RegularCaptainInfo = () => { + //TODO: ADD UNIT CAPTAIN DATA INSTEAD OF GLOBAL DATA + const { data: absenceRate, isFetching: isFetchingAbsence } = + useGetAbsenceRateQuery(); + + const { data: scoutsCount, isFetching: isFetchingScoutsCount } = + useGetAllScoutsCountQuery(); + + return ( + <> + + + + ); + }; + + const UnitCaptainInfo = () => { + //TODO: ADD UNIT CAPTAIN DATA INSTEAD OF GLOBAL DATA + const { data: captains, isFetching } = useGetCaptainsQuery(); + const captainCount = captains?.body.length; + + const { data: absenceRate, isFetching: isFetchingAbsence } = + useGetAbsenceRateQuery(); + + const { data: scoutsCount, isFetching: isFetchingScoutsCount } = + useGetAllScoutsCountQuery(); + + return ( + <> + + + + + ); + }; + + return ( +
+ {type === "general" && } + {type === "regular" && } + {type === "unit" && } +
+ ); } diff --git a/client/src/components/common/NotificationBox.jsx b/client/src/components/common/NotificationBox.jsx index ba28a42b..95926108 100644 --- a/client/src/components/common/NotificationBox.jsx +++ b/client/src/components/common/NotificationBox.jsx @@ -1,5 +1,9 @@ import "../../assets/styles/components/NotificationBox.scss"; export default function NotificationBox() { - return
NotificationBox
; + return ( +
+ سيتم العمل على هذا القسم قريباً +
+ ); } diff --git a/client/src/components/common/TermInfoSection.jsx b/client/src/components/common/TermInfoSection.jsx index af80a9c2..e924fb12 100644 --- a/client/src/components/common/TermInfoSection.jsx +++ b/client/src/components/common/TermInfoSection.jsx @@ -1,8 +1,75 @@ - import "../../assets/styles/components/TermInfoSection.scss"; +import { + useGetCurTermQuery, + useGetCurWeekQuery, + useGetRemainingWeeksQuery, +} from "../../redux/slices/termApiSlice"; +import Button from "./Button"; +import InfoBox from "./InfoBox"; export default function TermInfoSection() { + const { data: termInfo, isFetching: isFetchingTerm } = useGetCurTermQuery(); + const { data: curWeek, isFetching: isFetchingWeek } = useGetCurWeekQuery(); + const { data: weeksLeft, isFetching: isFetchingWeeksLeft } = + useGetRemainingWeeksQuery(); + + console.log({ + termInfo, + curWeek, + weeksLeft, + }); + return ( -
TermInfoSection
- ) +
+
+ + + +
+
+ + +
+
+ ); } diff --git a/client/src/components/login/logIn.jsx b/client/src/components/login/logIn.jsx index 7c5d6ea2..1ae83847 100644 --- a/client/src/components/login/logIn.jsx +++ b/client/src/components/login/logIn.jsx @@ -15,7 +15,7 @@ export default function LogIn() { const navigate = useNavigate(); const dispatch = useDispatch(); - const [login, { isLoading, error }] = useLoginMutation(); + const [login, { isLoading}] = useLoginMutation(); const { userInfo } = useSelector((state) => state.auth); diff --git a/client/src/components/signup/signUp.jsx b/client/src/components/signup/signUp.jsx index 0d7f58f6..143fa777 100644 --- a/client/src/components/signup/signUp.jsx +++ b/client/src/components/signup/signUp.jsx @@ -21,7 +21,7 @@ export default function SignUp() { const navigate = useNavigate(); const dispatch = useDispatch(); - const [signup, { isLoading, error }] = useSignupMutation(); + const [signup, { isLoading }] = useSignupMutation(); const { userInfo } = useSelector((state) => state.auth); diff --git a/client/src/redux/slices/apiSlice.js b/client/src/redux/slices/apiSlice.js index 196da5cd..cadab8ab 100644 --- a/client/src/redux/slices/apiSlice.js +++ b/client/src/redux/slices/apiSlice.js @@ -1,6 +1,7 @@ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; const baseUrl = + // eslint-disable-next-line no-undef process.env.NODE_ENV === "production" ? "https://scouts-managment-system-development.onrender.com" : ""; diff --git a/client/src/redux/slices/captainsApiSlice.js b/client/src/redux/slices/captainsApiSlice.js new file mode 100644 index 00000000..f3e23950 --- /dev/null +++ b/client/src/redux/slices/captainsApiSlice.js @@ -0,0 +1,17 @@ +import { apiSlice } from "./apiSlice"; + +const CAPTAINS_URL = "/api/captain"; + +export const captainsApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + GetCaptains: builder.query({ + query: () => ({ + url: `${CAPTAINS_URL}/allCaptains/info`, + method: "GET", + }), + }), + + }), +}); + +export const { useGetCaptainsQuery } = captainsApi; diff --git a/client/src/redux/slices/financeApiSlice.js b/client/src/redux/slices/financeApiSlice.js new file mode 100644 index 00000000..c429ba25 --- /dev/null +++ b/client/src/redux/slices/financeApiSlice.js @@ -0,0 +1,16 @@ +import { apiSlice } from "./apiSlice"; + +const FINANCE_URL = "/api/finance"; + +export const financeApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + GetBudget: builder.query({ + query: () => ({ + url: `${FINANCE_URL}/budget`, + method: "GET", + }), + }), + }), +}); + +export const { useGetBudgetQuery } = financeApi; diff --git a/client/src/redux/slices/scoutApiSlice.js b/client/src/redux/slices/scoutApiSlice.js new file mode 100644 index 00000000..40b3b980 --- /dev/null +++ b/client/src/redux/slices/scoutApiSlice.js @@ -0,0 +1,16 @@ +import { apiSlice } from "./apiSlice"; + +const SCOUT_URL = "/api/scout"; + +export const scoutsApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + GetAllScoutsCount: builder.query({ + query: () => ({ + url: `${SCOUT_URL}/allScouts/count`, + method: "GET", + }), + }), + }), +}); + +export const { useGetAllScoutsCountQuery } = scoutsApi; diff --git a/client/src/redux/slices/statsApiSlice.js b/client/src/redux/slices/statsApiSlice.js new file mode 100644 index 00000000..13452ede --- /dev/null +++ b/client/src/redux/slices/statsApiSlice.js @@ -0,0 +1,16 @@ +import { apiSlice } from "./apiSlice"; + +const STATS_URL = "/api/stats"; + +export const statsApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + GetAbsenceRate: builder.query({ + query: () => ({ + url: `${STATS_URL}/scouts`, + method: "GET", + }), + }), + }), +}); + +export const { useGetAbsenceRateQuery } = statsApi; diff --git a/client/src/redux/slices/termApiSlice.js b/client/src/redux/slices/termApiSlice.js new file mode 100644 index 00000000..14042b98 --- /dev/null +++ b/client/src/redux/slices/termApiSlice.js @@ -0,0 +1,32 @@ +import { apiSlice } from "./apiSlice"; + +const TERM_URL = "/api/term"; + +export const termApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + GetCurTerm: builder.query({ + query: () => ({ + url: `${TERM_URL}/`, + method: "GET", + }), + }), + GetCurWeek: builder.query({ + query: () => ({ + url: `${TERM_URL}/week`, + method: "GET", + }), + }), + GetRemainingWeeks: builder.query({ + query: () => ({ + url: `${TERM_URL}/remaining`, + method: "GET", + }), + }), + }), +}); + +export const { + useGetCurTermQuery, + useGetCurWeekQuery, + useGetRemainingWeeksQuery, +} = termApi;