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
62 changes: 52 additions & 10 deletions sp-dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,19 @@ <h1 class="title">Dashboard</h1>
<option value="month">Past Month</option>
<option value="year">Past Year</option>
<option value="custom">Custom Range...</option>
<option value="from-weekday">Starting from weekday</option>
</select>
</div>
<div id="weekday-picker-container" class="control-box hidden">
<label for="weekday-select">Weekday</label>
<select id="weekday-select">
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
<option value="6">Saturday</option>
<option value="0">Sunday</option>
</select>
</div>
</div>
Expand Down Expand Up @@ -517,20 +530,45 @@ <h3 class="card-title">Project Breakdown</h3>

const presetSelect = document.getElementById('date-preset');
const customContainer = document.getElementById('custom-date-container');
const weekdayPickerContainer = document.getElementById('weekday-picker-container');
const dateFromInput = document.getElementById('date-from');
const dateToInput = document.getElementById('date-to');
const weekdaySelect = document.getElementById('weekday-select');

const savedPreset = localStorage.getItem('sp-dashboard-date-preset');
if (savedPreset) {
presetSelect.value = savedPreset;
customContainer.classList.toggle('hidden', savedPreset !== 'custom');
weekdayPickerContainer.classList.toggle('hidden', savedPreset !== 'from-weekday');
const savedFrom = localStorage.getItem('sp-dashboard-date-from');
const savedTo = localStorage.getItem('sp-dashboard-date-to');
if (savedPreset === 'custom' && savedFrom) dateFromInput.value = savedFrom;
if (savedPreset === 'custom' && savedTo) dateToInput.value = savedTo;
const savedWeekday = localStorage.getItem('sp-dashboard-weekday-select');
if (savedPreset === 'from-weekday' && savedWeekday) weekdaySelect.value = savedWeekday;
}

presetSelect.addEventListener('change', (e) => {
if (e.target.value === 'custom') {
customContainer.classList.remove('hidden');
} else {
customContainer.classList.add('hidden');
}
customContainer.classList.toggle('hidden', e.target.value !== 'custom');
weekdayPickerContainer.classList.toggle('hidden', e.target.value !== 'from-weekday');
localStorage.setItem('sp-dashboard-date-preset', e.target.value);
processData(cachedTasks, cachedProjects);
});

document.getElementById('date-from').addEventListener('change', () => processData(cachedTasks, cachedProjects));
document.getElementById('date-to').addEventListener('change', () => processData(cachedTasks, cachedProjects));
document.getElementById('bar-chart-select').addEventListener('change', () => updateBarChart());
document.getElementById('pie-chart-select').addEventListener('change', () => updatePieChart());
weekdaySelect.addEventListener('change', () => { localStorage.setItem('sp-dashboard-weekday-select', weekdaySelect.value); processData(cachedTasks, cachedProjects); });

dateFromInput.addEventListener('change', () => { localStorage.setItem('sp-dashboard-date-from', dateFromInput.value); processData(cachedTasks, cachedProjects); });
dateToInput.addEventListener('change', () => { localStorage.setItem('sp-dashboard-date-to', dateToInput.value); processData(cachedTasks, cachedProjects); });
const barChartSelect = document.getElementById('bar-chart-select');
const pieChartSelect = document.getElementById('pie-chart-select');

const savedBar = localStorage.getItem('sp-dashboard-bar-chart-select');
const savedPie = localStorage.getItem('sp-dashboard-pie-chart-select');
if (savedBar) barChartSelect.value = savedBar;
if (savedPie) pieChartSelect.value = savedPie;

