Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
33801f4
Fix UI alignment, visibility, responsiveness, and dark mode hover sty…
Nov 20, 2025
7c9f1cb
Fix lint issues: add eslint disable comments for webpack import and c…
Nov 20, 2025
9aa4039
Fix dark mode background color and increase chart height to fill view…
Nov 21, 2025
7819949
Merge development branch into veda-UI-alignment-visibility-responsive…
Nov 22, 2025
ef7f268
Fix CSS module imports in ReviewsInsight components
Nov 22, 2025
ad74a9d
Fix CSS module imports in ReviewsInsight components
Nov 25, 2025
a69f64e
Fix lint error: remove invalid wait import from UserRoleTab test
Nov 25, 2025
3db497e
Remove console.log to improve reliability rating
Nov 25, 2025
ea36b34
Fix SonarQube issues: reduce cognitive complexity, fix exception hand…
Nov 25, 2025
72adf8b
Reduce cognitive complexity from 18 to ≤15 by extracting more helper …
Nov 25, 2025
64e49f2
Merge development into veda-UI-alignment-visibility-responsiveness-ch…
Nov 29, 2025
70adecd
Fix tooltip content visibility in dark mode for ApplicantsChart
Nov 29, 2025
ddf47d0
Rename DarkMode.css to index.css to comply with CI CSS file naming co…
Nov 29, 2025
78a470b
Fix date picker text visibility in dark mode and center error message
Nov 29, 2025
b0741fb
Add comprehensive CSS rules to ensure date picker input text is visib…
Nov 29, 2025
c1d8913
Display validation error message in center of chart area instead of b…
Nov 29, 2025
e2fc2d9
Show 'No data' instead of error message when start date is greater th…
Nov 29, 2025
8d830df
Merge origin/development into veda-UI-alignment-visibility-responsive…
Dec 3, 2025
efdeb5d
Fix: Correct CSS import paths - use index.css instead of non-existent…
Dec 3, 2025
c1c68ba
resolved conflicts
Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config-overrides.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const webpack = require('webpack');

module.exports = function override(config) {
Expand Down
230 changes: 170 additions & 60 deletions src/components/ApplicantsChart/AgeChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,187 @@
ResponsiveContainer,
LabelList,
} from 'recharts';
import { useSelector } from 'react-redux';
import styles from './ApplicationChart.module.css';
import styles from './ApplicantsChart.module.css';

