Fantasy Sports Draft Planner
This is your current roster. Click any cell (except 'Action') to edit the data. Totals will update automatically.
| Player Name | Position | Team | Cost ($) | Notes | Action |
|---|
Total Players:
0
Total Cost:
$0.00
Click a player from the pool to draft them to your roster. Use the filter to find players by position.
Available Players
Manually add or remove players from the database. This list feeds the 'Player Pool' tab.
Player Database
| Player Name | Pos | Team | Cost ($) | Action |
|---|
No players available. Check your filter or add players to the database.
'; return; } availablePlayers.forEach(player => { const div = document.createElement('div'); div.className = 'fdp-player-item'; div.dataset.id = player.id; div.innerHTML = `${player.name} (${player.pos})
${player.team} - $${player.cost.toFixed(2)}
`;
playerPool.appendChild(div);
});
};
// Populates Tab 2 (Builder) Filter
const populateFilterDropdown = () => {
const positions = [...new Set(playerDatabase.map(p => p.pos))];
filterPosition.innerHTML = '';
positions.sort().forEach(pos => {
filterPosition.innerHTML += ``;
});
};
// --- EVENT HANDLERS (TAB 1 - DASHBOARD) ---
logBody.addEventListener('blur', (e) => {
if (e.target.isContentEditable) {
const id = parseInt(e.target.dataset.id, 10);
const prop = e.target.dataset.prop;
let newValue = e.target.textContent.trim();
const itemIndex = myRoster.findIndex(item => item.id === id);
if (itemIndex > -1 && prop) {
if (prop === 'cost') {
newValue = parseFloat(newValue) || 0;
}
myRoster[itemIndex][prop] = newValue;
renderRosterTable(); // Re-render and calculate totals
}
}
}, true); // Use capture phase
logBody.addEventListener('click', (e) => {
if (e.target.classList.contains('fdp-btn-delete')) {
const id = parseInt(e.target.dataset.id, 10);
myRoster = myRoster.filter(item => item.id !== id);
renderRosterTable();
renderPlayerPool(); // Add player back to pool
}
});
// --- PDF DOWNLOAD FUNCTION (CORRECTED) ---
const downloadPDF = () => {
// 1. Check if jsPDF is loaded
if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') {
console.error('FDP Tool: jsPDF library not loaded. Please check your connection.');
return; // Fail silently in UI
}
if (typeof jspdf.autoTable === 'undefined') {
console.error('FDP Tool: jsPDF-AutoTable plugin not loaded. Please check your connection.');
return; // Fail silently in UI
}
// 2. Check for empty roster
if (myRoster.length === 0) {
console.log('FDP Tool: Roster is empty. Nothing to download.');
return; // Don't download an empty PDF
}
try {
const { jsPDF } = jspdf;
const doc = new jsPDF();
const head = [['Player Name', 'Position', 'Team', 'Cost ($)', 'Notes']];
const body = myRoster.map(item => [item.name, item.pos, item.team, item.cost.toFixed(2), item.notes || '']);
doc.setFontSize(18);
doc.text("My Team Roster", 14, 22);
jsPDF.autoTable.default(doc, {
startY: 30,
head: head,
body: body,
theme: 'grid',
headStyles: { fillColor: '#007bff' },
columnStyles: { 3: { halign: 'right' } }
});
// Add Summary
const finalY = doc.autoTable.previous.finalY;
doc.setFontSize(12);
doc.setFont('helvetica', 'bold');
doc.text(`Total Players: ${totalPlayers.textContent}`, 14, finalY + 10);
doc.text(`Total Cost: ${totalCost.textContent}`, doc.internal.pageSize.width - 14, finalY + 10, { align: 'right' });
doc.save('fantasy-roster.pdf');
} catch (e) {
console.error('FDP Tool: Error generating PDF:', e);
}
};
downloadPdfBtn.addEventListener('click', downloadPDF);
// --- EVENT HANDLERS (TAB 2 - BUILDER) ---
filterPosition.addEventListener('change', renderPlayerPool);
playerPool.addEventListener('click', (e) => {
const item = e.target.closest('.fdp-player-item');
if (!item) return;
const id = parseInt(item.dataset.id, 10);
const player = playerDatabase.find(p => p.id === id);
if (!player) return;
myRoster.push({ ...player, notes: '' }); // Add a copy with notes
renderRosterTable();
renderPlayerPool(); // Will remove player from pool
// Switch to dashboard (Spec II.B.4.o)
tabs[0].click();
});
// --- EVENT HANDLERS (TAB 3 - CONFIG) ---
addPlayerBtn.addEventListener('click', () => {
const name = newNameInput.value.trim();
const pos = newPosInput.value.trim().toUpperCase();
const team = newTeamInput.value.trim().toUpperCase();
const cost = parseFloat(newCostInput.value) || 0;
if (!name || !pos || !team) {
alert('Please fill in Name, Position, and Team.'); // Re-adding alert as it's not in PDF function
return;
}
const newId = (playerDatabase.length > 0 ? Math.max(...playerDatabase.map(p => p.id)) : 0) + 1;
playerDatabase.push({ id: newId, name, pos, team, cost });
renderDbTable();
configForm.reset();
});
dbBody.addEventListener('click', (e) => {
if (e.target.classList.contains('fdp-btn-delete')) {
const id = parseInt(e.target.dataset.id, 10);
// Check if player is on roster
if (myRoster.some(p => p.id === id)) {
alert('Cannot delete player: They are currently on your roster. Remove them from the roster first.');
return;
}
playerDatabase = playerDatabase.filter(item => item.id !== id);
renderDbTable();
}
});
// --- INITIALIZATION ---
const init = () => {
// Initial Renders
renderDbTable();
renderRosterTable();
// Set up tabs
updateNavButtons();
// Show the first tab on load
if (tabs.length > 0) {
fdpShowTab('fdp-dashboard-tab', tabs[0]);
}
};
init();
});
