diff --git a/common/certificate-of-conduct/certificateOfConduct.ts b/common/certificate-of-conduct/certificateOfConduct.ts index 8701a7486..d1039afee 100644 --- a/common/certificate-of-conduct/certificateOfConduct.ts +++ b/common/certificate-of-conduct/certificateOfConduct.ts @@ -18,7 +18,9 @@ export async function create(dateOfInspection: Date, dateOfIssue: Date, criminal }, }); logger.info(`Certificate of Conduct (${result.id}) created\n`); - await Notification.actionTaken(userForStudent(student), 'student_coc_updated', {}); + await Notification.actionTaken(userForStudent(student), 'student_coc_updated', { + date: dateOfIssue.toString(), + }); if (criminalRecords) { await deactivateStudent(student); } diff --git a/common/notification/actions.ts b/common/notification/actions.ts index df93ec6a1..2bdcd5e4f 100644 --- a/common/notification/actions.ts +++ b/common/notification/actions.ts @@ -425,7 +425,9 @@ const _notificationActions = { student_coc_updated: { description: 'Student / Certificate of Conduct handed in', - sampleContext: {}, + sampleContext: { + date: '20. Juli 1969', + }, }, coc_reminder: { description: 'Student / Certificate of Conduct Request', @@ -637,11 +639,17 @@ const _notificationActions = { }, pupil_registration_verified_email: { description: 'Pupil / E-Mail verified', - sampleContext: {}, + sampleContext: { + date: 'Wed Jul 28 1993 14:39:07 GMT+0200 (CEST)', + email: 'max-mustermann@abc.de', + }, }, student_registration_verified_email: { description: 'Student / E-Mail verified', - sampleContext: {}, + sampleContext: { + date: 'Wed Jul 28 1993 14:39:07 GMT+0200 (CEST)', + email: 'max-mustermann@abc.de', + }, }, user_achievement_reward_issued: { diff --git a/common/secret/token.ts b/common/secret/token.ts index 5175a471c..bddec1007 100644 --- a/common/secret/token.ts +++ b/common/secret/token.ts @@ -10,6 +10,7 @@ import { Email } from '../notification/types'; import { isEmailAvailable } from '../user/email'; import { secret_type_enum as SecretType } from '@prisma/client'; import { createSecretEmailToken } from './emailToken'; +import moment from 'moment'; const logger = getLogger('Token'); @@ -168,7 +169,10 @@ export async function verifyEmail(user: User) { data: { verifiedAt: new Date(), verification: null }, where: { id: user.studentId }, }); - await Notification.actionTaken(user, 'student_registration_verified_email', {}); + await Notification.actionTaken(user, 'student_registration_verified_email', { + date: moment(verifiedAt).format('DD. MMMM YYYY'), + email: user.email, + }); logger.info(`Student(${user.studentId}) verified their e-mail by logging in with an e-mail token`); } @@ -184,8 +188,10 @@ export async function verifyEmail(user: User) { data: { verifiedAt: new Date(), verification: null }, where: { id: user.pupilId }, }); - await Notification.actionTaken(user, 'pupil_registration_verified_email', {}); - + await Notification.actionTaken(user, 'pupil_registration_verified_email', { + date: moment(verifiedAt).format('DD. MMMM YYYY'), + email: user.email, + }); logger.info(`Pupil(${user.pupilId}) verified their e-mail by logging in with an e-mail token`); } } diff --git a/integration-tests/15_achievements.ts b/integration-tests/15_achievements.ts index 2eca2dc96..f62d84998 100644 --- a/integration-tests/15_achievements.ts +++ b/integration-tests/15_achievements.ts @@ -72,12 +72,12 @@ void test('Reward student onboarding achievement sequence', async () => { assert.ok(studentOnboarding2); // Create Certificate of Conduct - const newDate = JSON.stringify(new Date()); + const newDate = new Date().toISOString(); await adminClient.request(` mutation CreateCertificateOfConduct { certificateOfConductCreate( - dateOfInspection: ${newDate}, - dateOfIssue: ${newDate}, + dateOfInspection: "${newDate}", + dateOfIssue: "${newDate}", criminalRecords: false, studentId: ${student.student.id}, ) @@ -585,7 +585,7 @@ const createStudentOnboardingTemplates = async () => { stepName: 'Verifizieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: '', image: 'Puzzle_00', achievedImage: '', actionName: 'E-Mail erneut senden', @@ -605,7 +605,8 @@ const createStudentOnboardingTemplates = async () => { stepName: 'Kennenlerngespräch buchen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', image: 'Puzzle_01', achievedImage: '', actionName: 'Termin vereinbaren', @@ -627,7 +628,8 @@ const createStudentOnboardingTemplates = async () => { stepName: 'Screening absolvieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Wir sind gespannt darauf, dich kennenzulernen! In einem kurzen, 15-minütigen Zoom-Gespräch möchten wir dir gerne unsere vielfältigen Engagement-Möglichkeiten vorstellen und alle deine Fragen beantworten. Buche einfach einen Termin, um mehr zu erfahren und dann voller Tatendrang direkt durchzustarten. Falls dir etwas dazwischen kommt, sage den Termin bitte ab und buche dir einen neuen.', image: 'Puzzle_02', achievedImage: '', actionName: 'Screening absolvieren', @@ -647,7 +649,8 @@ const createStudentOnboardingTemplates = async () => { stepName: 'Führungszeugnis einreichen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Der Schutz von Kindern und Jugendlichen liegt uns sehr am Herzen, daher benötigen wir von allen Ehrenamtlichen ein erweitertes Führungszeugnis. Im nächsten Schritt findest du eine Anleitung zur Beantragung sowie eine Bescheinigung zur Kostenübernahme für das erweiterte Führungszeugnis. Um deinen Account aktiv zu halten, bitten wir dich, das erweiterte Führungszeugnis bis zum {{date}} bei uns einzureichen. Gemeinsam setzen wir uns für eine sichere Umgebung ein, in der alle sich wohl und geschützt fühlen können.', image: 'Puzzle_02', achievedImage: '', actionName: 'Zeugnis einreichen', @@ -667,7 +670,8 @@ const createStudentOnboardingTemplates = async () => { stepName: 'Onboarding abgeschlossen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Herzlichen Glückwunsch! Du hast alle Onboarding-Schritte erfolgreich gemeistert und dir das Abflugticket für Loki gesichert. Wir sind begeistert, dass du nun Teil unseres Teams bist und Schüler:innen auf ihrem Lernweg begleitest. Gemeinsam setzen wir uns für eine bessere Bildung in Deutschland ein. Du bist bereits jetzt ein:e Lern-Fair Held:in! ❤️ Danke für dein Engagement und deine Begeisterung!', image: 'Flugticket', achievedImage: '', actionName: null, @@ -689,7 +693,8 @@ const createPupilOnboardingTemplates = async () => { stepName: 'Verifizieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', image: 'Puzzle_00', achievedImage: '', actionName: 'E-Mail erneut senden', @@ -709,7 +714,8 @@ const createPupilOnboardingTemplates = async () => { stepName: 'Kennenlerngespräch buchen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', image: 'Puzzle_01', achievedImage: '', actionName: 'Termin vereinbaren', @@ -731,7 +737,8 @@ const createPupilOnboardingTemplates = async () => { stepName: 'Screening absolvieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Wir sind gespannt darauf, dich kennenzulernen! In einem kurzen, 15-minütigen Zoom-Gespräch möchten wir dir gerne unsere vielfältigen kostenlose Angebote vorstellen und dir die beste Unterstützung ermöglichen sowie alle deine Fragen beantworten. Buche einfach einen Termin, um mehr zu erfahren und dann voller Tatendrang direkt durchzustarten. Falls dir etwas dazwischen kommt, sage den Termin bitte ab und buche dir einen neuen.', image: 'Puzzle_02', achievedImage: '', actionName: 'Screening absolvieren', @@ -752,7 +759,8 @@ const createPupilOnboardingTemplates = async () => { stepName: 'Onboarding abgeschlossen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', + description: + 'Herzlichen Glückwunsch! Du hast alle Onboarding-Schritte erfolgreich gemeistert und dir das Abflugticket für Loki gesichert. Wir sind begeistert, dass du nun Teil unserer Lerncommunity bist und hoffen dich gut auf deiner Lernreise begleiten zu können. Loki und unser Team werden immer für dich da sein!', image: 'Flugticket', achievedImage: '', condition: 'pupil_screened_events > 0', @@ -1051,13 +1059,16 @@ const createStudentRegularLearningTemplate = async () => { stepName: '', type: achievement_type_enum.STREAK, subtitle: 'Nachhilfe mit {{matchpartner}}', - description: 'Dieser Text muss noch geliefert werden.', - image: 'Hat_grey', - achievedImage: 'Hat_gold', - actionName: null, + description: + 'Du hast {{num}} Woche(n) in Folge mit {{name}} gelernt! Um diese Serie aufrechtzuerhalten, setze deine gemeinsamen Lernsessions mit {{name}} weiter fort. Regelmäßiges Lernen bringt eine Fülle an Vorteilen mit sich, von verbessertem Wissen und Verständnis bis hin zu gesteigerter Effizienz und Selbstvertrauen. Ihr seid definitiv auf dem richtigen Weg, um eure Ziele zu erreichen!', + image: 'gamification/achievements/tmp/streaks/regular_learning_set.png', + achievedImage: 'gamification/achievements/tmp/streaks/regular_learning_achieved.png', + actionName: 'Noch {{num}} Woche(n) bis zum neuen Rekord!', actionRedirectLink: null, actionType: null, achievedText: 'Juhu! Rekord gebrochen.', + progressDescription: 'Noch {{leftProgress}} Woche(n) bis zum neuen Rekord!', + streakProgress: 'Du warst bei {{progress}} Termin(en) in Folge anwesend!', condition: 'student_match_learning_events > recordValue', conditionDataAggregations: { student_match_learning_events: { @@ -1081,13 +1092,16 @@ const createPupilRegularLearningTemplate = async () => { stepName: '', type: achievement_type_enum.STREAK, subtitle: 'Nachhilfe mit {{matchpartner}}', - description: 'Dieser Text muss noch geliefert werden.', - image: 'Hat_grey', - achievedImage: 'Hat_gold', - actionName: null, + description: + 'Du hast {{progress}} Woche(n) in Folge mit {{name}} gelernt! Um diese Serie aufrechtzuerhalten, setze deine gemeinsamen Lernsessions mit {{name}} weiter fort. Regelmäßiges Lernen bringt eine Fülle an Vorteilen mit sich, von verbessertem Wissen und Verständnis bis hin zu gesteigerter Effizienz und Selbstvertrauen. Ihr seid definitiv auf dem richtigen Weg, um eure Ziele zu erreichen!', + image: 'gamification/achievements/tmp/streaks/regular_learning_set.png', + achievedImage: 'gamification/achievements/tmp/streaks/regular_learning_achieved.png', + actionName: 'Noch {{progress}} Woche(n) bis zum neuen Rekord!', actionRedirectLink: null, actionType: null, achievedText: 'Juhu! Rekord gebrochen.', + progressDescription: 'Noch {{leftProgress}} Woche(n) bis zum neuen Rekord!', + streakProgress: 'Du warst bei {{progress}} Termin(en) in Folge anwesend!', condition: 'pupil_match_learning_events > recordValue', conditionDataAggregations: { pupil_match_learning_events: { diff --git a/seed-db.ts b/seed-db.ts index 9002ef199..c324a7a41 100644 --- a/seed-db.ts +++ b/seed-db.ts @@ -753,8 +753,8 @@ void (async function setupDevDB() { stepName: 'Verifizieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/empty_state.png', + description: '', + image: 'Puzzle_00', achievedImage: '', actionName: 'E-Mail erneut senden', actionRedirectLink: '', @@ -773,8 +773,9 @@ void (async function setupDevDB() { stepName: 'Kennenlerngespräch buchen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/step_1.png', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', + image: 'Puzzle_01', achievedImage: '', actionName: 'Termin vereinbaren', actionRedirectLink: 'https://calendly.com', @@ -795,8 +796,9 @@ void (async function setupDevDB() { stepName: 'Screening absolvieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/step_2.png', + description: + 'Wir sind gespannt darauf, dich kennenzulernen! In einem kurzen, 15-minütigen Zoom-Gespräch möchten wir dir gerne unsere vielfältigen Engagement-Möglichkeiten vorstellen und alle deine Fragen beantworten. Buche einfach einen Termin, um mehr zu erfahren und dann voller Tatendrang direkt durchzustarten. Falls dir etwas dazwischen kommt, sage den Termin bitte ab und buche dir einen neuen.', + image: 'Puzzle_02', achievedImage: '', actionName: 'Screening absolvieren', actionRedirectLink: '', @@ -815,11 +817,12 @@ void (async function setupDevDB() { stepName: 'Führungszeugnis einreichen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/step_3.png', + description: + 'Der Schutz von Kindern und Jugendlichen liegt uns sehr am Herzen, daher benötigen wir von allen Ehrenamtlichen ein erweitertes Führungszeugnis. Im nächsten Schritt findest du eine Anleitung zur Beantragung sowie eine Bescheinigung zur Kostenübernahme für das erweiterte Führungszeugnis. Um deinen Account aktiv zu halten, bitten wir dich, das erweiterte Führungszeugnis bis zum {{date}} bei uns einzureichen. Gemeinsam setzen wir uns für eine sichere Umgebung ein, in der alle sich wohl und geschützt fühlen können.', + image: 'Puzzle_02', achievedImage: '', actionName: 'Zeugnis einreichen', - actionRedirectLink: '/certificate-of-conduct', + actionRedirectLink: 'mailto:fz@lern-fair.de', actionType: achievement_action_type_enum.Action, condition: 'student_coc_success_events > 0', conditionDataAggregations: { student_coc_success_events: { metric: 'student_onboarding_coc_success', aggregator: 'count' } }, @@ -835,8 +838,9 @@ void (async function setupDevDB() { stepName: 'Onboarding abgeschlossen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/step_4.png', + description: + 'Herzlichen Glückwunsch! Du hast alle Onboarding-Schritte erfolgreich gemeistert und dir das Abflugticket für Loki gesichert. Wir sind begeistert, dass du nun Teil unseres Teams bist und Schüler:innen auf ihrem Lernweg begleitest. Gemeinsam setzen wir uns für eine bessere Bildung in Deutschland ein. Du bist bereits jetzt ein:e Lern-Fair Held:in! ❤️ Danke für dein Engagement und deine Begeisterung!', + image: 'Flugticket', achievedImage: '', actionName: null, actionRedirectLink: null, @@ -856,8 +860,9 @@ void (async function setupDevDB() { stepName: 'Verifizieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/four_pieces/empty_state.png', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', + image: 'Puzzle_00', achievedImage: '', actionName: 'E-Mail erneut senden', actionRedirectLink: '', @@ -876,8 +881,9 @@ void (async function setupDevDB() { stepName: 'Kennenlerngespräch buchen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/three_pieces/step_1.png', + description: + 'Hurra! Am {{date}} haben wir eine E-Mail an deine Adresse {{email}} gesendet. Um deine E-Mail zu bestätigen, klicke einfach auf den Button in der Nachricht. Solltest du unsere E-Mail nicht finden, kannst du hier eine erneute Zustellung anfordern und voller Vorfreude auf unser Weiterkommen warten.', + image: 'Puzzle_01', achievedImage: '', actionName: 'Termin vereinbaren', actionRedirectLink: 'https://calendly.com', @@ -898,8 +904,9 @@ void (async function setupDevDB() { stepName: 'Screening absolvieren', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/three_pieces/step_2.png', + description: + 'Wir sind gespannt darauf, dich kennenzulernen! In einem kurzen, 15-minütigen Zoom-Gespräch möchten wir dir gerne unsere vielfältigen kostenlose Angebote vorstellen und dir die beste Unterstützung ermöglichen sowie alle deine Fragen beantworten. Buche einfach einen Termin, um mehr zu erfahren und dann voller Tatendrang direkt durchzustarten. Falls dir etwas dazwischen kommt, sage den Termin bitte ab und buche dir einen neuen.', + image: 'Puzzle_02', achievedImage: '', actionName: 'Screening absolvieren', actionRedirectLink: '', @@ -909,7 +916,6 @@ void (async function setupDevDB() { isActive: true, }, }); - await prisma.achievement_template.create({ data: { name: 'Onboarding abschließen', @@ -919,8 +925,9 @@ void (async function setupDevDB() { stepName: 'Onboarding abgeschlossen', type: achievement_type_enum.SEQUENTIAL, subtitle: 'Jetzt durchstarten', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finish_onboarding/three_pieces/step_3.png', + description: + 'Herzlichen Glückwunsch! Du hast alle Onboarding-Schritte erfolgreich gemeistert und dir das Abflugticket für Loki gesichert. Wir sind begeistert, dass du nun Teil unserer Lerncommunity bist und hoffen dich gut auf deiner Lernreise begleiten zu können. Loki und unser Team werden immer für dich da sein!', + image: 'Flugticket', achievedImage: '', actionName: null, actionRedirectLink: null, @@ -1293,10 +1300,11 @@ void (async function setupDevDB() { stepName: '', type: achievement_type_enum.STREAK, subtitle: 'Nachhilfe mit {{matchpartner}}', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finished_course_sucessfully/finished_course_sucessfully.jpg', - achievedImage: 'Hat_gold', - actionName: null, + description: + 'Du hast {{progress}} Woche(n) in Folge mit {{name}} gelernt! Um diese Serie aufrechtzuerhalten, setze deine gemeinsamen Lernsessions mit {{name}} weiter fort. Regelmäßiges Lernen bringt eine Fülle an Vorteilen mit sich, von verbessertem Wissen und Verständnis bis hin zu gesteigerter Effizienz und Selbstvertrauen. Ihr seid definitiv auf dem richtigen Weg, um eure Ziele zu erreichen!', + image: 'gamification/achievements/tmp/streaks/regular_learning_set.png', + achievedImage: 'gamification/achievements/tmp/streaks/regular_learning_achieved.png', + actionName: 'Noch {{progress}} Woche(n) bis zum neuen Rekord!', actionRedirectLink: null, actionType: null, achievedText: 'Juhu! Rekord gebrochen.', @@ -1325,10 +1333,11 @@ void (async function setupDevDB() { stepName: '', type: achievement_type_enum.STREAK, subtitle: 'Nachhilfe mit {{matchpartner}}', - description: 'Dieser Text muss noch geliefert werden.', - image: 'gamification/achievements/tmp/finished_course_sucessfully/finished_course_sucessfully.jpg', - achievedImage: 'Hat_gold', - actionName: null, + description: + 'Du hast {{progress}} Woche(n) in Folge mit {{name}} gelernt! Um diese Serie aufrechtzuerhalten, setze deine gemeinsamen Lernsessions mit {{name}} weiter fort. Regelmäßiges Lernen bringt eine Fülle an Vorteilen mit sich, von verbessertem Wissen und Verständnis bis hin zu gesteigerter Effizienz und Selbstvertrauen. Ihr seid definitiv auf dem richtigen Weg, um eure Ziele zu erreichen!', + image: 'gamification/achievements/tmp/streaks/regular_learning_set.png', + achievedImage: 'gamification/achievements/tmp/streaks/regular_learning_achieved.png', + actionName: 'Noch {{progress}} Woche(n) bis zum neuen Rekord!', actionRedirectLink: null, actionType: null, achievedText: 'Juhu! Rekord gebrochen.',