22
33import type { ColumnDef } from "@tanstack/react-table" ;
44import { format } from "date-fns" ;
5- import { PlayIcon , TrashIcon } from "lucide-react" ;
5+ import { AlertTriangleIcon , TrashIcon } from "lucide-react" ;
6+ import Link from "next/link" ;
67import { useMemo , useState } from "react" ;
78import { toast } from "sonner" ;
8- import type { ThirdwebClient } from "thirdweb" ;
99import {
1010 deleteWebhook ,
1111 type WebhookFilters ,
1212 type WebhookResponse ,
1313} from "@/api/insight/webhooks" ;
14+ import type { Project } from "@/api/projects" ;
1415import { TWTable } from "@/components/blocks/TWTable" ;
1516import { Badge } from "@/components/ui/badge" ;
1617import { Button } from "@/components/ui/button" ;
1718import { CopyTextButton } from "@/components/ui/CopyTextButton" ;
1819import { Spinner } from "@/components/ui/Spinner/Spinner" ;
1920import { useDashboardRouter } from "@/lib/DashboardRouter" ;
20- import { useTestWebhook } from "../hooks/useTestWebhook" ;
21- import { CreateContractWebhookButton } from "./CreateWebhookModal" ;
2221import { RelativeTime } from "./RelativeTime" ;
2322
2423function getEventType ( filters : WebhookFilters ) : string {
@@ -32,27 +31,24 @@ function getEventType(filters: WebhookFilters): string {
3231
3332interface WebhooksTableProps {
3433 webhooks : WebhookResponse [ ] ;
35- projectClientId : string ;
36- supportedChainIds : number [ ] ;
37- client : ThirdwebClient ;
34+ project : Project ;
3835}
3936
4037export function ContractsWebhooksTable ( {
4138 webhooks,
42- projectClientId,
43- client,
44- supportedChainIds,
39+ project,
4540} : WebhooksTableProps ) {
4641 const [ isDeleting , setIsDeleting ] = useState < Record < string , boolean > > ( { } ) ;
47- const { testWebhookEndpoint, isTestingMap } = useTestWebhook ( projectClientId ) ;
4842 const router = useDashboardRouter ( ) ;
4943
50- const handleDeleteWebhook = async ( webhookId : string ) => {
44+ const webhooksPath = `/team/${ project . teamId } /${ project . slug } /webhooks` ;
45+
46+ const _handleDeleteWebhook = async ( webhookId : string ) => {
5147 if ( isDeleting [ webhookId ] ) return ;
5248
5349 try {
5450 setIsDeleting ( ( prev ) => ( { ...prev , [ webhookId ] : true } ) ) ;
55- await deleteWebhook ( webhookId , projectClientId ) ;
51+ await deleteWebhook ( webhookId , project . publishableKey ) ;
5652 toast . success ( "Webhook deleted successfully" ) ;
5753 router . refresh ( ) ;
5854 } catch ( error ) {
@@ -68,41 +64,31 @@ export function ContractsWebhooksTable({
6864 }
6965 } ;
7066
71- const handleTestWebhook = async ( webhook : WebhookResponse ) => {
72- const filterType = getEventType ( webhook . filters ) ;
73- if ( filterType === "Unknown" ) {
74- toast . error ( "Cannot test webhook" , {
75- description :
76- "This webhook does not have a valid event type (event or transaction)." ,
77- } ) ;
78- return ;
79- }
80- await testWebhookEndpoint (
81- webhook . webhook_url ,
82- filterType . toLowerCase ( ) as "event" | "transaction" ,
83- webhook . id ,
84- ) ;
85- } ;
86-
8767 const columns : ColumnDef < WebhookResponse > [ ] = [
8868 {
8969 accessorKey : "name" ,
90- cell : ( { row } ) => (
91- < div className = "flex items-center gap-2" >
92- < span className = "max-w-40 truncate" title = { row . original . name } >
93- { row . original . name }
94- </ span >
95- </ div >
96- ) ,
70+ cell : ( { row } ) => {
71+ const webhook = row . original ;
72+ return (
73+ < div className = "flex items-center gap-2" >
74+ < span
75+ className = "max-w-40 truncate text-muted-foreground"
76+ title = { webhook . name }
77+ >
78+ { webhook . name }
79+ </ span >
80+ </ div >
81+ ) ;
82+ } ,
9783 header : "Name" ,
9884 } ,
9985 {
10086 accessorKey : "filters" ,
10187 cell : ( { getValue } ) => {
10288 const filters = getValue ( ) as WebhookFilters ;
103- if ( ! filters ) return < span > -</ span > ;
89+ if ( ! filters ) return < span className = "text-muted-foreground" > -</ span > ;
10490 const eventType = getEventType ( filters ) ;
105- return < span > { eventType } </ span > ;
91+ return < span className = "text-muted-foreground" > { eventType } </ span > ;
10692 } ,
10793 header : "Event Type" ,
10894 } ,
@@ -112,7 +98,9 @@ export function ContractsWebhooksTable({
11298 const url = getValue ( ) as string ;
11399 return (
114100 < div className = "flex items-center gap-2" >
115- < span className = "max-w-60 truncate" > { url } </ span >
101+ < span className = "max-w-60 truncate text-muted-foreground" >
102+ { url }
103+ </ span >
116104 < CopyTextButton
117105 className = "flex h-6 w-6 items-center justify-center"
118106 copyIconPosition = "right"
@@ -138,7 +126,7 @@ export function ContractsWebhooksTable({
138126 return (
139127 < div className = "flex flex-col" >
140128 < RelativeTime date = { date } />
141- < span className = "text-muted-foreground text-xs" >
129+ < span className = "text-muted-foreground text-xs opacity-50 " >
142130 { formattedDate }
143131 </ span >
144132 </ div >
@@ -148,12 +136,10 @@ export function ContractsWebhooksTable({
148136 } ,
149137 {
150138 accessorKey : "suspended_at" ,
151- cell : ( { row } ) => {
152- const webhook = row . original ;
153- const isSuspended = Boolean ( webhook . suspended_at ) ;
139+ cell : ( ) => {
154140 return (
155- < Badge variant = { isSuspended ? "destructive" : "default" } >
156- { isSuspended ? "Suspended" : "Active" }
141+ < Badge variant = "secondary" className = "bg-gray-100 text-gray-600" >
142+ Deprecated
157143 </ Badge >
158144 ) ;
159145 } ,
@@ -166,25 +152,11 @@ export function ContractsWebhooksTable({
166152
167153 return (
168154 < div className = "flex items-center justify-end gap-2" >
169- < Button
170- aria-label = { `Test webhook ${ webhook . name } ` }
171- className = "h-8 w-8"
172- disabled = { isTestingMap [ webhook . id ] || isDeleting [ webhook . id ] }
173- onClick = { ( ) => handleTestWebhook ( webhook ) }
174- size = "icon"
175- variant = "outline"
176- >
177- { isTestingMap [ webhook . id ] ? (
178- < Spinner className = "h-4 w-4" />
179- ) : (
180- < PlayIcon className = "h-4 w-4" />
181- ) }
182- </ Button >
183155 < Button
184156 aria-label = { `Delete webhook ${ webhook . name } ` }
185157 className = "h-8 w-8 text-red-500 hover:border-red-700 hover:text-red-700"
186158 disabled = { isDeleting [ webhook . id ] }
187- onClick = { ( ) => handleDeleteWebhook ( webhook . id ) }
159+ onClick = { ( ) => _handleDeleteWebhook ( webhook . id ) }
188160 size = "icon"
189161 variant = "outline"
190162 >
@@ -217,20 +189,36 @@ export function ContractsWebhooksTable({
217189
218190 return (
219191 < div className = "w-full" >
192+ { /* Deprecation Notice */ }
193+ < div className = "mb-4 rounded-lg border border-amber-200 bg-amber-50 p-4" >
194+ < div className = "flex items-start gap-3" >
195+ < AlertTriangleIcon className = "h-5 w-5 text-amber-600 mt-0.5" />
196+ < div className = "flex-1" >
197+ < h3 className = "text-sm font-medium text-amber-800" >
198+ Legacy Webhooks (Deprecated)
199+ </ h3 >
200+ < p className = "mt-1 text-sm text-amber-700" >
201+ Contract webhooks are deprecated, but will continue to work for
202+ the time being. New unified webhooks are available in the{ " " }
203+ < Link
204+ className = "inline-flex items-center rounded-md bg-blue-50 px-2.5 py-0.5 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10 hover:bg-blue-100 transition-colors"
205+ href = { webhooksPath }
206+ >
207+ Webhooks
208+ </ Link > { " " }
209+ section.
210+ </ p >
211+ </ div >
212+ </ div >
213+ </ div >
214+
220215 < TWTable
221216 columns = { columns }
222217 data = { sortedWebhooks }
223218 isFetched = { true }
224219 isPending = { false }
225- title = "Webhooks"
220+ title = "Legacy Webhooks"
226221 />
227- < div className = "mt-4 flex justify-end" >
228- < CreateContractWebhookButton
229- client = { client }
230- projectClientId = { projectClientId }
231- supportedChainIds = { supportedChainIds }
232- />
233- </ div >
234222 </ div >
235223 ) ;
236224}
0 commit comments