function AgeChart({ data, compareLabel }) {
const darkMode = useSelector(state => state.theme.darkMode);
const axisColor = darkMode ? '#f3f4f6' : '#111827';
const axisLineColor = darkMode ? '#d1d5db' : '#374151';
const gridColor = darkMode ? '#9ca3af' : '#d1d5db';
const tickFontSize = 14;
function AgeChart({ data, compareLabel, darkMode }) {

Check warning on line 13 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'darkMode' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBT-&open=AZqpRQgI1Hi29yoTyBT-&pullRequest=4435

Check warning on line 13 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'data' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBT8&open=AZqpRQgI1Hi29yoTyBT8&pullRequest=4435

Check warning on line 13 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'compareLabel' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBT9&open=AZqpRQgI1Hi29yoTyBT9&pullRequest=4435
// Guard against invalid data
if (!data || !Array.isArray(data) || data.length === 0) {

Check warning on line 15 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'data.length' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBT_&open=AZqpRQgI1Hi29yoTyBT_&pullRequest=4435
return null;
}

const formatTooltip = (value, name, props) => {
const { change } = props.payload;
if (compareLabel && change !== undefined) {
let changeText = '';
// Validate data structure
const validData = data.filter(

Check warning on line 20 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'data.filter' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBUA&open=AZqpRQgI1Hi29yoTyBUA&pullRequest=4435
item => item && item.ageGroup && typeof item.applicants === 'number' && !isNaN(item.applicants),

Check warning on line 21 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBUB&open=AZqpRQgI1Hi29yoTyBUB&pullRequest=4435

Check warning on line 21 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `Number.isNaN` over `isNaN`.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZqpRQgI1Hi29yoTyBUC&open=AZqpRQgI1Hi29yoTyBUC&pullRequest=4435
);

if (validData.length === 0) {
return null;
}

// Custom tooltip content component
const CustomTooltip = ({ active, payload, label }) => {

Check warning on line 29 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'label' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtq&open=AZrRaYu14fu7CA6Ciwtq&pullRequest=4435

Check warning on line 29 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move this component definition out of the parent component and pass data as props.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtr&open=AZrRaYu14fu7CA6Ciwtr&pullRequest=4435

Check warning on line 29 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'active' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwto&open=AZrRaYu14fu7CA6Ciwto&pullRequest=4435

Check warning on line 29 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtp&open=AZrRaYu14fu7CA6Ciwtp&pullRequest=4435

Check failure on line 29 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwts&open=AZrRaYu14fu7CA6Ciwts&pullRequest=4435
if (!active || !payload || !payload.length) {

Check warning on line 30 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload.length' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtu&open=AZrRaYu14fu7CA6Ciwtu&pullRequest=4435

Check warning on line 30 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtt&open=AZrRaYu14fu7CA6Ciwtt&pullRequest=4435
return null;
}

const dataPoint = payload[0];
if (!dataPoint) {
return null;
}

// Try multiple ways to access the data - Recharts passes data in payload[0].payload
const payloadData = dataPoint.payload || {};

Check warning on line 40 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload[].payload' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtv&open=AZrRaYu14fu7CA6Ciwtv&pullRequest=4435
// Also check if label is passed directly (from XAxis)
const ageGroup = label || payloadData.ageGroup || dataPoint.name || '';

Check warning on line 42 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload[].name' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtw&open=AZrRaYu14fu7CA6Ciwtw&pullRequest=4435
const applicants =
dataPoint.value !== undefined && dataPoint.value !== null

Check warning on line 44 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload[].value' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtx&open=AZrRaYu14fu7CA6Ciwtx&pullRequest=4435

Check warning on line 44 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload[].value' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwty&open=AZrRaYu14fu7CA6Ciwty&pullRequest=4435
? dataPoint.value

Check warning on line 45 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'payload[].value' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwtz&open=AZrRaYu14fu7CA6Ciwtz&pullRequest=4435
: payloadData.applicants !== undefined

Check warning on line 46 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwt0&open=AZrRaYu14fu7CA6Ciwt0&pullRequest=4435
? payloadData.applicants
: 0;

Check warning on line 48 in src/components/ApplicantsChart/AgeChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrRaYu14fu7CA6Ciwt1&open=AZrRaYu14fu7CA6Ciwt1&pullRequest=4435
const change = payloadData.change;

// Debug: log to see what we're getting (remove in production)
// console.log('Tooltip data:', { active, payload, label, dataPoint, payloadData, ageGroup, applicants, change });

let changeText = '';
if (compareLabel && change !== undefined && change !== null) {
if (change > 0) {
changeText = `${change}% more than ${compareLabel}`;
changeText = `(${change}% more than ${compareLabel})`;
} else if (change < 0) {
changeText = `${Math.abs(change)}% less than ${compareLabel}`;
changeText = `(${Math.abs(change)}% less than ${compareLabel})`;
} else {
changeText = `No change from ${compareLabel}`;
changeText = `(No change from ${compareLabel})`;
}
return [`${value} (${changeText})`, 'Applicants'];
}
return [`${value}`, 'Applicants'];

// Ensure we always render content, even if some values are missing
const displayAgeGroup = ageGroup || 'N/A';
const displayApplicants = applicants !== undefined && applicants !== null ? applicants : 0;

return (
<div
className={styles.customTooltip}
style={{
backgroundColor: '#ffffff',
border: `1px solid ${darkMode ? '#555' : '#ccc'}`,
borderRadius: '4px',
padding: '8px 12px',
boxShadow: darkMode ? '0 2px 8px rgba(0, 0, 0, 0.3)' : '0 2px 8px rgba(0, 0, 0, 0.15)',
zIndex: 1000,
minWidth: '150px',
position: 'relative',
}}
>
<div
className={styles.tooltipAgeGroup}
style={{
fontWeight: '600',
color: '#000000',
marginBottom: '4px',
fontSize: '14px',
display: 'block',
}}
>
{displayAgeGroup}
</div>
<div
className={styles.tooltipApplicants}
style={{
color: '#000000',
marginBottom: changeText ? '2px' : '0',
fontSize: '13px',
display: 'block',
}}
>
Applicants :{' '}
<strong style={{ color: '#000000', fontWeight: '700' }}>{displayApplicants}</strong>
</div>
{changeText && (
<div
className={styles.tooltipChange}
style={{
color: '#000000',
fontSize: '12px',
marginTop: '2px',
display: 'block',
}}
>
{changeText}
</div>
)}
</div>
);
};

return (
<div className={`${styles.AgeChart} ${darkMode ? 'darkMode' : ''}`}>
<h2 style={{ color: axisColor }}>Applicants grouped by Age</h2>
<ResponsiveContainer width="100%" height={400}>
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 20 }} barSize={80}>
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" strokeWidth={1.5} />
<XAxis
dataKey="ageGroup"
stroke={axisLineColor}
tick={{ fill: axisColor, fontSize: tickFontSize, fontWeight: 'bold' }}
label={{
value: 'Age Group',
position: 'insideBottom',
offset: -10,
fill: axisColor,
fontWeight: 'bold',
}}
/>
<YAxis
stroke={axisLineColor}
tick={{ fill: axisColor, fontSize: tickFontSize, fontWeight: 'bold' }}
label={{
value: 'Applicants',
angle: -90,
position: 'insideLeft',
fill: axisColor,
fontWeight: 'bold',
}}
/>
<Tooltip
formatter={formatTooltip}
contentStyle={{
backgroundColor: darkMode ? '#1f2937' : '#ffffff',
fontWeight: 'bold',
}}
labelStyle={{
color: darkMode ? '#f3f4f6' : '#111827',
fontWeight: 'bold',
<div
className={darkMode ? 'bg-oxford-blue text-light' : 'bg-white text-black'}
style={{
width: '100%',
maxWidth: '100%',
margin: '0 auto',
padding: 'clamp(10px, 2vw, 20px) clamp(10px, 2vw, 20px) 0 clamp(10px, 2vw, 20px)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<div
style={{
width: '100%',
height: 'calc(100vh - 150px)',
minHeight: '600px',
maxWidth: '100%',
position: 'relative',
backgroundColor: darkMode ? '#1b2a41' : '#fff',
}}
>
<ResponsiveContainer width="100%" height="100%" debounce={1}>
<BarChart
data={validData}
margin={{
top: 20,
right: 30,
left: 20,
bottom: 20,
}}
/>
<Bar dataKey="applicants" fill="#3b82f6">
<LabelList dataKey="applicants" position="top" fill={axisColor} fontWeight="bold" />
</Bar>
</BarChart>
</ResponsiveContainer>
barSize={60}
>
<CartesianGrid strokeDasharray="3 3" stroke={darkMode ? '#555' : '#ccc'} />
<XAxis
dataKey="ageGroup"
label={{
value: 'Age Group',
position: 'insideBottom',
offset: -5,
fill: darkMode ? '#fff' : '#000',
}}
tick={{ fill: darkMode ? '#fff' : '#000' }}
/>
<YAxis
label={{
value: 'Number of Applicants',
angle: -90,
position: 'insideLeft',
offset: -5,
fill: darkMode ? '#fff' : '#000',
}}
tick={{ fill: darkMode ? '#fff' : '#000' }}
domain={[0, 'auto']}
/>
<Tooltip
content={CustomTooltip}
wrapperStyle={{ zIndex: 1000, pointerEvents: 'none' }}
cursor={{ fill: 'rgba(0, 0, 0, 0.1)' }}
allowEscapeViewBox={{ x: false, y: false }}
/>
<Bar dataKey="applicants" fill={darkMode ? '#60a5fa' : '#3b82f6'}>
<LabelList dataKey="applicants" position="top" fill={darkMode ? '#fff' : '#000'} />
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
</div>
);
}
Expand Down
Loading
Loading