From 197fea970e24d9cd54910dfca66c06edcd926ce4 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Mon, 25 Mar 2024 23:27:37 -0700 Subject: [PATCH 001/265] simplify and generalize getTimeEntriesForPeriod() --- .../TeamMemberTasks/TeamMemberTasks.jsx | 46 +++---------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index c26169018c..7003c4210b 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -120,48 +120,16 @@ const TeamMemberTasks = React.memo(props => { }; const getTimeEntriesForPeriod = async (selectedPeriod) => { - const oneDayAgo = moment() - .tz('America/Los_Angeles') - .subtract(1, 'days') - .format('YYYY-MM-DD'); - - const twoDaysAgo = moment() - .tz('America/Los_Angeles') - .subtract(2, 'days') - .format('YYYY-MM-DD'); - - const threeDaysAgo = moment() - .tz('America/Los_Angeles') - .subtract(3, 'days') - .format('YYYY-MM-DD'); - - const fourDaysAgo = moment() + if(isNaN(parseInt(selectedPeriod))) { + setTimeEntriesList([]); + } else { + const xDaysAgo = moment() .tz('America/Los_Angeles') - .subtract(4, 'days') + .subtract(parseInt(selectedPeriod), 'days') .format('YYYY-MM-DD'); - switch (selectedPeriod) { - case '1': - const oneDaysList = usersWithTimeEntries.filter(entry => moment(entry.dateOfWork).isAfter(oneDayAgo)); - setTimeEntriesList(oneDaysList); - break; - case '2': - const twoDaysList = usersWithTimeEntries.filter(entry => moment(entry.dateOfWork).isAfter(twoDaysAgo)); - setTimeEntriesList(twoDaysList); - break; - case '3': - const threeDaysList = usersWithTimeEntries.filter(entry => moment(entry.dateOfWork).isAfter(threeDaysAgo)); - setTimeEntriesList(threeDaysList); - break; - case '4': - const fourDaysList = usersWithTimeEntries.filter(entry => moment(entry.dateOfWork).isAfter(fourDaysAgo)); - setTimeEntriesList(fourDaysList); - break; - case '7': - setTimeEntriesList(usersWithTimeEntries); - break; - default: - setTimeEntriesList([]); + const xDaysList = usersWithTimeEntries.filter(entry => moment(entry.dateOfWork).isAfter(xDaysAgo)); + setTimeEntriesList(xDaysList); } setFinishLoading(true); From 3c82dc4fcd8b2992c7c45e7ec20a13f912c9cfd6 Mon Sep 17 00:00:00 2001 From: Charitha2009 <70010999+Charitha2009@users.noreply.github.com> Date: Tue, 12 Aug 2025 22:53:52 -0400 Subject: [PATCH 002/265] made changes to and added a new component education experience donut chart --- package-lock.json | 24 +- package.json | 8 +- .../EducationExperienceDonutChart.jsx | 358 ++++++++++++++++++ src/routes.jsx | 3 + yarn.lock | 44 +-- 5 files changed, 399 insertions(+), 38 deletions(-) create mode 100644 src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx diff --git a/package-lock.json b/package-lock.json index e515b98ef2..38549d0613 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "ajv": "^8.0.0", "ajv-keywords": "^5.1.0", "assert": "^2.1.0", - "axios": "^1.9.0", + "axios": "^1.11.0", "axios-mock-adapter": "^1.22.0", "bootstrap": "^4.5.3", "braces": "^3.0.3", @@ -79,7 +79,7 @@ "react-chartjs-2": "^5.3.0", "react-circular-progressbar": "^2.1.0", "react-collapsible": "^2.10.0", - "react-datepicker": "^4.8.0", + "react-datepicker": "^4.25.0", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", "react-icons": "^4.12.0", @@ -90,7 +90,7 @@ "react-router": "^5.3.4", "react-router-dom": "^5.2.0", "react-router-hash-link": "^2.3.1", - "react-select": "^5.7.2", + "react-select": "^5.10.2", "react-spinners": "^0.15.0", "react-sticky": "^6.0.3", "react-table": "^7.8.0", @@ -102,7 +102,7 @@ "reactjs-popup": "^2.0.5", "reactstrap": "^8.4.1", "read-excel-file": "^5.5.3", - "recharts": "^2.1.9", + "recharts": "^2.15.4", "redux": "^4.0.5", "redux-actions": "^2.6.5", "redux-concatenate-reducers": "^1.0.0", @@ -4698,16 +4698,16 @@ }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", - "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { @@ -6698,13 +6698,13 @@ } }, "node_modules/axios": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", - "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, diff --git a/package.json b/package.json index 19d783b87f..e704b3996b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "ajv": "^8.0.0", "ajv-keywords": "^5.1.0", "assert": "^2.1.0", - "axios": "^1.9.0", + "axios": "^1.11.0", "axios-mock-adapter": "^1.22.0", "bootstrap": "^4.5.3", "braces": "^3.0.3", @@ -76,7 +76,7 @@ "react-chartjs-2": "^5.3.0", "react-circular-progressbar": "^2.1.0", "react-collapsible": "^2.10.0", - "react-datepicker": "^4.8.0", + "react-datepicker": "^4.25.0", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", "react-icons": "^4.12.0", @@ -87,7 +87,7 @@ "react-router": "^5.3.4", "react-router-dom": "^5.2.0", "react-router-hash-link": "^2.3.1", - "react-select": "^5.7.2", + "react-select": "^5.10.2", "react-spinners": "^0.15.0", "react-sticky": "^6.0.3", "react-table": "^7.8.0", @@ -99,7 +99,7 @@ "reactjs-popup": "^2.0.5", "reactstrap": "^8.4.1", "read-excel-file": "^5.5.3", - "recharts": "^2.1.9", + "recharts": "^2.15.4", "redux": "^4.0.5", "redux-actions": "^2.6.5", "redux-concatenate-reducers": "^1.0.0", diff --git a/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx b/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx new file mode 100644 index 0000000000..8fea50fe0c --- /dev/null +++ b/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx @@ -0,0 +1,358 @@ +import React, { useMemo, useState, useEffect } from 'react'; +import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer, Label } from 'recharts'; +import DatePicker from 'react-datepicker'; +import Select from 'react-select'; +import 'react-datepicker/dist/react-datepicker.css'; + +/** ---------- Stable color mapping by category ---------- */ +const COLOR_BY_CATEGORY = { + 'High School': '#FF4D4F', + "Associate's Degree": '#FFC107', + "Bachelor's Degree": '#1890FF', + "Master's Degree": '#00C49F', + "Bachelor's Degree + Experience": '#8884D8', + "Master's Degree + Experience": '#00BFFF', +}; + +const ORDERED_CATEGORIES = [ + 'High School', + "Associate's Degree", + "Bachelor's Degree", + "Master's Degree", + "Bachelor's Degree + Experience", + "Master's Degree + Experience", +]; + +/** ---------- Dummy rows (have role & date so filters work) ---------- */ +const DUMMY_ROWS = [ + { category: "Master's Degree", value: 12, role: 'Frontend Developer', date: '2025-07-30' }, + { category: "Master's Degree", value: 10, role: 'Backend Developer', date: '2025-08-01' }, + { + category: "Master's Degree + Experience", + value: 15, + role: 'Frontend Developer', + date: '2025-08-02', + }, + { category: "Bachelor's Degree", value: 20, role: 'Backend Developer', date: '2025-07-28' }, + { + category: "Bachelor's Degree + Experience", + value: 18, + role: 'Data Engineer', + date: '2025-08-03', + }, + { category: "Associate's Degree", value: 9, role: 'Frontend Developer', date: '2025-07-25' }, + { category: 'High School', value: 6, role: 'QA Engineer', date: '2025-08-04' }, +]; + +/** ---------- Helpers ---------- */ +const toDateOnlyString = d => (d ? d.toISOString().split('T')[0] : null); + +const useIsMobile = (bp = 640) => { + const [w, setW] = useState(typeof window !== 'undefined' ? window.innerWidth : 1024); + useEffect(() => { + const onResize = () => setW(window.innerWidth); + window.addEventListener('resize', onResize); + return () => window.removeEventListener('resize', onResize); + }, []); + return w < bp; +}; + +const summarizeRolesForCenter = (selectedRoles, isMobile) => { + if (!selectedRoles?.length) return 'ALL ROLES'; + const names = selectedRoles.map(r => r.value); + if (!isMobile) return names.join(', '); + + // Mobile: show "FirstRole [+N more]" and clamp first role length + const first = names[0] || ''; + const firstClamped = first.length > 18 ? first.slice(0, 18) + '…' : first; + const rest = names.length - 1; + return rest > 0 ? `${firstClamped} +${rest} more` : firstClamped; +}; + +const formatDatesForCenter = (startDate, endDate) => { + if (!startDate && !endDate) return 'ALL DATES'; + return `${toDateOnlyString(startDate) || '…'} → ${toDateOnlyString(endDate) || '…'}`; +}; + +const EducationExperienceDonutChart = () => { + // Swap to fetched rows later; using dummy for now + const [rows] = useState(DUMMY_ROWS); + const [startDate, setStartDate] = useState(null); // All dates by default + const [endDate, setEndDate] = useState(null); + const [selectedRoles, setSelectedRoles] = useState([]); // All roles when empty + const [loading] = useState(false); + const [error, setError] = useState(null); + const isMobile = useIsMobile(640); + + /** Role dropdown options */ + const roleOptions = useMemo(() => { + const uniq = Array.from(new Set(rows.map(r => r.role))); + return uniq.map(r => ({ label: r, value: r })); + }, [rows]); + + /** Filter + aggregate into pie data */ + const data = useMemo(() => { + try { + const s = toDateOnlyString(startDate); + const e = toDateOnlyString(endDate); + const selected = new Set(selectedRoles.map(r => r.value)); + + const inRange = d => { + if (!s && !e) return true; + if (s && d < s) return false; + if (e && d > e) return false; + return true; + }; + const roleMatch = r => (selected.size === 0 ? true : selected.has(r)); + + const filtered = rows.filter(r => inRange(r.date) && roleMatch(r.role)); + + const byCat = filtered.reduce((acc, cur) => { + acc[cur.category] = (acc[cur.category] || 0) + cur.value; + return acc; + }, {}); + + return ORDERED_CATEGORIES.map(cat => ({ category: cat, value: byCat[cat] || 0 })).filter( + d => d.value > 0, + ); + } catch (err) { + setError('Failed to process data'); + return []; + } + }, [rows, startDate, endDate, selectedRoles]); + + const total = useMemo(() => data.reduce((sum, d) => sum + d.value, 0), [data]); + + /** Center text lines (roles / dates / total) */ + const centerLine1 = useMemo(() => summarizeRolesForCenter(selectedRoles, isMobile), [ + selectedRoles, + isMobile, + ]); + const centerLine2 = useMemo(() => formatDatesForCenter(startDate, endDate), [startDate, endDate]); + + /** Adaptive labels: + * - Desktop: outside with leader, "Category: Count (XX.X%)" + * - Mobile: inside slice, percent only; hide on tiny slices + */ + const renderLabel = props => { + const { cx, cy, midAngle, innerRadius, outerRadius, percent, name, value, payload } = props; + const RAD = Math.PI / 180; + const labelName = name || payload?.category || ''; + const pctText = `${(percent * 100).toFixed(1)}%`; + + if (isMobile) { + // Mobile: keep things clean—hide very small slices + if (percent < 0.08) return null; + const r = innerRadius + (outerRadius - innerRadius) * 0.5; + const x = cx + r * Math.cos(-midAngle * RAD); + const y = cy + r * Math.sin(-midAngle * RAD); + return ( + + {pctText} + + ); + } + + // Desktop: outside label + const r = outerRadius + 18; + const x = cx + r * Math.cos(-midAngle * RAD); + const y = cy + r * Math.sin(-midAngle * RAD); + const text = `${labelName}: ${value} (${pctText})`; + + return ( + cx ? 'start' : 'end'} + dominantBaseline="central" + fontSize={12} + fill="#111" + > + {text} + + ); + }; + + if (error) { + return
Something went wrong: {error}
; + } + + return ( +
+

+ Breakdown of Candidates by Experience and Educational Level +

+ + {/* Filters */} +
+
+ Dates +
+ + +
+
+ +
+ Role + { - // console.log('Date filter changed to:', e.target.value); - setDateFilter(e.target.value); - }} - className="filter-select-job-analytics" + onChange={e => setDateFilter(e.target.value)} + className={styles.filterSelectJobAnalytics} > @@ -194,15 +183,12 @@ function JobAnalytics() {
{/* Role Filter */} -
-
Role
+
+
Role
+ {chartData.length > 0 ? ( ) : ( -
+
No data available. Please add some applicant volunteer ratio data.
)} diff --git a/src/components/ApplicantVolunteerRatio/ApplicantVolunteerRatio.module.css b/src/components/ApplicantVolunteerRatio/ApplicantVolunteerRatio.module.css new file mode 100644 index 0000000000..09cdd09c2a --- /dev/null +++ b/src/components/ApplicantVolunteerRatio/ApplicantVolunteerRatio.module.css @@ -0,0 +1,38 @@ +/* Layout */ +.container { + max-width: 900px; + margin: 0 auto; + padding: 24px; +} + +.header { + margin: 0 0 8px 0; +} + +/* Controls row */ +.controls { + display: flex; + gap: 16px; + margin-bottom: 24px; + flex-wrap: wrap; +} + +/* Date controls */ +.dateGroup { display: flex; align-items: center; gap: 8px; } +.label { font-weight: 500; } + +/* Role select wrapper */ +.selectWrapper { min-width: 220px; } + +/* States */ +.loading { color: #3c4043; } +.error { color: red; } +.noData { text-align: center; padding: 40px 0; } + +/* Optional: local tweaks for third-party styles without leaking globally */ +:global(.react-datepicker-wrapper) { display: inline-block; } +:global(.react-datepicker__input-container input) { + padding: 6px 8px; + border: 1px solid #dadce0; + border-radius: 4px; +} \ No newline at end of file From c37c1adaf6dd72a016f5d4cf43568407b5678882 Mon Sep 17 00:00:00 2001 From: Neeraj-Kondaveeti Date: Fri, 24 Oct 2025 19:50:26 -0400 Subject: [PATCH 006/265] feat:show inactive users in correct final week window --- .../WeeklySummariesReport/FormattedReport.jsx | 160 ++++------ .../WeeklySummariesReport.jsx | 8 +- .../WeeklySummariesReport.module.scss | 24 +- yarn.lock | 280 ++++++++++++++++++ 4 files changed, 361 insertions(+), 111 deletions(-) diff --git a/src/components/WeeklySummariesReport/FormattedReport.jsx b/src/components/WeeklySummariesReport/FormattedReport.jsx index 87329abcf8..74982d04ae 100644 --- a/src/components/WeeklySummariesReport/FormattedReport.jsx +++ b/src/components/WeeklySummariesReport/FormattedReport.jsx @@ -3,8 +3,6 @@ import { useState, useRef, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; -// import moment from 'moment'; -// import 'moment-timezone'; import moment from 'moment-timezone'; import parse from 'html-react-parser'; import { Link } from 'react-router-dom'; @@ -34,7 +32,6 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { assignStarDotColors, showStar } from '~/utils/leaderboardPermissions'; - import { postLeaderboardData } from '~/actions/leaderBoardData'; import { calculateDurationBetweenDates, showTrophyIcon } from '~/utils/anniversaryPermissions'; import { toggleUserBio } from '~/actions/weeklySummariesReport'; @@ -47,6 +44,8 @@ import { ENDPOINTS } from '~/utils/URL'; import ToggleSwitch from '../UserProfile/UserProfileEdit/ToggleSwitch'; import GoogleDocIcon from '../common/GoogleDocIcon'; +const TZ = 'America/Los_Angeles'; + const textColors = { Default: '#000000', 'Not Required': '#708090', @@ -60,23 +59,17 @@ const textColors = { 'Team Amethyst': '#9400D3', }; -const isLastWeekReport = (startDateStr, endDateStr) => { - if (!startDateStr || !endDateStr) return false; - const summaryStart = new Date(startDateStr); - const summaryEnd = new Date(endDateStr); - - const weekStartLA = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week') - .toDate(); - const weekEndLA = moment() - .tz('America/Los_Angeles') - .endOf('week') - .subtract(1, 'week') - .toDate(); - - return summaryStart <= weekEndLA && summaryEnd >= weekStartLA; +/** + * Which tab (0..3) should this endDate appear on? + * 0 = This Week, 1 = Last Week, 2 = Week Before Last, 3 = Three Weeks Ago + * Returns null if endDate is outside the 4-week window or missing. + */ +const weekIndexFromEndDate = endDate => { + if (!endDate) return null; + const end = moment.tz(endDate, TZ).startOf('week'); + const nowStart = moment.tz(TZ).startOf('week'); + const diff = nowStart.diff(end, 'weeks'); // 0=this week, 1=last week, etc. + return diff >= 0 && diff <= 3 ? diff : null; }; function ListGroupItem({ children, darkMode }) { @@ -113,42 +106,19 @@ function FormattedReport({ const loggedInUserEmail = auth?.user?.email ? auth.user.email : ''; - // Determining if it's the final week: - // const isFinalWeek = - // !summaries.isActive && // backend tells user is inactive - // summaries.startDate && - // summaries.endDate && - // isLastWeekReport(summaries.startDate, summaries.endDate) && - // weekIndex === 1; // second report row - - // // Final week date range to show in message - // const finalWeekStart = moment() - // .tz('America/Los_Angeles') - // .startOf('week') - // .subtract(1, 'week') - // .format('MMM D, YYYY'); - - // const finalWeekEnd = moment() - // .tz('America/Los_Angeles') - // .endOf('week') - // .subtract(1, 'week') - // .format('MMM D, YYYY'); - return ( <> {summaries.map(summary => { - // Add safety check for each summary - if (!summary || !summary.totalSeconds) { - return null; - } - - const isFinalWeek = - !summary.isActive && // THIS now refers to individual user - summary.startDate && - summary.endDate && - isLastWeekReport(summary.startDate, summary.endDate) && - weekIndex === 1; + // Safety + if (!summary || !summary.totalSeconds) return null; + + // Work out which tab their final week belongs to based on endDate + const displayIdx = weekIndexFromEndDate(summary.endDate); + const isFinalWeek = displayIdx !== null && displayIdx === weekIndex; + + // If the user is inactive (has an endDate), only render them on that final-week tab + if (summary.endDate && !isFinalWeek) return null; return ( @@ -388,7 +355,6 @@ function WeeklySummaryMessage({ summary, weekIndex }) { ); } - // Add safety check for weeklySummaries array and weekIndex if ( !summary.weeklySummaries || !Array.isArray(summary.weeklySummaries) || @@ -404,11 +370,12 @@ function WeeklySummaryMessage({ summary, weekIndex }) { const summaryText = summary?.weeklySummaries[weekIndex]?.summary; let summaryDate = moment() - .tz('America/Los_Angeles') + .tz(TZ) .endOf('week') .subtract(weekIndex, 'week') .format('YYYY-MMM-DD'); let summaryDateText = `Weekly Summary (${summaryDate}):`; + const summaryContent = (() => { if (summaryText) { const style = { @@ -416,7 +383,7 @@ function WeeklySummaryMessage({ summary, weekIndex }) { }; summaryDate = moment(summary.weeklySummaries[weekIndex]?.uploadDate) - .tz('America/Los_Angeles') + .tz(TZ) .format('MMM-DD-YY'); summaryDateText = `Summary Submitted On (${summaryDate}):`; @@ -577,7 +544,6 @@ function TotalValidWeeklySummaries({ summary, canEditSummaryCount, darkMode }) { }; const [weeklySummariesCount, setWeeklySummariesCount] = useState( - // parseInt() returns an integer or NaN, convert to 0 if it's NaM parseInt(summary.weeklySummariesCount, 10) || 0, ); @@ -691,12 +657,12 @@ function BioLabel({ bioPosted, summary }) { function WeeklyBadge({ summary, weekIndex, badges }) { const badgeEndDate = moment() - .tz('America/Los_Angeles') + .tz(TZ) .endOf('week') .subtract(weekIndex, 'week') .format('YYYY-MM-DD'); const badgeStartDate = moment() - .tz('America/Los_Angeles') + .tz(TZ) .startOf('week') .subtract(weekIndex, 'week') .format('YYYY-MM-DD'); @@ -776,10 +742,11 @@ function Index({ loadTrophies, handleSpecialColorDotClick, isFinalWeek, + darkMode, }) { const colors = ['purple', 'green', 'navy']; const hoursLogged = (summary.totalSeconds[weekIndex] || 0) / 3600; - const currentDate = moment.tz('America/Los_Angeles').startOf('day'); + const currentDate = moment.tz(TZ).startOf('day'); const [setTrophyFollowedUp] = useState(summary?.trophyFollowedUp); const dispatch = useDispatch(); @@ -794,9 +761,7 @@ function Index({ const handleChangingTrophyIcon = async newTrophyStatus => { setModalOpen(false); await dispatch(postLeaderboardData(summary._id, newTrophyStatus)); - setTrophyFollowedUp(newTrophyStatus); - toast.success('Trophy status updated successfully'); }; @@ -809,7 +774,7 @@ function Index({ }, undefined); const summarySubmissionDate = moment() - .tz('America/Los_Angeles') + .tz(TZ) .endOf('week') .subtract(weekIndex, 'week') .format('YYYY-MM-DD'); @@ -820,32 +785,25 @@ function Index({ ); const handleIconContent = duration => { - if (duration.months >= 5.8 && duration.months <= 6.2) { - return '6M'; - } - if (duration.years >= 0.9) { - return `${Math.round(duration.years)}Y`; - } + if (duration.months >= 5.8 && duration.months <= 6.2) return '6M'; + if (duration.years >= 0.9) return `${Math.round(duration.years)}Y`; return null; }; - // if (isLastWeekReport(weekIndex)) { - // return FINAL WEEK REPORTING; - // } - - // const isFinalWeek = isLastWeekReport(weekIndex); - // const isFinalWeek = weekIndex === 0 && isLastWeekReport(summary.startDate, summary.endDate); - - const finalWeekStart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week') - .format('MMM D, YYYY'); - const finalWeekEnd = moment() - .tz('America/Los_Angeles') - .endOf('week') - .subtract(1, 'week') - .format('MMM D, YYYY'); + // Drive the banner’s dates from the user’s actual endDate + const end = summary?.endDate ? moment.tz(summary.endDate, TZ) : null; + const finalWeekStart = end + ? end + .clone() + .startOf('week') + .format('MMM D, YYYY') + : ''; + const finalWeekEnd = end + ? end + .clone() + .endOf('week') + .format('MMM D, YYYY') + : ''; return ( <> @@ -907,12 +865,7 @@ function Index({ {' '} - @@ -921,7 +874,7 @@ function Index({
- {colors.map(color => ( + {['purple', 'green', 'navy'].map(color => ( handleSpecialColorDotClick(summary._id, color)} @@ -939,14 +892,8 @@ function Index({ ))}
- {/* This conditional message ONLY on last week tab */} - {/* {isFinalWeek && ( -

- FINAL WEEK REPORTING: This team member is no longer active -

- )} */} {isFinalWeek && ( -

+

FINAL WEEK REPORTING: This team member is no longer active
@@ -987,7 +934,6 @@ function Index({ } FormattedReport.propTypes = { - // eslint-disable-next-line react/forbid-prop-types summaries: PropTypes.arrayOf(PropTypes.object).isRequired, weekIndex: PropTypes.number.isRequired, }; diff --git a/src/components/WeeklySummariesReport/WeeklySummariesReport.jsx b/src/components/WeeklySummariesReport/WeeklySummariesReport.jsx index f20f21f84c..a9b439ed45 100644 --- a/src/components/WeeklySummariesReport/WeeklySummariesReport.jsx +++ b/src/components/WeeklySummariesReport/WeeklySummariesReport.jsx @@ -348,7 +348,7 @@ const WeeklySummariesReport = props => { // Shallow copy and sort let summariesCopy = [...summaries]; summariesCopy = alphabetize(summariesCopy); - summariesCopy = summariesCopy.filter(summary => summary?.isActive !== false); + //summariesCopy = summariesCopy.filter(summary => summary?.isActive !== false); // Add new key of promised hours by week summariesCopy = summariesCopy.map(summary => { const promisedHoursByWeek = weekDates.map(weekDate => @@ -613,9 +613,11 @@ const WeeklySummariesReport = props => { // return false; // Skip inactive members unless their summary is from last week // } // } - if (summary?.isActive === false && !isLastWeekReport(summary.startDate, summary.endDate)) { - return false; + // If this user has an endDate, only include them when you're on their final week tab + if (summary.endDate) { + if (summary.finalWeekIndex !== weekIndex) return false; } + const isMeetCriteria = summary.totalTangibleHrs > 80 && summary.daysInTeam > 60 && diff --git a/src/components/WeeklySummariesReport/WeeklySummariesReport.module.scss b/src/components/WeeklySummariesReport/WeeklySummariesReport.module.scss index 6027768a2a..3b4d515669 100644 --- a/src/components/WeeklySummariesReport/WeeklySummariesReport.module.scss +++ b/src/components/WeeklySummariesReport/WeeklySummariesReport.module.scss @@ -154,4 +154,26 @@ .warningBorder { border: 2px solid red !important; border-radius: 5px; -} \ No newline at end of file +} +/* Final-week notice */ +.finalWeekNotice { + color: #b00020; /* accessible red on light bg */ + font-weight: 700; + background: rgba(255, 235, 59, 0.18); + padding: 6px 10px; + border-radius: 6px; + line-height: 1.3; + margin-top: 5px; + + small { + display: block; + margin-top: 2px; + opacity: 0.9; + font-weight: 600; + } +} + +.finalWeekNoticeDark { + color: #ffd1d1; /* light red for dark bg */ + background: rgba(255, 255, 255, 0.08); +} diff --git a/yarn.lock b/yarn.lock index 0a06a19bae..a0b203a4a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1385,11 +1385,136 @@ "@ephox/katamari" "^9.1.6" "@ephox/sand" "^6.0.10" +"@esbuild/aix-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz" + integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA== + +"@esbuild/android-arm@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz" + integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ== + +"@esbuild/android-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz" + integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg== + +"@esbuild/android-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz" + integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw== + "@esbuild/darwin-arm64@0.25.9": version "0.25.9" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz" integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg== +"@esbuild/darwin-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz" + integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ== + +"@esbuild/freebsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz" + integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q== + +"@esbuild/freebsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz" + integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg== + +"@esbuild/linux-arm@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz" + integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw== + +"@esbuild/linux-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz" + integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw== + +"@esbuild/linux-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz" + integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A== + +"@esbuild/linux-loong64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz" + integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ== + +"@esbuild/linux-mips64el@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz" + integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA== + +"@esbuild/linux-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz" + integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w== + +"@esbuild/linux-riscv64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz" + integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg== + +"@esbuild/linux-s390x@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz" + integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA== + +"@esbuild/linux-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz" + integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg== + +"@esbuild/netbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz" + integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q== + +"@esbuild/netbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz" + integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g== + +"@esbuild/openbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz" + integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ== + +"@esbuild/openbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz" + integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA== + +"@esbuild/openharmony-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz" + integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg== + +"@esbuild/sunos-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz" + integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw== + +"@esbuild/win32-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz" + integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ== + +"@esbuild/win32-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz" + integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww== + +"@esbuild/win32-x64@0.25.9": + version "0.25.9" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz" + integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.7.0": version "4.7.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz" @@ -1990,11 +2115,71 @@ resolved "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + "@parcel/watcher-darwin-arm64@2.5.1": version "2.5.1" resolved "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz" integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + +"@parcel/watcher-win32-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz" + integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== + "@parcel/watcher@^2.4.1": version "2.5.1" resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz" @@ -2144,11 +2329,106 @@ resolved "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz" integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA== +"@rollup/rollup-android-arm-eabi@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz" + integrity sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA== + +"@rollup/rollup-android-arm64@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz" + integrity sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w== + "@rollup/rollup-darwin-arm64@4.49.0": version "4.49.0" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz" integrity sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw== +"@rollup/rollup-darwin-x64@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz" + integrity sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg== + +"@rollup/rollup-freebsd-arm64@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz" + integrity sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA== + +"@rollup/rollup-freebsd-x64@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz" + integrity sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w== + +"@rollup/rollup-linux-arm-gnueabihf@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz" + integrity sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w== + +"@rollup/rollup-linux-arm-musleabihf@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz" + integrity sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA== + +"@rollup/rollup-linux-arm64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz" + integrity sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg== + +"@rollup/rollup-linux-arm64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz" + integrity sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg== + +"@rollup/rollup-linux-loongarch64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz" + integrity sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ== + +"@rollup/rollup-linux-ppc64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz" + integrity sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g== + +"@rollup/rollup-linux-riscv64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz" + integrity sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw== + +"@rollup/rollup-linux-riscv64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz" + integrity sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw== + +"@rollup/rollup-linux-s390x-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz" + integrity sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A== + +"@rollup/rollup-linux-x64-gnu@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz" + integrity sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA== + +"@rollup/rollup-linux-x64-musl@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz" + integrity sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg== + +"@rollup/rollup-win32-arm64-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz" + integrity sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA== + +"@rollup/rollup-win32-ia32-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz" + integrity sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA== + +"@rollup/rollup-win32-x64-msvc@4.49.0": + version "4.49.0" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz" + integrity sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz" From 16602c0a15c557cf2042213fd7f5e28dba4a0772 Mon Sep 17 00:00:00 2001 From: siva venkata naga pavan putti <73236071+pavanputti@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:18:11 -0400 Subject: [PATCH 007/265] fix: Move Show Past Events button to header aligned with Figma design - Moved 'Show Past Events' button from bottom of events section to top-right of header - Button now positioned beside 'All Events' title in dashboard-controls div - Updated CSS to properly align button with search bar using flexbox - Removed old dashboard-actions section that contained button at bottom - Matches Figma design for better visibility and design consistency Note: CPDashboard.css is an existing file. Modified styling only. --- .../CommunityPortal/CPDashboard.css | 22 ++++++++++++------- .../CommunityPortal/CPDashboard.jsx | 6 ++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/components/CommunityPortal/CPDashboard.css b/src/components/CommunityPortal/CPDashboard.css index 87c9d71c38..bc97c11038 100644 --- a/src/components/CommunityPortal/CPDashboard.css +++ b/src/components/CommunityPortal/CPDashboard.css @@ -31,13 +31,23 @@ body { color: #2c3e50; } +.dashboard-controls { + display: flex; + align-items: center; + gap: 15px; +} + +.dashboard-search-container { + flex: 1; + max-width: 600px; +} + .dashboard-search-container input { border: 2px solid #2c3e50; border-radius: 25px; padding: 12px 20px; font-size: 1rem; width: 100%; - max-width: 600px; transition: all 0.3s ease; } @@ -133,12 +143,7 @@ body { margin: 5px 0; } -.dashboard-actions { - text-align: center; - margin-top: 20px; -} - -.dashboard-actions button { +.show-past-events-btn { background-color: #2c3e50; color: #ffffff; border: none; @@ -148,9 +153,10 @@ body { cursor: pointer; transition: all 0.3s ease; font-weight: bold; + white-space: nowrap; } -.dashboard-actions button:hover { +.show-past-events-btn:hover { background-color: #34495e; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } diff --git a/src/components/CommunityPortal/CPDashboard.jsx b/src/components/CommunityPortal/CPDashboard.jsx index 4b5e5cdb00..35437a0bb3 100644 --- a/src/components/CommunityPortal/CPDashboard.jsx +++ b/src/components/CommunityPortal/CPDashboard.jsx @@ -51,6 +51,9 @@ export function CPDashboard() { className="dashboard-search" />

+ {/* Community Portal @@ -137,9 +140,6 @@ export function CPDashboard() {
No events available
)} -
- -
From 83b7f82958f1b47912083b4d0fe3b59a80dcc237 Mon Sep 17 00:00:00 2001 From: siva venkata naga pavan putti <73236071+pavanputti@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:44:39 -0400 Subject: [PATCH 008/265] fix: Move Show Past Events button inside dashboard-main section - Moved button from header to inside dashboard-main col-md-9 section - Positioned button aligned with Events heading, all the way to the right - Added events-header flex container for proper alignment - Updated CSS to use space-between for button positioning at far right --- src/components/CommunityPortal/CPDashboard.css | 12 ++++++++++-- src/components/CommunityPortal/CPDashboard.jsx | 10 ++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/CommunityPortal/CPDashboard.css b/src/components/CommunityPortal/CPDashboard.css index bc97c11038..e6e97ee752 100644 --- a/src/components/CommunityPortal/CPDashboard.css +++ b/src/components/CommunityPortal/CPDashboard.css @@ -97,12 +97,20 @@ body { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } +.events-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + width: 100%; +} + .section-title { font-size: 2.2rem; color: #2c3e50; - margin-bottom: 20px; + margin-bottom: 0; font-weight: bold; - text-align: center; + text-align: left; } .event-card { diff --git a/src/components/CommunityPortal/CPDashboard.jsx b/src/components/CommunityPortal/CPDashboard.jsx index 35437a0bb3..1999451844 100644 --- a/src/components/CommunityPortal/CPDashboard.jsx +++ b/src/components/CommunityPortal/CPDashboard.jsx @@ -51,9 +51,6 @@ export function CPDashboard() { className="dashboard-search" />
- {/* Community Portal @@ -112,7 +109,12 @@ export function CPDashboard() { -

Events

+
+

Events

+ +
{events.length > 0 ? ( events.map(event => ( From b680e4c5e6bb77ac56c772d6e5dcb8bc25483781 Mon Sep 17 00:00:00 2001 From: siva venkata naga pavan putti <73236071+pavanputti@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:37:39 -0500 Subject: [PATCH 009/265] refactor: Convert CPDashboard.css to CSS module - Renamed CPDashboard.css to CPDashboard.module.css - Updated import statement to use CSS module - Converted all className props to use styles object - Removed body styles (should be in global CSS) - Added missing CSS classes (dashboardSearch, filterOptionsHorizontal, dateFilter, eventCardCol, eventCardImg, eventIcon, noEvents) - Matches project policy for CSS modules to prevent style conflicts --- .../CommunityPortal/CPDashboard.jsx | 62 +++++------ ...CPDashboard.css => CPDashboard.module.css} | 101 ++++++++++++------ 2 files changed, 100 insertions(+), 63 deletions(-) rename src/components/CommunityPortal/{CPDashboard.css => CPDashboard.module.css} (68%) diff --git a/src/components/CommunityPortal/CPDashboard.jsx b/src/components/CommunityPortal/CPDashboard.jsx index 1999451844..3f5ff37820 100644 --- a/src/components/CommunityPortal/CPDashboard.jsx +++ b/src/components/CommunityPortal/CPDashboard.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import { Container, Row, Col, Card, CardBody, Button, Input } from 'reactstrap'; -import './CPDashboard.css'; +import styles from './CPDashboard.module.css'; import { FaCalendarAlt, FaMapMarkerAlt, FaUserAlt } from 'react-icons/fa'; export function CPDashboard() { @@ -38,17 +38,17 @@ export function CPDashboard() { }, []); return ( - -
+ +

All Events

-
-
+
+
setSearch(e.target.value)} - className="dashboard-search" + className={styles.dashboardSearch} />
{/* @@ -66,12 +66,12 @@ export function CPDashboard() {
- -
+ +

Search Filters

-
+
-
+
Tomorrow
@@ -79,27 +79,27 @@ export function CPDashboard() { This Weekend
- +
-
+
Online Only
-
+
-
+
-
+
@@ -108,38 +108,38 @@ export function CPDashboard() {
- -
-

Events

-
{events.length > 0 ? ( events.map(event => ( - - -
- {event.title} + + +
+ {event.title}
-
{event.title}
-

- {event.date} +

{event.title}
+

+ {event.date}

-

- {event.location} +

+ {event.location}

-

- {event.organizer} +

+ {event.organizer}

)) ) : ( -
No events available
+
No events available
)} diff --git a/src/components/CommunityPortal/CPDashboard.css b/src/components/CommunityPortal/CPDashboard.module.css similarity index 68% rename from src/components/CommunityPortal/CPDashboard.css rename to src/components/CommunityPortal/CPDashboard.module.css index e6e97ee752..2c7fd6bccc 100644 --- a/src/components/CommunityPortal/CPDashboard.css +++ b/src/components/CommunityPortal/CPDashboard.module.css @@ -1,11 +1,4 @@ -body { - font-family: 'Poppins', sans-serif; - background: #fff; - margin: 0; - padding: 0; -} - -.dashboard-container { +.dashboardContainer { padding: 40px 20px; max-width: 1400px; margin: 0 auto; @@ -14,7 +7,7 @@ body { box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); } -.dashboard-header { +.dashboardHeader { display: flex; justify-content: space-between; align-items: center; @@ -25,24 +18,24 @@ body { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } -.dashboard-header h1 { +.dashboardHeader h1 { font-size: 2.5rem; font-weight: bold; color: #2c3e50; } -.dashboard-controls { +.dashboardControls { display: flex; align-items: center; gap: 15px; } -.dashboard-search-container { +.dashboardSearchContainer { flex: 1; max-width: 600px; } -.dashboard-search-container input { +.dashboardSearch { border: 2px solid #2c3e50; border-radius: 25px; padding: 12px 20px; @@ -51,28 +44,51 @@ body { transition: all 0.3s ease; } -.dashboard-search-container input:focus { +.dashboardSearch:focus { border-color: #34495e; box-shadow: 0 0 8px rgba(52, 73, 94, 0.3); outline: none; } -.dashboard-sidebar { +.dashboardSidebar { padding: 30px; background: #f9f9f9; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } -.filter-section h4 { +.filterSection h4 { font-size: 1.8rem; color: #2c3e50; margin-bottom: 20px; font-weight: 600; } -.filter-item input, -.filter-item select { +.filterOptionsHorizontal { + display: flex; + gap: 15px; + margin-top: 10px; +} + +.dateFilter { + margin-top: 10px; + padding: 12px 15px; + border: 1px solid #ddd; + border-radius: 8px; + width: 100%; + font-size: 1rem; + background: #ffffff; + transition: all 0.3s ease; +} + +.dateFilter:focus { + border-color: #2c3e50; + box-shadow: 0 0 5px rgba(44, 62, 80, 0.4); + outline: none; +} + +.filterItem input, +.filterItem select { padding: 12px 15px; margin-top: 10px; border: 1px solid #ddd; @@ -83,21 +99,21 @@ body { transition: all 0.3s ease; } -.filter-item input:focus, -.filter-item select:focus { +.filterItem input:focus, +.filterItem select:focus { border-color: #2c3e50; box-shadow: 0 0 5px rgba(44, 62, 80, 0.4); outline: none; } -.dashboard-main { +.dashboardMain { padding: 30px; background: #ffffff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } -.events-header { +.eventsHeader { display: flex; justify-content: space-between; align-items: center; @@ -105,7 +121,7 @@ body { width: 100%; } -.section-title { +.sectionTitle { font-size: 2.2rem; color: #2c3e50; margin-bottom: 0; @@ -113,7 +129,7 @@ body { text-align: left; } -.event-card { +.eventCard { margin-bottom: 20px; border-radius: 12px; overflow: hidden; @@ -121,18 +137,38 @@ body { transition: transform 0.3s ease, box-shadow 0.3s ease; } -.event-card:hover { +.eventCard:hover { transform: scale(1.05); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); } -.event-card-img-container img { +.eventCardCol { + margin-bottom: 20px; +} + +.eventCardImgContainer img { width: 100%; height: auto; border-bottom: 3px solid #34495e; } -.event-title { +.eventCardImg { + width: 100%; + height: auto; +} + +.eventIcon { + margin-right: 8px; +} + +.noEvents { + text-align: center; + padding: 40px; + color: #555; + font-size: 1.2rem; +} + +.eventTitle { text-align: center; color: #2c3e50; margin: 10px 0; @@ -140,9 +176,9 @@ body { font-size: 1.5rem; } -.event-date, -.event-location, -.event-organizer { +.eventDate, +.eventLocation, +.eventOrganizer { font-size: 1rem; color: #555; display: flex; @@ -151,7 +187,7 @@ body { margin: 5px 0; } -.show-past-events-btn { +.showPastEventsBtn { background-color: #2c3e50; color: #ffffff; border: none; @@ -164,7 +200,8 @@ body { white-space: nowrap; } -.show-past-events-btn:hover { +.showPastEventsBtn:hover { background-color: #34495e; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } + From 9344a4890dc7aa39e3777e2d3e4e4d083d325fa7 Mon Sep 17 00:00:00 2001 From: Test Date: Thu, 13 Nov 2025 15:31:14 -0500 Subject: [PATCH 010/265] fix: route education experience donut chart --- src/routes.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/routes.jsx b/src/routes.jsx index ca23c1390f..5228a5914d 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -3,6 +3,7 @@ import { Route, Switch } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import ApplicantsChart from './components/ApplicantsChart'; +import EducationExperienceDonutChart from './components/EducationExperienceDonutChart/EducationExperienceDonutChart'; import AutoUpdate from './components/AutoUpdate'; import TaskEditSuggestions from './components/TaskEditSuggestions/TaskEditSuggestions'; import RoutePermissions from './utils/routePermissions'; @@ -843,6 +844,11 @@ export default ( + {/* ----- PR Dashboard ----- */} From cca0e1a89994e405798f6101e56d5fdc50bcfc47 Mon Sep 17 00:00:00 2001 From: Test Date: Thu, 13 Nov 2025 15:41:46 -0500 Subject: [PATCH 011/265] style: extract education experience chart styles --- .../EducationExperienceDonutChart.jsx | 189 ++++++++++-------- .../EducationExperienceDonutChart.module.css | 146 ++++++++++++++ 2 files changed, 250 insertions(+), 85 deletions(-) create mode 100644 src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.module.css diff --git a/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx b/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx index 8fea50fe0c..3493634e78 100644 --- a/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx +++ b/src/components/EducationExperienceDonutChart/EducationExperienceDonutChart.jsx @@ -3,6 +3,8 @@ import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer, Label } from 'rechar import DatePicker from 'react-datepicker'; import Select from 'react-select'; import 'react-datepicker/dist/react-datepicker.css'; +import { useSelector } from 'react-redux'; +import styles from './EducationExperienceDonutChart.module.css'; /** ---------- Stable color mapping by category ---------- */ const COLOR_BY_CATEGORY = { @@ -83,6 +85,7 @@ const EducationExperienceDonutChart = () => { const [loading] = useState(false); const [error, setError] = useState(null); const isMobile = useIsMobile(640); + const darkMode = useSelector(state => state.theme?.darkMode); /** Role dropdown options */ const roleOptions = useMemo(() => { @@ -174,76 +177,98 @@ const EducationExperienceDonutChart = () => { }; if (error) { - return
Something went wrong: {error}
; + return
Something went wrong: {error}
; } + const wrapperClass = `${styles.wrapper} ${darkMode ? styles.wrapperDark : ''}`; + const headingClass = `${styles.heading} ${darkMode ? styles.headingDark : ''}`; + const filtersClass = `${styles.filters} ${isMobile ? styles.filtersMobile : ''}`; + const sectionClass = `${styles.section} ${isMobile ? styles.sectionFull : ''}`; + const titleClass = `${styles.sectionTitle} ${darkMode ? styles.sectionTitleDark : ''}`; + const datePickerClass = `${styles.datePicker} ${darkMode ? 'hgn-datepicker-dark' : ''}`; + const chartWrapperClass = `${styles.chartWrapper} ${isMobile ? styles.chartWrapperMobile : ''}`; + return ( -
-

- Breakdown of Candidates by Experience and Educational Level -

- - {/* Filters */} -
-
- Dates -
- - +
+
+

Breakdown of Candidates by Experience and Educational Level

+ + {/* Filters */} +
+
+ Dates +
+ + +
-
-
- Role - ({ + ...provided, + backgroundColor: '#1f2937', + borderColor: '#3b82f6', + color: '#e5e7eb', + }), + menu: provided => ({ + ...provided, + backgroundColor: '#111827', + color: '#e5e7eb', + }), + multiValue: provided => ({ + ...provided, + backgroundColor: '#2563eb', + }), + multiValueLabel: provided => ({ + ...provided, + color: '#f8fafc', + }), + } + : undefined + } + /> +
-
- {/* Chart / Empty / Loading */} - {loading ? ( -
Loading…
- ) : total === 0 ? ( -
- No data for the selected filters. Try widening the date range or clearing roles. -
- ) : ( - <> -
+ {/* Chart / Empty / Loading */} + {loading ? ( +
Loading…
+ ) : total === 0 ? ( +
+ No data for the selected filters. Try widening the date range or clearing roles. +
+ ) : ( + <> +
{/* overflow visible so outside labels aren't clipped */} {