Goal Dashboard
Manage Goal & Key Results
Reflection Notes for
Please select a goal from the dropdown above or add a new goal from the Dashboard.
Archived Goals (Achieved or Cancelled)
Target Date: ${goal.targetDate ? new Date(goal.targetDate+"T00:00:00").toLocaleDateString() : 'Not set'}
Progress: ${progress}%
`;
dashboardArea.appendChild(card);
});
}
function wgt_initAddNewGoal() {
wgt_currentGoalIdForManagement = null; // Clear any selected goal
// Reset form fields on manage tab for a new goal
document.getElementById('wgt-goalDetailForm').reset();
document.getElementById('wgt-detailGoalId').value = '';
document.getElementById('wgt-detailGoalColor').value = `#${Math.floor(Math.random()*16777215).toString(16).padStart(6,'0')}`; // Random color
const nextMonth = new Date(WGT_TODAY_CONTEXT); nextMonth.setMonth(nextMonth.getMonth()+1); nextMonth.setDate(new Date(nextMonth.getFullYear(), nextMonth.getMonth() + 1, 0).getDate()); // End of next month
document.getElementById('wgt-detailTargetDate').value = nextMonth.toISOString().split('T')[0];
document.getElementById('wgt-detailGoalStatus').value = "Not Started";
document.getElementById('wgt-detailGoalPriority').value = "Medium";
document.getElementById('wgt-keyResultsList').innerHTML = '
Save the goal first to add key results.';
document.getElementById('wgt-goalReflectionNotes').value = '';
document.getElementById('wgt-krGoalName').textContent = "New Goal";
document.getElementById('wgt-reflectGoalName').textContent = "New Goal";
// Switch to manage tab
const manageTabButton = document.querySelector(`.wgt-tab-button[onclick*="'wgt-manageGoalTab'"]`);
wgt_openTab({currentTarget: manageTabButton}, 'wgt-manageGoalTab');
document.getElementById('wgt-goalManagementArea').style.display = 'block';
document.getElementById('wgt-noGoalSelectedMessage').style.display = 'none';
document.getElementById('wgt-selectGoalToManage').value = ""; // Ensure dropdown is cleared
}
// --- Manage Goal & Key Results Tab ---
function wgt_initManageGoalTab() {
wgt_populateGoalSelectForManagement();
if (wgt_currentGoalIdForManagement) {
wgt_loadGoalForManagement(wgt_currentGoalIdForManagement);
} else {
document.getElementById('wgt-goalManagementArea').style.display = 'none';
document.getElementById('wgt-noGoalSelectedMessage').style.display = 'block';
}
}
function wgt_populateGoalSelectForManagement() {
const selectEl = document.getElementById('wgt-selectGoalToManage');
const activeGoals = wgt_goals.filter(g => g.status !== 'Achieved' && g.status !== 'Cancelled');
selectEl.innerHTML = '
';
activeGoals.forEach(goal => {
const option = document.createElement('option');
option.value = goal.id;
option.textContent = goal.name;
selectEl.appendChild(option);
});
if (wgt_currentGoalIdForManagement && activeGoals.find(g => g.id === wgt_currentGoalIdForManagement)) {
selectEl.value = wgt_currentGoalIdForManagement;
} else if (activeGoals.length > 0 && !wgt_currentGoalIdForManagement) {
// If no goal was selected, but there are active goals, don't auto-select, let user choose.
// wgt_loadGoalForManagement(activeGoals[0].id); // Optionally auto-load first
}
}
function wgt_loadGoalForManagement(goalId, switchToTab = false) {
if (!goalId) {
wgt_currentGoalIdForManagement = null;
document.getElementById('wgt-goalManagementArea').style.display = 'none';
document.getElementById('wgt-noGoalSelectedMessage').style.display = 'block';
return;
}
wgt_currentGoalIdForManagement = goalId;
const goal = wgt_goals.find(g => g.id === goalId);
if (!goal) {
wgt_currentGoalIdForManagement = null; // Clear if goal not found
document.getElementById('wgt-goalManagementArea').style.display = 'none';
document.getElementById('wgt-noGoalSelectedMessage').style.display = 'block';
alert("Selected goal not found.");
return;
}
document.getElementById('wgt-detailGoalId').value = goal.id;
document.getElementById('wgt-detailGoalName').value = goal.name;
document.getElementById('wgt-detailGoalDescription').value = goal.description || '';
document.getElementById('wgt-detailTargetDate').value = goal.targetDate || '';
document.getElementById('wgt-detailGoalStatus').value = goal.status || 'Not Started';
document.getElementById('wgt-detailGoalPriority').value = goal.priority || 'Medium';
document.getElementById('wgt-detailGoalColor').value = goal.color || '#10B981';
document.getElementById('wgt-goalReflectionNotes').value = goal.reflectionNotes || '';
document.getElementById('wgt-krGoalName').textContent = goal.name;
document.getElementById('wgt-reflectGoalName').textContent = goal.name;
wgt_renderKeyResultsList(goalId);
wgt_resetKeyResultForm(); // Clear KR form for new entry
document.getElementById('wgt-goalManagementArea').style.display = 'block';
document.getElementById('wgt-noGoalSelectedMessage').style.display = 'none';
document.getElementById('wgt-selectGoalToManage').value = goalId;
if (switchToTab) {
const manageTabButton = document.querySelector(`.wgt-tab-button[onclick*="'wgt-manageGoalTab'"]`);
wgt_openTab({currentTarget: manageTabButton}, 'wgt-manageGoalTab');
}
}
document.getElementById('wgt-goalDetailForm').onsubmit = (e) => {
e.preventDefault();
const goalId = document.getElementById('wgt-detailGoalId').value;
if (!goalId) { // This means it's a new goal being created via "Add New Goal" button flow
const newGoal = {
id: wgt_generateId(),
name: document.getElementById('wgt-detailGoalName').value.trim(),
description: document.getElementById('wgt-detailGoalDescription').value.trim(),
targetDate: document.getElementById('wgt-detailTargetDate').value,
status: document.getElementById('wgt-detailGoalStatus').value,
priority: document.getElementById('wgt-detailGoalPriority').value,
color: document.getElementById('wgt-detailGoalColor').value,
keyResults: [],
reflectionNotes: ''
};
if (!newGoal.name) { alert("Goal name is required."); return; }
wgt_goals.push(newGoal);
wgt_currentGoalIdForManagement = newGoal.id; // Set current to this new goal
} else { // Editing existing goal
const goalIndex = wgt_goals.findIndex(g => g.id === goalId);
if (goalIndex === -1) { alert("Goal not found for update."); return; }
wgt_goals[goalIndex].name = document.getElementById('wgt-detailGoalName').value.trim();
wgt_goals[goalIndex].description = document.getElementById('wgt-detailGoalDescription').value.trim();
wgt_goals[goalIndex].targetDate = document.getElementById('wgt-detailTargetDate').value;
wgt_goals[goalIndex].status = document.getElementById('wgt-detailGoalStatus').value;
wgt_goals[goalIndex].priority = document.getElementById('wgt-detailGoalPriority').value;
wgt_goals[goalIndex].color = document.getElementById('wgt-detailGoalColor').value;
}
wgt_saveData();
alert("Goal details saved!");
wgt_renderGoalDashboard(); // Update dashboard if name/status changed
wgt_populateGoalSelectForManagement(); // Refresh dropdown
document.getElementById('wgt-selectGoalToManage').value = wgt_currentGoalIdForManagement; // Re-select current goal
wgt_loadGoalForManagement(wgt_currentGoalIdForManagement); // Reload to reflect changes and KR list for current goal
};
// Key Results Management
document.getElementById('wgt-keyResultForm').onsubmit = (e) => {
e.preventDefault();
if (!wgt_currentGoalIdForManagement) { alert("No goal selected to add key result to."); return; }
const goalIndex = wgt_goals.findIndex(g => g.id === wgt_currentGoalIdForManagement);
if (goalIndex === -1) { alert("Selected goal not found."); return; }
const krId = document.getElementById('wgt-keyResultId').value;
const krData = {
id: krId || wgt_generateId(),
description: document.getElementById('wgt-krDescription').value.trim(),
dueDate: document.getElementById('wgt-krDueDate').value || null,
isDone: document.getElementById('wgt-krIsDone').checked
};
if (!krData.description) { alert("Key result description is required."); return; }
if (!wgt_goals[goalIndex].keyResults) wgt_goals[goalIndex].keyResults = [];
if (krId) { // Editing KR
const krIndex = wgt_goals[goalIndex].keyResults.findIndex(kr => kr.id === krId);
if (krIndex > -1) wgt_goals[goalIndex].keyResults[krIndex] = krData;
} else { // Adding new KR
wgt_goals[goalIndex].keyResults.push(krData);
}
wgt_saveData();
wgt_renderKeyResultsList(wgt_currentGoalIdForManagement);
wgt_resetKeyResultForm();
wgt_renderGoalDashboard(); // Update progress on dashboard
};
function wgt_resetKeyResultForm() {document.getElementById('wgt-keyResultForm').reset(); document.getElementById('wgt-keyResultId').value=''; document.getElementById('wgt-krIsDone').checked=false; document.getElementById('wgt-cancelKrEditBtn').style.display='none';}
function wgt_renderKeyResultsList(goalId) {
const listEl = document.getElementById('wgt-keyResultsList');
const goal = wgt_goals.find(g => g.id === goalId);
listEl.innerHTML = '';
if (!goal || !goal.keyResults || goal.keyResults.length === 0) {
listEl.innerHTML = '
No key results defined for this goal yet.'; return;
}
goal.keyResults.sort((a,b) => (a.dueDate || '9999-12-31') > (b.dueDate || '9999-12-31') ? 1 : -1).forEach(kr => {
const li = document.createElement('li');
li.className = `wgt-keyresult-item ${kr.isDone ? 'done' : ''}`;
li.innerHTML = `
${kr.description}
${kr.dueDate ? new Date(kr.dueDate+"T00:00:00").toLocaleDateString() : 'No due date'}
`;
listEl.appendChild(li);
});
}
function wgt_editKeyResult(goalId, krId) {
const goal = wgt_goals.find(g => g.id === goalId);
const kr = goal ? goal.keyResults.find(k => k.id === krId) : null;
if (!kr) return;
document.getElementById('wgt-keyResultId').value = kr.id;
document.getElementById('wgt-krDescription').value = kr.description;
document.getElementById('wgt-krDueDate').value = kr.dueDate || '';
document.getElementById('wgt-krIsDone').checked = kr.isDone;
document.getElementById('wgt-cancelKrEditBtn').style.display = 'inline-block';
}
function wgt_deleteKeyResult(goalId, krId) {
const goalIndex = wgt_goals.findIndex(g => g.id === goalId);
if (goalIndex === -1) return;
if (confirm('Delete this key result?')) {
wgt_goals[goalIndex].keyResults = wgt_goals[goalIndex].keyResults.filter(kr => kr.id !== krId);
wgt_saveData();
wgt_renderKeyResultsList(goalId);
wgt_renderGoalDashboard(); // Update progress
}
}
function wgt_toggleKeyResultStatus(goalId, krId, isDone) {
const goalIndex = wgt_goals.findIndex(g => g.id === goalId);
if (goalIndex === -1) return;
const krIndex = wgt_goals[goalIndex].keyResults.findIndex(kr => kr.id === krId);
if (krIndex > -1) {
wgt_goals[goalIndex].keyResults[krIndex].isDone = isDone;
wgt_saveData();
wgt_renderKeyResultsList(goalId); // Re-render list for visual update (strikethrough)
wgt_renderGoalDashboard(); // Update progress bar on dashboard
}
}
function wgt_saveGoalReflection() {
if (!wgt_currentGoalIdForManagement) return;
const goalIndex = wgt_goals.findIndex(g => g.id === wgt_currentGoalIdForManagement);
if (goalIndex > -1) {
wgt_goals[goalIndex].reflectionNotes = document.getElementById('wgt-goalReflectionNotes').value.trim();
wgt_saveData();
alert("Reflection notes saved.");
}
}
// --- Archived Goals Tab ---
function wgt_renderArchivedGoals() {
const listEl = document.getElementById('wgt-archivedGoalsList');
listEl.innerHTML = '';
const archivedGoals = wgt_goals.filter(goal => goal.status === 'Achieved' || goal.status === 'Cancelled');
if (archivedGoals.length === 0) {
listEl.innerHTML = '
No goals have been archived yet.'; return;
}
archivedGoals.sort((a,b)=> new Date(b.targetDate || 0) - new Date(a.targetDate || 0)); // Sort by most recent target date
archivedGoals.forEach(goal => {
const li = document.createElement('li');
li.style.borderLeftColor = goal.color || '#ccc';
li.innerHTML = `
${goal.name} - Status: ${goal.status}
Target: ${goal.targetDate ? new Date(goal.targetDate+"T00:00:00").toLocaleDateString() : 'N/A'} | Progress: ${wgt_calculateGoalProgress(goal)}%
`;
listEl.appendChild(li);
});
}
function wgt_viewArchivedGoalDetails(goalId) {
wgt_loadGoalForManagement(goalId, true); // Load in manage tab and switch
// Potentially disable editing fields if it's just "viewing" archived
}
function wgt_unarchiveGoal(goalId) {
const goalIndex = wgt_goals.findIndex(g => g.id === goalId);
if (goalIndex > -1) {
if (confirm(`Restore "${wgt_goals[goalIndex].name}" to active goals? It will be set to 'On Hold'.`)) {
wgt_goals[goalIndex].status = 'On Hold'; // Or 'In Progress'
wgt_saveData();
wgt_renderArchivedGoals();
wgt_renderGoalDashboard();
wgt_populateGoalSelectForManagement();
}
}
}
// --- PDF Download ---
document.getElementById('wgt-downloadPdfBtn').onclick = async () => {
const { jsPDF } = window.jspdf; const pdf = new jsPDF('p', 'mm', 'a4');
let currentY = 15; const margin = 15; const contentWidth = pdf.internal.pageSize.getWidth() - 2*margin;
const accentColor = '#10B981'; const textColor = '#047857';
pdf.setFontSize(18); pdf.setTextColor(accentColor);
pdf.text("Work Goals Report", pdf.internal.pageSize.getWidth() / 2, currentY, { align: 'center' });
currentY += 8;
pdf.setFontSize(10); pdf.setTextColor(textColor);
pdf.text(`Report Generated: ${new Date().toLocaleDateString()}`, pdf.internal.pageSize.getWidth() / 2, currentY, { align: 'center'});
currentY += 10;
const activeGoalsForPdf = wgt_goals.filter(g => g.status !== 'Achieved' && g.status !== 'Cancelled');
if (activeGoalsForPdf.length === 0) {
pdf.text("No active goals to report.", margin, currentY);
}
activeGoalsForPdf.forEach(async (goal, index) => {
if (index > 0 && currentY > pdf.internal.pageSize.getHeight() - 60) { // Check space for new goal section
pdf.addPage(); currentY = margin;
}
const progress = wgt_calculateGoalProgress(goal);
const goalColorRgb = wgt_hexToRgb(goal.color || accentColor);
pdf.setFontSize(14); pdf.setTextColor(goal.color || accentColor);
pdf.text(goal.name, margin, currentY); currentY += 6;
pdf.setFontSize(9); pdf.setTextColor(textColor);
pdf.text(`Status: ${goal.status} | Priority: ${goal.priority || 'N/A'} | Target: ${goal.targetDate ? new Date(goal.targetDate+"T00:00:00").toLocaleDateString() : 'N/A'}`, margin, currentY); currentY += 5;
pdf.text(`Progress: ${progress}%`, margin, currentY);
// Simple progress bar for PDF
if (goalColorRgb) pdf.setFillColor(goalColorRgb.r, goalColorRgb.g, goalColorRgb.b); else pdf.setFillColor(16,185,129);
pdf.rect(margin + 30, currentY - 3.5, 50 * (progress/100), 3, 'F'); // 50mm wide bar
pdf.setDrawColor(100,100,100); pdf.rect(margin + 30, currentY - 3.5, 50, 3, 'S'); // Border
currentY += 6;
if (goal.description) {
const descLines = pdf.splitTextToSize(`Description: ${goal.description}`, contentWidth);
pdf.text(descLines, margin, currentY); currentY += (descLines.length * 4) + 2;
}
if (goal.keyResults && goal.keyResults.length > 0) {
if (currentY > pdf.internal.pageSize.getHeight() - 20) { pdf.addPage(); currentY = margin; }
pdf.setFontSize(10); pdf.setTextColor(textColor); pdf.text("Key Results:", margin, currentY); currentY += 5;
const krBody = goal.keyResults.map(kr => [kr.description, kr.isDone ? "Done" : "To Do", kr.dueDate ? new Date(kr.dueDate+"T00:00:00").toLocaleDateString() : "-"]);
pdf.autoTable({
head: [["Description", "Status", "Due Date"]], body: krBody, startY: currentY,
theme: 'grid', headStyles: { fillColor: '#D1FAE5', textColor: '#047857' }, styles: { fontSize: 8, cellPadding:1.5 },
columnStyles: {0:{cellWidth: contentWidth * 0.5}, 1:{cellWidth:contentWidth*0.15}}
});
currentY = pdf.lastAutoTable.finalY + 5;
}
if(goal.reflectionNotes){
if (currentY > pdf.internal.pageSize.getHeight() - 20) { pdf.addPage(); currentY = margin; }
pdf.setFontSize(10); pdf.setTextColor(textColor); pdf.text("Reflection:", margin, currentY); currentY += 5;
const reflectLines = pdf.splitTextToSize(goal.reflectionNotes, contentWidth);
pdf.setFontSize(9); pdf.text(reflectLines, margin + 5, currentY); currentY += (reflectLines.length * 4) + 3;
}
currentY += 5; // Space between goals
});
pdf.save(`Work_Goals_Report_${WGT_TODAY_CONTEXT.toISOString().slice(0,10)}.pdf`);
};
function wgt_hexToRgb(hex) { const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return r ? {r:parseInt(r[1],16),g:parseInt(r[2],16),b:parseInt(r[3],16)}:null;}
// --- Initial Load ---
document.addEventListener('DOMContentLoaded', () => {
wgt_openTab(null, wgt_tabs[0]);
// Redundant check if wgt_openTab correctly sets active class.
// const firstTabButton = document.querySelector(`.wgt-tab-button[onclick*="'${wgt_tabs[0]}'"]`);
// if (firstTabButton) firstTabButton.classList.add('active');
// else console.error("First tab button not found for initial activation.");
wgt_updateNavButtons();
});