|
90 | 90 | } |
91 | 91 |
|
92 | 92 | function renderCertificate(data) { |
93 | | - function renderContact() { |
94 | | - return ` |
95 | | - <div class="verify-result-footer"> |
96 | | - <p class="verify-contact">Bei Fragen kontaktieren Sie uns: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></p> |
97 | | - </div> |
98 | | - `; |
| 93 | + function renderContactLine() { |
| 94 | + return `<p class="verify-contact">Bei Rückfragen kann folgende Adresse kontaktiert werden: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></p>`; |
99 | 95 | } |
100 | 96 |
|
101 | | - function renderHeader(badge, title, description, tone) { |
102 | | - return ` |
103 | | - <div class="verify-result-header ${tone}"> |
104 | | - <span class="verify-result-badge">${escapeHtml(badge)}</span> |
105 | | - <h3 class="verify-result-title">${escapeHtml(title)}</h3> |
106 | | - <p class="verify-result-description">${escapeHtml(description)}</p> |
107 | | - </div> |
108 | | - `; |
| 97 | + function formatDateTime(iso) { |
| 98 | + try { |
| 99 | + const d = new Date(iso); |
| 100 | + const dd = String(d.getUTCDate()).padStart(2, '0'); |
| 101 | + const mm = String(d.getUTCMonth() + 1).padStart(2, '0'); |
| 102 | + const yyyy = d.getUTCFullYear(); |
| 103 | + const hh = String(d.getUTCHours()).padStart(2, '0'); |
| 104 | + const min = String(d.getUTCMinutes()).padStart(2, '0'); |
| 105 | + return `${dd}.${mm}.${yyyy}, ${hh}:${min} UTC`; |
| 106 | + } catch (e) { |
| 107 | + return iso; |
| 108 | + } |
109 | 109 | } |
110 | 110 |
|
111 | 111 | if (data.status === 'valid') { |
| 112 | + const verifiedAt = data.verified_at ? formatDateTime(data.verified_at) : ''; |
112 | 113 | return ` |
113 | 114 | <div class="verify-result-card verify-result-success"> |
114 | | - ${renderHeader('Verifiziert', 'Zertifikat gültig', 'Dieses Zertifikat wurde erfolgreich bestätigt.', 'success')} |
115 | | - <div class="verify-details-grid"> |
116 | | - ${renderMeta('Teilnehmer', data.student_name)} |
117 | | - ${renderMeta('Kurs', data.course_title)} |
118 | | - ${renderMeta('Abschlussdatum', data.completion_date)} |
119 | | - ${renderMeta('Dauer', `${data.duration_hours} Stunden`)} |
120 | | - ${data.attendance_percentage != null ? renderMeta('Anwesenheit', `${data.attendance_percentage}%`) : ''} |
121 | | - ${data.assignment_completion_percentage != null ? renderMeta('Aufgaben', `${data.assignment_completion_percentage}%`) : ''} |
122 | | - ${data.course_level ? renderMeta('Niveau', data.course_level) : ''} |
123 | | - ${data.course_format ? renderMeta('Format', data.course_format) : ''} |
124 | | - ${data.instruction_language ? renderMeta('Sprache', data.instruction_language) : ''} |
125 | | - ${renderMeta('Herausgeber', data.issuer)} |
126 | | - ${renderMeta('Dozent', data.instructor)} |
127 | | - ${renderMeta('Zertifikat‑ID', data.certificate_id)} |
128 | | - ${data.verified_at ? renderMeta('Bestätigt am', data.verified_at) : ''} |
| 115 | + <div class="verify-result-header success"> |
| 116 | + <span class="verify-result-badge">Verifiziert</span> |
| 117 | + <h3 class="verify-result-title">Verifiziertes Zertifikat</h3> |
| 118 | + <p class="verify-result-description">Dieses Zertifikat wurde erfolgreich geprüft und als gültig bestätigt.</p> |
129 | 119 | </div> |
130 | | - <div class="verify-note">Dieses Zertifikat wurde von MathCodeLab ausgestellt. Weitere Informationen unter <a href="https://mathcodelab.de" target="_blank" rel="noreferrer">mathcodelab.de</a>.</div> |
131 | | - ${renderContact()} |
132 | | - </div> |
133 | | - `; |
134 | | - } else if (data.status === 'revoked') { |
135 | | - return ` |
136 | | - <div class="verify-result-card verify-result-revoked"> |
137 | | - ${renderHeader('Widerrufen', 'Zertifikat widerrufen', 'Dieses Zertifikat ist nicht mehr gültig.', 'warning')} |
138 | 120 | <div class="verify-details-grid"> |
139 | | - ${renderMeta('Zertifikat‑ID', data.certificate_id)} |
140 | | - ${data.revocation_reason ? renderMeta('Widerrufsgrund', data.revocation_reason) : ''} |
| 121 | + ${renderMeta('Teilnehmer', data.student_name || '-')} |
| 122 | + ${renderMeta('Kurs', data.course_title || '-')} |
| 123 | + ${renderMeta('Abschlussdatum', data.completion_date || '-')} |
| 124 | + ${renderMeta('Dauer', (data.duration_hours != null) ? `${data.duration_hours} Unterrichtsstunden` : '-')} |
| 125 | + ${renderMeta('Herausgeber', data.issuer || 'MathCodeLab')} |
| 126 | + ${renderMeta('Dozent', data.instructor || 'Mohammad Orabe')} |
| 127 | + ${renderMeta('Zertifikat-ID', data.certificate_id)} |
| 128 | + ${verifiedAt ? renderMeta('Verifiziert am', verifiedAt) : ''} |
141 | 129 | </div> |
142 | | - <div class="verify-note">Dieses Zertifikat wurde von MathCodeLab widerrufen.</div> |
143 | | - ${renderContact()} |
| 130 | + <div class="verify-note">Hinweis:\nDieses Zertifikat bestätigt die erfolgreiche Teilnahme bzw. den Abschluss eines von MathCodeLab durchgeführten Kurses. Es stellt keinen akademischen Abschluss dar und beinhaltet keine Vergabe von Leistungspunkten (ECTS). Eine mögliche Anerkennung durch Dritten erfolgt ausschließlich im Ermessen der jeweiligen Institution.<br>Weitere Informationen sind unter <a href="https://mathcodelab.de" target="_blank" rel="noreferrer">https://mathcodelab.de</a> verfügbar.</div> |
| 131 | + <div class="verify-result-footer">${renderContactLine()}</div> |
144 | 132 | </div> |
145 | 133 | `; |
146 | 134 | } else { |
147 | 135 | return ` |
148 | 136 | <div class="verify-result-card verify-result-invalid"> |
149 | | - ${renderHeader('Nicht gefunden', 'Zertifikat nicht gefunden', 'Es wurde kein Zertifikat mit dieser ID im MathCodeLab-Verifizierungssystem gefunden.', 'danger')} |
150 | | - <div class="verify-suggestion">Vorschläge: Überprüfen Sie das ID‑Format, entfernen Sie Leerzeichen oder versuchen Sie folgendes Beispiel: <strong>MCL-2026-GLMMEO7</strong>.</div> |
151 | | - ${renderContact()} |
| 137 | + <div class="verify-result-header danger"> |
| 138 | + <span class="verify-result-badge">Nicht gefunden</span> |
| 139 | + <h3 class="verify-result-title">Zertifikat nicht gefunden</h3> |
| 140 | + <p class="verify-result-description">Zu der angegebenen Zertifikat-ID konnte kein Eintrag in der MathCodeLab-Zertifikatsdatenbank gefunden werden. Es wird gebeten, die eingegebene ID zu überprüfen und erneut einzugeben.</p> |
| 141 | + </div> |
| 142 | + <div class="verify-result-footer">${renderContactLine()}</div> |
152 | 143 | </div> |
153 | 144 | `; |
154 | 145 | } |
|
176 | 167 | showLoading(true); |
177 | 168 | try { |
178 | 169 | const resp = await fetch(`${API_BASE}/verify/${encodeURIComponent(id)}`); |
179 | | - if (!resp.ok) throw new Error('not found'); |
| 170 | + if (resp.status === 404) { |
| 171 | + showResult(renderCertificate({status: 'invalid', certificate_id: id})); |
| 172 | + return; |
| 173 | + } |
| 174 | + if (!resp.ok) { |
| 175 | + throw new Error('server'); |
| 176 | + } |
180 | 177 | const data = await resp.json(); |
| 178 | + // ensure status field |
| 179 | + data.status = data.status || 'valid'; |
181 | 180 | showResult(renderCertificate(data)); |
182 | 181 | } catch (err) { |
183 | | - if (err.message === 'not found') { |
184 | | - showResult(renderCertificate({status: 'invalid', certificate_id: id})); |
185 | | - } else { |
186 | | - showResult('<div class="verify-result-card verify-result-invalid"><div class="verify-result-header danger"><span class="verify-result-badge">Fehler</span><h3 class="verify-result-title">Verifizierungsdienst nicht erreichbar</h3><p class="verify-result-description">Der Verifizierungsdienst ist derzeit nicht erreichbar.</p></div><div class="verify-note verify-note-warn">Bitte versuchen Sie es später erneut.</div><div class="verify-result-footer"><p class="verify-contact">Kontakt: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></p></div></div>'); |
187 | | - } |
| 182 | + // server / network errors -> show server error card |
| 183 | + showResult(` |
| 184 | + <div class="verify-result-card verify-result-invalid"> |
| 185 | + <div class="verify-result-header danger"> |
| 186 | + <span class="verify-result-badge">Fehler</span> |
| 187 | + <h3 class="verify-result-title">Fehler bei der Verifizierung</h3> |
| 188 | + <p class="verify-result-description">Der Verifizierungsdienst ist derzeit vorübergehend nicht erreichbar. Es wird gebeten, die Anfrage zu einem späteren Zeitpunkt erneut durchzuführen. Sollte das Problem weiterhin bestehen, kann der Support kontaktiert werden.</p> |
| 189 | + </div> |
| 190 | + <div class="verify-result-footer"><p class="verify-contact">Kontakt: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></p></div> |
| 191 | + </div> |
| 192 | + `); |
188 | 193 | } finally { |
189 | 194 | setFormBusy(false); |
190 | 195 | } |
|
200 | 205 | const id = document.getElementById('certificate-id').value.trim(); |
201 | 206 | if (!id) return; |
202 | 207 | if (!CERT_PATTERN.test(id)) { |
203 | | - showResult(`<div class="verify-status invalid">Ungültiges Format</div><div class="verify-note verify-note-warn">Bitte verwenden Sie das Format <strong>MCL-JJJJ-XXXXXXX</strong>. Beispiel: <strong>MCL-2026-GLMMEO7</strong>.</div><div class="verify-contact">kontaktieren Sie uns: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></div>`); |
| 208 | + showResult(` |
| 209 | + <div class="verify-result-card verify-result-invalid"> |
| 210 | + <div class="verify-result-header danger"> |
| 211 | + <span class="verify-result-badge">Ungültige Eingabe</span> |
| 212 | + <h3 class="verify-result-title">Ungültige Eingabe</h3> |
| 213 | + <p class="verify-result-description">Die eingegebene Zertifikat-ID entspricht nicht dem erwarteten Format. Es wird gebeten, folgendes Format zu verwenden: <strong>MCL-JJJJ-XXXXXXX</strong></p> |
| 214 | + </div> |
| 215 | + <div class="verify-suggestion">Beispiel: <strong>MCL-2026-GLMMEO7</strong></div> |
| 216 | + <div class="verify-result-footer"><p class="verify-contact">Bei Rückfragen kann folgende Adresse kontaktiert werden: <a href="mailto:info@mathcodelab.de">info@mathcodelab.de</a></p></div> |
| 217 | + </div> |
| 218 | + `); |
204 | 219 | return; |
205 | 220 | } |
206 | 221 | verifyCertificate(id); |
|
0 commit comments