From 9eec3208bbcd61d7b9f52c0e7909fd9ebda29ade Mon Sep 17 00:00:00 2001 From: Vamsidhar858 <145138793+Vamsidhar858@users.noreply.github.com> Date: Wed, 31 Dec 2025 18:32:48 -0800 Subject: [PATCH 1/5] fix: calendar dark mode and issue chart visibility with consistent numbering --- .../BMDashboard/Issues/issueChart.module.css | 156 ++++++++++++++++++ .../BMDashboard/Issues/openIssueCharts.jsx | 80 ++++++++- .../Calendar/CommunityCalendar.module.css | 81 +++++++-- 3 files changed, 302 insertions(+), 15 deletions(-) diff --git a/src/components/BMDashboard/Issues/issueChart.module.css b/src/components/BMDashboard/Issues/issueChart.module.css index bf6d4d6a38..b13fba9d0b 100644 --- a/src/components/BMDashboard/Issues/issueChart.module.css +++ b/src/components/BMDashboard/Issues/issueChart.module.css @@ -269,12 +269,51 @@ font-size: 14px; } +.dateLight { + background: #ffffff; + color: #000000; +} + +.dateLight::placeholder { + color: #999999 !important; + opacity: 1 !important; +} + .dateDark { background: #22272e; color: #cfd7e3; border-color: #3d444d; } +.dateDark::placeholder { + color: #8b949e !important; + opacity: 1 !important; +} + +/* Also style the react-datepicker input placeholder */ +:global(.react-datepicker__input-container input::placeholder) { + color: #999999 !important; + opacity: 1 !important; +} + +:global(.dark-mode .react-datepicker__input-container input::placeholder) { + color: #8b949e !important; + opacity: 1 !important; +} + +/* Style the input container itself */ +:global(.react-datepicker__input-container input) { + background-color: #ffffff !important; + color: #000000 !important; + border: 1px solid #ccc !important; +} + +:global(.dark-mode .react-datepicker__input-container input) { + background-color: #22272e !important; + color: #cfd7e3 !important; + border-color: #3d444d !important; +} + /* React select */ .selectReact { width: 100%; @@ -286,6 +325,123 @@ font-size: 18px; } +/* Light mode styles for react-datepicker calendar - default */ +:global(.react-datepicker) { + background-color: #ffffff !important; + color: #000000 !important; + border: 1px solid #ccc !important; + font-family: inherit !important; +} + +:global(.react-datepicker__header) { + background-color: #f0f0f0 !important; + border-bottom: 1px solid #ccc !important; +} + +:global(.react-datepicker__current-month) { + color: #000000 !important; + font-weight: 600 !important; +} + +:global(.react-datepicker__day-name) { + color: #000000 !important; + font-weight: 600 !important; +} + +:global(.react-datepicker__day) { + color: #000000 !important; +} + +:global(.react-datepicker__day:hover) { + background-color: #f0f0f0 !important; + color: #000000 !important; +} + +:global(.react-datepicker__day--selected), +:global(.react-datepicker__day--in-selecting-range), +:global(.react-datepicker__day--in-range) { + background-color: #0066cc !important; + color: #ffffff !important; +} + +:global(.react-datepicker__day--keyboard-selected) { + background-color: #e6f2ff !important; + color: #000000 !important; +} + +:global(.react-datepicker__day--outside-month) { + color: #ccc !important; +} + +:global(.react-datepicker__navigation-icon::before) { + border-color: #000000 !important; +} + +:global(.react-datepicker__month-container) { + background-color: #ffffff !important; +} + +:global(.react-datepicker__time-container) { + background-color: #ffffff !important; + border-left: 1px solid #ccc !important; +} + +:global(.react-datepicker__time-container .react-datepicker__time) { + background-color: #ffffff !important; +} + +:global(.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box) { + background-color: #ffffff !important; +} + +/* Dark mode styles for react-datepicker calendar - only apply when dark mode class is present */ +:global(.dark-mode .react-datepicker) { + background-color: #3A506B !important; + color: #ffffff !important; + border: 1px solid #555 !important; +} + +:global(.dark-mode .react-datepicker__header) { + background-color: #1C2541 !important; + border-bottom: 1px solid #555 !important; +} + +:global(.dark-mode .react-datepicker__current-month) { + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__day-name) { + background-color: #1C2541 !important; + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__day) { + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__day:hover) { + background-color: #1C2541 !important; + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__day--selected) { + background-color: #1C2541 !important; + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__day--keyboard-selected) { + background-color: #1C2541 !important; + color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__navigation-icon::before) { + border-color: #ffffff !important; +} + +:global(.dark-mode .react-datepicker__month-container) { + background-color: #3A506B !important; +} + /* DARK MODE CONTROL */ .controlDark { background: #22272e !important; diff --git a/src/components/BMDashboard/Issues/openIssueCharts.jsx b/src/components/BMDashboard/Issues/openIssueCharts.jsx index 729cc19032..6c269fb252 100644 --- a/src/components/BMDashboard/Issues/openIssueCharts.jsx +++ b/src/components/BMDashboard/Issues/openIssueCharts.jsx @@ -38,11 +38,83 @@ function IssueCharts() { const tooltipBorder = darkMode ? '#4a5568' : '#e2e8f0'; // Normalize issues for chart + // Number issues per project to avoid conflicts when multiple projects are selected + // Prefix with project name when multiple projects are selected to distinguish them const normalizedIssues = useMemo(() => { - return (issues || []).map((item, index) => ({ - issueName: item.issueName || `Issue #${index + 1}`, - durationOpen: item.durationOpen ?? 0, - })); + if (!issues || issues.length === 0) return []; + + // Check if multiple projects are selected + const uniqueProjectIds = new Set((issues || []).map(item => item.projectId).filter(Boolean)); + const multipleProjects = uniqueProjectIds.size > 1; + + // Group issues by projectId + const issuesByProject = new Map(); + (issues || []).forEach(item => { + const projectId = item.projectId || 'unknown'; + if (!issuesByProject.has(projectId)) { + issuesByProject.set(projectId, []); + } + issuesByProject.get(projectId).push(item); + }); + + // Create per-project numbering maps + const projectNumberMaps = new Map(); + + issuesByProject.forEach((projectIssues, projectId) => { + const issueIdToNumber = new Map(); + let counter = 1; + + // Sort issues by issueId within each project for consistent ordering + const sortedById = [...projectIssues].sort((a, b) => { + const idA = a.issueId || ''; + const idB = b.issueId || ''; + return idA.localeCompare(idB); + }); + + // Assign numbers to issues without names within this project + sortedById.forEach(item => { + if (!item.issueName && item.issueId && !issueIdToNumber.has(item.issueId)) { + issueIdToNumber.set(item.issueId, counter++); + } + }); + + projectNumberMaps.set(projectId, issueIdToNumber); + }); + + // Map back to original order (sorted by duration) but use per-project numbers + return (issues || []).map(item => { + const projectId = item.projectId || 'unknown'; + const projectNumberMap = projectNumberMaps.get(projectId); + + // Generate the base issue name + let baseIssueName = item.issueName; + let isGeneratedName = false; + + if (!baseIssueName) { + // If no name, generate Issue #X based on project numbering + if (item.issueId && projectNumberMap && projectNumberMap.has(item.issueId)) { + baseIssueName = `Issue #${projectNumberMap.get(item.issueId)}`; + isGeneratedName = true; + } else { + baseIssueName = 'Untitled Issue'; + isGeneratedName = true; + } + } + + // Only prefix with project name if: + // 1. Multiple projects are selected AND + // 2. The issue name was generated (Issue #X), not a real name + // This keeps the display clean for named issues while distinguishing unnamed issues + const finalIssueName = + multipleProjects && isGeneratedName && item.projectName + ? `${item.projectName} - ${baseIssueName}` + : baseIssueName; + + return { + issueName: finalIssueName, + durationOpen: item.durationOpen ?? 0, + }; + }); }, [issues]); // Load projects on mount diff --git a/src/components/CommunityPortal/Calendar/CommunityCalendar.module.css b/src/components/CommunityPortal/Calendar/CommunityCalendar.module.css index 26fbf1ee88..77deaf0bbf 100644 --- a/src/components/CommunityPortal/Calendar/CommunityCalendar.module.css +++ b/src/components/CommunityPortal/Calendar/CommunityCalendar.module.css @@ -65,12 +65,13 @@ border: 2px solid #ddd; border-radius: 8px; overflow: hidden; - background-color: #fff; + background-color: #fff !important; + color: #000 !important; } .reactCalendarDarkMode { - background-color: #1B2A41; - color: #FFFFFF; + background-color: #1B2A41 !important; + color: #FFFFFF !important; border: 1px solid #444; } @@ -123,6 +124,19 @@ .reactCalendar :global(.react-calendar__month-view__weekdays__weekday) abbr { text-decoration: none !important; + color: #000 !important; +} + +.reactCalendar :global(.react-calendar__month-view__weekdays__weekday) { + color: #000 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__month-view__weekdays__weekday) { + color: #FFFFFF !important; +} + +.reactCalendarDarkMode :global(.react-calendar__month-view__weekdays__weekday) abbr { + color: #FFFFFF !important; } .reactCalendar :global(.react-calendar__month-view__days__day) { @@ -130,32 +144,70 @@ border: 1px solid #000000; vertical-align: top; padding: 2px; + color: #000 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__month-view__days__day) { + color: #FFFFFF !important; + border: 1px solid #666 !important; } .reactCalendar :global(.react-calendar__navigation) { - background-color: #f9f9f9; + background-color: #f9f9f9 !important; border-bottom: 1px solid #ddd; margin-bottom: 0px !important; + color: #000 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__navigation) { + background-color: #1B2A41 !important; + color: #FFFFFF !important; + border-bottom: 1px solid #444; +} + +.reactCalendar :global(.react-calendar__navigation button) { + color: #000 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__navigation button) { + color: #FFFFFF !important; +} + +.reactCalendar :global(.react-calendar__navigation button:hover), +.reactCalendar :global(.react-calendar__navigation button:enabled:hover) { + background-color: #e6e6e6 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__navigation button:hover), +.reactCalendarDarkMode :global(.react-calendar__navigation button:enabled:hover) { + background-color: #3A506B !important; } .reactCalendar :global(.react-calendar__tile) { display: block; height: 90px; - background: #fff; + background: #fff !important; border: 1px solid #dee2e6 !important; box-sizing: border-box; transition: background 0.3s, border-color 0.3s ease; overflow: hidden; padding: 4px; + color: #000 !important; } .reactCalendarDarkMode :global(.react-calendar__tile) { - background: transparent; - color: #FFFFFF; + background: transparent !important; + color: #FFFFFF !important; + border: 1px solid #444 !important; } .reactCalendar :global(.react-calendar__tile):hover { - background-color: #f5f5f5; - border-color: #999; + background-color: #f5f5f5 !important; + border-color: #999 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__tile):hover { + background-color: #3A506B !important; + border-color: #666 !important; } .reactCalendar :global(.react-calendar__tile) .tileEvents { @@ -214,9 +266,16 @@ transform: scale(1.03); } -.react-calendar__tile--active, -.react-calendar__tile--now { +.reactCalendar :global(.react-calendar__tile--active), +.reactCalendar :global(.react-calendar__tile--now) { + background-color: transparent !important; + color: #000 !important; +} + +.reactCalendarDarkMode :global(.react-calendar__tile--active), +.reactCalendarDarkMode :global(.react-calendar__tile--now) { background-color: transparent !important; + color: #FFFFFF !important; } .hasEvents { From a9327923d5157eef4d058cb11b94a6a7ffe587ca Mon Sep 17 00:00:00 2001 From: Vamsidhar858 <145138793+Vamsidhar858@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:12:43 -0800 Subject: [PATCH 2/5] Resolve merge conflicts in issueCharts components by merging both branches' features --- .../BMDashboard/Issues/issueCharts.module.css | 200 ++++++++--- .../BMDashboard/Issues/openIssueCharts.jsx | 331 ++++++++++-------- 2 files changed, 342 insertions(+), 189 deletions(-) diff --git a/src/components/BMDashboard/Issues/issueCharts.module.css b/src/components/BMDashboard/Issues/issueCharts.module.css index f31fbcf82b..04702fdd62 100644 --- a/src/components/BMDashboard/Issues/issueCharts.module.css +++ b/src/components/BMDashboard/Issues/issueCharts.module.css @@ -1,15 +1,17 @@ -/* Issue Charts Module CSS */ +/* Issue Charts Module CSS - Final */ + +/* ---------- Container ---------- */ .issueChartContainer { - max-width: 900px; + max-width: 960px; margin: 0 auto; - padding: 20px; + padding: 24px; } .issueChartContainerDark { - background: #121212; + background-color: #121212; + color: #e2e8f0; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.9); - color: #ccd1dc; } .issueChartEventContainer { @@ -86,14 +88,17 @@ box-shadow: 0 0 15px rgba(0, 0, 0, 0.9); } +/* ---------- Labels ---------- */ + .issueChartLabel { font-size: 16px; - color: #555; - margin-right: 10px; + font-weight: 500; + color: #2d3748; + margin-bottom: 8px; } .issueChartLabelDark { - color: #aab1bf; + color: #cbd5e0; } .selectContainer { @@ -130,53 +135,131 @@ border-color: #4caf50; } +/* ---------- Filters row (Date + Projects) ---------- */ + .filtersContainer { display: flex; - gap: 16px; - margin-bottom: 20px; flex-wrap: wrap; + gap: 20px; + margin-bottom: 24px; + align-items: flex-end; +} + +/* left: date range column with fixed width */ +.dateFilter { + display: flex; + flex-direction: column; + flex: 0 0 520px; /* approx 220 + 220 + separator + gaps */ + max-width: 520px; + min-width: 420px; + text-align: center; +} + +/* right: projects select grows to fill */ +.projectFilter { + display: flex; + flex-direction: column; + flex: 1 1 260px; + min-width: 260px; } +/* optional generic filter class if needed elsewhere */ .filter { display: flex; flex-direction: column; - gap: 8px; + width: 100%; } +/* ---------- Date range layout (no shifting) ---------- */ + .dateRangePicker { - display: flex; - align-items: center; - gap: 8px; + display: block; + width: 100%; + white-space: nowrap; + text-align: left; } -.filterSelect { - padding: 6px 8px; - border: 1px solid #ccc; - border-radius: 4px; - background-color: #fff; - color: #333; +.dateRangePickerStart, +.dateRangePickerEnd { + display: inline-block; + vertical-align: middle; } -.filterSelectDark { - background-color: #22272e; - border: 1px solid #3d444d; - color: #cfd7e3; +/* middle "to" label */ +.dateRangeSeparator { + display: inline-block; + vertical-align: middle; + margin: 0 8px; +} + +/* fixed width for each DatePicker wrapper div from react-datepicker */ +.dateRangePickerStart :global(.react-datepicker-wrapper), +.dateRangePickerEnd :global(.react-datepicker-wrapper) { + display: inline-block; + width: 220px; /* tweak width if needed */ +} + +/* inner container full width */ +.dateRangePickerStart :global(.react-datepicker__input-container), +.dateRangePickerEnd :global(.react-datepicker__input-container) { + width: 100%; +} + +/* actual input fills wrapper and doesn't change layout */ +.dateRangePickerStart + :global(.react-datepicker__input-container input), +.dateRangePickerEnd + :global(.react-datepicker__input-container input) { + width: 100%; + box-sizing: border-box; + height: 38px; +} + +/* ---------- Select / input base styles ---------- */ + +.filterSelect, +.issueChartSelect { + height: 60px; + padding: 8px 12px; + font-size: 15px; + border-radius: 6px; + border: 1px solid #cbd5e0; + background-color: #ffffff; + color: #2d3748; + width: 100%; + box-sizing: border-box; +} + +.filterSelectDark, +.issueChartSelectDark { + background-color: #2d3748; + border: 1px solid #4a5568; + color: #edf2f7; } +.filterSelect:focus, +.issueChartSelect:focus { + border-color: #4caf50; + outline: none; +} + +/* ---------- Chart container ---------- */ + .chartContainer { width: 100%; - height: 400px; - background: white; - padding: 20px; + min-height: 450px; + height: auto; + background-color: #ffffff; + padding: 24px; border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - color: #000; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + color: #1a202c; } .chartContainerDark { - background: #1e1e1e; + background-color: #1a202c; + color: #edf2f7; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.9); - color: #cfd7e3; } .noDataMessage { @@ -200,44 +283,59 @@ } .noDataContent h3 { - color: #666; - font-size: 20px; + font-size: 22px; + font-weight: 600; margin-bottom: 16px; - font-weight: 500; + color: #2d3748; } .noDataContentDark h3 { - color: #ccc; + color: #e2e8f0; } .noDataContent p { - color: #888; - font-size: 14px; - line-height: 1.5; - margin-bottom: 8px; -} - -.noDataContent p:last-child { - margin-bottom: 0; + font-size: 15px; + line-height: 1.6; + color: #4a5568; + margin-bottom: 10px; } .noDataContentDark p { - color: #aaa; + color: #cbd5e0; } -/* Responsive styles */ -@media (max-width: 768px) { - .chartContainer { - height: 250px; - padding: 10px; - } +/* ---------- Responsive styles ---------- */ +@media (max-width: 900px) { .filtersContainer { flex-direction: column; } - .filter { + .dateFilter, + .projectFilter { + flex: 1 1 100%; + max-width: 100%; + min-width: 0; + } + + .dateRangePicker { + white-space: normal; + } + + .dateRangeSeparator { + display: block; + margin: 8px 0; + } + + .dateRangePickerStart :global(.react-datepicker-wrapper), + .dateRangePickerEnd :global(.react-datepicker-wrapper) { width: 100%; } } +@media (max-width: 768px) { + .chartContainer { + height: 280px; + padding: 16px; + } +} diff --git a/src/components/BMDashboard/Issues/openIssueCharts.jsx b/src/components/BMDashboard/Issues/openIssueCharts.jsx index 6c269fb252..9df0b3f316 100644 --- a/src/components/BMDashboard/Issues/openIssueCharts.jsx +++ b/src/components/BMDashboard/Issues/openIssueCharts.jsx @@ -8,6 +8,7 @@ import { XAxis, YAxis, CartesianGrid, + Tooltip, ResponsiveContainer, LabelList, } from 'recharts'; @@ -17,25 +18,100 @@ import { fetchLongestOpenIssues, setProjectFilter, } from '../../../actions/bmdashboard/issueChartActions'; -import styles from './issueChart.module.css'; +import styles from './issueCharts.module.css'; + +/* ---------- helpers ---------- */ + +const getThemeColors = isDark => ({ + textColor: isDark ? '#f7fafc' : '#1a202c', + gridColor: isDark ? '#4a5568' : '#e2e8f0', + tooltipBg: isDark ? '#2d3748' : '#ffffff', + tooltipBorder: isDark ? '#4a5568' : '#e2e8f0', + hoverBg: isDark ? '#2d3748' : '#e2e8f0', +}); + +const getErrorColor = isDark => (isDark ? '#fca5a5' : '#dc2626'); + +const getOptionBackground = (isDark, isFocused) => { + if (isFocused) { + return isDark ? '#2d3748' : '#e2e8f0'; + } + return isDark ? '#1a202c' : '#ffffff'; +}; + +const getChartClasses = (css, isDark) => ({ + containerClass: `${css.issueChartContainer} ${isDark ? css.issueChartContainerDark : ''}`, + labelClass: `${css.issueChartLabel} ${isDark ? css.issueChartLabelDark : ''}`, + filterSelectClass: `${css.filterSelect} ${isDark ? css.filterSelectDark : ''}`, + chartContainerClass: `${css.chartContainer} ${isDark ? css.chartContainerDark : ''}`, + noDataMessageClass: `${css.noDataMessage} ${isDark ? css.noDataMessageDark : ''}`, + noDataContentClass: `${css.noDataContent} ${isDark ? css.noDataContentDark : ''}`, +}); + +const createSelectStyles = (isDark, textColor) => ({ + control: (base, state) => ({ + ...base, + backgroundColor: isDark ? '#2d3748' : '#ffffff', + borderColor: isDark ? '#4a5568' : '#cbd5e0', + boxShadow: state.isFocused ? '0 0 0 1px #4caf50' : 'none', + '&:hover': { + borderColor: '#4caf50', + }, + color: textColor, + }), + menu: base => ({ + ...base, + backgroundColor: isDark ? '#1a202c' : '#ffffff', + color: textColor, + }), + option: (base, state) => ({ + ...base, + backgroundColor: getOptionBackground(isDark, state.isFocused), + color: textColor, + cursor: 'pointer', + }), + singleValue: base => ({ + ...base, + color: textColor, + }), + multiValue: base => ({ + ...base, + backgroundColor: isDark ? '#4a5568' : '#e2e8f0', + }), + multiValueLabel: base => ({ + ...base, + color: textColor, + }), + placeholder: base => ({ + ...base, + color: isDark ? '#a0aec0' : '#718096', + }), +}); + +/* --------------------------- component --------------------------- */ function IssueCharts() { const dispatch = useDispatch(); - + const darkMode = useSelector(state => state.theme?.darkMode); const { issues, loading, error, selectedProjects } = useSelector(state => state.bmissuechart); const projects = useSelector(state => state.bmProjects); - const darkMode = useSelector(state => state.theme?.darkMode); const [startDate, setStartDate] = useState(null); const [endDate, setEndDate] = useState(null); const chartContainerRef = useRef(null); const [containerWidth, setContainerWidth] = useState(window.innerWidth); - // Enhanced color scheme for accessibility - const textColor = darkMode ? '#f7fafc' : '#1a202c'; - const gridColor = darkMode ? '#4a5568' : '#e2e8f0'; - const tooltipBg = darkMode ? '#2d3748' : '#ffffff'; - const tooltipBorder = darkMode ? '#4a5568' : '#e2e8f0'; + const { textColor, gridColor, tooltipBg, tooltipBorder, hoverBg } = getThemeColors(darkMode); + const errorColor = getErrorColor(darkMode); + const { + containerClass, + labelClass, + filterSelectClass, + chartContainerClass, + noDataMessageClass, + noDataContentClass, + } = getChartClasses(styles, darkMode); + const selectStyles = createSelectStyles(darkMode, textColor); // Normalize issues for chart // Number issues per project to avoid conflicts when multiple projects are selected @@ -117,14 +193,13 @@ function IssueCharts() { }); }, [issues]); - // Load projects on mount useEffect(() => { dispatch(fetchBMProjects()); }, [dispatch]); - // Fetch issues when filters change useEffect(() => { let dateRange = []; + if (startDate && endDate) { dateRange = [ `${startDate.toISOString().split('T')[0]},${endDate.toISOString().split('T')[0]}`, @@ -139,7 +214,6 @@ function IssueCharts() { dispatch(fetchLongestOpenIssues(dateRange, selectedProjects)); }, [dispatch, startDate, endDate, selectedProjects]); - // Handle chart container width useEffect(() => { function handleResize() { if (chartContainerRef.current) { @@ -171,158 +245,139 @@ function IssueCharts() { const { margin, yAxisWidth } = getChartLayout(); - if (loading) { - return ( + /* ------------ decide what to show inside chart container ------------ */ + + let chartContent; + + if (error) { + chartContent = ( +
There are currently no open issues matching your selected criteria.
+Try adjusting your date range or project filters to see more results.
+No issues found.
- ) : ( -There are currently no open issues matching your selected criteria.
+Try adjusting your date range or project filters to see more results.
+There are currently no open issues matching your selected criteria.
-Try adjusting your date range or project filters to see more results.
-