Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
301
composables/useNotificationLogs.js
Normal file
301
composables/useNotificationLogs.js
Normal file
@@ -0,0 +1,301 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useNotificationLogs = () => {
|
||||
// Use Nuxt's useFetch instead of $fetch
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// Logs data state
|
||||
const logs = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
pages: 1
|
||||
})
|
||||
const summaryStats = ref({
|
||||
totalLogs: 0,
|
||||
failedDeliveries: 0,
|
||||
successfulDeliveries: 0,
|
||||
successRate: 0
|
||||
})
|
||||
|
||||
// Filters state
|
||||
const filters = ref({
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
action: null,
|
||||
channel: null,
|
||||
status: null,
|
||||
actor: '',
|
||||
keyword: ''
|
||||
})
|
||||
|
||||
// Analytics state
|
||||
const analyticsData = ref(null)
|
||||
const analyticsLoading = ref(false)
|
||||
const analyticsError = ref(null)
|
||||
|
||||
// Monitoring state
|
||||
const monitoringData = ref(null)
|
||||
const monitoringLoading = ref(false)
|
||||
const monitoringError = ref(null)
|
||||
|
||||
// Fetch logs with filters and pagination
|
||||
const fetchLogs = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
// Build query parameters
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('page', pagination.value.page)
|
||||
queryParams.append('limit', pagination.value.limit)
|
||||
|
||||
// Add filters if they exist
|
||||
if (filters.value.startDate) queryParams.append('startDate', filters.value.startDate)
|
||||
if (filters.value.endDate) queryParams.append('endDate', filters.value.endDate)
|
||||
if (filters.value.action) queryParams.append('action', filters.value.action)
|
||||
if (filters.value.channel) queryParams.append('channel', filters.value.channel)
|
||||
if (filters.value.status) queryParams.append('status', filters.value.status)
|
||||
if (filters.value.actor) queryParams.append('actor', filters.value.actor)
|
||||
if (filters.value.keyword) queryParams.append('keyword', filters.value.keyword)
|
||||
|
||||
// Make API call with useFetch
|
||||
const { data, error: fetchError } = await useFetch(`/api/notifications/logs`, {
|
||||
method: 'GET',
|
||||
params: {
|
||||
page: pagination.value.page,
|
||||
limit: pagination.value.limit,
|
||||
...filters.value
|
||||
}
|
||||
})
|
||||
|
||||
if (fetchError.value) {
|
||||
throw new Error(fetchError.value.message || 'Failed to fetch logs');
|
||||
}
|
||||
|
||||
if (data.value && data.value.body && data.value.body.success) {
|
||||
logs.value = data.value.body.data.logs || [];
|
||||
pagination.value = data.value.body.data.pagination || pagination.value;
|
||||
|
||||
// Ensure summary stats are properly assigned
|
||||
if (data.value.body.data.summary) {
|
||||
summaryStats.value = {
|
||||
totalLogs: data.value.body.data.summary.totalLogs || 0,
|
||||
failedDeliveries: data.value.body.data.summary.failedDeliveries || 0,
|
||||
successfulDeliveries: data.value.body.data.summary.successfulDeliveries || 0,
|
||||
successRate: data.value.body.data.summary.successRate || 0
|
||||
};
|
||||
}
|
||||
|
||||
console.log('Logs fetched successfully:', {
|
||||
logsCount: logs.value.length,
|
||||
pagination: pagination.value,
|
||||
summaryStats: summaryStats.value
|
||||
});
|
||||
} else {
|
||||
throw new Error('Failed to fetch logs: ' + (data.value?.body?.message || 'Unknown error'))
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message || 'An error occurred'
|
||||
console.error('Error fetching logs:', err)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Get a specific log by ID
|
||||
const getLogById = async (id) => {
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
// Make API call
|
||||
const { data } = await useFetch(`/api/notifications/logs/${id}`, {
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
if (data.value && data.value.body && data.value.body.success) {
|
||||
return data.value.body.data
|
||||
} else {
|
||||
throw new Error('Failed to fetch log details')
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message || 'An error occurred'
|
||||
console.error('Error fetching log details:', err)
|
||||
return null
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Update filters and fetch logs
|
||||
const applyFilters = async (newFilters) => {
|
||||
filters.value = { ...filters.value, ...newFilters }
|
||||
pagination.value.page = 1 // Reset to first page when filters change
|
||||
await fetchLogs()
|
||||
}
|
||||
|
||||
// Clear all filters
|
||||
const clearFilters = async () => {
|
||||
filters.value = {
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
action: null,
|
||||
channel: null,
|
||||
status: null,
|
||||
actor: '',
|
||||
keyword: ''
|
||||
}
|
||||
pagination.value.page = 1
|
||||
await fetchLogs()
|
||||
}
|
||||
|
||||
// Change page
|
||||
const changePage = async (page) => {
|
||||
pagination.value.page = page
|
||||
await fetchLogs()
|
||||
}
|
||||
|
||||
// Fetch analytics data
|
||||
const fetchAnalytics = async (period = '7d', channel = 'all') => {
|
||||
try {
|
||||
analyticsLoading.value = true
|
||||
analyticsError.value = null
|
||||
|
||||
// Make API call
|
||||
const { data } = await useFetch(`/api/notifications/logs/analytics`, {
|
||||
method: 'GET',
|
||||
params: {
|
||||
period,
|
||||
channel
|
||||
}
|
||||
})
|
||||
|
||||
if (data.value && data.value.body && data.value.body.success) {
|
||||
analyticsData.value = data.value.body.data
|
||||
} else {
|
||||
throw new Error('Failed to fetch analytics data')
|
||||
}
|
||||
} catch (err) {
|
||||
analyticsError.value = err.message || 'An error occurred'
|
||||
console.error('Error fetching analytics data:', err)
|
||||
} finally {
|
||||
analyticsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch monitoring data
|
||||
const fetchMonitoringData = async () => {
|
||||
try {
|
||||
monitoringLoading.value = true
|
||||
monitoringError.value = null
|
||||
|
||||
// Make API call
|
||||
const { data } = await useFetch('/api/notifications/logs/monitoring', {
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
if (data.value && data.value.body && data.value.body.success) {
|
||||
monitoringData.value = data.value.body.data
|
||||
} else {
|
||||
throw new Error('Failed to fetch monitoring data')
|
||||
}
|
||||
} catch (err) {
|
||||
monitoringError.value = err.message || 'An error occurred'
|
||||
console.error('Error fetching monitoring data:', err)
|
||||
} finally {
|
||||
monitoringLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Format date for display
|
||||
const formatDate = (date, includeTime = false) => {
|
||||
if (!date) return ''
|
||||
const options = { year: 'numeric', month: 'short', day: 'numeric' }
|
||||
if (includeTime) {
|
||||
options.hour = '2-digit'
|
||||
options.minute = '2-digit'
|
||||
}
|
||||
return new Date(date).toLocaleDateString(undefined, options)
|
||||
}
|
||||
|
||||
// Format time ago (e.g., "2 minutes ago")
|
||||
const formatTimeAgo = (timestamp) => {
|
||||
const now = new Date()
|
||||
const time = new Date(timestamp)
|
||||
const diffInMinutes = Math.floor((now - time) / (1000 * 60))
|
||||
|
||||
if (diffInMinutes < 1) return "Just now"
|
||||
if (diffInMinutes < 60) return `${diffInMinutes} minutes ago`
|
||||
if (diffInMinutes < 1440) return `${Math.floor(diffInMinutes / 60)} hours ago`
|
||||
return `${Math.floor(diffInMinutes / 1440)} days ago`
|
||||
}
|
||||
|
||||
// Get available actions for filters
|
||||
const availableActions = [
|
||||
{ label: 'All Actions', value: null },
|
||||
{ label: 'Notification Created', value: 'Notification Created' },
|
||||
{ label: 'Notification Sent', value: 'Notification Sent' },
|
||||
{ label: 'Delivery Attempted', value: 'Delivery Attempted' },
|
||||
{ label: 'Delivery Failed', value: 'Delivery Failed' },
|
||||
{ label: 'Notification Opened', value: 'Notification Opened' },
|
||||
{ label: 'Template Updated', value: 'Template Updated' },
|
||||
{ label: 'Notification Queued', value: 'Notification Queued' },
|
||||
]
|
||||
|
||||
// Get available channels for filters
|
||||
const availableChannels = [
|
||||
{ label: 'All Channels', value: null },
|
||||
{ label: 'Email', value: 'Email' },
|
||||
{ label: 'SMS', value: 'SMS' },
|
||||
{ label: 'Push Notification', value: 'Push Notification' },
|
||||
{ label: 'Webhook', value: 'Webhook' }
|
||||
]
|
||||
|
||||
// Get available statuses for filters
|
||||
const availableStatuses = [
|
||||
{ label: 'All Statuses', value: null },
|
||||
{ label: 'Sent', value: 'Sent' },
|
||||
{ label: 'Failed', value: 'Failed' },
|
||||
{ label: 'Bounced', value: 'Bounced' },
|
||||
{ label: 'Opened', value: 'Opened' },
|
||||
{ label: 'Queued', value: 'Queued' },
|
||||
{ label: 'Created', value: 'Created' },
|
||||
{ label: 'Updated', value: 'Updated' }
|
||||
]
|
||||
|
||||
return {
|
||||
// State
|
||||
logs,
|
||||
loading,
|
||||
error,
|
||||
pagination,
|
||||
summaryStats,
|
||||
filters,
|
||||
analyticsData,
|
||||
analyticsLoading,
|
||||
analyticsError,
|
||||
monitoringData,
|
||||
monitoringLoading,
|
||||
monitoringError,
|
||||
|
||||
// Methods
|
||||
fetchLogs,
|
||||
getLogById,
|
||||
applyFilters,
|
||||
clearFilters,
|
||||
changePage,
|
||||
fetchAnalytics,
|
||||
fetchMonitoringData,
|
||||
formatDate,
|
||||
formatTimeAgo,
|
||||
|
||||
// Filter options
|
||||
availableActions,
|
||||
availableChannels,
|
||||
availableStatuses
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user