/**
* @file 12d-weeklyreport.js — Weekly report draft.
*
* Groups this calendar week's (Mon–Sun) finished, non-cancelled, non-utility
* entries by Jira ticket key via buildWeeklyTicketSummary()/
* formatWeeklyTicketSummaryText() (pure-fns-weeklyreport.js), so writing a
* status report no longer means reconstructing "what did I touch" by hand
* across Jira/Confluence/memory. Opens a modal with the rendered text and a
* copy-to-clipboard button — mirrors 12c-gapreport.js's modal wiring and
* 25-rollingsummary.js's copy-to-clipboard pattern.
*
* Pure helpers (buildWeeklyTicketSummary, formatWeeklyTicketSummaryText) live
* in pure-fns-weeklyreport.js and are unit-tested there. This module is the
* localStorage + DOM glue around them.
*/
import {
buildWeeklyTicketSummary,
formatWeeklyTicketSummaryText,
} from './pure-fns-weeklyreport.js';
import { mondayOfWeek, fmtDurLong } from './pure-fns-format.js';
import { wlLog } from './logger.js';
import { getEntries } from './state.js';
import { trapFocusInOverlay } from './focus-utils.js';
// Element that had focus when the report was opened, restored on close —
// same convention as the gap-report modal in 12c-gapreport.js.
let _weeklyReportTrigger = null;
/**
* Formats a week-start timestamp as a "Mon DD Mon – Sun DD Mon" range label.
* @param {number} weekStart - Monday 00:00 local time, in ms.
* @returns {string} The formatted range.
*/
export function weekRangeLabel(weekStart) {
const opts = { weekday: 'short', day: '2-digit', month: 'short' };
const start = new Date(weekStart).toLocaleDateString('en', opts);
const end = new Date(weekStart + 6 * 24 * 60 * 60 * 1000).toLocaleDateString('en', opts);
return `${start} – ${end}`;
}
/**
* Opens the weekly report draft: this calendar week's entries grouped by
* ticket. Builds the text fresh from current `entries` state every time
* it's opened, so it always reflects the latest data.
* @returns {void}
*/
export function openWeeklyReportOverlay() {
const overlay = document.getElementById('weeklyReportOverlay');
if (!overlay) return;
_weeklyReportTrigger = document.activeElement;
const weekStart = mondayOfWeek();
const weekEnd = weekStart + 7 * 24 * 60 * 60 * 1000;
const { ticketOrder, grouped } = buildWeeklyTicketSummary(getEntries(), weekStart, weekEnd);
const lines = formatWeeklyTicketSummaryText(ticketOrder, grouped, fmtDurLong);
const subtitleEl = document.getElementById('weeklyReportSubtitle');
const textEl = document.getElementById('weeklyReportText');
if (subtitleEl) subtitleEl.textContent = weekRangeLabel(weekStart);
if (textEl) {
textEl.textContent = lines.length ? lines.join('\n') : 'Nothing tracked yet this week.';
}
overlay.classList.add('show');
setTimeout(() => {
const first = overlay.querySelector('button, [tabindex]:not([tabindex="-1"])');
if (first) first.focus();
}, 50);
}
/**
* Restores focus to whatever triggered the report, then clears the trigger.
* @returns {void}
*/
export function restoreWeeklyReportFocus() {
if (_weeklyReportTrigger) {
_weeklyReportTrigger.focus();
_weeklyReportTrigger = null;
}
}
/**
* Hides the weekly-report overlay and restores focus to its trigger.
* @returns {void}
*/
export function closeWeeklyReportOverlay() {
const overlay = document.getElementById('weeklyReportOverlay');
if (overlay) overlay.classList.remove('show');
restoreWeeklyReportFocus();
}
/**
* Copies the rendered report text to the clipboard. Reads directly from the
* visible `<pre>` block rather than rebuilding a parallel string, so the
* copied text can never drift from what's on screen. Shows a brief
* "Copied!" confirmation on success, or logs a warning on failure.
* @returns {void}
*/
export function copyWeeklyReportText() {
const textEl = document.getElementById('weeklyReportText');
if (!textEl) return;
navigator.clipboard
.writeText(textEl.textContent)
.then(() => {
const fb = document.getElementById('weeklyReportCopyFeedback');
if (fb) {
fb.textContent = 'Copied!';
setTimeout(() => {
fb.textContent = '';
}, 2000);
}
})
.catch((err) => {
wlLog.warn('copyWeeklyReportText: clipboard write failed', err);
});
}
/**
* Binds the weekly-report modal buttons. Called exactly once from the boot
* sequence in 07-lifecycle.js. Safe to call when any button is missing.
* @returns {void}
*/
export function initWeeklyReport() {
const weeklyReportBtn = document.getElementById('weeklyReportBtn');
const weeklyReportOverlay = document.getElementById('weeklyReportOverlay');
const weeklyReportClose = document.getElementById('weeklyReportClose');
const weeklyReportCopyBtn = document.getElementById('weeklyReportCopyBtn');
if (weeklyReportBtn) weeklyReportBtn.addEventListener('click', openWeeklyReportOverlay);
if (weeklyReportClose) weeklyReportClose.addEventListener('click', closeWeeklyReportOverlay);
if (weeklyReportCopyBtn) weeklyReportCopyBtn.addEventListener('click', copyWeeklyReportText);
if (weeklyReportOverlay) {
weeklyReportOverlay.addEventListener('click', (e) => {
if (e.target === weeklyReportOverlay) closeWeeklyReportOverlay();
});
weeklyReportOverlay.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeWeeklyReportOverlay();
if (e.key === 'Tab') trapFocusInOverlay(weeklyReportOverlay, e);
});
}
}