From 4007e2b582f3af8f2d0b8b0614a2baa9a1aa02af Mon Sep 17 00:00:00 2001 From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com> Date: Tue, 26 Mar 2024 18:09:54 +0545 Subject: [PATCH] Feat reviewstate api integration (#1376) * feat updateReviewState: post update review-state api integration * feat commonUtils: function to convert camel case to readable format * feat submissionTable: reviewState add to table column, update reviewState status on table * fix submissionModel: type fix * fix submissionReviewState: reviewState key add to submissionSlice * fix submissionDetails: update submissionDetails on reviewState update --- src/frontend/src/api/SubmissionService.ts | 35 ++++++++ .../ProjectSubmissions/SubmissionsTable.tsx | 16 +++- .../UpdateReviewStatusModal.tsx | 83 ++++++++++++++----- .../src/models/submission/submissionModel.ts | 2 +- .../src/store/slices/SubmissionSlice.ts | 37 ++++++++- src/frontend/src/store/types/ISubmissions.ts | 6 +- src/frontend/src/utilfunctions/commonUtils.ts | 4 + src/frontend/src/views/SubmissionDetails.tsx | 5 +- 8 files changed, 161 insertions(+), 27 deletions(-) diff --git a/src/frontend/src/api/SubmissionService.ts b/src/frontend/src/api/SubmissionService.ts index 2ba55763b7..9d6a6b18fc 100644 --- a/src/frontend/src/api/SubmissionService.ts +++ b/src/frontend/src/api/SubmissionService.ts @@ -1,4 +1,5 @@ import CoreModules from '@/shared/CoreModules'; +import { CommonActions } from '@/store/slices/CommonSlice'; import { ProjectActions } from '@/store/slices/ProjectSlice'; // import { HomeProjectCardModel } from '@/models/home/homeModel'; import { SubmissionActions } from '@/store/slices/SubmissionSlice'; @@ -114,3 +115,37 @@ export const SubmissionTableService: Function = (url: string, payload) => { await fetchSubmissionTable(url, payload); }; }; + +export const UpdateReviewStateService: Function = (url: string) => { + return async (dispatch) => { + const UpdateReviewState = async (url: string) => { + try { + dispatch(SubmissionActions.UpdateReviewStateLoading(true)); + const response = await CoreModules.axios.post(url); + dispatch(SubmissionActions.UpdateSubmissionTableDataReview(response.data)); + dispatch( + SubmissionActions.SetUpdateReviewStatusModal({ + toggleModalStatus: false, + projectId: null, + instanceId: null, + taskId: null, + reviewState: '', + }), + ); + dispatch(SubmissionActions.UpdateReviewStateLoading(false)); + } catch (error) { + dispatch( + CommonActions.SetSnackBar({ + open: true, + message: 'Failed to update review state.', + variant: 'error', + duration: 2000, + }), + ); + dispatch(SubmissionActions.UpdateReviewStateLoading(false)); + } + }; + + await UpdateReviewState(url); + }; +}; diff --git a/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx b/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx index a8bf4b61a5..2cafde9e42 100644 --- a/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx +++ b/src/frontend/src/components/ProjectSubmissions/SubmissionsTable.tsx @@ -21,6 +21,7 @@ import filterParams from '@/utilfunctions/filterParams'; import UpdateReviewStatusModal from '@/components/ProjectSubmissions/UpdateReviewStatusModal'; import { projectInfoType } from '@/models/project/projectModel'; import { useAppSelector } from '@/types/reduxTypes'; +import { camelToFlat } from '@/utilfunctions/commonUtils'; type filterType = { task_id: string | null; @@ -406,6 +407,16 @@ const SubmissionsTable = ({ toggleView }) => { rowClassName="snRow" dataFormat={(row, _, index) => {index + 1}} /> + ( + + {row?.__system?.reviewState ? camelToFlat(row?.__system?.reviewState) : '-'} + + )} + /> {updatedSubmissionFormFields?.map((field: any): React.ReactNode | null => { if (field) { return ( @@ -446,7 +457,10 @@ const SubmissionsTable = ({ toggleView }) => { dispatch( SubmissionActions.SetUpdateReviewStatusModal({ toggleModalStatus: true, - submissionId: row?.meta?.instanceID, + instanceId: row?.meta?.instanceID, + taskId: row?.phonenumber, + projectId: decodedId, + reviewState: row?.__system?.reviewState, }), ); }} diff --git a/src/frontend/src/components/ProjectSubmissions/UpdateReviewStatusModal.tsx b/src/frontend/src/components/ProjectSubmissions/UpdateReviewStatusModal.tsx index 49b0b0ef31..c104ee4ee3 100644 --- a/src/frontend/src/components/ProjectSubmissions/UpdateReviewStatusModal.tsx +++ b/src/frontend/src/components/ProjectSubmissions/UpdateReviewStatusModal.tsx @@ -1,11 +1,12 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Modal } from '@/components/common/Modal'; -import CoreModules from '@/shared/CoreModules'; import { useDispatch } from 'react-redux'; import { SubmissionActions } from '@/store/slices/SubmissionSlice'; import { reviewListType } from '@/models/submission/submissionModel'; +import { UpdateReviewStateService } from '@/api/SubmissionService'; import TextArea from '../common/TextArea'; import Button from '../common/Button'; +import { useAppSelector } from '@/types/reduxTypes'; const reviewList: reviewListType[] = [ { @@ -15,7 +16,7 @@ const reviewList: reviewListType[] = [ hoverClass: 'hover:fmtm-text-[#40B449] hover:fmtm-border-[#40B449]', }, { - id: 'hasIssue', + id: 'hasIssues', title: 'Has Issue', className: 'fmtm-bg-[#E9DFCF] fmtm-text-[#D99F00] fmtm-border-[#D99F00]', hoverClass: 'hover:fmtm-text-[#D99F00] hover:fmtm-border-[#D99F00]', @@ -30,9 +31,35 @@ const reviewList: reviewListType[] = [ const UpdateReviewStatusModal = () => { const dispatch = useDispatch(); - const [reviewStatus, setReviewStatus] = useState(''); - const [noteComments, setNoteComments] = useState(''); - const updateReviewStatusModal = CoreModules.useAppSelector((state) => state.submission.updateReviewStatusModal); + const [noteComments, setNoteComments] = useState(''); + const [error, setError] = useState(''); + const [reviewStatus, setReviewStatus] = useState(''); + const updateReviewStatusModal = useAppSelector((state) => state.submission.updateReviewStatusModal); + const updateReviewStateLoading = useAppSelector((state) => state.submission.updateReviewStateLoading); + + useEffect(() => { + setReviewStatus(updateReviewStatusModal.reviewState); + }, [updateReviewStatusModal.reviewState]); + + const handleStatusUpdate = () => { + if (!updateReviewStatusModal.instanceId || !updateReviewStatusModal.projectId || !updateReviewStatusModal.taskId) { + return; + } + + if (!reviewStatus) { + setError('Review state needs to be selected.'); + return; + } + dispatch( + UpdateReviewStateService( + `${import.meta.env.VITE_API_URL}/submission/update_review_state/${ + updateReviewStatusModal.projectId + }?project_id=${updateReviewStatusModal.projectId}&task_id=${parseInt( + updateReviewStatusModal.taskId, + )}&instance_id=${updateReviewStatusModal.instanceId}&review_state=${reviewStatus}`, + ), + ); + }; return ( { className="!fmtm-w-fit !fmtm-outline-none fmtm-rounded-xl" description={ - - {reviewList.map((reviewBtn) => ( - setReviewStatus(reviewBtn.id)} - > - {reviewBtn.title} - - ))} + + + {reviewList.map((reviewBtn) => ( + setReviewStatus(reviewBtn.id)} + > + {reviewBtn.title} + + ))} + + {error && {error}} { SubmissionActions.SetUpdateReviewStatusModal({ toggleModalStatus: false, submissionId: null, + instanceId: null, + taskId: null, + reviewState: '', }), ); }} /> {}} + onClick={handleStatusUpdate} /> } open={updateReviewStatusModal.toggleModalStatus} onOpenChange={(value) => { + setError(''); dispatch( SubmissionActions.SetUpdateReviewStatusModal({ toggleModalStatus: value, - submissionId: null, + projectId: null, + instanceId: null, + taskId: null, + reviewState: '', }), ); }} diff --git a/src/frontend/src/models/submission/submissionModel.ts b/src/frontend/src/models/submission/submissionModel.ts index a09e698d71..d5bb0dccc3 100644 --- a/src/frontend/src/models/submission/submissionModel.ts +++ b/src/frontend/src/models/submission/submissionModel.ts @@ -29,7 +29,7 @@ export type taskDataTypes = { }; export type submissionTableDataTypes = { - results: []; + results: any[]; pagination: { total: number | null; page: number | null; diff --git a/src/frontend/src/store/slices/SubmissionSlice.ts b/src/frontend/src/store/slices/SubmissionSlice.ts index ea42f09040..a4ad76d74e 100644 --- a/src/frontend/src/store/slices/SubmissionSlice.ts +++ b/src/frontend/src/store/slices/SubmissionSlice.ts @@ -25,7 +25,14 @@ const initialState: SubmissionStateTypes = { submissionTableRefreshing: false, validatedVsMappedInfographics: [], validatedVsMappedLoading: false, - updateReviewStatusModal: { toggleModalStatus: false, submissionId: null }, + updateReviewStatusModal: { + toggleModalStatus: false, + instanceId: null, + taskId: null, + projectId: null, + reviewState: '', + }, + updateReviewStateLoading: false, }; const SubmissionSlice = createSlice({ @@ -74,6 +81,34 @@ const SubmissionSlice = createSlice({ SetUpdateReviewStatusModal(state, action) { state.updateReviewStatusModal = action.payload; }, + UpdateReviewStateLoading(state, action) { + state.updateReviewStateLoading = action.payload; + }, + UpdateSubmissionTableDataReview(state, action) { + const updatedSubmission = action.payload; + + // submission-instance table update + if (state.submissionTableData.results.length > 0) { + const updatedSubmissionDataList = state.submissionTableData.results.map((submissionData: any) => { + if (updatedSubmission.instanceId === submissionData.meta.instanceID) { + return { + ...submissionData, + __system: { ...submissionData.__system, reviewState: updatedSubmission.reviewState }, + }; + } + return submissionData; + }); + state.submissionTableData.results = updatedSubmissionDataList; + } + + // submission-instance key value pair update + if (state.submissionDetails) { + state.submissionDetails = { + ...state.submissionDetails, + __system: { ...state.submissionDetails.__system, reviewState: updatedSubmission.reviewState }, + }; + } + }, }, }); diff --git a/src/frontend/src/store/types/ISubmissions.ts b/src/frontend/src/store/types/ISubmissions.ts index e5dcde9721..fcb6fdc98d 100644 --- a/src/frontend/src/store/types/ISubmissions.ts +++ b/src/frontend/src/store/types/ISubmissions.ts @@ -21,9 +21,13 @@ export type SubmissionStateTypes = { validatedVsMappedInfographics: validatedVsMappedInfographicsTypes[]; validatedVsMappedLoading: boolean; updateReviewStatusModal: updateReviewStatusModal; + updateReviewStateLoading: boolean; }; type updateReviewStatusModal = { toggleModalStatus: boolean; - submissionId: string | null; + instanceId: string | null; + taskId: string | null; + projectId: number | null; + reviewState: string; }; diff --git a/src/frontend/src/utilfunctions/commonUtils.ts b/src/frontend/src/utilfunctions/commonUtils.ts index ea5cfc2b47..e019ef4b78 100644 --- a/src/frontend/src/utilfunctions/commonUtils.ts +++ b/src/frontend/src/utilfunctions/commonUtils.ts @@ -5,3 +5,7 @@ export const isInputEmpty = (text: string): boolean => { const trimmedText = text.trim(); return trimmedText === ''; }; + +export const camelToFlat = (word: string): string => ( + (word = word.replace(/[A-Z]/g, ' $&')), word[0].toUpperCase() + word.slice(1) +); diff --git a/src/frontend/src/views/SubmissionDetails.tsx b/src/frontend/src/views/SubmissionDetails.tsx index ce97851142..5276569263 100644 --- a/src/frontend/src/views/SubmissionDetails.tsx +++ b/src/frontend/src/views/SubmissionDetails.tsx @@ -160,7 +160,10 @@ const SubmissionDetails = () => { dispatch( SubmissionActions.SetUpdateReviewStatusModal({ toggleModalStatus: true, - submissionId: paramsInstanceId, + instanceId: paramsInstanceId, + projectId: decodedProjectId, + taskId: taskId, + reviewState: submissionDetails?.__system?.reviewState, }), ); }}
{error}