feat: Add 8 certificate templates with different courses and lecturers

Templates:
- AIcertifikat (Zdarílek), AIcertifikatGablas, AIcertifikatPatrik
- ScrumMaster, ScrumProductOwner (blue background)
- ITILFoundation (green background)
- PRINCE2Foundation, PRINCE2Practitioner (orange background)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
richardtekula
2026-01-29 17:15:44 +01:00
parent f7d252ee7b
commit e923e42a65
10 changed files with 630 additions and 113 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -16,28 +16,56 @@ const TEMPLATES_DIR = path.join(process.cwd(), 'src', 'templates', 'certificates
* Available certificate templates
*/
export const CERTIFICATE_TEMPLATES = {
// AI certifikáty s dynamickým názvom kurzu a rôznymi lektormi
AIcertifikat: {
name: 'AI Certifikát',
name: 'AI Certifikát (Zdarílek)',
file: 'AIcertifikat.html',
description: 'Osvedčenie o absolvovaní AI kurzu',
description: 'AI kurz - lektor Zdarílek + Gablasová',
background: 'background.jpeg',
},
ScrumGeneric: {
name: 'Scrum (Gablas)',
file: 'ScrumGeneric.html',
description: 'Scrum Master / Product Owner - lektor Gablas',
AIcertifikatGablas: {
name: 'AI Certifikát (Gablas)',
file: 'AIcertifikatGablas.html',
description: 'AI kurz - lektor Gablas + Gablasová',
background: 'background.jpeg',
},
AIcertifikatPatrik: {
name: 'AI Certifikát (Patrik)',
file: 'AIcertifikatPatrik.html',
description: 'AI kurz - lektor Patrik + Gablasová',
background: 'background.jpeg',
},
// Scrum certifikáty - fixný názov kurzu, podpisy v pozadí
ScrumMaster: {
name: 'Scrum Master',
file: 'ScrumMaster.html',
description: 'Scrum Master - Gablas + Gablasová',
background: 'background-blue.jpeg',
},
ITIL: {
name: 'ITIL (Husam)',
file: 'ITIL.html',
description: 'ITIL Foundation - lektor Husam',
ScrumProductOwner: {
name: 'Scrum Product Owner',
file: 'ScrumProductOwner.html',
description: 'Scrum Product Owner - Gablas + Gablasová',
background: 'background-blue.jpeg',
},
// ITIL certifikát - fixný názov kurzu, podpisy v pozadí
ITILFoundation: {
name: 'ITIL® 4 Foundation',
file: 'ITILFoundation.html',
description: 'ITIL Foundation - Husam + Gablasová',
background: 'background-green.jpeg',
},
PRINCE2: {
name: 'PRINCE2 (Gablas)',
file: 'PRINCE2.html',
description: 'PRINCE2 Foundation/Practitioner - lektor Gablas',
// PRINCE2 certifikáty - fixný názov kurzu, podpisy v pozadí
PRINCE2Foundation: {
name: 'PRINCE2® Foundation',
file: 'PRINCE2Foundation.html',
description: 'PRINCE2 Foundation - Gablas + Gablasová',
background: 'background-orange.jpeg',
},
PRINCE2Practitioner: {
name: 'PRINCE2® Practitioner',
file: 'PRINCE2Practitioner.html',
description: 'PRINCE2 Practitioner - Gablas + Gablasová',
background: 'background-orange.jpeg',
},
};
@@ -74,16 +102,20 @@ const loadAssets = async (templateName) => {
const template = CERTIFICATE_TEMPLATES[templateName];
const backgroundFile = template?.background || 'background.jpeg';
const [background, signatureGablasova, signatureZdarilek] = await Promise.all([
const [background, signatureGablasova, signatureZdarilek, signatureGablas, signaturePatrik] = await Promise.all([
fs.readFile(path.join(ASSETS_DIR, backgroundFile)),
fs.readFile(path.join(ASSETS_DIR, 'signature-gablasova.png')),
fs.readFile(path.join(ASSETS_DIR, 'signature-zdarilek.png')),
fs.readFile(path.join(ASSETS_DIR, 'signature-gablas.png')),
fs.readFile(path.join(ASSETS_DIR, 'signature-patrik.png')),
]);
return {
backgroundImage: `data:image/jpeg;base64,${background.toString('base64')}`,
signatureGablasova: `data:image/png;base64,${signatureGablasova.toString('base64')}`,
signatureZdarilek: `data:image/png;base64,${signatureZdarilek.toString('base64')}`,
signatureGablas: `data:image/png;base64,${signatureGablas.toString('base64')}`,
signaturePatrik: `data:image/png;base64,${signaturePatrik.toString('base64')}`,
};
};

View File

@@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Osvedčenie - {{participantName}}</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Open+Sans:wght@300;400;500;600&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
height: 210mm;
position: relative;
background-image: url('{{backgroundImage}}');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.content {
position: absolute;
top: 28mm;
left: 0;
right: 0;
text-align: center;
}
.main-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: 52pt;
font-weight: 700;
letter-spacing: 14px;
color: #1a1a1a;
text-transform: uppercase;
margin-bottom: 2mm;
}
.subtitle {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 18pt;
font-weight: 400;
color: #333;
letter-spacing: 1px;
margin-bottom: 18mm;
}
.course-section { margin-top: 5mm; }
.course-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: 32pt;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 3mm;
}
.course-modules {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 13pt;
font-weight: 500;
color: #333;
line-height: 1.5;
margin-bottom: 2mm;
}
.course-dates {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 12pt;
font-weight: 400;
color: #444;
}
.participant-name {
font-family: 'Playfair Display', Georgia, serif;
font-size: 36pt;
font-weight: 600;
color: #1a1a1a;
margin-top: 14mm;
}
.footer-section {
position: absolute;
bottom: 28mm;
left: 25mm;
right: 25mm;
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.date-location {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 11pt;
color: #333;
}
.signatures { display: flex; gap: 25mm; }
.signature { text-align: center; min-width: 55mm; }
.signature-image { height: 18mm; margin-bottom: 1mm; object-fit: contain; }
.signature-line { width: 55mm; height: 0.4mm; background: #333; margin: 0 auto 2mm auto; }
.signature-name { font-family: 'Open Sans', Arial, sans-serif; font-size: 10pt; font-weight: 600; color: #1a1a1a; }
.signature-title { font-family: 'Open Sans', Arial, sans-serif; font-size: 9pt; font-weight: 400; color: #555; }
.certificate-id {
position: absolute;
bottom: 20mm;
right: 25mm;
font-family: 'Open Sans', Arial, sans-serif;
font-size: 7pt;
color: #999;
letter-spacing: 0.5px;
}
</style>
</head>
<body>
<div class="certificate">
<div class="content">
<h1 class="main-title">O S V E D Č E N I E</h1>
<p class="subtitle">o absolvovaní kurzu</p>
<div class="course-section">
<h2 class="course-title">{{courseTitle}}</h2>
{{#if courseModules}}
<p class="course-modules">{{courseModules}}</p>
{{/if}}
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
</div>
<h3 class="participant-name">{{participantName}}</h3>
</div>
<div class="footer-section">
<div class="date-location">
V Bratislave {{issueDate}}
</div>
<div class="signatures">
<div class="signature">
<img src="{{signatureGablas}}" alt="Podpis" class="signature-image" />
<div class="signature-line"></div>
<p class="signature-name">Ing. Branislav Gablas, PhD.</p>
<p class="signature-title">lektor</p>
</div>
<div class="signature">
<img src="{{signatureGablasova}}" alt="Podpis" class="signature-image" />
<div class="signature-line"></div>
<p class="signature-name">Ing. Jana Gablasová</p>
<p class="signature-title">konateľ</p>
</div>
</div>
</div>
<div class="certificate-id">ID: {{certificateId}}</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Osvedčenie - {{participantName}}</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Open+Sans:wght@300;400;500;600&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
height: 210mm;
position: relative;
background-image: url('{{backgroundImage}}');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.content {
position: absolute;
top: 28mm;
left: 0;
right: 0;
text-align: center;
}
.main-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: 52pt;
font-weight: 700;
letter-spacing: 14px;
color: #1a1a1a;
text-transform: uppercase;
margin-bottom: 2mm;
}
.subtitle {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 18pt;
font-weight: 400;
color: #333;
letter-spacing: 1px;
margin-bottom: 18mm;
}
.course-section { margin-top: 5mm; }
.course-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: 32pt;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 3mm;
}
.course-modules {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 13pt;
font-weight: 500;
color: #333;
line-height: 1.5;
margin-bottom: 2mm;
}
.course-dates {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 12pt;
font-weight: 400;
color: #444;
}
.participant-name {
font-family: 'Playfair Display', Georgia, serif;
font-size: 36pt;
font-weight: 600;
color: #1a1a1a;
margin-top: 14mm;
}
.footer-section {
position: absolute;
bottom: 28mm;
left: 25mm;
right: 25mm;
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.date-location {
font-family: 'Open Sans', Arial, sans-serif;
font-size: 11pt;
color: #333;
}
.signatures { display: flex; gap: 25mm; }
.signature { text-align: center; min-width: 55mm; }
.signature-image { height: 18mm; margin-bottom: 1mm; object-fit: contain; }
.signature-line { width: 55mm; height: 0.4mm; background: #333; margin: 0 auto 2mm auto; }
.signature-name { font-family: 'Open Sans', Arial, sans-serif; font-size: 10pt; font-weight: 600; color: #1a1a1a; }
.signature-title { font-family: 'Open Sans', Arial, sans-serif; font-size: 9pt; font-weight: 400; color: #555; }
.certificate-id {
position: absolute;
bottom: 20mm;
right: 25mm;
font-family: 'Open Sans', Arial, sans-serif;
font-size: 7pt;
color: #999;
letter-spacing: 0.5px;
}
</style>
</head>
<body>
<div class="certificate">
<div class="content">
<h1 class="main-title">O S V E D Č E N I E</h1>
<p class="subtitle">o absolvovaní kurzu</p>
<div class="course-section">
<h2 class="course-title">{{courseTitle}}</h2>
{{#if courseModules}}
<p class="course-modules">{{courseModules}}</p>
{{/if}}
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
</div>
<h3 class="participant-name">{{participantName}}</h3>
</div>
<div class="footer-section">
<div class="date-location">
V Bratislave {{issueDate}}
</div>
<div class="signatures">
<div class="signature">
<img src="{{signaturePatrik}}" alt="Podpis" class="signature-image" />
<div class="signature-line"></div>
<p class="signature-name">Mgr. Patrik Gablík</p>
<p class="signature-title">lektor</p>
</div>
<div class="signature">
<img src="{{signatureGablasova}}" alt="Podpis" class="signature-image" />
<div class="signature-line"></div>
<p class="signature-name">Ing. Jana Gablasová</p>
<p class="signature-title">konateľ</p>
</div>
</div>
</div>
<div class="certificate-id">ID: {{certificateId}}</div>
</div>
</body>
</html>

View File

@@ -7,27 +7,10 @@
<style>
@import url('https://fonts.googleapis.com/css2?family=Bahnschrift:wght@400;600;700&family=Open+Sans:wght@300;400;500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@page {
size: A4 landscape;
margin: 0;
}
html, body {
width: 297mm;
height: 210mm;
overflow: hidden;
}
body {
font-family: 'Open Sans', Arial, sans-serif;
background: #fff;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
@@ -39,7 +22,6 @@
background-repeat: no-repeat;
}
/* Main content - centered in the white area */
.main-content {
position: absolute;
top: 50%;
@@ -58,7 +40,7 @@
.course-title {
font-family: 'Bahnschrift', 'Open Sans', Arial, sans-serif;
font-size: 24pt;
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 4mm;
@@ -77,7 +59,6 @@
color: #1a1a1a;
}
/* Issue date - above "Dátum" at bottom left */
.issue-date {
position: absolute;
bottom: 42mm;
@@ -99,13 +80,11 @@
<div class="certificate">
<div class="main-content">
<h3 class="participant-name">{{participantName}}</h3>
<h2 class="course-title">{{courseTitle}}</h2>
<h2 class="course-title">ITIL® 4 Foundation</h2>
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
{{#if courseHours}}
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
{{/if}}
<p class="course-hours">v rozsahu 24 hodín</p>
</div>
<div class="issue-date">{{issueDate}}</div>

View File

@@ -7,27 +7,10 @@
<style>
@import url('https://fonts.googleapis.com/css2?family=Bahnschrift:wght@400;600;700&family=Open+Sans:wght@300;400;500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@page {
size: A4 landscape;
margin: 0;
}
html, body {
width: 297mm;
height: 210mm;
overflow: hidden;
}
body {
font-family: 'Open Sans', Arial, sans-serif;
background: #fff;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
@@ -39,7 +22,6 @@
background-repeat: no-repeat;
}
/* Main content - centered in the white area */
.main-content {
position: absolute;
top: 50%;
@@ -58,7 +40,7 @@
.course-title {
font-family: 'Bahnschrift', 'Open Sans', Arial, sans-serif;
font-size: 24pt;
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 4mm;
@@ -77,7 +59,6 @@
color: #1a1a1a;
}
/* Issue date - above "Dátum" at bottom left */
.issue-date {
position: absolute;
bottom: 42mm;
@@ -99,13 +80,11 @@
<div class="certificate">
<div class="main-content">
<h3 class="participant-name">{{participantName}}</h3>
<h2 class="course-title">{{courseTitle}}</h2>
<h2 class="course-title">PRINCE2® Foundation</h2>
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
{{#if courseHours}}
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
{{/if}}
<p class="course-hours">v rozsahu 16 hodín</p>
</div>
<div class="issue-date">{{issueDate}}</div>

View File

@@ -7,27 +7,10 @@
<style>
@import url('https://fonts.googleapis.com/css2?family=Bahnschrift:wght@400;600;700&family=Open+Sans:wght@300;400;500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@page {
size: A4 landscape;
margin: 0;
}
html, body {
width: 297mm;
height: 210mm;
overflow: hidden;
}
body {
font-family: 'Open Sans', Arial, sans-serif;
background: #fff;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
@@ -39,7 +22,6 @@
background-repeat: no-repeat;
}
/* Main content - centered in the white area */
.main-content {
position: absolute;
top: 50%;
@@ -58,7 +40,7 @@
.course-title {
font-family: 'Bahnschrift', 'Open Sans', Arial, sans-serif;
font-size: 24pt;
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 4mm;
@@ -77,7 +59,6 @@
color: #1a1a1a;
}
/* Issue date - above "Dátum" at bottom left */
.issue-date {
position: absolute;
bottom: 42mm;
@@ -99,13 +80,11 @@
<div class="certificate">
<div class="main-content">
<h3 class="participant-name">{{participantName}}</h3>
<h2 class="course-title">{{courseTitle}}</h2>
<h2 class="course-title">PRINCE2® Practitioner</h2>
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
{{#if courseHours}}
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
{{/if}}
<p class="course-hours">v rozsahu 24 hodín</p>
</div>
<div class="issue-date">{{issueDate}}</div>

View File

@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Osvedčenie - {{participantName}}</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Bahnschrift:wght@400;600;700&family=Open+Sans:wght@300;400;500;600;700&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
height: 210mm;
position: relative;
background-image: url('{{backgroundImage}}');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.main-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
margin-top: -15mm;
}
.participant-name {
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 8mm;
}
.course-title {
font-family: 'Bahnschrift', 'Open Sans', Arial, sans-serif;
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 4mm;
}
.course-dates {
font-size: 14pt;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 2mm;
}
.course-hours {
font-size: 14pt;
font-weight: 600;
color: #1a1a1a;
}
.issue-date {
position: absolute;
bottom: 42mm;
left: 28mm;
font-size: 12pt;
color: #333;
}
.certificate-id {
position: absolute;
bottom: 10mm;
right: 18mm;
font-size: 7pt;
color: #666;
}
</style>
</head>
<body>
<div class="certificate">
<div class="main-content">
<h3 class="participant-name">{{participantName}}</h3>
<h2 class="course-title">Scrum Master</h2>
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
<p class="course-hours">v rozsahu 16 hodín</p>
</div>
<div class="issue-date">{{issueDate}}</div>
<div class="certificate-id">ID: {{certificateId}}</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Osvedčenie - {{participantName}}</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Bahnschrift:wght@400;600;700&family=Open+Sans:wght@300;400;500;600;700&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
@page { size: A4 landscape; margin: 0; }
html, body { width: 297mm; height: 210mm; overflow: hidden; }
body { font-family: 'Open Sans', Arial, sans-serif; background: #fff; }
.certificate {
width: 297mm;
height: 210mm;
position: relative;
background-image: url('{{backgroundImage}}');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.main-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
margin-top: -15mm;
}
.participant-name {
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 8mm;
}
.course-title {
font-family: 'Bahnschrift', 'Open Sans', Arial, sans-serif;
font-size: 28pt;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 4mm;
}
.course-dates {
font-size: 14pt;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 2mm;
}
.course-hours {
font-size: 14pt;
font-weight: 600;
color: #1a1a1a;
}
.issue-date {
position: absolute;
bottom: 42mm;
left: 28mm;
font-size: 12pt;
color: #333;
}
.certificate-id {
position: absolute;
bottom: 10mm;
right: 18mm;
font-size: 7pt;
color: #666;
}
</style>
</head>
<body>
<div class="certificate">
<div class="main-content">
<h3 class="participant-name">{{participantName}}</h3>
<h2 class="course-title">Scrum Product Owner</h2>
{{#if dateRange}}
<p class="course-dates">{{dateRange}}</p>
{{/if}}
<p class="course-hours">v rozsahu 16 hodín</p>
</div>
<div class="issue-date">{{issueDate}}</div>
<div class="certificate-id">ID: {{certificateId}}</div>
</div>
</body>
</html>

View File

@@ -1,15 +1,49 @@
Refactoring Smoke Test Checklist
=================================
Task 1: Changed "Todos" to "Úlohy" in Sidebar
1. [x] Start server (npm run dev) — does it boot without import errors?
2. [x] Login — check audit log entry exists
3. [x] Create a company — check audit log
4. [x] Add a note to the company
5. [x] Add a reminder to the company
6. [x] Assign a user to the company
7. [x] Create a project, assign user
8. [x] Create a todo with assigned users — check push notification
9. [x] Start/stop/pause/resume a timer
10. [x] Generate a monthly timesheet XLSX — open and verify
11. [x] Upload a file to a project (check size/type limits)
12. [x] AI Kurzy: create course, participant, registration
Task 2: Fixed EventDetail panel width from w-max to w-80
Task 3: Chat Online Indicator:
- Added sendHeartbeat() to userApi
- Added heartbeat interval (30s) in AppDataContext
- Added green dot indicator in ChatList for users online < 60s
Task 4: Updated search placeholder in CompaniesPage
Task 5: Calendar Notification Badge:
- Created CalendarCountContext.jsx
- Added getTodayCount() to eventApi
- Added badge to Calendar button in Sidebar
Task 6: Calendar Reminders Display:
- Added reminders state to useCalendarData
- Display reminders in CalendarGrid with orange styling and bell icon
Task 7: team_leader role access in Sidebar
Task 8: Changed "AI Kurzy" to "Všetky kurzy" in Sidebar
Task 9: User Flagging System:
- Added needsFollowup checkbox column to RegistrationsTable
- Added red ring around rows when needsFollowup is true
Task 10: Sidebar Reorganization with logical sections:
- Quick Access: Profil, Dashboard, Chat, Kalendár
- Work Management: Úlohy, Sledovanie času, Výkazy
- CRM: Firmy, Projekty, Kontakty
- Communication: Emaily, Doručené
- Services: Služby
- Admin: Používatelia, História akcií, Všetky kurzy
---
Next Steps:
1. Run npm run db:push in crm-server to apply database changes
2. Test all features
3. Commit changes when ready
- i cant see online users there is not any green indicator and should be there
- i wanted to search comapny by her title,number , email address or website linked to company
now when i type phone nuber for exasmle it not display any company
- badge was added to kalendar button in Sidebar but i want to show number for whole day todos,reminders,dostupnost not only meetings/events
- i cant see the new role team_leader why ?? i cant create user with that role or edit role to team team_leader
-