feat(calendar): click due-date day to navigate to filtered Reporting view
- CalendarWidget accepts onDateClick prop; due-date cells are clickable
with pointer cursor, red hover highlight, and updated tooltip
- App.js wires onDateClick: sets calendarFilter state and navigates to
the Reporting page
- NavDrawer navigation to Reporting clears calendarFilter so it only
applies on calendar-initiated navigation
- ReportingPage accepts filterDate prop; initializes columnFilters with
{ dueDate: Set([filterDate]) } so the view lands pre-filtered
- Existing Clear Filters button lets the user dismiss the filter normally
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -178,6 +178,7 @@ export default function App() {
|
|||||||
const [quickCheckResult, setQuickCheckResult] = useState(null);
|
const [quickCheckResult, setQuickCheckResult] = useState(null);
|
||||||
const [currentPage, setCurrentPage] = useState('home');
|
const [currentPage, setCurrentPage] = useState('home');
|
||||||
const [navOpen, setNavOpen] = useState(false);
|
const [navOpen, setNavOpen] = useState(false);
|
||||||
|
const [calendarFilter, setCalendarFilter] = useState(null);
|
||||||
const [showAddCVE, setShowAddCVE] = useState(false);
|
const [showAddCVE, setShowAddCVE] = useState(false);
|
||||||
const [showUserManagement, setShowUserManagement] = useState(false);
|
const [showUserManagement, setShowUserManagement] = useState(false);
|
||||||
const [showAuditLog, setShowAuditLog] = useState(false);
|
const [showAuditLog, setShowAuditLog] = useState(false);
|
||||||
@@ -961,7 +962,11 @@ export default function App() {
|
|||||||
isOpen={navOpen}
|
isOpen={navOpen}
|
||||||
onClose={() => setNavOpen(false)}
|
onClose={() => setNavOpen(false)}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
onNavigate={setCurrentPage}
|
onNavigate={(page) => {
|
||||||
|
// Clear calendar filter when navigating directly via the nav drawer
|
||||||
|
if (page === 'reporting') setCalendarFilter(null);
|
||||||
|
setCurrentPage(page);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{/* Scanning line effect */}
|
{/* Scanning line effect */}
|
||||||
<div className="scan-line"></div>
|
<div className="scan-line"></div>
|
||||||
@@ -1036,7 +1041,7 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Page content */}
|
{/* Page content */}
|
||||||
{currentPage === 'reporting' && <ReportingPage />}
|
{currentPage === 'reporting' && <ReportingPage filterDate={calendarFilter} />}
|
||||||
{currentPage === 'knowledge-base' && <KnowledgeBasePage />}
|
{currentPage === 'knowledge-base' && <KnowledgeBasePage />}
|
||||||
{currentPage === 'exports' && <ExportsPage />}
|
{currentPage === 'exports' && <ExportsPage />}
|
||||||
|
|
||||||
@@ -2220,7 +2225,12 @@ export default function App() {
|
|||||||
Calendar
|
Calendar
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<CalendarWidget />
|
<CalendarWidget
|
||||||
|
onDateClick={(dateStr) => {
|
||||||
|
setCalendarFilter(dateStr);
|
||||||
|
setCurrentPage('reporting');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Open Vendor Tickets */}
|
{/* Open Vendor Tickets */}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function toLocalDateStr(date) {
|
|||||||
return `${y}-${m}-${d}`;
|
return `${y}-${m}-${d}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CalendarWidget() {
|
export default function CalendarWidget({ onDateClick }) {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const todayStr = toLocalDateStr(today);
|
const todayStr = toLocalDateStr(today);
|
||||||
|
|
||||||
@@ -116,15 +116,19 @@ export default function CalendarWidget() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={idx}
|
key={idx}
|
||||||
title={hasDue ? `${dueCount} finding${dueCount > 1 ? 's' : ''} due` : undefined}
|
title={hasDue ? `${dueCount} finding${dueCount > 1 ? 's' : ''} due — click to view` : undefined}
|
||||||
|
onClick={hasDue && onDateClick ? () => onDateClick(dateStr) : undefined}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex', flexDirection: 'column', alignItems: 'center',
|
display: 'flex', flexDirection: 'column', alignItems: 'center',
|
||||||
gap: '2px', padding: '3px 1px',
|
gap: '2px', padding: '3px 1px',
|
||||||
borderRadius: '4px',
|
borderRadius: '4px',
|
||||||
background: isToday ? 'rgba(14,165,233,0.2)' : 'transparent',
|
background: isToday ? 'rgba(14,165,233,0.2)' : 'transparent',
|
||||||
border: isToday ? '1px solid rgba(14,165,233,0.5)' : '1px solid transparent',
|
border: isToday ? '1px solid rgba(14,165,233,0.5)' : '1px solid transparent',
|
||||||
cursor: hasDue ? 'default' : 'default',
|
cursor: hasDue ? 'pointer' : 'default',
|
||||||
|
transition: hasDue ? 'background 0.15s' : undefined,
|
||||||
}}
|
}}
|
||||||
|
onMouseEnter={hasDue ? (e) => { e.currentTarget.style.background = isToday ? 'rgba(14,165,233,0.35)' : 'rgba(239,68,68,0.15)'; } : undefined}
|
||||||
|
onMouseLeave={hasDue ? (e) => { e.currentTarget.style.background = isToday ? 'rgba(14,165,233,0.2)' : 'transparent'; } : undefined}
|
||||||
>
|
>
|
||||||
<span style={{
|
<span style={{
|
||||||
fontSize: '0.7rem', fontFamily: 'monospace', lineHeight: 1,
|
fontSize: '0.7rem', fontFamily: 'monospace', lineHeight: 1,
|
||||||
|
|||||||
@@ -564,7 +564,7 @@ function TableCell({ colKey, finding }) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Main ReportingPage
|
// Main ReportingPage
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
export default function ReportingPage() {
|
export default function ReportingPage({ filterDate }) {
|
||||||
const [findings, setFindings] = useState([]);
|
const [findings, setFindings] = useState([]);
|
||||||
const [total, setTotal] = useState(null);
|
const [total, setTotal] = useState(null);
|
||||||
const [syncedAt, setSyncedAt] = useState(null);
|
const [syncedAt, setSyncedAt] = useState(null);
|
||||||
@@ -574,7 +574,9 @@ export default function ReportingPage() {
|
|||||||
const [syncing, setSyncing] = useState(false);
|
const [syncing, setSyncing] = useState(false);
|
||||||
const [sort, setSort] = useState({ field: 'severity', dir: 'desc' });
|
const [sort, setSort] = useState({ field: 'severity', dir: 'desc' });
|
||||||
const [columnOrder, setColumnOrder] = useState(loadColumnOrder);
|
const [columnOrder, setColumnOrder] = useState(loadColumnOrder);
|
||||||
const [columnFilters, setColumnFilters] = useState({});
|
const [columnFilters, setColumnFilters] = useState(() =>
|
||||||
|
filterDate ? { dueDate: new Set([filterDate]) } : {}
|
||||||
|
);
|
||||||
const [openFilter, setOpenFilter] = useState(null);
|
const [openFilter, setOpenFilter] = useState(null);
|
||||||
const filterBtnRefs = useRef({});
|
const filterBtnRefs = useRef({});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user