From b53bf8650107b48eedab55f71872922b5910e42c Mon Sep 17 00:00:00 2001 From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com> Date: Thu, 15 Feb 2024 19:49:01 +0545 Subject: [PATCH] feat: improve submissions dynamic filtering (#1217) * fix submissionTable: filterObj key name change, reviewStateData constant add * feat: filters on submission table * fix inputTextField: input label fix * fix submissionTable: submitted by textField add * feat customDatePicker: react-datepicker add * fix projectSubmissions: datepicker add & payload add for api fetch * fix projectSubmissions: submissionFilters UI enhancement * fix projectSubmissions: toggle infographics/table view UI re-arrangement * feat pieChart: legend add * fix submissionInfographics: dynamic value for projectProgress pieChart * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: sujanadh Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/frontend/package.json | 2 + src/frontend/pnpm-lock.yaml | 79 +++++ src/frontend/src/api/SubmissionService.ts | 8 +- .../ProjectSubmissions/ProjectInfo.tsx | 4 +- .../SubmissionsInfographics.tsx | 36 ++- .../ProjectSubmissions/SubmissionsTable.tsx | 296 +++++++----------- .../components/common/CustomDatePicker.tsx | 22 ++ .../src/components/common/InputTextField.tsx | 16 +- .../src/components/common/PieChart.tsx | 11 +- .../constants/projectSubmissionsConstants.ts | 9 + src/frontend/src/index.css | 14 + src/frontend/src/views/ProjectSubmissions.tsx | 47 +-- 12 files changed, 316 insertions(+), 228 deletions(-) create mode 100644 src/frontend/src/components/common/CustomDatePicker.tsx create mode 100644 src/frontend/src/constants/projectSubmissionsConstants.ts diff --git a/src/frontend/package.json b/src/frontend/package.json index e98f098e3a..5d65bc8a84 100755 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -65,6 +65,7 @@ "axios": "^1.2.2", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", + "date-fns": "^3.3.1", "env-cmd": "^10.1.0", "eslint": "^8.44.0", "eslint-config-prettier": "^8.8.0", @@ -79,6 +80,7 @@ "pako": "^2.1.0", "qrcode-generator": "^1.4.4", "react": "^17.0.2", + "react-datepicker": "^6.1.0", "react-dom": "^17.0.2", "react-lazy-load-image-component": "^1.5.6", "react-loading-skeleton": "^3.1.0", diff --git a/src/frontend/pnpm-lock.yaml b/src/frontend/pnpm-lock.yaml index f3caeae63f..31db273d5b 100644 --- a/src/frontend/pnpm-lock.yaml +++ b/src/frontend/pnpm-lock.yaml @@ -71,6 +71,9 @@ dependencies: clsx: specifier: ^2.0.0 version: 2.0.0 + date-fns: + specifier: ^3.3.1 + version: 3.3.1 env-cmd: specifier: ^10.1.0 version: 10.1.0 @@ -113,6 +116,9 @@ dependencies: react: specifier: ^17.0.2 version: 17.0.2 + react-datepicker: + specifier: ^6.1.0 + version: 6.1.0(react-dom@17.0.2)(react@17.0.2) react-dom: specifier: ^17.0.2 version: 17.0.2(react@17.0.2) @@ -1810,6 +1816,13 @@ packages: '@floating-ui/utils': 0.1.6 dev: false + /@floating-ui/dom@1.6.2: + resolution: {integrity: sha512-xymkSSowKdGqo0SRr2Mp4czH5A8o2Pum35PAD0ftb3gCcPacWzwhvtUeUqmVXm9EVtm2hThD/lRrFNcahMOaSQ==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.2.1 + dev: false + /@floating-ui/react-dom@2.0.2(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==} peerDependencies: @@ -1821,10 +1834,38 @@ packages: react-dom: 17.0.2(react@17.0.2) dev: false + /@floating-ui/react-dom@2.0.8(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.6.2 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + dev: false + + /@floating-ui/react@0.26.9(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-p86wynZJVEkEq2BBjY/8p2g3biQ6TlgT4o/3KgFKyTWoJLU1GZ8wpctwRqtkEl2tseYA+kw7dBAIDFcednfI5w==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/react-dom': 2.0.8(react-dom@17.0.2)(react@17.0.2) + '@floating-ui/utils': 0.2.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + tabbable: 6.2.0 + dev: false + /@floating-ui/utils@0.1.6: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: false + /@floating-ui/utils@0.2.1: + resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + dev: false + /@humanwhocodes/config-array@0.11.11: resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} @@ -4047,6 +4088,10 @@ packages: clsx: 2.0.0 dev: false + /classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + dev: false + /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -4281,6 +4326,10 @@ packages: whatwg-url: 12.0.1 dev: true + /date-fns@3.3.1: + resolution: {integrity: sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==} + dev: false + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -6717,6 +6766,21 @@ packages: dependencies: quickselect: 2.0.0 + /react-datepicker@6.1.0(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-8uz+hAOpvHqZGvD4Ky1hJ0/tLI4S9B0Gu9LV7LtLxRKXODs/xrxEay0aMVp7AW9iizTeImZh/6aA00fFaRZpJw==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 + react-dom: ^16.9.0 || ^17 || ^18 + dependencies: + '@floating-ui/react': 0.26.9(react-dom@17.0.2)(react@17.0.2) + classnames: 2.5.1 + date-fns: 3.3.1 + prop-types: 15.8.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + react-onclickoutside: 6.13.0(react-dom@17.0.2)(react@17.0.2) + dev: false + /react-dom@17.0.2(react@17.0.2): resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} peerDependencies: @@ -6761,6 +6825,16 @@ packages: react: 17.0.2 dev: false + /react-onclickoutside@6.13.0(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==} + peerDependencies: + react: ^15.5.x || ^16.x || ^17.x || ^18.x + react-dom: ^15.5.x || ^16.x || ^17.x || ^18.x + dependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + dev: false + /react-redux@8.1.3(@types/react-dom@17.0.21)(@types/react@17.0.67)(react-dom@17.0.2)(react@17.0.2)(redux@4.2.1): resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==} peerDependencies: @@ -7495,6 +7569,10 @@ packages: tslib: 2.6.2 dev: false + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + /tailwind-merge@1.14.0: resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} dev: false @@ -8320,6 +8398,7 @@ packages: /workbox-google-analytics@7.0.0: resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} + deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained dependencies: workbox-background-sync: 7.0.0 workbox-core: 7.0.0 diff --git a/src/frontend/src/api/SubmissionService.ts b/src/frontend/src/api/SubmissionService.ts index c6d6859b2b..40915ce7ab 100644 --- a/src/frontend/src/api/SubmissionService.ts +++ b/src/frontend/src/api/SubmissionService.ts @@ -112,12 +112,12 @@ export const SubmissionFormFieldsService: Function = (url: string) => { }; }; -export const SubmissionTableService: Function = (url: string) => { +export const SubmissionTableService: Function = (url: string, payload) => { return async (dispatch) => { - const fetchSubmissionTable = async (url: string) => { + const fetchSubmissionTable = async (url: string, payload) => { try { dispatch(SubmissionActions.SetSubmissionTableLoading(true)); - const response = await CoreModules.axios.get(url); + const response = await CoreModules.axios.get(url, { params: payload }); const submissionTableData: any = response.data; dispatch(SubmissionActions.SetSubmissionTable(submissionTableData)); dispatch(SubmissionActions.SetSubmissionTableLoading(false)); @@ -128,6 +128,6 @@ export const SubmissionTableService: Function = (url: string) => { } }; - await fetchSubmissionTable(url); + await fetchSubmissionTable(url, payload); }; }; diff --git a/src/frontend/src/components/ProjectSubmissions/ProjectInfo.tsx b/src/frontend/src/components/ProjectSubmissions/ProjectInfo.tsx index 519bffcfd2..4e701d99df 100644 --- a/src/frontend/src/components/ProjectSubmissions/ProjectInfo.tsx +++ b/src/frontend/src/components/ProjectSubmissions/ProjectInfo.tsx @@ -43,10 +43,8 @@ const ProjectInfo = () => { ); - const widthStyle = window.innerWidth >= 640 ? { width: 'calc(100% - 80px)' } : { width: '100%' }; - return ( -
+

{ +const SubmissionsInfographics = ({ toggleView }) => { const formSubmissionRef = useRef(null); const projectProgressRef = useRef(null); const totalContributorsRef = useRef(null); @@ -106,6 +106,8 @@ const SubmissionsInfographics = () => { (state) => state.submission.validatedVsMappedInfographics, ); const validatedVsMappedLoading = CoreModules.useAppSelector((state) => state.submission.validatedVsMappedLoading); + const taskData = CoreModules.useAppSelector((state) => state.task.taskData); + const taskLoading = CoreModules.useAppSelector((state) => state.task.taskLoading); useEffect(() => { dispatch( @@ -146,18 +148,25 @@ const SubmissionsInfographics = () => {

); - // Test data for project progress - const featCount = 500; - const current = 450; - const remaining = featCount - current; - - const pieData = [ - { names: 'Current Progress', value: current }, - { names: 'Remaining', value: remaining }, + const projectProgressData = [ + { + names: 'Current', + value: + taskData?.submission_count > taskData?.feature_count || + (taskData?.submission_count === 0 && taskData?.feature_count === 0) + ? 100 + : taskData?.submission_count, + }, + { + names: 'Remaining', + value: + taskData?.submission_count > taskData?.feature_count ? 0 : taskData?.feature_count - taskData?.submission_count, + }, ]; return (
+ {toggleView}
{ cardRef={projectProgressRef} header="Project Progress" body={ - false ? ( + taskLoading ? ( - ) : pieData.length > 0 ? ( - ) : ( -
- No data available! -
+ ) } /> @@ -299,7 +304,6 @@ const SubmissionsInfographics = () => { } />
-
diff --git a/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx b/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx index 7aae1e50af..6f55abf406 100644 --- a/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx +++ b/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import AssetModules from '@/shared/AssetModules.js'; import { CustomSelect } from '@/components/common/Select.js'; import windowDimention from '@/hooks/WindowDimension'; @@ -9,22 +9,25 @@ import environment from '@/environment'; import { SubmissionsTableSkeletonLoader } from '@/components/ProjectSubmissions/ProjectSubmissionsSkeletonLoader.js'; import { Loader2 } from 'lucide-react'; import { SubmissionActions } from '@/store/slices/SubmissionSlice'; +import { reviewStateData } from '@/constants/projectSubmissionsConstants'; +import CustomDatePicker from '@/components/common/CustomDatePicker'; +import { format } from 'date-fns'; +import Button from '../common/Button'; type filterType = { - taskId: number | null; - submittedBy: string | null; - reviewState: string | null; - submittedDate: Date | null; + task_id: number | null; + submitted_by: string; + review_state: string | null; + submitted_date: string | null; }; -const SubmissionsTable = () => { +const SubmissionsTable = ({ toggleView }) => { const initialFilterState = { - taskId: null, - submittedBy: null, - reviewState: null, - submittedDate: null, + task_id: null, + submitted_by: '', + review_state: null, + submitted_date: null, }; - const [showFilter, setShowFilter] = useState(true); const [filter, setFilter] = useState(initialFilterState); const { windowSize } = windowDimention(); const dispatch = CoreModules.useAppDispatch(); @@ -39,19 +42,8 @@ const SubmissionsTable = () => { const submissionTableDataLoading = CoreModules.useAppSelector((state) => state.submission.submissionTableDataLoading); const submissionTableRefreshing = CoreModules.useAppSelector((state) => state.submission.submissionTableRefreshing); const taskInfo = CoreModules.useAppSelector((state) => state.task.taskInfo); - const [numberOfFilters, setNumberOfFilters] = useState(0); const [paginationPage, setPaginationPage] = useState(1); - - useEffect(() => { - let count = 0; - const filters = Object.keys(filter); - filters?.map((fltr) => { - if (filter[fltr]) { - count = count + 1; - } - }); - setNumberOfFilters(count); - }, [filter]); + const [submittedBy, setSubmittedBy] = useState(''); const updatedSubmissionFormFields = submissionFormFields?.map((formField) => { if (formField.type !== 'structure') { @@ -71,36 +63,25 @@ const SubmissionsTable = () => { }, []); useEffect(() => { - if (!filter.taskId) { + if (!filter.task_id) { dispatch( - SubmissionTableService( - `${import.meta.env.VITE_API_URL}/submission/submission_table/${decodedId}?page=${paginationPage}`, - ), + SubmissionTableService(`${import.meta.env.VITE_API_URL}/submission/submission_table/${decodedId}`, { + page: paginationPage, + ...filter, + }), ); } else { dispatch( - SubmissionTableService( - `${import.meta.env.VITE_API_URL}/submission/task_submissions/${decodedId}?task_id=${ - filter.taskId - }&page=${paginationPage}`, - ), + SubmissionTableService(`${import.meta.env.VITE_API_URL}/submission/task_submissions/${decodedId}`, { + page: paginationPage, + ...filter, + }), ); } - }, [paginationPage]); + }, [filter, paginationPage]); useEffect(() => { setPaginationPage(1); - if (!filter.taskId) { - dispatch( - SubmissionTableService(`${import.meta.env.VITE_API_URL}/submission/submission_table/${decodedId}?page=1`), - ); - } else { - dispatch( - SubmissionTableService( - `${import.meta.env.VITE_API_URL}/submission/task_submissions/${decodedId}?task_id=${filter.taskId}&page=1`, - ), - ); - } }, [filter]); const refreshTable = () => { @@ -108,23 +89,30 @@ const SubmissionsTable = () => { SubmissionFormFieldsService(`${import.meta.env.VITE_API_URL}/submission/submission_form_fields/${decodedId}`), ); dispatch(SubmissionActions.SetSubmissionTableRefreshing(true)); - if (!filter.taskId) { + if (!filter.task_id) { dispatch( - SubmissionTableService( - `${import.meta.env.VITE_API_URL}/submission/submission_table/${decodedId}?page=${paginationPage}`, - ), + SubmissionTableService(`${import.meta.env.VITE_API_URL}/submission/submission_table/${decodedId}`, { + page: paginationPage, + ...filter, + }), ); } else { dispatch( - SubmissionTableService( - `${import.meta.env.VITE_API_URL}/submission/task_submissions/${decodedId}?task_id=${ - filter.taskId - }&page=${paginationPage}`, - ), + SubmissionTableService(`${import.meta.env.VITE_API_URL}/submission/task_submissions/${decodedId}`, { + page: paginationPage, + ...filter, + }), ); } }; + useEffect(() => { + const timeoutId = setTimeout(() => { + setFilter((prev) => ({ ...prev, submitted_by: submittedBy })); + }, 500); + return () => clearTimeout(timeoutId); + }, [submittedBy, 500]); + const handleChangePage = ( e: React.ChangeEvent | React.KeyboardEvent, newPage: number, @@ -140,159 +128,109 @@ const SubmissionsTable = () => { setFilter(initialFilterState); }; - const TableFilter = () => ( -
-
-
-
-
- -
-

FILTER

-
-

{numberOfFilters}

-
-
- -
- {showFilter && ( -
+ function getValueByPath(obj: any, path: string) { + let value = obj; + path?.split('.')?.map((item) => { + if (path === 'start' || path === 'end') { + value = `${value[item]?.split('T')[0]} ${value[item]?.split('T')[1]}`; + } else if (item === 'point') { + value = `${value[item].type} (${value[item].coordinates})`; + } else { + value = value[item]; + } + }); + return value ? value : '-'; + } + + return ( +
+
+
+
value && setFilter((prev) => ({ ...prev, taskId: +value }))} - className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0" - /> -
-
- {}} - errorMsg="" - className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0" + onValueChange={(value) => value && setFilter((prev) => ({ ...prev, task_id: +value }))} + className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0 fmtm-bg-white" />
{}} + onValueChange={(value) => value && setFilter((prev) => ({ ...prev, review_state: value.toString() }))} errorMsg="" - className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0" + className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0 fmtm-bg-white" />
- {}} - errorMsg="" - className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0" + selectedDate={filter?.submitted_date} + setSelectedDate={(date) => + setFilter((prev) => ({ ...prev, submitted_date: format(new Date(date), 'yyyy-MM-dd') })) + } + className="fmtm-text-grey-700 fmtm-text-sm !fmtm-mb-0 fmtm-w-full" />
+
+

Submitted By

+
+ setSubmittedBy(e.target.value)} + > + search +
+
+
- )} - -
setShowFilter(!showFilter)} - > - +
+
+ + {toggleView}
-
- -
-
- ); - - function getValueByPath(obj: any, path: string) { - let value = obj; - path?.split('.')?.map((item) => { - if (path === 'start' || path === 'end') { - value = `${value[item]?.split('T')[0]} ${value[item]?.split('T')[1]}`; - } else if (item === 'point') { - value = `${value[item].type} (${value[item].coordinates})`; - } else { - value = value[item]; - } - }); - return value ? value : '-'; - } - - return ( -
- {submissionTableDataLoading || submissionFormFieldsLoading ? ( ) : ( diff --git a/src/frontend/src/components/common/CustomDatePicker.tsx b/src/frontend/src/components/common/CustomDatePicker.tsx new file mode 100644 index 0000000000..558ce7ead1 --- /dev/null +++ b/src/frontend/src/components/common/CustomDatePicker.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; + +const CustomDatePicker = ({ title, className, selectedDate, setSelectedDate }) => { + return ( +
+ {title && ( +

{title}

+ )} + setSelectedDate(date)} + className="fmtm-outline-none fmtm-border-[1px] fmtm-border-gray-300 fmtm-h-[2rem] fmtm-w-full fmtm-z-50 fmtm-px-2 fmtm-text-base fmtm-pt-1 hover" + placeholderText="YYYY/MM/DD" + dateFormat="yyyy/MM/dd" + /> +
+ ); +}; + +export default CustomDatePicker; diff --git a/src/frontend/src/components/common/InputTextField.tsx b/src/frontend/src/components/common/InputTextField.tsx index 5c695c9a00..6ee6e68c90 100644 --- a/src/frontend/src/components/common/InputTextField.tsx +++ b/src/frontend/src/components/common/InputTextField.tsx @@ -5,7 +5,7 @@ export const blockInvalidChar = (e) => ['e', 'E', '+', '-'].includes(e.key) && e interface IInputTextFieldProps { id?: string; - label: string; + label?: string; subLabel?: string | React.JSX.Element; onChange: (event: React.ChangeEvent) => void; onKeyDown?: (event: React.KeyboardEvent) => void; @@ -44,13 +44,15 @@ function InputTextField({ }: IInputTextFieldProps) { return (
-
-
-

{label}

- {required &&

*

} + {label && ( +
+
+

{label}

+ {required &&

*

} +
+ {subLabel &&

{subLabel}

}
- {subLabel &&

{subLabel}

} -
+ )}
diff --git a/src/frontend/src/components/common/PieChart.tsx b/src/frontend/src/components/common/PieChart.tsx index 7b54067e7e..21e90204f1 100644 --- a/src/frontend/src/components/common/PieChart.tsx +++ b/src/frontend/src/components/common/PieChart.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { PieChart, Pie, Sector, Cell, ResponsiveContainer, Tooltip } from 'recharts'; +import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts'; const COLORS = ['#F19C3C', '#D73F3F', '#FFB74D', '#EC407A']; @@ -38,6 +38,15 @@ const CustomPieChart = ({ data, dataKey, nameKey }) => { ))} + ); diff --git a/src/frontend/src/constants/projectSubmissionsConstants.ts b/src/frontend/src/constants/projectSubmissionsConstants.ts new file mode 100644 index 0000000000..e574d43819 --- /dev/null +++ b/src/frontend/src/constants/projectSubmissionsConstants.ts @@ -0,0 +1,9 @@ +type reviewStateDataType = { label: string; value: string }; + +export const reviewStateData: reviewStateDataType[] = [ + { label: 'Received', value: 'received' }, + { label: 'Has issues', value: 'hasIssues' }, + { label: 'Edited', value: 'edited' }, + { label: 'Approved', value: 'approved' }, + { label: 'Rejected', value: 'rejected' }, +]; diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css index f35428d486..e2a4665eeb 100755 --- a/src/frontend/src/index.css +++ b/src/frontend/src/index.css @@ -231,3 +231,17 @@ button { background-position: 50px 50px; } } + +/* react-date-picker */ +.react-datepicker-popper { + z-index: 9000; +} +.react-datepicker__day--selected { + background-color: #d73f3e; +} +.react-datepicker__day--selected:hover { + background-color: #bc2c2c; +} +.react-datepicker__day--keyboard-selected { + background-color: #fcc2c2; +} diff --git a/src/frontend/src/views/ProjectSubmissions.tsx b/src/frontend/src/views/ProjectSubmissions.tsx index 36116f0cce..93042cdf57 100644 --- a/src/frontend/src/views/ProjectSubmissions.tsx +++ b/src/frontend/src/views/ProjectSubmissions.tsx @@ -51,29 +51,40 @@ const ProjectSubmissions = () => { dispatch(GetProjectDashboard(`${import.meta.env.VITE_API_URL}/projects/project_dashboard/${decodedId}`)); }, []); + const ToggleView = () => ( +
+
+ setViewBy('infographics')} + /> +
+
+ setViewBy('table')} + /> +
+
+ ); + return ( -
+
-
- setViewBy('infographics')} - /> - setViewBy('table')} - /> -
- {viewBy === 'infographics' ? : } + {viewBy === 'infographics' ? ( + } /> + ) : ( + } /> + )}
);