ADD new frontend
This commit is contained in:
621
frontend/src/hooks/business/useAlerts.ts
Normal file
621
frontend/src/hooks/business/useAlerts.ts
Normal file
@@ -0,0 +1,621 @@
|
||||
/**
|
||||
* Alerts hook for managing bakery alerts and notifications
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { InventoryService } from '../../services/api/inventory.service';
|
||||
import { ProductionService } from '../../services/api/production.service';
|
||||
import { NotificationService } from '../../services/api/notification.service';
|
||||
|
||||
export type AlertType = 'inventory' | 'production' | 'quality' | 'maintenance' | 'safety' | 'system' | 'custom';
|
||||
export type AlertPriority = 'low' | 'medium' | 'high' | 'critical';
|
||||
export type AlertStatus = 'active' | 'acknowledged' | 'resolved' | 'dismissed';
|
||||
|
||||
export interface Alert {
|
||||
id: string;
|
||||
type: AlertType;
|
||||
priority: AlertPriority;
|
||||
status: AlertStatus;
|
||||
title: string;
|
||||
message: string;
|
||||
details?: Record<string, any>;
|
||||
source: string;
|
||||
sourceId?: string;
|
||||
createdAt: Date;
|
||||
updatedAt?: Date;
|
||||
acknowledgedAt?: Date;
|
||||
acknowledgedBy?: string;
|
||||
resolvedAt?: Date;
|
||||
resolvedBy?: string;
|
||||
dismissedAt?: Date;
|
||||
dismissedBy?: string;
|
||||
expiresAt?: Date;
|
||||
actions?: {
|
||||
id: string;
|
||||
label: string;
|
||||
action: string;
|
||||
parameters?: Record<string, any>;
|
||||
}[];
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface AlertRule {
|
||||
id: string;
|
||||
name: string;
|
||||
type: AlertType;
|
||||
priority: AlertPriority;
|
||||
condition: {
|
||||
field: string;
|
||||
operator: 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'greater_or_equal' | 'less_or_equal' | 'contains' | 'not_contains';
|
||||
value: any;
|
||||
}[];
|
||||
actions: string[];
|
||||
enabled: boolean;
|
||||
cooldownPeriod?: number; // in minutes
|
||||
lastTriggered?: Date;
|
||||
}
|
||||
|
||||
interface AlertsState {
|
||||
alerts: Alert[];
|
||||
rules: AlertRule[];
|
||||
unreadCount: number;
|
||||
criticalCount: number;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
filters: {
|
||||
types: AlertType[];
|
||||
priorities: AlertPriority[];
|
||||
statuses: AlertStatus[];
|
||||
sources: string[];
|
||||
};
|
||||
}
|
||||
|
||||
interface AlertsActions {
|
||||
// Alert Management
|
||||
fetchAlerts: (filters?: Partial<AlertsState['filters']>) => Promise<void>;
|
||||
acknowledgeAlert: (id: string) => Promise<boolean>;
|
||||
resolveAlert: (id: string, resolution?: string) => Promise<boolean>;
|
||||
dismissAlert: (id: string, reason?: string) => Promise<boolean>;
|
||||
bulkAcknowledge: (ids: string[]) => Promise<boolean>;
|
||||
bulkResolve: (ids: string[], resolution?: string) => Promise<boolean>;
|
||||
bulkDismiss: (ids: string[], reason?: string) => Promise<boolean>;
|
||||
|
||||
// Alert Creation
|
||||
createAlert: (alert: Omit<Alert, 'id' | 'createdAt' | 'status'>) => Promise<boolean>;
|
||||
createCustomAlert: (title: string, message: string, priority?: AlertPriority, details?: Record<string, any>) => Promise<boolean>;
|
||||
|
||||
// Alert Rules
|
||||
fetchAlertRules: () => Promise<void>;
|
||||
createAlertRule: (rule: Omit<AlertRule, 'id'>) => Promise<boolean>;
|
||||
updateAlertRule: (id: string, rule: Partial<AlertRule>) => Promise<boolean>;
|
||||
deleteAlertRule: (id: string) => Promise<boolean>;
|
||||
testAlertRule: (rule: AlertRule) => Promise<boolean>;
|
||||
|
||||
// Monitoring and Checks
|
||||
checkInventoryAlerts: () => Promise<void>;
|
||||
checkProductionAlerts: () => Promise<void>;
|
||||
checkQualityAlerts: () => Promise<void>;
|
||||
checkMaintenanceAlerts: () => Promise<void>;
|
||||
checkSystemAlerts: () => Promise<void>;
|
||||
|
||||
// Analytics
|
||||
getAlertAnalytics: (period: string) => Promise<any>;
|
||||
getAlertTrends: (days: number) => Promise<any>;
|
||||
getMostFrequentAlerts: (period: string) => Promise<any>;
|
||||
|
||||
// Filters and Search
|
||||
setFilters: (filters: Partial<AlertsState['filters']>) => void;
|
||||
searchAlerts: (query: string) => Promise<Alert[]>;
|
||||
|
||||
// Real-time Updates
|
||||
subscribeToAlerts: (callback: (alert: Alert) => void) => () => void;
|
||||
|
||||
// Utilities
|
||||
clearError: () => void;
|
||||
refresh: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useAlerts = (): AlertsState & AlertsActions => {
|
||||
const [state, setState] = useState<AlertsState>({
|
||||
alerts: [],
|
||||
rules: [],
|
||||
unreadCount: 0,
|
||||
criticalCount: 0,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
filters: {
|
||||
types: [],
|
||||
priorities: [],
|
||||
statuses: [],
|
||||
sources: [],
|
||||
},
|
||||
});
|
||||
|
||||
const inventoryService = new InventoryService();
|
||||
const productionService = new ProductionService();
|
||||
const notificationService = new NotificationService();
|
||||
|
||||
// Fetch alerts
|
||||
const fetchAlerts = useCallback(async (filters?: Partial<AlertsState['filters']>) => {
|
||||
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
||||
|
||||
try {
|
||||
// Combine filters
|
||||
const activeFilters = { ...state.filters, ...filters };
|
||||
|
||||
// Fetch alerts from different sources
|
||||
const [inventoryAlerts, productionAlerts, systemAlerts] = await Promise.all([
|
||||
getInventoryAlerts(activeFilters),
|
||||
getProductionAlerts(activeFilters),
|
||||
getSystemAlerts(activeFilters),
|
||||
]);
|
||||
|
||||
const allAlerts = [...inventoryAlerts, ...productionAlerts, ...systemAlerts]
|
||||
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
||||
|
||||
// Calculate counts
|
||||
const unreadCount = allAlerts.filter(alert => alert.status === 'active').length;
|
||||
const criticalCount = allAlerts.filter(alert => alert.priority === 'critical' && alert.status === 'active').length;
|
||||
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
alerts: allAlerts,
|
||||
unreadCount,
|
||||
criticalCount,
|
||||
isLoading: false,
|
||||
filters: activeFilters,
|
||||
}));
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
error: 'Error al cargar alertas',
|
||||
}));
|
||||
}
|
||||
}, [state.filters]);
|
||||
|
||||
// Get inventory alerts
|
||||
const getInventoryAlerts = async (filters: Partial<AlertsState['filters']>): Promise<Alert[]> => {
|
||||
try {
|
||||
const response = await inventoryService.getAlerts();
|
||||
|
||||
if (response.success && response.data) {
|
||||
return response.data.map((alert: any) => convertToAlert(alert, 'inventory'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching inventory alerts:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// Get production alerts
|
||||
const getProductionAlerts = async (filters: Partial<AlertsState['filters']>): Promise<Alert[]> => {
|
||||
try {
|
||||
const response = await productionService.getAlerts?.();
|
||||
|
||||
if (response?.success && response.data) {
|
||||
return response.data.map((alert: any) => convertToAlert(alert, 'production'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching production alerts:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// Get system alerts
|
||||
const getSystemAlerts = async (filters: Partial<AlertsState['filters']>): Promise<Alert[]> => {
|
||||
try {
|
||||
const response = await notificationService.getNotifications();
|
||||
|
||||
if (response.success && response.data) {
|
||||
return response.data
|
||||
.filter((notif: any) => notif.type === 'alert')
|
||||
.map((alert: any) => convertToAlert(alert, 'system'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching system alerts:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// Convert API response to Alert format
|
||||
const convertToAlert = (apiAlert: any, source: string): Alert => {
|
||||
return {
|
||||
id: apiAlert.id,
|
||||
type: apiAlert.type || (source as AlertType),
|
||||
priority: mapPriority(apiAlert.priority || apiAlert.severity),
|
||||
status: mapStatus(apiAlert.status),
|
||||
title: apiAlert.title || apiAlert.message?.substring(0, 50) || 'Alert',
|
||||
message: apiAlert.message || apiAlert.description || '',
|
||||
details: apiAlert.details || apiAlert.data,
|
||||
source,
|
||||
sourceId: apiAlert.source_id,
|
||||
createdAt: new Date(apiAlert.created_at || Date.now()),
|
||||
updatedAt: apiAlert.updated_at ? new Date(apiAlert.updated_at) : undefined,
|
||||
acknowledgedAt: apiAlert.acknowledged_at ? new Date(apiAlert.acknowledged_at) : undefined,
|
||||
acknowledgedBy: apiAlert.acknowledged_by,
|
||||
resolvedAt: apiAlert.resolved_at ? new Date(apiAlert.resolved_at) : undefined,
|
||||
resolvedBy: apiAlert.resolved_by,
|
||||
dismissedAt: apiAlert.dismissed_at ? new Date(apiAlert.dismissed_at) : undefined,
|
||||
dismissedBy: apiAlert.dismissed_by,
|
||||
expiresAt: apiAlert.expires_at ? new Date(apiAlert.expires_at) : undefined,
|
||||
actions: apiAlert.actions || [],
|
||||
metadata: apiAlert.metadata || {},
|
||||
};
|
||||
};
|
||||
|
||||
// Map priority from different sources
|
||||
const mapPriority = (priority: string): AlertPriority => {
|
||||
const priorityMap: Record<string, AlertPriority> = {
|
||||
'low': 'low',
|
||||
'medium': 'medium',
|
||||
'high': 'high',
|
||||
'critical': 'critical',
|
||||
'urgent': 'critical',
|
||||
'warning': 'medium',
|
||||
'error': 'high',
|
||||
'info': 'low',
|
||||
};
|
||||
|
||||
return priorityMap[priority?.toLowerCase()] || 'medium';
|
||||
};
|
||||
|
||||
// Map status from different sources
|
||||
const mapStatus = (status: string): AlertStatus => {
|
||||
const statusMap: Record<string, AlertStatus> = {
|
||||
'active': 'active',
|
||||
'new': 'active',
|
||||
'open': 'active',
|
||||
'acknowledged': 'acknowledged',
|
||||
'ack': 'acknowledged',
|
||||
'resolved': 'resolved',
|
||||
'closed': 'resolved',
|
||||
'dismissed': 'dismissed',
|
||||
'ignored': 'dismissed',
|
||||
};
|
||||
|
||||
return statusMap[status?.toLowerCase()] || 'active';
|
||||
};
|
||||
|
||||
// Acknowledge alert
|
||||
const acknowledgeAlert = useCallback(async (id: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const alert = state.alerts.find(a => a.id === id);
|
||||
if (!alert) return false;
|
||||
|
||||
// Call appropriate service based on source
|
||||
let success = false;
|
||||
if (alert.source === 'inventory') {
|
||||
const response = await inventoryService.markAlertAsRead(id);
|
||||
success = response.success;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
alerts: prev.alerts.map(a =>
|
||||
a.id === id
|
||||
? { ...a, status: 'acknowledged', acknowledgedAt: new Date() }
|
||||
: a
|
||||
),
|
||||
unreadCount: Math.max(0, prev.unreadCount - 1),
|
||||
}));
|
||||
}
|
||||
|
||||
return success;
|
||||
} catch (error) {
|
||||
setState(prev => ({ ...prev, error: 'Error al confirmar alerta' }));
|
||||
return false;
|
||||
}
|
||||
}, [state.alerts, inventoryService]);
|
||||
|
||||
// Resolve alert
|
||||
const resolveAlert = useCallback(async (id: string, resolution?: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const alert = state.alerts.find(a => a.id === id);
|
||||
if (!alert) return false;
|
||||
|
||||
// Call appropriate service based on source
|
||||
let success = false;
|
||||
if (alert.source === 'inventory') {
|
||||
const response = await inventoryService.dismissAlert(id);
|
||||
success = response.success;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
alerts: prev.alerts.map(a =>
|
||||
a.id === id
|
||||
? { ...a, status: 'resolved', resolvedAt: new Date(), metadata: { ...a.metadata, resolution } }
|
||||
: a
|
||||
),
|
||||
unreadCount: a.status === 'active' ? Math.max(0, prev.unreadCount - 1) : prev.unreadCount,
|
||||
criticalCount: a.priority === 'critical' && a.status === 'active' ? Math.max(0, prev.criticalCount - 1) : prev.criticalCount,
|
||||
}));
|
||||
}
|
||||
|
||||
return success;
|
||||
} catch (error) {
|
||||
setState(prev => ({ ...prev, error: 'Error al resolver alerta' }));
|
||||
return false;
|
||||
}
|
||||
}, [state.alerts, inventoryService]);
|
||||
|
||||
// Dismiss alert
|
||||
const dismissAlert = useCallback(async (id: string, reason?: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const alert = state.alerts.find(a => a.id === id);
|
||||
if (!alert) return false;
|
||||
|
||||
// Call appropriate service based on source
|
||||
let success = false;
|
||||
if (alert.source === 'inventory') {
|
||||
const response = await inventoryService.dismissAlert(id);
|
||||
success = response.success;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
alerts: prev.alerts.map(a =>
|
||||
a.id === id
|
||||
? { ...a, status: 'dismissed', dismissedAt: new Date(), metadata: { ...a.metadata, dismissReason: reason } }
|
||||
: a
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
return success;
|
||||
} catch (error) {
|
||||
setState(prev => ({ ...prev, error: 'Error al descartar alerta' }));
|
||||
return false;
|
||||
}
|
||||
}, [state.alerts, inventoryService]);
|
||||
|
||||
// Bulk acknowledge
|
||||
const bulkAcknowledge = useCallback(async (ids: string[]): Promise<boolean> => {
|
||||
const results = await Promise.all(ids.map(id => acknowledgeAlert(id)));
|
||||
return results.every(result => result);
|
||||
}, [acknowledgeAlert]);
|
||||
|
||||
// Bulk resolve
|
||||
const bulkResolve = useCallback(async (ids: string[], resolution?: string): Promise<boolean> => {
|
||||
const results = await Promise.all(ids.map(id => resolveAlert(id, resolution)));
|
||||
return results.every(result => result);
|
||||
}, [resolveAlert]);
|
||||
|
||||
// Bulk dismiss
|
||||
const bulkDismiss = useCallback(async (ids: string[], reason?: string): Promise<boolean> => {
|
||||
const results = await Promise.all(ids.map(id => dismissAlert(id, reason)));
|
||||
return results.every(result => result);
|
||||
}, [dismissAlert]);
|
||||
|
||||
// Create alert
|
||||
const createAlert = useCallback(async (alert: Omit<Alert, 'id' | 'createdAt' | 'status'>): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const newAlert: Alert = {
|
||||
...alert,
|
||||
id: generateAlertId(),
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
};
|
||||
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
alerts: [newAlert, ...prev.alerts],
|
||||
unreadCount: prev.unreadCount + 1,
|
||||
criticalCount: newAlert.priority === 'critical' ? prev.criticalCount + 1 : prev.criticalCount,
|
||||
}));
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
setState(prev => ({ ...prev, error: 'Error al crear alerta' }));
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Create custom alert
|
||||
const createCustomAlert = useCallback(async (
|
||||
title: string,
|
||||
message: string,
|
||||
priority: AlertPriority = 'medium',
|
||||
details?: Record<string, any>
|
||||
): Promise<boolean> => {
|
||||
return createAlert({
|
||||
type: 'custom',
|
||||
priority,
|
||||
title,
|
||||
message,
|
||||
details,
|
||||
source: 'user',
|
||||
});
|
||||
}, [createAlert]);
|
||||
|
||||
// Check inventory alerts
|
||||
const checkInventoryAlerts = useCallback(async () => {
|
||||
try {
|
||||
// Check for low stock
|
||||
const stockResponse = await inventoryService.getStockLevels();
|
||||
if (stockResponse.success && stockResponse.data) {
|
||||
const lowStockItems = stockResponse.data.filter((item: any) =>
|
||||
item.current_quantity <= item.reorder_point
|
||||
);
|
||||
|
||||
for (const item of lowStockItems) {
|
||||
await createAlert({
|
||||
type: 'inventory',
|
||||
priority: item.current_quantity === 0 ? 'critical' : 'high',
|
||||
title: 'Stock bajo',
|
||||
message: `Stock bajo para ${item.ingredient?.name}: ${item.current_quantity} ${item.unit}`,
|
||||
source: 'inventory',
|
||||
sourceId: item.id,
|
||||
details: { item },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check for expiring items
|
||||
const expirationResponse = await inventoryService.getExpirationReport();
|
||||
if (expirationResponse?.success && expirationResponse.data) {
|
||||
const expiringItems = expirationResponse.data.expiring_soon || [];
|
||||
|
||||
for (const item of expiringItems) {
|
||||
await createAlert({
|
||||
type: 'inventory',
|
||||
priority: 'medium',
|
||||
title: 'Producto próximo a expirar',
|
||||
message: `${item.name} expira el ${item.expiration_date}`,
|
||||
source: 'inventory',
|
||||
sourceId: item.id,
|
||||
details: { item },
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking inventory alerts:', error);
|
||||
}
|
||||
}, [inventoryService, createAlert]);
|
||||
|
||||
// Generate unique ID
|
||||
const generateAlertId = (): string => {
|
||||
return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
};
|
||||
|
||||
// Set filters
|
||||
const setFilters = useCallback((filters: Partial<AlertsState['filters']>) => {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
filters: { ...prev.filters, ...filters },
|
||||
}));
|
||||
}, []);
|
||||
|
||||
// Clear error
|
||||
const clearError = useCallback(() => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
}, []);
|
||||
|
||||
// Refresh alerts
|
||||
const refresh = useCallback(async () => {
|
||||
await fetchAlerts(state.filters);
|
||||
}, [fetchAlerts, state.filters]);
|
||||
|
||||
// Placeholder implementations for remaining functions
|
||||
const fetchAlertRules = useCallback(async () => {
|
||||
setState(prev => ({ ...prev, rules: [] }));
|
||||
}, []);
|
||||
|
||||
const createAlertRule = useCallback(async (rule: Omit<AlertRule, 'id'>): Promise<boolean> => {
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
const updateAlertRule = useCallback(async (id: string, rule: Partial<AlertRule>): Promise<boolean> => {
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
const deleteAlertRule = useCallback(async (id: string): Promise<boolean> => {
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
const testAlertRule = useCallback(async (rule: AlertRule): Promise<boolean> => {
|
||||
return true;
|
||||
}, []);
|
||||
|
||||
const checkProductionAlerts = useCallback(async () => {
|
||||
// Implementation for production alerts
|
||||
}, []);
|
||||
|
||||
const checkQualityAlerts = useCallback(async () => {
|
||||
// Implementation for quality alerts
|
||||
}, []);
|
||||
|
||||
const checkMaintenanceAlerts = useCallback(async () => {
|
||||
// Implementation for maintenance alerts
|
||||
}, []);
|
||||
|
||||
const checkSystemAlerts = useCallback(async () => {
|
||||
// Implementation for system alerts
|
||||
}, []);
|
||||
|
||||
const getAlertAnalytics = useCallback(async (period: string): Promise<any> => {
|
||||
return {};
|
||||
}, []);
|
||||
|
||||
const getAlertTrends = useCallback(async (days: number): Promise<any> => {
|
||||
return {};
|
||||
}, []);
|
||||
|
||||
const getMostFrequentAlerts = useCallback(async (period: string): Promise<any> => {
|
||||
return {};
|
||||
}, []);
|
||||
|
||||
const searchAlerts = useCallback(async (query: string): Promise<Alert[]> => {
|
||||
return state.alerts.filter(alert =>
|
||||
alert.title.toLowerCase().includes(query.toLowerCase()) ||
|
||||
alert.message.toLowerCase().includes(query.toLowerCase())
|
||||
);
|
||||
}, [state.alerts]);
|
||||
|
||||
const subscribeToAlerts = useCallback((callback: (alert: Alert) => void): (() => void) => {
|
||||
// Implementation would set up real-time subscription
|
||||
return () => {
|
||||
// Cleanup subscription
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Initialize alerts on mount
|
||||
useEffect(() => {
|
||||
fetchAlerts();
|
||||
}, []);
|
||||
|
||||
// Set up periodic checks
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
checkInventoryAlerts();
|
||||
}, 5 * 60 * 1000); // Check every 5 minutes
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [checkInventoryAlerts]);
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchAlerts,
|
||||
acknowledgeAlert,
|
||||
resolveAlert,
|
||||
dismissAlert,
|
||||
bulkAcknowledge,
|
||||
bulkResolve,
|
||||
bulkDismiss,
|
||||
createAlert,
|
||||
createCustomAlert,
|
||||
fetchAlertRules,
|
||||
createAlertRule,
|
||||
updateAlertRule,
|
||||
deleteAlertRule,
|
||||
testAlertRule,
|
||||
checkInventoryAlerts,
|
||||
checkProductionAlerts,
|
||||
checkQualityAlerts,
|
||||
checkMaintenanceAlerts,
|
||||
checkSystemAlerts,
|
||||
getAlertAnalytics,
|
||||
getAlertTrends,
|
||||
getMostFrequentAlerts,
|
||||
setFilters,
|
||||
searchAlerts,
|
||||
subscribeToAlerts,
|
||||
clearError,
|
||||
refresh,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user