NotificationDetail.tsx114 lines · main
1import { Archive, ArchiveRestoreIcon, ExternalLink } from 'lucide-react'
2import Link from 'next/link'
3import { Button } from 'ui'
4
5import { Markdown } from '@/components/interfaces/Markdown'
6import { Notification, NotificationData } from '@/data/notifications/notifications-v2-query'
7import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
8import { useProjectDetailQuery } from '@/data/projects/project-detail-query'
9
10interface NotificationDetailProps {
11 notification: Notification
12 onUpdateStatus: (id: string, status: 'archived' | 'seen') => void
13}
14
15export const NotificationDetail = ({ notification, onUpdateStatus }: NotificationDetailProps) => {
16 const data = notification.data as NotificationData
17
18 const { data: project } = useProjectDetailQuery({ ref: data.project_ref })
19 const { data: organizations } = useOrganizationsQuery()
20
21 const organization =
22 data.org_slug !== undefined
23 ? organizations?.find((org) => org.slug === data.org_slug)
24 : project !== undefined
25 ? organizations?.find((org) => org.id === project.organization_id)
26 : undefined
27
28 const onButtonAction = (type?: string) => {
29 // [Joshen] Implement accordingly - BE team will need to give us a heads up on this
30 console.log('Action', type)
31 }
32
33 return (
34 <div>
35 {(project !== undefined || organization !== undefined) && (
36 <>
37 <h3 className="text-sm mb-2">Context</h3>
38 <div className="flex items-center gap-2 flex-wrap mb-6">
39 {organization !== undefined && (
40 <Link
41 title={organization.name}
42 href={`/org/${organization.slug}/general`}
43 className="text-link"
44 >
45 {organization.name}
46 </Link>
47 )}
48 {project !== undefined && (
49 <Link title={project.name} href={`/project/${project.ref}`} className="text-link">
50 {project.name}
51 </Link>
52 )}
53 </div>
54 </>
55 )}
56
57 {data.message !== undefined && (
58 <>
59 <h3 className="text-sm mb-2">Message</h3>
60 <Markdown
61 className="leading-6 text-sm text-foreground-light mb-6"
62 content={data.message}
63 />
64 </>
65 )}
66
67 <h3 className="text-sm mb-2">Actions</h3>
68 <div className="flex items-center gap-2">
69 {(data.actions ?? []).map((action, idx) => {
70 const key = `${notification.id}-action-${idx}`
71 if (action.url !== undefined) {
72 const url = action.url.includes('[ref]')
73 ? action.url.replace('[ref]', project?.ref ?? '_')
74 : action.url.includes('[slug]')
75 ? action.url.replace('[slug]', organization?.slug ?? '_')
76 : action.url
77 return (
78 <Button key={key} type="default" icon={<ExternalLink strokeWidth={1.5} />} asChild>
79 <Link href={url} target="_blank" rel="noreferrer">
80 {action.label}
81 </Link>
82 </Button>
83 )
84 } else if (action.action_type !== undefined) {
85 return (
86 <Button key={key} type="default" onClick={() => onButtonAction(action.action_type)}>
87 {action.label}
88 </Button>
89 )
90 } else {
91 return null
92 }
93 })}
94 {notification.status === 'archived' ? (
95 <Button
96 type="default"
97 icon={<ArchiveRestoreIcon size={14} strokeWidth={1.5} />}
98 onClick={() => onUpdateStatus(notification.id, 'seen')}
99 >
100 Unarchive
101 </Button>
102 ) : (
103 <Button
104 type="default"
105 icon={<Archive size={14} strokeWidth={1.5} />}
106 onClick={() => onUpdateStatus(notification.id, 'archived')}
107 >
108 Archive
109 </Button>
110 )}
111 </div>
112 </div>
113 )
114}