From 0a0302d4445b1d644a613dca213e4f439612b5af Mon Sep 17 00:00:00 2001 From: sayali-2308 Date: Thu, 7 May 2026 05:19:11 -0400 Subject: [PATCH 1/2] fix: fix reviewer feedback issues - load reviewers from config, fix auth token, fix React Fragment key --- .../prAnalytics/weeklyGradingActions.js | 19 ++- .../PRGradingScreen/PRGradingScreen.jsx | 8 +- .../PRGradingScreen/PRGradingTest.jsx | 4 +- src/components/PRGradingScreen/index.jsx | 118 ++++++++++++++---- src/utils/URL.js | 72 ++--------- 5 files changed, 121 insertions(+), 100 deletions(-) diff --git a/src/actions/prAnalytics/weeklyGradingActions.js b/src/actions/prAnalytics/weeklyGradingActions.js index 067a6fc0c5..ed3b3cbb65 100644 --- a/src/actions/prAnalytics/weeklyGradingActions.js +++ b/src/actions/prAnalytics/weeklyGradingActions.js @@ -1,15 +1,12 @@ import axios from 'axios'; import { ENDPOINTS } from '../../utils/URL'; -export const getWeeklyGrading = (teamCode, date, token) => async dispatch => { +export const getWeeklyGrading = (teamCode, date) => async dispatch => { try { const params = { team: teamCode }; if (date) params.date = date; - const response = await axios.get(ENDPOINTS.WEEKLY_GRADING, { - params, - headers: { Authorization: `${token}` }, - }); + const response = await axios.get(ENDPOINTS.WEEKLY_GRADING, { params }); return response.data; } catch (error) { dispatch({ type: 'SET_ERROR', error: error.message }); @@ -17,13 +14,13 @@ export const getWeeklyGrading = (teamCode, date, token) => async dispatch => { } }; -export const saveWeeklyGrading = (teamCode, date, gradings, token) => async dispatch => { +export const saveWeeklyGrading = (teamCode, date, gradings) => async dispatch => { try { - const response = await axios.post( - ENDPOINTS.WEEKLY_GRADING_SAVE, - { teamCode, date, gradings }, - { headers: { Authorization: `${token}` } }, - ); + const response = await axios.post(ENDPOINTS.WEEKLY_GRADING_SAVE, { + teamCode, + date, + gradings, + }); return response.data; } catch (error) { dispatch({ type: 'SET_ERROR', error: error.message }); diff --git a/src/components/PRGradingScreen/PRGradingScreen.jsx b/src/components/PRGradingScreen/PRGradingScreen.jsx index c52470326e..579d17c7a2 100644 --- a/src/components/PRGradingScreen/PRGradingScreen.jsx +++ b/src/components/PRGradingScreen/PRGradingScreen.jsx @@ -1,6 +1,6 @@ import axios from 'axios'; import PropTypes from 'prop-types'; -import { useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Button, Card, Col, Container, Row } from 'react-bootstrap'; import { useDispatch, useSelector } from 'react-redux'; import { v4 as uuidv4 } from 'uuid'; @@ -315,8 +315,8 @@ const PRGradingScreen = ({ teamData, reviewers }) => { {reviewerData.map(reviewer => ( - <> - + + {reviewer.reviewer} { )} - + ))} diff --git a/src/components/PRGradingScreen/PRGradingTest.jsx b/src/components/PRGradingScreen/PRGradingTest.jsx index 0a6429d7c2..94eb192073 100644 --- a/src/components/PRGradingScreen/PRGradingTest.jsx +++ b/src/components/PRGradingScreen/PRGradingTest.jsx @@ -33,8 +33,6 @@ const PRGradingTest = () => { cfg.testDataType }${cfg.notes ? ` — ${cfg.notes}` : ''}`, fromDB: true, - reviewerCount: cfg.reviewerCount, - reviewerNames: cfg.reviewerNames || [], })); setDynamicTeams(fetched); } catch { @@ -50,7 +48,7 @@ const PRGradingTest = () => { const handleTeamSelect = teamId => { const team = allTeams.find(t => t.id === teamId); - history.push('/pr-grading-screen', { teamId, config: team }); + history.push('/pr-grading-screen', { teamId, teamName: team?.name }); }; const handleDeleteConfig = async (e, teamId) => { diff --git a/src/components/PRGradingScreen/index.jsx b/src/components/PRGradingScreen/index.jsx index fc465f994a..853a666433 100644 --- a/src/components/PRGradingScreen/index.jsx +++ b/src/components/PRGradingScreen/index.jsx @@ -1,37 +1,109 @@ +import { useEffect, useState } from 'react'; +import { Spinner } from 'react-bootstrap'; +import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; -import { v4 as uuidv4 } from 'uuid'; +import { getWeeklyGrading } from '../../actions/prAnalytics/weeklyGradingActions'; import { getDataByTeamId } from './mockData'; import PRGradingScreen from './PRGradingScreen'; -const STATIC_IDS = ['team1', 'team2', 'team3']; - const PRGradingScreenContainer = () => { const location = useLocation(); + const dispatch = useDispatch(); + const token = useSelector(state => state.auth.token); + const teamId = location.state?.teamId || 'team1'; - const config = location.state?.config || null; - - if (!STATIC_IDS.includes(teamId) && config) { - const reviewers = Array.from({ length: config.reviewerCount }, (_, i) => ({ - id: uuidv4(), - reviewer: config.reviewerNames?.[i] || `Reviewer ${i + 1}`, - prsNeeded: 10, - prsReviewed: 0, - gradedPrs: [], - })); - - const teamData = { - teamName: config.teamName, - dateRange: { - start: new Date().toLocaleDateString(), - end: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toLocaleDateString(), - }, + const isStaticTeam = ['team1', 'team2', 'team3'].includes(teamId); + + const [teamData, setTeamData] = useState(null); + const [reviewers, setReviewers] = useState([]); + const [loading, setLoading] = useState(!isStaticTeam); + + useEffect(() => { + if (isStaticTeam) { + const data = getDataByTeamId(teamId); + setTeamData(data.teamData); + setReviewers(data.reviewers); + return; + } + + // Dynamic team — fetch from backend + const fetchData = async () => { + setLoading(true); + try { + const today = new Date(); + const weekStart = new Date(today); + weekStart.setDate(today.getDate() - today.getDay()); + const weekEnd = new Date(weekStart); + weekEnd.setDate(weekStart.getDate() + 6); + + const formatDate = d => `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`; + + const weekStartStr = formatDate(weekStart); + const weekEndStr = formatDate(weekEnd); + + // Fetch team config to get reviewer names + const { default: axios } = await import('axios'); + const { ENDPOINTS } = await import('../../utils/URL'); + const configRes = await axios.get(ENDPOINTS.PR_GRADING_CONFIG); + const config = configRes.data.find(c => c._id === teamId); + + const teamName = config?.teamName || location.state?.teamName || teamId; + + setTeamData({ + teamCode: teamId, + teamName, + dateRange: { start: weekStartStr, end: weekEndStr }, + }); + + // Fetch existing grading data + const gradingData = await dispatch(getWeeklyGrading(teamId, weekStartStr, token)); + + const { v4: uuidv4 } = await import('uuid'); + + if (gradingData && gradingData.length > 0) { + const mapped = gradingData.map(entry => ({ + id: uuidv4(), + reviewer: entry.reviewer, + prsNeeded: entry.prsNeeded, + prsReviewed: entry.prsReviewed, + gradedPrs: (entry.gradedPrs || []).map(pr => ({ ...pr, id: uuidv4() })), + })); + setReviewers(mapped); + } else if (config?.reviewerNames?.length > 0) { + // No grading yet — populate from config reviewer names + const mapped = config.reviewerNames.map((name, index) => ({ + id: uuidv4(), + reviewer: name || `Reviewer ${index + 1}`, + prsNeeded: 10, + prsReviewed: 0, + gradedPrs: [], + })); + setReviewers(mapped); + } else { + setReviewers([]); + } + } catch { + setReviewers([]); + } finally { + setLoading(false); + } }; - return ; + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [teamId]); + + if (loading) { + return ( +
+ +
+ ); } - const data = getDataByTeamId(teamId); - return ; + if (!teamData) return
Error: Team not found
; + + return ; }; export default PRGradingScreenContainer; diff --git a/src/utils/URL.js b/src/utils/URL.js index 1d768d34e3..3d0689ad7b 100644 --- a/src/utils/URL.js +++ b/src/utils/URL.js @@ -29,7 +29,7 @@ export const ENDPOINTS = { MODIFY_BLUE_SQUARE: (userId, blueSquareId) => `${APIEndpoint}/userprofile/${userId}/infringements/${blueSquareId}`, - + // Blue Square Email Triggers BLUE_SQUARE_RESEND_INFRINGEMENT_EMAILS: () => `${APIEndpoint}/blueSquare/resend-infringement-emails-only`, @@ -38,6 +38,8 @@ export const ENDPOINTS = { USERS_ALLTEAMCODE_CHANGE: `${APIEndpoint}/AllTeamCodeChanges`, REPLACE_TEAM_CODE: `${APIEndpoint}/userProfile/replaceTeamCode`, + GET_JOB_FORMS: `${APIEndpoint}/jobForms`, + USERS_REMOVE_PROFILE_IMAGE: `${APIEndpoint}/userProfile/profileImage/remove`, USERS_UPDATE_PROFILE_FROM_WEBSITE: `${APIEndpoint}/userProfile/profileImage/imagefromwebsite`, USER_PROFILE_BASIC_INFO: source => `${APIEndpoint}/userProfile/basicInfo/${source}`, @@ -135,6 +137,7 @@ export const ENDPOINTS = { DELETE_WARNING_DESCRIPTION: warningId => `${APIEndpoint}/currentWarnings/${warningId}`, EDIT_WARNING_DESCRIPTION: () => `${APIEndpoint}/currentWarnings/edit`, GET_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, + GET_SPECIAL_WARNINGS: userId => `${APIEndpoint}/warnings/${userId}/special`, POST_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, DELETE_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, AUTHORIZE_WEEKLY_SUMMARY_REPORTS: () => @@ -243,11 +246,11 @@ export const ENDPOINTS = { if (startDate) params.append('startDate', startDate); if (endDate) params.append('endDate', endDate); if (groupBy) params.append('groupBy', groupBy); - + const queryString = params.toString(); return queryString ? `${url}?${queryString}` : url; }, - + INJURY_PROJECTS: () => `${APIEndpoint}/injuries/projects`, PRESETS: () => `${APIEndpoint}/rolePreset`, @@ -299,34 +302,6 @@ export const ENDPOINTS = { GET_TOTAL_COUNTRY_COUNT: () => `${APIEndpoint}/getTotalCountryCount`, - ANALYTICS_AVAILABLE_ROLES: () => `${APIEndpoint}/analytics/roles`, - - // Country Application Map Chart endpoints - COUNTRY_APPLICATION_DATA: (params = {}) => { - let url = `${APIEndpoint}/analytics/country-applications`; - const queryParams = new URLSearchParams(); - - if (params.roles && params.roles.length > 0) { - queryParams.append('roles', params.roles.join(',')); - } - // Include ALL so the API uses filter=all; omit timeFrame when startDate/endDate define the range - if (params.timeFrame) { - queryParams.append('timeFrame', params.timeFrame); - } - if (params.startDate) { - queryParams.append('startDate', params.startDate); - } - if (params.endDate) { - queryParams.append('endDate', params.endDate); - } - if (params.customDateRange) { - queryParams.append('customDateRange', 'true'); - } - - const queryString = queryParams.toString(); - return queryString ? `${url}?${queryString}` : url; - }, - GET_ALL_FOLLOWUPS: () => `${APIEndpoint}/followup`, SET_USER_FOLLOWUP: (userId, taskId) => `${APIEndpoint}/followup/${userId}/${taskId}`, @@ -434,8 +409,8 @@ export const ENDPOINTS = { BM_ORGS_WITH_LOCATION: `${APIEndpoint}/bm/orgLocation`, ORG_DETAILS: projectId => `${APIEndpoint}/bm/orgLocation/${projectId}`, BM_PROJECT_MEMBERS: projectId => `${APIEndpoint}/bm/project/${projectId}/users`, - BM_UPDATE_NAME_AND_UNIT: invtypeId => `${APIEndpoint}/bm/invtypes/material/${invtypeId}`, - BM_ITEM_UPDATE_HISTORY: invtypeId => `${APIEndpoint}/bm/invtypes/${invtypeId}/history`, + BM_UPDATE_NAME_AND_UNIT :invtypeId => `${APIEndpoint}/bm/invtypes/material/${invtypeId}`, + BM_ITEM_UPDATE_HISTORY: invtypeId =>`${APIEndpoint}/bm/invtypes/${invtypeId}/history`, PROJECT_GLOBAL_DISTRIBUTION: `${APIEndpoint}/projectglobaldistribution`, @@ -480,8 +455,6 @@ export const ENDPOINTS = { USER_STATE_SELECTIONS_BATCH: `${APIEndpoint}/userstate/selections/batch`, USER_STATE_CATALOG_USAGE: key => `${APIEndpoint}/userstate/catalog/${key}/usage`, - HGN_FORM_GET_TEAM_MEMBERS_BY_SKILL: skill => `${APIEndpoint}/userProfile/skills/${skill}`, - CREATE_JOB_FORM: `${APIEndpoint}/jobforms`, UPDATE_JOB_FORM: `${APIEndpoint}/jobforms`, GET_JOB_FORM: formId => `${APIEndpoint}/jobforms/${formId}`, @@ -515,7 +488,7 @@ export const ENDPOINTS = { // event endpoint EVENTS: `${APIEndpoint}/events`, - EVENTS_BY_ID: (activityId) => `${APIEndpoint}/events/${activityId}`, + EVENT_BY_ID: id => `${APIEndpoint}/events/${id}`, EVENT_TYPES: `${APIEndpoint}/events/types`, EVENT_LOCATIONS: `${APIEndpoint}/events/locations`, EVENT_ATTENDANCE_STATS: `${APIEndpoint}/events/attendance/stats`, @@ -564,22 +537,8 @@ export const ENDPOINTS = { LB_LISTING_AVAILABILITY: `${APIEndpoint}/lb/listing/availability`, LB_LISTING_BOOK: `${APIEndpoint}/lb/listing/availability/booking`, HELP_CATEGORIES: `${APIEndpoint}/help-categories`, - HELP_REQUEST_CREATE: `${APIEndpoint}/helprequest/create`, APPLICANT_SOURCES: `${APIEndpoint}/applicant-analytics/applicant-sources`, - OPT_STATUS_BREAKDOWN: (startDate, endDate, role) => { - let url = `${APIEndpoint}/analytics/opt-status`; - const params = []; - - if (startDate) params.push(`startDate=${startDate}`); - if (endDate) params.push(`endDate=${endDate}`); - if (role) params.push(`role=${role}`); - - return params.length > 0 ? `${url}?${params.join("&")}` : url; -}, - - - // job analytics HOURS_PLEDGED: `${APIEndpoint}/analytics/hours-pledged`, JOB_HITS_AND_APPLICATIONS: `${APIEndpoint}/analytics/job-hits-and-applications`, @@ -632,11 +591,6 @@ export const ENDPOINTS = { WEEKLY_GRADING_SAVE: `${APIEndpoint}/weekly-grading/save`, // Education Portal endpoints - PROGRESS_EDUCATOR_STUDENT: studentId => `${APIEndpoint}/progress/educator/student-progress/${studentId}`, - EDUCATION_TASKS_BY_STUDENT: studentId => `${APIEndpoint}/education-tasks/student/${studentId}`, - EDUCATION_TASK: taskId => `${APIEndpoint}/education-tasks/${taskId}`, - EDUCATION_TASK_STATUS: taskId => `${APIEndpoint}/education-tasks/${taskId}/status`, - STUDENT_PROFILE: `${APIEndpoint}/student/profile`, STUDENT_SUBJECT_TASKS: subjectId => `${APIEndpoint}/student/profile/subject/${subjectId}`, EDUCATOR_ASSIGN_ATOMS: () => `${APIEndpoint}/educator/assign-atoms`, @@ -661,10 +615,10 @@ export const ENDPOINTS = { KI_CALENDAR_EVENTS: (month, year) => `${APIEndpoint}/kitchenandinventory/calendar?month=${month}&year=${year}`, // Help Request & Feedback Modal endpoints - HGN_FORM_RANKED: `${APIEndpoint}/hgnform/ranked`, - HELP_REQUEST_CHECK_MODAL: userId => `${APIEndpoint}/helprequest/check-modal/${userId}`, - FEEDBACK_CLOSE_PERMANENTLY: `${APIEndpoint}/feedback/close-permanently`, - FEEDBACK_SUBMIT: `${APIEndpoint}/feedback/submit`, +HGN_FORM_RANKED: `${APIEndpoint}/hgnform/ranked`, +HELP_REQUEST_CHECK_MODAL: userId => `${APIEndpoint}/helprequest/check-modal/${userId}`, +FEEDBACK_CLOSE_PERMANENTLY: `${APIEndpoint}/feedback/close-permanently`, +FEEDBACK_SUBMIT: `${APIEndpoint}/feedback/submit`, // application time analytics APPLICATION_TIME_DATA: (startDate, endDate, roles) => { let url = `${APIEndpoint}/analytics/application-time?`; From 2227cb353b9bfea886135054303d88ee797a0ab7 Mon Sep 17 00:00:00 2001 From: sayali-2308 Date: Sat, 9 May 2026 17:54:33 -0400 Subject: [PATCH 2/2] fix: auto-fill reviewer names based on count and set prsNeeded based on testDataType --- src/components/PRGradingScreen/index.jsx | 29 ++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/components/PRGradingScreen/index.jsx b/src/components/PRGradingScreen/index.jsx index 853a666433..0cee00087c 100644 --- a/src/components/PRGradingScreen/index.jsx +++ b/src/components/PRGradingScreen/index.jsx @@ -69,18 +69,33 @@ const PRGradingScreenContainer = () => { gradedPrs: (entry.gradedPrs || []).map(pr => ({ ...pr, id: uuidv4() })), })); setReviewers(mapped); - } else if (config?.reviewerNames?.length > 0) { - // No grading yet — populate from config reviewer names - const mapped = config.reviewerNames.map((name, index) => ({ + } else { + // No grading yet — populate from config using reviewerCount, auto-fill missing names + const count = config?.reviewerCount || 0; + const names = config?.reviewerNames || []; + const getPrsNeeded = dataType => { + switch (dataType) { + case 'minimal': + return 1; + case 'mixed': + return 5; + case 'edge cases': + return 12; + case 'custom': + return 10; + default: + return 10; + } + }; + + const mapped = Array.from({ length: count }, (_, index) => ({ id: uuidv4(), - reviewer: name || `Reviewer ${index + 1}`, - prsNeeded: 10, + reviewer: names[index] || `Reviewer ${index + 1}`, + prsNeeded: getPrsNeeded(config?.testDataType), prsReviewed: 0, gradedPrs: [], })); setReviewers(mapped); - } else { - setReviewers([]); } } catch { setReviewers([]);