Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
71 changes: 71 additions & 0 deletions src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useState } from 'react';
import axios from 'axios';
import { toast } from 'react-toastify';
import { ENDPOINTS } from '../../../utils/URL';
import { EXPORT_FORMATS } from './constants';
import styles from './UtilizationChart.module.css';

function ExportReportButton({ tool, project, startDate, endDate }) {

Check warning on line 8 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'startDate' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V79&open=AZ0tlwhElpSFCu4-_V79&pullRequest=5073

Check warning on line 8 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'project' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V78&open=AZ0tlwhElpSFCu4-_V78&pullRequest=5073

Check warning on line 8 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'tool' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V77&open=AZ0tlwhElpSFCu4-_V77&pullRequest=5073

Check warning on line 8 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'endDate' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V7-&open=AZ0tlwhElpSFCu4-_V7-&pullRequest=5073
const [exportingFormat, setExportingFormat] = useState(null);

const handleExport = async format => {
setExportingFormat(format);
try {
const params = {
format,
tool,
project,
...(startDate && { startDate: startDate.toISOString() }),

Check warning on line 18 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'startDate.toISOString' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V7_&open=AZ0tlwhElpSFCu4-_V7_&pullRequest=5073
...(endDate && { endDate: endDate.toISOString() }),

Check warning on line 19 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'endDate.toISOString' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V8A&open=AZ0tlwhElpSFCu4-_V8A&pullRequest=5073
};
const response = await axios.get(ENDPOINTS.BM_TOOL_UTILIZATION_EXPORT, {
params,
headers: { Authorization: localStorage.getItem('token') },
responseType: 'blob',
});

const contentDisposition = response.headers['content-disposition'] || '';
const filenameMatch = contentDisposition.match(/filename="?([^"]+)"?/);
const filename = filenameMatch ? filenameMatch[1] : `tool-utilization-report.${format}`;

const url = window.URL.createObjectURL(response.data);

Check warning on line 31 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V8B&open=AZ0tlwhElpSFCu4-_V8B&pullRequest=5073
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);

Check warning on line 38 in src/components/BMDashboard/UtilizationChart/ExportReportButton.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhElpSFCu4-_V8C&open=AZ0tlwhElpSFCu4-_V8C&pullRequest=5073
} catch {
toast.error(`Failed to export ${format.toUpperCase()} report.`);
} finally {
setExportingFormat(null);
}
};

return (
<div className={styles.exportSection}>
<span className={styles.exportLabel}>Export Report:</span>
<button
type="button"
className={styles.exportButton}
onClick={() => handleExport(EXPORT_FORMATS.PDF)}
disabled={exportingFormat !== null}
aria-label="Export as PDF"
>
{exportingFormat === EXPORT_FORMATS.PDF ? 'Exporting...' : 'PDF'}
</button>
<button
type="button"
className={styles.exportButton}
onClick={() => handleExport(EXPORT_FORMATS.CSV)}
disabled={exportingFormat !== null}
aria-label="Export as CSV"
>
{exportingFormat === EXPORT_FORMATS.CSV ? 'Exporting...' : 'CSV'}
</button>
</div>
);
}

export default ExportReportButton;
51 changes: 51 additions & 0 deletions src/components/BMDashboard/UtilizationChart/ForecastModeToggle.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useRef } from 'react';
import { FORECAST_MODE_LABELS } from './constants';
import styles from './UtilizationChart.module.css';

const MODES = Object.entries(FORECAST_MODE_LABELS);

function ForecastModeToggle({ value, onChange }) {

Check warning on line 7 in src/components/BMDashboard/UtilizationChart/ForecastModeToggle.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'onChange' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwZblpSFCu4-_V7u&open=AZ0tlwZblpSFCu4-_V7u&pullRequest=5073

Check warning on line 7 in src/components/BMDashboard/UtilizationChart/ForecastModeToggle.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'value' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwZblpSFCu4-_V7t&open=AZ0tlwZblpSFCu4-_V7t&pullRequest=5073
const buttonRefs = useRef([]);

const handleKeyDown = (e, index) => {
const count = MODES.length;
let nextIndex = -1;

if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
e.preventDefault();
nextIndex = (index + 1) % count;
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
e.preventDefault();
nextIndex = (index - 1 + count) % count;
}

if (nextIndex !== -1) {
onChange(MODES[nextIndex][0]);
buttonRefs.current[nextIndex]?.focus();
}
};

