Round 10: WYSIWYG Editor, Notification System, Calendar Events, Student UI, Drag-Reorder, Styling
This commit is contained in:
1 parent
62f4a150e0
commit
b90ad85b91
18 files changed
+3105
-626
No files matched your search
+110
@@ -142,6 +142,7 @@ export interface ClassGroup {
|
||||
teachers: Array<{ id: string; userId: string; role: string; user: { id: string; firstName: string; lastName: string; email: string } }>;
|
||||
studentCount?: number;
|
||||
teacherList?: Array<{ id: string; firstName: string; lastName: string; teacherRole: string }>;
|
||||
_count?: { enrollments?: number; competencyAssignments?: number; [key: string]: unknown };
|
||||
}
|
||||
|
||||
export function fetchClasses(schoolId?: string, schoolYearId?: string): Promise<ClassGroup[]> {
|
||||
@@ -1339,6 +1340,69 @@ export function fetchCalendarEvents(schoolId: string, month: string): Promise<Ca
|
||||
return apiGet<CalendarResponse>(`/api/calendar?${sp.toString()}`);
|
||||
}
|
||||
|
||||
/* ── Calendar Events (Custom) ──────────────────────────────────── */
|
||||
|
||||
export type CalendarEventItemType = 'assessment' | 'lesson' | 'reminder';
|
||||
|
||||
export interface CalendarEventItem {
|
||||
id: string;
|
||||
schoolId: string;
|
||||
teacherId: string;
|
||||
title: string;
|
||||
date: string;
|
||||
startTime: string | null;
|
||||
endTime: string | null;
|
||||
eventType: CalendarEventItemType;
|
||||
subjectId: string | null;
|
||||
classGroupId: string | null;
|
||||
notes: string | null;
|
||||
allDay: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
subject: { id: string; name: string } | null;
|
||||
classGroup: { id: string; name: string } | null;
|
||||
}
|
||||
|
||||
export function fetchCalendarEventItems(schoolId: string, month: string): Promise<CalendarEventItem[]> {
|
||||
const sp = new URLSearchParams();
|
||||
sp.set('schoolId', schoolId);
|
||||
sp.set('month', month);
|
||||
return apiGet<CalendarEventItem[]>(`/api/calendar-events?${sp.toString()}`);
|
||||
}
|
||||
|
||||
export function createCalendarEventItem(data: {
|
||||
schoolId: string;
|
||||
title: string;
|
||||
date: string;
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
eventType: CalendarEventItemType;
|
||||
subjectId?: string | null;
|
||||
classGroupId?: string | null;
|
||||
notes?: string | null;
|
||||
allDay?: boolean;
|
||||
}): Promise<CalendarEventItem> {
|
||||
return apiPost<CalendarEventItem>('/api/calendar-events', data);
|
||||
}
|
||||
|
||||
export function updateCalendarEventItem(id: string, data: {
|
||||
title?: string;
|
||||
date?: string;
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
eventType?: CalendarEventItemType;
|
||||
subjectId?: string | null;
|
||||
classGroupId?: string | null;
|
||||
notes?: string | null;
|
||||
allDay?: boolean;
|
||||
}): Promise<CalendarEventItem> {
|
||||
return apiPut<CalendarEventItem>(`/api/calendar-events/${id}`, data);
|
||||
}
|
||||
|
||||
export function deleteCalendarEventItem(id: string): Promise<{ success: boolean }> {
|
||||
return apiDelete<{ success: boolean }>(`/api/calendar-events/${id}`);
|
||||
}
|
||||
|
||||
/* ── Lesson Plans ────────────────────────────────────────────────── */
|
||||
|
||||
export type LessonPlanStatus = 'draft' | 'scheduled' | 'completed' | 'cancelled';
|
||||
@@ -1974,20 +2038,66 @@ export interface MissingObservationNotification {
|
||||
isRead: boolean;
|
||||
}
|
||||
|
||||
/** @deprecated Use DBNotification instead */
|
||||
export interface NotificationData {
|
||||
upcomingAssessments: AssessmentNotification[];
|
||||
missingObservations: MissingObservationNotification[];
|
||||
unreadCount: number;
|
||||
}
|
||||
|
||||
/** New DB-backed notification type */
|
||||
export interface DBNotification {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
message: string;
|
||||
isRead: boolean;
|
||||
actionUrl: string | null;
|
||||
relatedId: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface DBNotificationData {
|
||||
notifications: DBNotification[];
|
||||
unreadCount: number;
|
||||
}
|
||||
|
||||
export function fetchNotifications(): Promise<NotificationData> {
|
||||
return apiGet<NotificationData>('/api/notifications');
|
||||
}
|
||||
|
||||
export function fetchDBNotifications(): Promise<DBNotificationData> {
|
||||
return apiGet<DBNotificationData>('/api/notifications');
|
||||
}
|
||||
|
||||
export function markServerNotificationsRead(ids: string[]): Promise<{ success: boolean }> {
|
||||
return apiPut<{ success: boolean }>('/api/notifications', { ids });
|
||||
}
|
||||
|
||||
export function markAllNotificationsRead(): Promise<{ success: boolean }> {
|
||||
return apiPut<{ success: boolean }>('/api/notifications', { markAll: true });
|
||||
}
|
||||
|
||||
export function markSingleNotificationRead(id: string): Promise<{ success: boolean }> {
|
||||
return apiPut<{ success: boolean }>('/api/notifications', { ids: [id] });
|
||||
}
|
||||
|
||||
export function createNotification(data: {
|
||||
schoolId: string;
|
||||
userId: string;
|
||||
type: string;
|
||||
title: string;
|
||||
message: string;
|
||||
actionUrl?: string;
|
||||
relatedId?: string;
|
||||
}): Promise<{ notification: DBNotification }> {
|
||||
return apiPost<{ notification: DBNotification }>('/api/notifications', data);
|
||||
}
|
||||
|
||||
export function deleteNotifications(ids?: string[]): Promise<{ success: boolean }> {
|
||||
return apiDelete<{ success: boolean }>(`/api/notifications${ids ? `?ids=${ids.join(',')}` : ''}`);
|
||||
}
|
||||
|
||||
/* ── Batch Delete & Reorder ─────────────────────────────────────────── */
|
||||
|
||||
export async function deleteBatchProgressEntries(ids: string[]): Promise<void> {
|
||||
|
||||
+200
@@ -1898,6 +1898,22 @@ const de: TranslationDict = {
|
||||
'notebooks.toolbar_align_left': 'Linksbuendig',
|
||||
'notebooks.toolbar_align_center': 'Zentriert',
|
||||
'notebooks.toolbar_align_right': 'Rechtsbuendig',
|
||||
'notebooks.toolbar_strikethrough': 'Durchgestrichen',
|
||||
'notebooks.toolbar_text_color': 'Textfarbe',
|
||||
'notebooks.toolbar_highlight': 'Hervorhebung',
|
||||
'notebooks.toolbar_highlight_yellow': 'Gelb',
|
||||
'notebooks.toolbar_highlight_green': 'Gruen',
|
||||
'notebooks.toolbar_highlight_blue': 'Blau',
|
||||
'notebooks.toolbar_highlight_pink': 'Rosa',
|
||||
'notebooks.toolbar_highlight_none': 'Keine',
|
||||
'notebooks.toolbar_color_black': 'Schwarz',
|
||||
'notebooks.toolbar_color_red': 'Rot',
|
||||
'notebooks.toolbar_color_blue': 'Blau',
|
||||
'notebooks.toolbar_color_green': 'Gruen',
|
||||
'notebooks.toolbar_color_orange': 'Orange',
|
||||
'notebooks.reorder_pages': 'Seiten neu anordnen',
|
||||
'notebooks.reorder_success': 'Reihenfolge gespeichert',
|
||||
'notebooks.reorder_error': 'Fehler beim Speichern der Reihenfolge',
|
||||
'notebooks.auto_saving': 'Automatisch speichern...',
|
||||
'notebooks.auto_saved': 'Automatisch gespeichert',
|
||||
'notebooks.page_thumbnail': 'Seitenvorschau',
|
||||
@@ -1957,6 +1973,90 @@ const de: TranslationDict = {
|
||||
'notebooks.template_science_desc': 'Kariertes Heft fuer Experimente',
|
||||
'notebooks.tab_all': 'Meine Hefte',
|
||||
'notebooks.owner': 'Von',
|
||||
|
||||
// ─── Enhanced Notifications ──────────────────────────────────────
|
||||
'notifications.today': 'Heute',
|
||||
'notifications.yesterday': 'Gestern',
|
||||
'notifications.this_week': 'Diese Woche',
|
||||
'notifications.earlier': 'Frueher',
|
||||
'notifications.mark_read': 'Als gelesen markieren',
|
||||
'notifications.clear_all': 'Alle loeschen',
|
||||
'notifications.type_assessment_due': 'Anstehende Pruefung',
|
||||
'notifications.type_missing_observation': 'Fehlende Beobachtung',
|
||||
'notifications.type_notebook_shared': 'Heft geteilt',
|
||||
'notifications.type_behavior_alert': 'Verhaltenswarnung',
|
||||
'notifications.type_grade_computed': 'Note berechnet',
|
||||
'notifications.type_attendance_alert': 'Anwesenheitswarnung',
|
||||
'notifications.type_report_ready': 'Bericht fertig',
|
||||
'notifications.type_general': 'Allgemein',
|
||||
|
||||
// ─── Student Dashboard ──────────────────────────────────────────────
|
||||
'student.dashboard_title': 'Mein Dashboard',
|
||||
'student.my_competencies': 'Meine Kompetenzen',
|
||||
'student.my_competencies_desc': 'Uebersicht deiner Kompetenzentwicklung',
|
||||
'student.my_grades': 'Meine Noten',
|
||||
'student.my_grades_desc': 'Aktuelle Bewertungsergebnisse',
|
||||
'student.my_notebooks': 'Meine Hefte',
|
||||
'student.my_notebooks_desc': 'Schnellzugriff auf deine Hefte',
|
||||
'student.my_attendance': 'Meine Anwesenheit',
|
||||
'student.my_attendance_desc': 'Anwesenheitsuebersicht',
|
||||
'student.upcoming_assessments': 'Anstehende Pruefungen',
|
||||
'student.upcoming_assessments_desc': 'Pruefungen in den naechsten Tagen',
|
||||
'student.no_competencies': 'Noch keine Kompetenzdaten vorhanden',
|
||||
'student.no_grades': 'Noch keine Noten vorhanden',
|
||||
'student.no_notebooks': 'Noch keine Hefte vorhanden',
|
||||
'student.no_attendance': 'Keine Anwesenheitsdaten vorhanden',
|
||||
'student.no_assessments': 'Keine anstehenden Pruefungen',
|
||||
'student.competency_level': 'Kompetenzniveau',
|
||||
'student.grade_in': 'Note in',
|
||||
'student.days_until': 'Tage bis',
|
||||
'student.attendance_rate': 'Anwesenheitsrate',
|
||||
'student.present': 'Anwesend',
|
||||
'student.absent': 'Abwesend',
|
||||
'student.late': 'Verspaetet',
|
||||
'student.view_all': 'Alle anzeigen',
|
||||
'student.welcome_back': 'Willkommen zurueck',
|
||||
'student.progress_overview': 'Dein Lernfortschritt',
|
||||
'nav.student_competencies': 'Meine Kompetenzen',
|
||||
'nav.student_grades': 'Meine Noten',
|
||||
'nav.student_notebooks': 'Meine Hefte',
|
||||
'nav.student_attendance': 'Meine Anwesenheit',
|
||||
'role.student': 'Schueler',
|
||||
|
||||
// Calendar (enhanced - Task 4)
|
||||
'calendar.new_event': 'Neues Ereignis',
|
||||
'calendar.edit_event': 'Ereignis bearbeiten',
|
||||
'calendar.week_view': 'Wochenansicht',
|
||||
'calendar.month_view': 'Monatsansicht',
|
||||
'calendar.all_day': 'Ganztägig',
|
||||
'calendar.event_type': 'Ereignistyp',
|
||||
'calendar.reminder': 'Erinnerung',
|
||||
'calendar.start_time': 'Startzeit',
|
||||
'calendar.end_time': 'Endzeit',
|
||||
'calendar.notes': 'Notizen',
|
||||
'calendar.notes_placeholder': 'Zusätzliche Notizen...',
|
||||
'calendar.delete_confirm': 'Ereignis wirklich löschen?',
|
||||
'calendar.delete_confirm_desc': 'Dieses Ereignis wird unwiderruflich gelöscht.',
|
||||
'calendar.event_created': 'Ereignis erstellt',
|
||||
'calendar.event_updated': 'Ereignis aktualisiert',
|
||||
'calendar.event_deleted': 'Ereignis gelöscht',
|
||||
'calendar.event_create_error': 'Fehler beim Erstellen des Ereignisses',
|
||||
'calendar.event_update_error': 'Fehler beim Aktualisieren des Ereignisses',
|
||||
'calendar.event_delete_error': 'Fehler beim Löschen des Ereignisses',
|
||||
|
||||
// Dashboard (enhanced - Task 4)
|
||||
'dashboard.new_assessment': 'Neue Bewertung',
|
||||
'dashboard.record_progress': 'Fortschritt erfassen',
|
||||
'dashboard.my_competencies': 'Meine Kompetenzen',
|
||||
'dashboard.my_grades': 'Meine Noten',
|
||||
'dashboard.paper_saved': 'Papier gespart',
|
||||
'dashboard.view_all': 'Alle anzeigen',
|
||||
|
||||
// Notifications (enhanced - Task 4)
|
||||
'notifications.no_notifications': 'Keine Benachrichtigungen',
|
||||
|
||||
// Student (enhanced - Task 4)
|
||||
'student.shared_with_me': 'Mit mir geteilt',
|
||||
};
|
||||
|
||||
const en: TranslationDict = {
|
||||
@@ -3854,6 +3954,22 @@ const en: TranslationDict = {
|
||||
'notebooks.toolbar_align_left': 'Align Left',
|
||||
'notebooks.toolbar_align_center': 'Align Center',
|
||||
'notebooks.toolbar_align_right': 'Align Right',
|
||||
'notebooks.toolbar_strikethrough': 'Strikethrough',
|
||||
'notebooks.toolbar_text_color': 'Text Color',
|
||||
'notebooks.toolbar_highlight': 'Highlight',
|
||||
'notebooks.toolbar_highlight_yellow': 'Yellow',
|
||||
'notebooks.toolbar_highlight_green': 'Green',
|
||||
'notebooks.toolbar_highlight_blue': 'Blue',
|
||||
'notebooks.toolbar_highlight_pink': 'Pink',
|
||||
'notebooks.toolbar_highlight_none': 'None',
|
||||
'notebooks.toolbar_color_black': 'Black',
|
||||
'notebooks.toolbar_color_red': 'Red',
|
||||
'notebooks.toolbar_color_blue': 'Blue',
|
||||
'notebooks.toolbar_color_green': 'Green',
|
||||
'notebooks.toolbar_color_orange': 'Orange',
|
||||
'notebooks.reorder_pages': 'Reorder Pages',
|
||||
'notebooks.reorder_success': 'Order saved',
|
||||
'notebooks.reorder_error': 'Error saving order',
|
||||
'notebooks.auto_saving': 'Auto-saving...',
|
||||
'notebooks.auto_saved': 'Auto-saved',
|
||||
'notebooks.page_thumbnail': 'Page Thumbnail',
|
||||
@@ -3913,6 +4029,90 @@ const en: TranslationDict = {
|
||||
'notebooks.template_science_desc': 'Grid notebook for experiments',
|
||||
'notebooks.tab_all': 'My Notebooks',
|
||||
'notebooks.owner': 'By',
|
||||
|
||||
// ─── Enhanced Notifications ──────────────────────────────────────
|
||||
'notifications.today': 'Today',
|
||||
'notifications.yesterday': 'Yesterday',
|
||||
'notifications.this_week': 'This Week',
|
||||
'notifications.earlier': 'Earlier',
|
||||
'notifications.mark_read': 'Mark as read',
|
||||
'notifications.clear_all': 'Clear all',
|
||||
'notifications.type_assessment_due': 'Assessment Due',
|
||||
'notifications.type_missing_observation': 'Missing Observation',
|
||||
'notifications.type_notebook_shared': 'Notebook Shared',
|
||||
'notifications.type_behavior_alert': 'Behavior Alert',
|
||||
'notifications.type_grade_computed': 'Grade Computed',
|
||||
'notifications.type_attendance_alert': 'Attendance Alert',
|
||||
'notifications.type_report_ready': 'Report Ready',
|
||||
'notifications.type_general': 'General',
|
||||
|
||||
// ─── Student Dashboard ──────────────────────────────────────────────
|
||||
'student.dashboard_title': 'My Dashboard',
|
||||
'student.my_competencies': 'My Competencies',
|
||||
'student.my_competencies_desc': 'Overview of your competency development',
|
||||
'student.my_grades': 'My Grades',
|
||||
'student.my_grades_desc': 'Latest assessment results',
|
||||
'student.my_notebooks': 'My Notebooks',
|
||||
'student.my_notebooks_desc': 'Quick access to your notebooks',
|
||||
'student.my_attendance': 'My Attendance',
|
||||
'student.my_attendance_desc': 'Attendance summary',
|
||||
'student.upcoming_assessments': 'Upcoming Assessments',
|
||||
'student.upcoming_assessments_desc': 'Assessments in the next days',
|
||||
'student.no_competencies': 'No competency data yet',
|
||||
'student.no_grades': 'No grades yet',
|
||||
'student.no_notebooks': 'No notebooks yet',
|
||||
'student.no_attendance': 'No attendance data yet',
|
||||
'student.no_assessments': 'No upcoming assessments',
|
||||
'student.competency_level': 'Competency Level',
|
||||
'student.grade_in': 'Grade in',
|
||||
'student.days_until': 'days until',
|
||||
'student.attendance_rate': 'Attendance Rate',
|
||||
'student.present': 'Present',
|
||||
'student.absent': 'Absent',
|
||||
'student.late': 'Late',
|
||||
'student.view_all': 'View all',
|
||||
'student.welcome_back': 'Welcome back',
|
||||
'student.progress_overview': 'Your Learning Progress',
|
||||
'nav.student_competencies': 'My Competencies',
|
||||
'nav.student_grades': 'My Grades',
|
||||
'nav.student_notebooks': 'My Notebooks',
|
||||
'nav.student_attendance': 'My Attendance',
|
||||
'role.student': 'Student',
|
||||
|
||||
// Calendar (enhanced - Task 4)
|
||||
'calendar.new_event': 'New Event',
|
||||
'calendar.edit_event': 'Edit Event',
|
||||
'calendar.week_view': 'Week View',
|
||||
'calendar.month_view': 'Month View',
|
||||
'calendar.all_day': 'All Day',
|
||||
'calendar.event_type': 'Event Type',
|
||||
'calendar.reminder': 'Reminder',
|
||||
'calendar.start_time': 'Start Time',
|
||||
'calendar.end_time': 'End Time',
|
||||
'calendar.notes': 'Notes',
|
||||
'calendar.notes_placeholder': 'Additional notes...',
|
||||
'calendar.delete_confirm': 'Delete this event?',
|
||||
'calendar.delete_confirm_desc': 'This event will be permanently deleted.',
|
||||
'calendar.event_created': 'Event created',
|
||||
'calendar.event_updated': 'Event updated',
|
||||
'calendar.event_deleted': 'Event deleted',
|
||||
'calendar.event_create_error': 'Error creating event',
|
||||
'calendar.event_update_error': 'Error updating event',
|
||||
'calendar.event_delete_error': 'Error deleting event',
|
||||
|
||||
// Dashboard (enhanced - Task 4)
|
||||
'dashboard.new_assessment': 'New Assessment',
|
||||
'dashboard.record_progress': 'Record Progress',
|
||||
'dashboard.my_competencies': 'My Competencies',
|
||||
'dashboard.my_grades': 'My Grades',
|
||||
'dashboard.paper_saved': 'Paper Saved',
|
||||
'dashboard.view_all': 'View All',
|
||||
|
||||
// Notifications (enhanced - Task 4)
|
||||
'notifications.no_notifications': 'No Notifications',
|
||||
|
||||
// Student (enhanced - Task 4)
|
||||
'student.shared_with_me': 'Shared with me',
|
||||
};
|
||||
|
||||
const translations: Record<string, TranslationDict> = { de, en };
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
// CompetenceTrack — Notification Helper
|
||||
// Server-side utility for creating notifications in the database
|
||||
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export type NotificationType =
|
||||
| 'ASSESSMENT_DUE'
|
||||
| 'MISSING_OBSERVATION'
|
||||
| 'NOTEBOOK_SHARED'
|
||||
| 'BEHAVIOR_ALERT'
|
||||
| 'GRADE_COMPUTED'
|
||||
| 'ATTENDANCE_ALERT'
|
||||
| 'REPORT_READY'
|
||||
| 'GENERAL';
|
||||
|
||||
/**
|
||||
* Create a notification for a specific user.
|
||||
* This is a server-side function that writes directly to the database.
|
||||
*/
|
||||
export async function createNotification(params: {
|
||||
schoolId: string;
|
||||
userId: string;
|
||||
type: NotificationType | string;
|
||||
title: string;
|
||||
message: string;
|
||||
actionUrl?: string;
|
||||
relatedId?: string;
|
||||
}) {
|
||||
const { schoolId, userId, type, title, message, actionUrl, relatedId } = params;
|
||||
|
||||
return db.notification.create({
|
||||
data: {
|
||||
schoolId,
|
||||
userId,
|
||||
type,
|
||||
title,
|
||||
message,
|
||||
actionUrl: actionUrl ?? null,
|
||||
relatedId: relatedId ?? null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a notification for multiple users (e.g., all students in a class).
|
||||
*/
|
||||
export async function createNotificationForUsers(params: {
|
||||
schoolId: string;
|
||||
userIds: string[];
|
||||
type: NotificationType | string;
|
||||
title: string;
|
||||
message: string;
|
||||
actionUrl?: string;
|
||||
relatedId?: string;
|
||||
}) {
|
||||
const { schoolId, userIds, type, title, message, actionUrl, relatedId } = params;
|
||||
|
||||
return db.notification.createMany({
|
||||
data: userIds.map((userId) => ({
|
||||
schoolId,
|
||||
userId,
|
||||
type,
|
||||
title,
|
||||
message,
|
||||
actionUrl: actionUrl ?? null,
|
||||
relatedId: relatedId ?? null,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all students in a class that a notebook has been shared.
|
||||
*/
|
||||
export async function notifyNotebookShared(params: {
|
||||
schoolId: string;
|
||||
classGroupId: string;
|
||||
notebookTitle: string;
|
||||
teacherName: string;
|
||||
notebookId: string;
|
||||
}) {
|
||||
const { schoolId, classGroupId, notebookTitle, teacherName, notebookId } = params;
|
||||
|
||||
// Get all student user IDs for the class
|
||||
const enrollments = await db.enrollment.findMany({
|
||||
where: {
|
||||
classGroupId,
|
||||
endDate: null,
|
||||
},
|
||||
include: {
|
||||
student: {
|
||||
select: { id: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Find User accounts linked to these students
|
||||
// Students may have a user account with the same email pattern
|
||||
const studentIds = enrollments.map((e) => e.student.id);
|
||||
|
||||
// For now, find users with STUDENT role in the school
|
||||
const studentUsers = await db.user.findMany({
|
||||
where: {
|
||||
schoolId,
|
||||
role: 'STUDENT',
|
||||
deletedAt: null,
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (studentUsers.length === 0) return;
|
||||
|
||||
return createNotificationForUsers({
|
||||
schoolId,
|
||||
userIds: studentUsers.map((u) => u.id),
|
||||
type: 'NOTEBOOK_SHARED',
|
||||
title: notebookTitle,
|
||||
message: `${teacherName} has shared a notebook with you`,
|
||||
actionUrl: 'notebooks',
|
||||
relatedId: notebookId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify a teacher about a behavior alert.
|
||||
*/
|
||||
export async function notifyBehaviorAlert(params: {
|
||||
schoolId: string;
|
||||
userId: string;
|
||||
studentName: string;
|
||||
className: string;
|
||||
incidentId: string;
|
||||
}) {
|
||||
return createNotification({
|
||||
...params,
|
||||
type: 'BEHAVIOR_ALERT',
|
||||
title: `Behavior Alert: ${params.studentName}`,
|
||||
message: `New behavior incident in ${params.className}`,
|
||||
actionUrl: 'behavior',
|
||||
relatedId: params.incidentId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify a student/teacher that a grade has been computed.
|
||||
*/
|
||||
export async function notifyGradeComputed(params: {
|
||||
schoolId: string;
|
||||
userId: string;
|
||||
studentName: string;
|
||||
className: string;
|
||||
gradeId: string;
|
||||
}) {
|
||||
return createNotification({
|
||||
...params,
|
||||
type: 'GRADE_COMPUTED',
|
||||
title: `Grade Computed: ${params.studentName}`,
|
||||
message: `New grade available for ${params.className}`,
|
||||
actionUrl: 'grading',
|
||||
relatedId: params.gradeId,
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user