UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 16.5 kB
{"version":3,"sources":["../src/store/notificationStore.ts"],"sourcesContent":["import { create } from 'zustand';\nimport { devtools } from 'zustand/middleware';\nimport {\n Notification,\n NotificationGroup,\n FetchNotificationsParams,\n BackendNotificationsResponse,\n BackendNotification,\n NotificationEntityType,\n NotificationType,\n NotificationApiClient,\n} from '../types/notifications';\n\n/**\n * Notification store state interface\n */\nexport interface NotificationState {\n /**\n * List of all notifications\n */\n notifications: Notification[];\n /**\n * Number of unread notifications\n */\n unreadCount: number;\n /**\n * Loading state\n */\n loading: boolean;\n /**\n * Error state\n */\n error: string | null;\n /**\n * Whether there are more notifications to load\n */\n hasMore: boolean;\n /**\n * Current page for pagination\n */\n currentPage: number;\n}\n\n/**\n * Notification store actions interface\n */\nexport interface NotificationActions {\n /**\n * Fetch notifications from API\n */\n fetchNotifications: (params?: FetchNotificationsParams) => Promise<void>;\n /**\n * Fetch unread notification count without loading the full list\n */\n fetchUnreadCount: () => Promise<void>;\n /**\n * Mark a specific notification as read\n */\n markAsRead: (id: string) => Promise<void>;\n /**\n * Mark all notifications as read\n */\n markAllAsRead: () => Promise<void>;\n /**\n * Delete a notification\n */\n deleteNotification: (id: string) => Promise<void>;\n /**\n * Clear all notifications\n */\n clearNotifications: () => void;\n /**\n * Reset error state\n */\n resetError: () => void;\n /**\n * Group notifications by time periods\n */\n getGroupedNotifications: () => NotificationGroup[];\n}\n\nexport type NotificationStore = NotificationState & NotificationActions;\n\n/**\n * Convert backend notification to frontend format\n */\nconst mapBackendNotification = (\n backendNotification: BackendNotification\n): Notification => {\n let type: NotificationType = 'GENERAL';\n let entityType: NotificationEntityType | null = null;\n\n if (backendNotification.entityType) {\n switch (backendNotification.entityType.toUpperCase()) {\n case NotificationEntityType.ACTIVITY:\n type = 'ACTIVITY';\n entityType = NotificationEntityType.ACTIVITY;\n break;\n case NotificationEntityType.TRAIL:\n type = 'TRAIL';\n entityType = NotificationEntityType.TRAIL;\n break;\n case NotificationEntityType.RECOMMENDEDCLASS:\n type = 'RECOMMENDEDCLASS';\n entityType = NotificationEntityType.RECOMMENDEDCLASS;\n break;\n default:\n break;\n }\n }\n\n return {\n id: backendNotification.id,\n title: backendNotification.title,\n message: backendNotification.description,\n type,\n isRead: backendNotification.read,\n createdAt: new Date(backendNotification.createdAt),\n entityType,\n entityId: backendNotification.entityId,\n sender: backendNotification.sender,\n activity: backendNotification.activity,\n recommendedClass: backendNotification.recommendedClass,\n actionLink: backendNotification.actionLink ?? null,\n linkImg: backendNotification.linkImg ?? null,\n };\n};\n\n/**\n * Group notifications by time periods\n */\nconst groupNotificationsByTime = (\n notifications: Notification[]\n): NotificationGroup[] => {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const lastWeek = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);\n const sortDesc = (a: Notification, b: Notification) =>\n +new Date(b.createdAt) - +new Date(a.createdAt);\n\n const todayNotifications = notifications\n .filter((notification) => new Date(notification.createdAt) >= today)\n .sort(sortDesc);\n\n const lastWeekNotifications = notifications\n .filter(\n (notification) =>\n new Date(notification.createdAt) >= lastWeek &&\n new Date(notification.createdAt) < today\n )\n .sort(sortDesc);\n\n const olderNotifications = notifications\n .filter((notification) => new Date(notification.createdAt) < lastWeek)\n .sort(sortDesc);\n\n const groups: NotificationGroup[] = [];\n\n if (todayNotifications.length > 0) {\n groups.push({\n label: 'Hoje',\n notifications: todayNotifications,\n });\n }\n\n if (lastWeekNotifications.length > 0) {\n groups.push({\n label: 'Última semana',\n notifications: lastWeekNotifications,\n });\n }\n\n if (olderNotifications.length > 0) {\n groups.push({\n label: 'Mais antigas',\n notifications: olderNotifications,\n });\n }\n\n return groups;\n};\n\n/**\n * Format time relative to now\n */\nexport const formatTimeAgo = (date: Date): string => {\n const now = new Date();\n const diffInMs = now.getTime() - new Date(date).getTime();\n const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60));\n const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));\n\n if (diffInHours < 24) {\n return `Há ${diffInHours}h`;\n } else if (diffInDays < 30) {\n const day = new Date(date).getDate();\n const months = [\n 'Jan',\n 'Fev',\n 'Mar',\n 'Abr',\n 'Mai',\n 'Jun',\n 'Jul',\n 'Ago',\n 'Set',\n 'Out',\n 'Nov',\n 'Dez',\n ];\n const month = months[new Date(date).getMonth()];\n return `${day} ${month}`;\n }\n\n return new Date(date).toLocaleDateString('pt-BR');\n};\n\n/**\n * Create notification store with injected API client\n */\nexport const createNotificationStore = (apiClient: NotificationApiClient) => {\n return create<NotificationStore>()(\n devtools(\n (set, get) => ({\n // Initial state\n notifications: [],\n unreadCount: 0,\n loading: false,\n error: null,\n hasMore: true,\n currentPage: 1,\n\n // Actions\n fetchNotifications: async (params: FetchNotificationsParams = {}) => {\n set({ loading: true, error: null });\n\n try {\n const response = await apiClient.get<BackendNotificationsResponse>(\n '/notifications',\n { params: { ...params } }\n );\n\n const mappedNotifications = response.data.notifications.map(\n mapBackendNotification\n );\n\n const page = response.data.pagination.page;\n const totalPages = response.data.pagination.totalPages;\n const merged =\n params.page && params.page > 1\n ? [...get().notifications, ...mappedNotifications]\n : mappedNotifications;\n // de-dup by id\n const deduped = Array.from(\n new Map(merged.map((n) => [n.id, n])).values()\n );\n\n const localUnread = deduped.filter((n) => !n.isRead).length;\n set({\n notifications: deduped,\n unreadCount: Math.max(localUnread, get().unreadCount),\n hasMore: page < totalPages,\n currentPage: page,\n loading: false,\n });\n } catch (error) {\n console.error('Error fetching notifications:', error);\n set({\n error: 'Erro ao carregar notificações',\n loading: false,\n });\n }\n },\n\n fetchUnreadCount: async () => {\n try {\n const response = await apiClient.get<BackendNotificationsResponse>(\n '/notifications',\n { params: { read: false, limit: 1, page: 1 } }\n );\n set({ unreadCount: response.data.pagination.total });\n } catch {\n // fail silently — badge keeps its last known value\n }\n },\n\n markAsRead: async (id: string) => {\n const { notifications } = get();\n\n // Find the notification to check if it's already read\n const notification = notifications.find((n) => n.id === id);\n\n // If notification is already read, just return without making API call\n if (notification?.isRead) {\n return;\n }\n\n try {\n await apiClient.patch(`/notifications/${id}`, { read: true });\n\n const updatedNotifications = notifications.map((notification) =>\n notification.id === id\n ? { ...notification, isRead: true }\n : notification\n );\n\n const unreadCount = updatedNotifications.filter(\n (n) => !n.isRead\n ).length;\n\n set({\n notifications: updatedNotifications,\n unreadCount,\n });\n } catch (error) {\n console.error('Error marking notification as read:', error);\n set({ error: 'Erro ao marcar notificação como lida' });\n }\n },\n\n markAllAsRead: async () => {\n const { notifications } = get();\n\n try {\n // Mark all unread notifications as read\n const unreadNotifications = notifications.filter((n) => !n.isRead);\n\n await Promise.all(\n unreadNotifications.map((notification) =>\n apiClient.patch(`/notifications/${notification.id}`, {\n read: true,\n })\n )\n );\n\n const updatedNotifications = notifications.map((notification) => ({\n ...notification,\n isRead: true,\n }));\n\n set({\n notifications: updatedNotifications,\n unreadCount: 0,\n });\n } catch (error) {\n console.error('Error marking all notifications as read:', error);\n set({ error: 'Erro ao marcar todas as notificações como lidas' });\n }\n },\n\n deleteNotification: async (id: string) => {\n const { notifications } = get();\n\n try {\n await apiClient.delete(`/notifications/${id}`);\n\n const updatedNotifications = notifications.filter(\n (notification) => notification.id !== id\n );\n\n const unreadCount = updatedNotifications.filter(\n (n) => !n.isRead\n ).length;\n\n set({\n notifications: updatedNotifications,\n unreadCount,\n });\n } catch (error) {\n console.error('Error deleting notification:', error);\n set({ error: 'Erro ao deletar notificação' });\n }\n },\n\n clearNotifications: () => {\n set({\n notifications: [],\n unreadCount: 0,\n hasMore: false,\n currentPage: 1,\n });\n },\n\n resetError: () => {\n set({ error: null });\n },\n\n getGroupedNotifications: () => {\n const { notifications } = get();\n return groupNotificationsByTime(notifications);\n },\n }),\n {\n name: 'notification-store',\n }\n )\n );\n};\n"],"mappings":"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","names":["notification"]}