return (
<div className={styles.forecastToggle} role="radiogroup" aria-label="Forecast mode">
{MODES.map(([mode, label], index) => (
<button
key={mode}
ref={el => {
buttonRefs.current[index] = el;
}}
type="button"
role="radio"
aria-checked={value === mode}
tabIndex={value === mode ? 0 : -1}
className={`${styles.toggleButton} ${value === mode ? styles.toggleButtonActive : ''}`}
onClick={() => onChange(mode)}
onKeyDown={e => handleKeyDown(e, index)}
>
{label}
</button>
))}
</div>
);
}

export default ForecastModeToggle;
32 changes: 32 additions & 0 deletions src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import styles from './UtilizationChart.module.css';

function InsightsSummaryBar({ summary }) {

Check warning on line 3 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V7z&open=AZ0tlwg3lpSFCu4-_V7z&pullRequest=5073
if (!summary) return null;

return (
<div className={styles.summaryBar} role="region" aria-label="Utilization summary">

Check warning on line 7 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use <section aria-label=...>, or <section aria-labelledby=...> instead of the "region" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V70&open=AZ0tlwg3lpSFCu4-_V70&pullRequest=5073
<div className={styles.summaryCard}>
<span className={styles.summaryValue}>{summary.totalToolTypes}</span>

Check warning on line 9 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary.totalToolTypes' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V71&open=AZ0tlwg3lpSFCu4-_V71&pullRequest=5073
<span className={styles.summaryLabel}>Tool Types</span>
</div>
<div className={styles.summaryCard}>
<span className={styles.summaryValue}>{summary.averageUtilization}%</span>

Check warning on line 13 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary.averageUtilization' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V72&open=AZ0tlwg3lpSFCu4-_V72&pullRequest=5073
<span className={styles.summaryLabel}>Avg Utilization</span>
</div>
<div className={`${styles.summaryCard} ${styles.summaryCardGreen}`}>
<span className={styles.summaryValue}>{summary.normal}</span>

Check warning on line 17 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary.normal' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V73&open=AZ0tlwg3lpSFCu4-_V73&pullRequest=5073
<span className={styles.summaryLabel}>Normal</span>
</div>
<div className={`${styles.summaryCard} ${styles.summaryCardYellow}`}>
<span className={styles.summaryValue}>{summary.underUtilized}</span>

Check warning on line 21 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary.underUtilized' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V74&open=AZ0tlwg3lpSFCu4-_V74&pullRequest=5073
<span className={styles.summaryLabel}>Under-utilized</span>
</div>
<div className={`${styles.summaryCard} ${styles.summaryCardRed}`}>
<span className={styles.summaryValue}>{summary.overUtilized}</span>

Check warning on line 25 in src/components/BMDashboard/UtilizationChart/InsightsSummaryBar.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'summary.overUtilized' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg3lpSFCu4-_V75&open=AZ0tlwg3lpSFCu4-_V75&pullRequest=5073
<span className={styles.summaryLabel}>Over-utilized</span>
</div>
</div>
);
}

export default InsightsSummaryBar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { URGENCY_STYLES } from './constants';
import styles from './UtilizationChart.module.css';

function MaintenanceAlertPanel({ alerts }) {

Check warning on line 4 in src/components/BMDashboard/UtilizationChart/MaintenanceAlertPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'alerts' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwg9lpSFCu4-_V76&open=AZ0tlwg9lpSFCu4-_V76&pullRequest=5073
const sortedAlerts = [...alerts].sort((a, b) =>
a.urgency === 'high' && b.urgency !== 'high' ? -1 : 1,
);

return (
<section className={styles.insightsPanel} aria-labelledby="maintenance-heading">
<h3 id="maintenance-heading" className={styles.panelTitle}>
Maintenance Alerts
</h3>
{sortedAlerts.length === 0 ? (
<p className={styles.emptyPanel}>No maintenance alerts.</p>
) : (
<ul className={styles.alertList}>
{sortedAlerts.map((alert, index) => (
<li
key={`${alert.toolName}-${alert.alertType}-${index}`}
className={styles.alertItem}
data-urgency={alert.urgency}
>
<div className={styles.alertHeader}>
<span
className={styles.urgencyBadge}
style={{ backgroundColor: URGENCY_STYLES[alert.urgency]?.color }}
>
{URGENCY_STYLES[alert.urgency]?.label}
</span>
<strong>{alert.toolName}</strong>
</div>
<p className={styles.alertMessage}>{alert.message}</p>
</li>
))}
</ul>
)}
</section>
);
}

