{"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"]}