barChartSelect.addEventListener('change', () => { localStorage.setItem('sp-dashboard-bar-chart-select', barChartSelect.value); updateBarChart(); });
pieChartSelect.addEventListener('change', () => { localStorage.setItem('sp-dashboard-pie-chart-select', pieChartSelect.value); updatePieChart(); });
Comment on lines +538 to +571
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The localStorage keys are currently hardcoded strings. It's a good practice to define these as constants (e.g., at the top of the script or in a dedicated constants object) to improve maintainability, prevent typos, and make it easier to manage them if they need to change in the future. This makes the code more robust and readable.

    const LS_PREFIX = 'sp-dashboard-';
    const LS_DATE_PRESET = LS_PREFIX + 'date-preset';
    const LS_DATE_FROM = LS_PREFIX + 'date-from';
    const LS_DATE_TO = LS_PREFIX + 'date-to';
    const LS_WEEKDAY_SELECT = LS_PREFIX + 'weekday-select';
    const LS_BAR_CHART_SELECT = LS_PREFIX + 'bar-chart-select';
    const LS_PIE_CHART_SELECT = LS_PREFIX + 'pie-chart-select';

    const savedPreset = localStorage.getItem(LS_DATE_PRESET);
    if (savedPreset) {
      presetSelect.value = savedPreset;
      customContainer.classList.toggle('hidden', savedPreset !== 'custom');
      weekdayPickerContainer.classList.toggle('hidden', savedPreset !== 'from-weekday');
      const savedFrom = localStorage.getItem(LS_DATE_FROM);
      const savedTo = localStorage.getItem(LS_DATE_TO);
      if (savedPreset === 'custom' && savedFrom) dateFromInput.value = savedFrom;
      if (savedPreset === 'custom' && savedTo) dateToInput.value = savedTo;
      const savedWeekday = localStorage.getItem(LS_WEEKDAY_SELECT);
      if (savedPreset === 'from-weekday' && savedWeekday) weekdaySelect.value = savedWeekday;
    }

    presetSelect.addEventListener('change', (e) => {
      customContainer.classList.toggle('hidden', e.target.value !== 'custom');
      weekdayPickerContainer.classList.toggle('hidden', e.target.value !== 'from-weekday');
      localStorage.setItem(LS_DATE_PRESET, e.target.value);
      processData(cachedTasks, cachedProjects);
    });

    weekdaySelect.addEventListener('change', () => { localStorage.setItem(LS_WEEKDAY_SELECT, weekdaySelect.value); processData(cachedTasks, cachedProjects); });

    dateFromInput.addEventListener('change', () => { localStorage.setItem(LS_DATE_FROM, dateFromInput.value); processData(cachedTasks, cachedProjects); });
    dateToInput.addEventListener('change', () => { localStorage.setItem(LS_DATE_TO, dateToInput.value); processData(cachedTasks, cachedProjects); });
    const barChartSelect = document.getElementById('bar-chart-select');
    const pieChartSelect = document.getElementById('pie-chart-select');

    const savedBar = localStorage.getItem(LS_BAR_CHART_SELECT);
    const savedPie = localStorage.getItem(LS_PIE_CHART_SELECT);
    if (savedBar) barChartSelect.value = savedBar;
    if (savedPie) pieChartSelect.value = savedPie;

    barChartSelect.addEventListener('change', () => { localStorage.setItem(LS_BAR_CHART_SELECT, barChartSelect.value); updateBarChart(); });
    pieChartSelect.addEventListener('change', () => { localStorage.setItem(LS_PIE_CHART_SELECT, pieChartSelect.value); updatePieChart(); });


// --- RENDER LOGIC ---
const updateDashboardUI = (metrics) => {
Expand Down Expand Up @@ -763,6 +801,10 @@ <h3 class="card-title">Project Breakdown</h3>
startObj.setMonth(endObj.getMonth() - 1);
} else if (preset === 'year') {
startObj.setFullYear(endObj.getFullYear() - 1);
} else if (preset === 'from-weekday') {
const targetDay = parseInt(document.getElementById('weekday-select').value, 10);
const daysBack = (endObj.getDay() - targetDay + 7) % 7;
startObj.setDate(endObj.getDate() - daysBack);
}
dateFromStr = startObj.toISOString().split('T')[0];
dateToStr = endObj.toISOString().split('T')[0];
Expand Down Expand Up @@ -1108,4 +1150,4 @@ <h3 class="card-title">Project Breakdown</h3>

</script>
</body>
</html>
</html>
27 changes: 27 additions & 0 deletions tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,33 @@ describe('Date Range Reporter UI', () => {
expect(pieLegend.querySelector('.legend-item')).not.toBeNull();
});

it('from-weekday preset with weekday picker should produce correct date range', () => {
const presetSelect = document.getElementById('date-preset');
const weekdaySelect = document.getElementById('weekday-select');
const barContainer = document.getElementById('bar-chart-container');
const weekdayPickerContainer = document.getElementById('weekday-picker-container');

presetSelect.value = 'from-weekday';
presetSelect.dispatchEvent(new Event('change'));
expect(weekdayPickerContainer.classList.contains('hidden')).toBe(false);

// Test each weekday
const today = new Date();
for (const targetDay of [0, 1, 2, 3, 4, 5, 6]) {
weekdaySelect.value = String(targetDay);
weekdaySelect.dispatchEvent(new Event('change'));
window.processData([], []);

const daysBack = (today.getDay() - targetDay + 7) % 7;
expect(barContainer.querySelectorAll('.bar-col').length).toBe(daysBack + 1);
}

// Switching away hides the picker
presetSelect.value = 'today';
presetSelect.dispatchEvent(new Event('change'));
expect(weekdayPickerContainer.classList.contains('hidden')).toBe(true);
});

it('detail list columns are sortable when headers are clicked', () => {
// create two tasks with different dates
const taskA = { id:'a', parentId:null, title:'A', isDone:false, dueDay:'2026-01-01', timeSpentOnDay:{'2026-01-01':3600000} };
Expand Down