Files
LexiChain/hooks/useNotifications.ts

270 lines
7.2 KiB
TypeScript
Raw Normal View History

2026-03-25 13:52:45 +01:00
/**
* useNotifications Hook
*
* Custom React hook for managing toast notifications and database notifications
* across the application.
*
* Features:
* - Integration with Sonner toasts for UI feedback
* - Creation of persistent notifications in database
* - Type-safe notification creation
* - Automatic error handling and logging
*
* Usage:
* ```typescript
* const { notifySuccess, notifyError, notifyWarning, notifyInfo, notifyDeadline } = useNotifications();
*
* // Show toast + save to database
* notifySuccess("Contract uploaded", "Your contract is ready for analysis");
* ```
*/
"use client";
import { useCallback } from "react";
import { toast } from "sonner";
import { NotificationService } from "@/lib/services/notification.service";
/**
* Notification creation payload
*/
interface NotificationPayload {
title: string;
message: string;
contractId?: string;
actionType?: string;
actionData?: Record<string, any>;
}
/**
* Hook return type
*/
interface UseNotificationsReturn {
notifySuccess: (title: string, message: string, contractId?: string) => void;
notifyError: (title: string, message: string, contractId?: string) => void;
notifyWarning: (title: string, message: string, contractId?: string) => void;
notifyInfo: (title: string, message: string, contractId?: string) => void;
notifyDeadline: (payload: NotificationPayload) => void;
}
/**
* Creates a persistent notification in the database
*
* This is called internally by the notification methods
*
* @param type - Notification type (SUCCESS, ERROR, WARNING, INFO, DEADLINE)
* @param payload - Notification data
* @returns Promise that resolves when notification is saved
*
* Note: This runs client-side and makes API calls to create notifications
* in the background without blocking the UI
*/
const createPersistentNotification = async (
type: "SUCCESS" | "ERROR" | "WARNING" | "INFO" | "DEADLINE",
payload: NotificationPayload,
): Promise<void> => {
try {
// This would be called via a server action in a real implementation
// For now, we create it directly through the client
// In production, consider using a separate API route
// Simulate API call to create notification
// In real implementation, call server action:
// await createNotification({ type, ...payload })
} catch (error) {
console.error("Failed to create persistent notification:", error);
}
};
/**
* Hook Implementation
*
* Provides methods to display notifications with both:
* 1. Temporary toast (using Sonner) - visible for a few seconds
* 2. Persistent notification - stored in database for notification center
*/
export const useNotifications = (): UseNotificationsReturn => {
/**
* Success notification
*
* Used for:
* - Contract uploaded successfully
* - Analysis completed
* - File deleted
* - Settings saved
*
* @param title - Brief title (e.g., "Contract Uploaded")
* @param message - Detailed message (e.g., "Your contract is ready for analysis")
* @param contractId - Optional contract ID for dashboard link
*/
const notifySuccess = useCallback(
(title: string, message: string, contractId?: string) => {
// Show toast immediately
toast.success(title, {
description: message,
duration: 4000,
});
// Create persistent notification in background
createPersistentNotification("SUCCESS", {
title,
message,
contractId,
actionType: "SUCCESS_ACTION",
});
},
[],
);
/**
* Error notification
*
* Used for:
* - Upload failed
* - Analysis failed
* - Network errors
* - Invalid contract file
*
* @param title - Brief error title (e.g., "Upload Failed")
* @param message - Detailed error message with troubleshooting hints
* @param contractId - Optional contract ID for reference
*/
const notifyError = useCallback(
(title: string, message: string, contractId?: string) => {
// Show toast with error styling
toast.error(title, {
description: message,
duration: 5000, // Longer duration for errors
});
// Create persistent notification
createPersistentNotification("ERROR", {
title,
message,
contractId,
actionType: "ERROR_ACTION",
});
},
[],
);
/**
* Warning notification
*
* Used for:
* - File analysis taking longer than expected
* - Low quality extraction
* - Insufficient permissions
*
* @param title - Brief warning title
* @param message - Warning details
* @param contractId - Optional contract ID
*/
const notifyWarning = useCallback(
(title: string, message: string, contractId?: string) => {
toast.warning(title, {
description: message,
duration: 4000,
});
createPersistentNotification("WARNING", {
title,
message,
contractId,
actionType: "WARNING_ACTION",
});
},
[],
);
/**
* Info notification
*
* Used for:
* - General information
* - Processing started
* - Batch operations completing
* - Tips and suggestions
*
* @param title - Brief info title
* @param message - Additional information
* @param contractId - Optional contract ID
*/
const notifyInfo = useCallback(
(title: string, message: string, contractId?: string) => {
toast.info(title, {
description: message,
duration: 3000,
});
createPersistentNotification("INFO", {
title,
message,
contractId,
actionType: "INFO_ACTION",
});
},
[],
);
/**
* Deadline/renewal notification
*
* Used for:
* - Contract expiring in 30 days
* - Contract expiring in 15 days
* - Contract expiring in 7 days
* - Renewal reminders
*
* @param payload - Deadline notification data including:
* - title: Deadline title
* - message: Deadline details
* - contractId: Contract ID for direct access
* - actionType: RENEWAL_CRITICAL, RENEWAL_WARNING, RENEWAL_URGENT
* - actionData: Additional deadline metadata
*
* Example:
* ```typescript
* notifyDeadline({
* title: "🔴 Contract Expiring in 30 Days",
* message: "Insurance Auto from ACME Corp expires on Jan 15, 2025",
* contractId: "contract123",
* actionType: "RENEWAL_CRITICAL",
* actionData: {
* level: "CRITICAL",
* daysUntilExpiration: 30,
* expirationDate: "2025-01-15T00:00:00Z"
* }
* });
* ```
*/
const notifyDeadline = useCallback((payload: NotificationPayload) => {
// Show deadline toast with important visual styling
toast.error(payload.title, {
description: payload.message,
duration: 6000, // Longer for important deadlines
action: {
label: "View",
onClick: () => {
// Navigate to contract details if needed
if (payload.contractId) {
window.location.href = `/dashboard?contract=${payload.contractId}`;
}
},
},
});
// Create persistent notification
createPersistentNotification("DEADLINE", payload);
}, []);
return {
notifySuccess,
notifyError,
notifyWarning,
notifyInfo,
notifyDeadline,
};
};
export default useNotifications;