Performance Review Generator
Select performance areas and ratings to generate constructive feedback phrases.
Phrase Generator
Suggested Phrases
Click the '+' to add a phrase to the review.
Review Document
${phrase}
`; suggestionsList.appendChild(item); }); suggestionsContainer.classList.remove('hidden'); } }; const addPhraseToReview = (e) => { if (e.target.classList.contains('add-phrase-btn')) { const phraseText = e.target.previousElementSibling.textContent; const areaLabel = performanceAreaSelect.options[performanceAreaSelect.selectedIndex].text; const ratingLabel = ratingSelect.options[ratingSelect.selectedIndex].text; const heading = `**${areaLabel} - ${ratingLabel}**`; let currentText = reviewTextarea.value; if (!currentText.includes(heading)) { currentText += `\n\n${heading}\n`; } // Add the phrase as a bullet point currentText += `- ${phraseText}\n`; reviewTextarea.value = currentText; } }; const formatForPdf = (text) => { // Basic Markdown to HTML conversion let html = text .replace(//g, ">") // Escape HTML tags .replace(/\n/g, '') // Newlines to
.replace(/\*\*(.*?)\*\*/g, '
$1
') // **bold** to
.replace(/^- (.*?)
/gm, '- $1
') // - list item
.replace(/
/g, '') // Clean up extra breaks
.replace(/<\/ul>
/g, '')
.replace(/<\/ul>
/g, '
');
return `${html}`;
};
const handleDownload = () => {
const reviewText = reviewTextarea.value;
if (!reviewText.trim()) {
alert("The review document is empty.");
return;
}
pdfOutput.innerHTML = formatForPdf(reviewText);
const { jsPDF } = window.jspdf;
html2canvas(pdfOutput, { scale: 2 }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
const employeeName = employeeNameInput.value.replace(/\s/g, '_') || 'Review';
pdf.save(`${employeeName}_Performance_Review.pdf`);
});
};
// --- Event Listeners ---
employeeNameInput.addEventListener('keyup', updateReviewTemplate);
jobTitleInput.addEventListener('keyup', updateReviewTemplate);
generateBtn.addEventListener('click', generateSuggestions);
suggestionsList.addEventListener('click', addPhraseToReview);
downloadPdfBtn.addEventListener('click', handleDownload);
// --- Initial Load ---
updateReviewTemplate();
});
- ') // Clean up extra breaks
.replace(/<\/ul>
- /g, '
- ')
.replace(/<\/ul>
/g, '
${html}
`;
};
const handleDownload = () => {
const reviewText = reviewTextarea.value;
if (!reviewText.trim()) {
alert("The review document is empty.");
return;
}
pdfOutput.innerHTML = formatForPdf(reviewText);
const { jsPDF } = window.jspdf;
html2canvas(pdfOutput, { scale: 2 }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
const employeeName = employeeNameInput.value.replace(/\s/g, '_') || 'Review';
pdf.save(`${employeeName}_Performance_Review.pdf`);
});
};
// --- Event Listeners ---
employeeNameInput.addEventListener('keyup', updateReviewTemplate);
jobTitleInput.addEventListener('keyup', updateReviewTemplate);
generateBtn.addEventListener('click', generateSuggestions);
suggestionsList.addEventListener('click', addPhraseToReview);
downloadPdfBtn.addEventListener('click', handleDownload);
// --- Initial Load ---
updateReviewTemplate();
});
