Implement multi-channel notification system with: - Core notification service with email, push, and in-app channels - Email templates for all notification types (welcome, plant registered, transport alerts, farm alerts, harvest ready, demand matches, weekly digest) - Push notification support with VAPID authentication - In-app notification management with read/unread tracking - Notification scheduler for recurring and scheduled notifications - API endpoints for notifications CRUD, preferences, and subscriptions - UI components (NotificationBell, NotificationList, NotificationItem, PreferencesForm) - Full notifications page with preferences management - Service worker for push notification handling
161 lines
4.1 KiB
TypeScript
161 lines
4.1 KiB
TypeScript
/**
|
|
* LocalGreenChain Notification System
|
|
* Multi-channel notifications with email, push, and in-app support
|
|
*/
|
|
|
|
export * from './types';
|
|
export { NotificationService, getNotificationService } from './service';
|
|
export { NotificationScheduler, getNotificationScheduler } from './scheduler';
|
|
export { EmailChannel } from './channels/email';
|
|
export { PushChannel } from './channels/push';
|
|
export { InAppChannel } from './channels/inApp';
|
|
|
|
// Convenience functions
|
|
import { getNotificationService } from './service';
|
|
import { getNotificationScheduler } from './scheduler';
|
|
import { NotificationPayload, NotificationChannel, NotificationPriority, NotificationRecipient } from './types';
|
|
|
|
/**
|
|
* Send a notification (convenience function)
|
|
*/
|
|
export async function sendNotification(
|
|
recipient: NotificationRecipient,
|
|
payload: NotificationPayload,
|
|
options?: {
|
|
channels?: NotificationChannel[];
|
|
priority?: NotificationPriority;
|
|
}
|
|
) {
|
|
return getNotificationService().send(recipient, payload, options);
|
|
}
|
|
|
|
/**
|
|
* Send a welcome notification
|
|
*/
|
|
export async function sendWelcomeNotification(userId: string, email: string, name?: string) {
|
|
return sendNotification(
|
|
{ userId, email },
|
|
{
|
|
type: 'welcome',
|
|
title: `Welcome to LocalGreenChain${name ? `, ${name}` : ''}!`,
|
|
message: 'Thank you for joining our community. Start tracking your plants today!',
|
|
actionUrl: '/dashboard'
|
|
},
|
|
{ channels: ['email', 'inApp'] }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send a plant registered notification
|
|
*/
|
|
export async function sendPlantRegisteredNotification(
|
|
userId: string,
|
|
email: string,
|
|
plantId: string,
|
|
species: string,
|
|
variety?: string
|
|
) {
|
|
return sendNotification(
|
|
{ userId, email },
|
|
{
|
|
type: 'plant_registered',
|
|
title: 'Plant Registered Successfully',
|
|
message: `Your ${species}${variety ? ` (${variety})` : ''} has been registered on the blockchain.`,
|
|
data: { plantId, species, variety },
|
|
actionUrl: `/plants/${plantId}`
|
|
},
|
|
{ channels: ['inApp', 'email'] }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send a transport alert
|
|
*/
|
|
export async function sendTransportAlert(
|
|
userId: string,
|
|
email: string,
|
|
plantId: string,
|
|
eventType: string,
|
|
distance?: number,
|
|
carbonKg?: number
|
|
) {
|
|
return sendNotification(
|
|
{ userId, email },
|
|
{
|
|
type: 'transport_alert',
|
|
title: 'Transport Event Recorded',
|
|
message: `A ${eventType} event has been logged for your plant.`,
|
|
data: { plantId, eventType, distance, carbonKg },
|
|
actionUrl: `/transport/journey/${plantId}`
|
|
},
|
|
{ channels: ['inApp'] }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send a farm alert
|
|
*/
|
|
export async function sendFarmAlert(
|
|
userId: string,
|
|
email: string,
|
|
farmId: string,
|
|
zone: string,
|
|
severity: 'info' | 'warning' | 'critical',
|
|
message: string,
|
|
recommendation?: string
|
|
) {
|
|
return sendNotification(
|
|
{ userId, email },
|
|
{
|
|
type: 'farm_alert',
|
|
title: `Farm Alert: ${zone}`,
|
|
message,
|
|
data: { farmId, zone, severity, recommendation },
|
|
actionUrl: `/vertical-farm/${farmId}`
|
|
},
|
|
{
|
|
channels: severity === 'critical' ? ['inApp', 'email', 'push'] : ['inApp'],
|
|
priority: severity === 'critical' ? 'urgent' : 'medium'
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send a demand match notification
|
|
*/
|
|
export async function sendDemandMatchNotification(
|
|
userId: string,
|
|
email: string,
|
|
matchDetails: {
|
|
crop: string;
|
|
quantity: number;
|
|
region: string;
|
|
matchId: string;
|
|
}
|
|
) {
|
|
return sendNotification(
|
|
{ userId, email },
|
|
{
|
|
type: 'demand_match',
|
|
title: 'New Demand Match Found!',
|
|
message: `A consumer is looking for ${matchDetails.quantity} units of ${matchDetails.crop} in ${matchDetails.region}.`,
|
|
data: { matchDetails },
|
|
actionUrl: `/marketplace/match/${matchDetails.matchId}`
|
|
},
|
|
{ channels: ['inApp', 'email'], priority: 'high' }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Start the notification scheduler
|
|
*/
|
|
export function startNotificationScheduler(intervalMs?: number) {
|
|
getNotificationScheduler().start(intervalMs);
|
|
}
|
|
|
|
/**
|
|
* Stop the notification scheduler
|
|
*/
|
|
export function stopNotificationScheduler() {
|
|
getNotificationScheduler().stop();
|
|
}
|