import dayjs from 'dayjs' import { Archive, ArchiveRestoreIcon, ExternalLink } from 'lucide-react' import Link from 'next/link' import { useEffect, useRef } from 'react' import { useInView } from 'react-intersection-observer' import { Button, cn } from 'ui' import { Markdown } from 'components/interfaces/Markdown' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import type { ItemRenderer } from 'components/ui/InfiniteList' import { Notification, NotificationData } from 'data/notifications/notifications-v2-query' import { useProjectDetailQuery } from 'data/projects/project-detail-query' import type { Organization } from 'types' import { CriticalIcon, WarningIcon } from 'ui' interface NotificationRowProps { setRowHeight: (idx: number, height: number) => void getOrganizationById: (id: number) => Organization getOrganizationBySlug: (slug: string) => Organization onUpdateNotificationStatus: (id: string, status: 'archived' | 'seen') => void queueMarkRead: (id: string) => void } const NotificationRow: ItemRenderer = ({ index, listRef, item: notification, setRowHeight, getOrganizationById, getOrganizationBySlug, onUpdateNotificationStatus, queueMarkRead, }) => { const ref = useRef(null) const { ref: viewRef, inView } = useInView() const { status, priority } = notification const data = notification.data as NotificationData const { data: project } = useProjectDetailQuery({ ref: data.project_ref }) const organization = data.org_slug !== undefined ? getOrganizationBySlug(data.org_slug) : project !== undefined ? getOrganizationById(project.organization_id) : undefined const daysFromNow = dayjs().diff(dayjs(notification.inserted_at), 'day') const formattedTimeFromNow = dayjs(notification.inserted_at).fromNow() const formattedInsertedAt = dayjs(notification.inserted_at).format('MMM DD, YYYY') const onButtonAction = (type?: string) => { // [Joshen] Implement accordingly - BE team will need to give us a heads up on this console.log('Action', type) } useEffect(() => { if (ref.current) { listRef?.current?.resetAfterIndex(0) setRowHeight(index, ref.current.clientHeight) } }, [ref]) useEffect(() => { if (inView && notification.status === 'new') { queueMarkRead(notification.id) } }, [inView]) return (
{(project !== undefined || organization !== undefined) && (
{organization !== undefined && ( {organization.name} )} {organization !== undefined && project !== undefined && ( )} {project !== undefined && ( {project.name} )}
)}

{data.title}{' '} {daysFromNow > 1 ? formattedInsertedAt : formattedTimeFromNow}

{data.message !== undefined && ( )} {(data.actions ?? []).length > 0 && (
{data.actions.map((action, idx) => { const key = `${notification.id}-action-${idx}` if (action.url !== undefined) { const url = action.url.includes('[ref]') ? action.url.replace('[ref]', project?.ref ?? '_') : action.url.includes('[slug]') ? action.url.replace('[slug]', organization?.slug ?? '_') : action.url return ( ) } else if (action.action_type !== undefined) { return ( ) } else { return null } })}
)}
{priority === 'Warning' && } {priority === 'Critical' && } {notification.status === 'archived' ? ( } className="p-1.5 group-hover:opacity-100 opacity-0 transition rounded-full" onClick={() => onUpdateNotificationStatus(notification.id, 'seen')} tooltip={{ content: { text: 'Unarchive', side: 'bottom' } }} /> ) : ( } className="p-1.5 group-hover:opacity-100 opacity-0 transition rounded-full" onClick={() => onUpdateNotificationStatus(notification.id, 'archived')} tooltip={{ content: { text: 'Archive', side: 'bottom' } }} /> )}
) } export default NotificationRow