export default MaintenanceAlertPanel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { TRAFFIC_LIGHT_COLORS } from './constants';
import styles from './UtilizationChart.module.css';

function RecommendationPanel({ recommendations }) {

Check warning on line 4 in src/components/BMDashboard/UtilizationChart/RecommendationPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'recommendations' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwgOlpSFCu4-_V7v&open=AZ0tlwgOlpSFCu4-_V7v&pullRequest=5073
return (
<section className={styles.insightsPanel} aria-labelledby="recommendations-heading">
<h3 id="recommendations-heading" className={styles.panelTitle}>
Utilization Recommendations
</h3>
{recommendations.length === 0 ? (

Check warning on line 10 in src/components/BMDashboard/UtilizationChart/RecommendationPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'recommendations.length' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwgOlpSFCu4-_V7w&open=AZ0tlwgOlpSFCu4-_V7w&pullRequest=5073
<p className={styles.emptyPanel}>No recommendations available.</p>
) : (
<ul className={styles.recommendationList}>
{recommendations.map(rec => (

Check warning on line 14 in src/components/BMDashboard/UtilizationChart/RecommendationPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'recommendations.map' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwgOlpSFCu4-_V7x&open=AZ0tlwgOlpSFCu4-_V7x&pullRequest=5073
<li key={rec.toolName} className={styles.recommendationItem}>
<span
className={styles.trafficDot}
style={{ backgroundColor: TRAFFIC_LIGHT_COLORS[rec.trafficLight] }}
aria-hidden="true"
/>
<div>
<strong className={styles.toolName}>{rec.toolName}</strong>
<span className={styles.classificationBadge} data-level={rec.trafficLight}>
{rec.label}
</span>
<p className={styles.actionText}>{rec.action}</p>
<span className={styles.rateText}>{rec.utilizationRate}% utilization</span>
</div>
</li>
))}
</ul>
)}
</section>
);
}

export default RecommendationPanel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import styles from './UtilizationChart.module.css';

function ResourceBalancingPanel({ suggestions }) {

Check warning on line 3 in src/components/BMDashboard/UtilizationChart/ResourceBalancingPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'suggestions' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhLlpSFCu4-_V8D&open=AZ0tlwhLlpSFCu4-_V8D&pullRequest=5073
return (
<section className={styles.insightsPanel} aria-labelledby="balancing-heading">
<h3 id="balancing-heading" className={styles.panelTitle}>
Resource Balancing
</h3>
{suggestions.length === 0 ? (

Check warning on line 9 in src/components/BMDashboard/UtilizationChart/ResourceBalancingPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'suggestions.length' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhLlpSFCu4-_V8E&open=AZ0tlwhLlpSFCu4-_V8E&pullRequest=5073
<p className={styles.emptyPanel}>Resources are balanced. No action needed.</p>
) : (
<ul className={styles.balancingList}>
{suggestions.map((item, index) => (

Check warning on line 13 in src/components/BMDashboard/UtilizationChart/ResourceBalancingPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'suggestions.map' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhLlpSFCu4-_V8F&open=AZ0tlwhLlpSFCu4-_V8F&pullRequest=5073
<li key={`balance-${index}`} className={styles.balancingItem}>

Check warning on line 14 in src/components/BMDashboard/UtilizationChart/ResourceBalancingPanel.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0tlwhLlpSFCu4-_V8G&open=AZ0tlwhLlpSFCu4-_V8G&pullRequest=5073
<p className={styles.suggestionText}>{item.suggestion}</p>
<div className={styles.balancingDetail}>
<span className={styles.fromTool}>
From: <strong>{item.fromTool}</strong>
</span>
{item.toTool && (
<span className={styles.toTool}>
&rarr; To: <strong>{item.toTool}</strong>
</span>
)}
</div>
<p className={styles.rationaleText}>{item.rationale}</p>
</li>
))}
</ul>
)}
</section>
);
}

export default ResourceBalancingPanel;
Loading
Loading