Skip to content

Commit 604c55a

Browse files
committed
Replace Select with Popover in webhook signature selection UI
1 parent 7c95211 commit 604c55a

File tree

1 file changed

+99
-84
lines changed
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components

1 file changed

+99
-84
lines changed

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx

Lines changed: 99 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ import {
1212
} from "@/components/ui/form";
1313
import { Input } from "@/components/ui/input";
1414
import {
15-
Select,
16-
SelectContent,
17-
SelectItem,
18-
SelectTrigger,
19-
SelectValue,
20-
} from "@/components/ui/select";
15+
Popover,
16+
PopoverContent,
17+
PopoverTrigger,
18+
} from "@/components/ui/popover";
2119
import { Textarea } from "@/components/ui/textarea";
2220
import { useThirdwebClient } from "@/constants/thirdweb.client";
21+
import { cn } from "@/lib/utils";
2322
import { useQueryClient } from "@tanstack/react-query";
23+
import { useState } from "react";
2424
import type { UseFormReturn } from "react-hook-form";
2525

2626
import { MultiNetworkSelector } from "@/components/blocks/NetworkSelectors";
@@ -74,6 +74,10 @@ export function FilterDetailsStep({
7474
: [];
7575
const contractAddresses = form.watch("addresses") || "";
7676

77+
// Popover open state hooks moved to top level
78+
const [eventPopoverOpen, setEventPopoverOpen] = useState(false);
79+
const [functionPopoverOpen, setFunctionPopoverOpen] = useState(false);
80+
7781
return (
7882
<>
7983
<div className="mb-4">
@@ -305,97 +309,108 @@ export function FilterDetailsStep({
305309
{watchFilterType === "event" &&
306310
Object.keys(fetchedAbis).length > 0 &&
307311
eventSignatures.length > 0 ? (
308-
<Select
309-
value={field.value}
310-
onValueChange={(value) => {
311-
field.onChange(value);
312-
// Find the selected event
313-
const selectedEvent = eventSignatures.find(
314-
(sig) => sig.signature === value,
315-
);
316-
// Set the ABI for the event
317-
form.setValue("sigHashAbi", selectedEvent?.abi || "");
318-
}}
312+
<Popover
313+
modal
314+
open={eventPopoverOpen}
315+
onOpenChange={setEventPopoverOpen}
319316
>
320-
<SelectTrigger>
321-
<SelectValue placeholder="Select an event signature">
317+
<PopoverTrigger asChild>
318+
<button
319+
type="button"
320+
className={cn(
321+
"h-10 w-full rounded-md border bg-background px-3 py-2 text-left text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
322+
!field.value && "text-muted-foreground",
323+
)}
324+
>
322325
{field.value
323326
? eventSignatures.find(
324327
(sig) => sig.signature === field.value,
325328
)?.name || ""
326-
: null}
327-
</SelectValue>
328-
</SelectTrigger>
329-
<SelectContent className="max-h-60 overflow-y-auto">
330-
{eventSignatures.map((event) => {
331-
// Truncate the hash for display purposes
332-
const truncatedHash = truncateMiddle(
333-
event.signature,
334-
6,
335-
4,
336-
);
337-
338-
return (
339-
<SelectItem
340-
key={event.signature}
341-
value={event.signature}
342-
title={event.name}
343-
>
344-
<div className="flex flex-col">
345-
<span className="font-medium">{event.name}</span>
346-
<span className="text-muted-foreground text-xs">
347-
Signature: {truncatedHash}
348-
</span>
349-
</div>
350-
</SelectItem>
351-
);
352-
})}
353-
</SelectContent>
354-
</Select>
329+
: "Select an event signature"}
330+
</button>
331+
</PopoverTrigger>
332+
<PopoverContent
333+
className="max-h-60 w-[--radix-popover-trigger-width] overflow-y-auto p-0"
334+
align="start"
335+
>
336+
<ul className="divide-y divide-border">
337+
{eventSignatures.map((event) => (
338+
<li key={event.signature}>
339+
<button
340+
type="button"
341+
className={cn(
342+
"w-full px-4 py-2 text-left text-sm hover:bg-accent focus:bg-accent",
343+
field.value === event.signature && "bg-accent",
344+
)}
345+
onClick={() => {
346+
field.onChange(event.signature);
347+
form.setValue("sigHashAbi", event.abi || "");
348+
setEventPopoverOpen(false);
349+
}}
350+
>
351+
<div className="font-medium">{event.name}</div>
352+
<div className="text-muted-foreground text-xs">
353+
Signature:{" "}
354+
{truncateMiddle(event.signature, 6, 4)}
355+
</div>
356+
</button>
357+
</li>
358+
))}
359+
</ul>
360+
</PopoverContent>
361+
</Popover>
355362
) : watchFilterType === "transaction" &&
356363
Object.keys(fetchedTxAbis).length > 0 &&
357364
functionSignatures.length > 0 ? (
358-
<Select
359-
value={field.value}
360-
onValueChange={(value) => {
361-
field.onChange(value);
362-
// Find the selected function
363-
const selectedFunction = functionSignatures.find(
364-
(sig) => sig.signature === value,
365-
);
366-
// Set the ABI for the function
367-
form.setValue("sigHashAbi", selectedFunction?.abi || "");
368-
}}
365+
<Popover
366+
modal
367+
open={functionPopoverOpen}
368+
onOpenChange={setFunctionPopoverOpen}
369369
>
370-
<SelectTrigger className="max-w-full">
371-
<SelectValue placeholder="Select a function signature">
370+
<PopoverTrigger asChild>
371+
<button
372+
type="button"
373+
className={cn(
374+
"h-10 w-full rounded-md border bg-background px-3 py-2 text-left text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
375+
!field.value && "text-muted-foreground",
376+
)}
377+
>
372378
{field.value
373379
? functionSignatures.find(
374380
(sig) => sig.signature === field.value,
375381
)?.name || ""
376-
: null}
377-
</SelectValue>
378-
</SelectTrigger>
379-
<SelectContent className="max-h-60 max-w-[600px] overflow-y-auto">
380-
{functionSignatures.map((func) => (
381-
<SelectItem
382-
key={func.signature}
383-
value={func.signature}
384-
title={func.signature}
385-
className="w-full overflow-x-auto"
386-
>
387-
<div className="flex w-full flex-col">
388-
<span className="overflow-x-auto whitespace-nowrap pb-1 font-medium">
389-
{func.name}
390-
</span>
391-
<span className="overflow-x-auto text-muted-foreground text-xs">
392-
Selector: {func.signature}
393-
</span>
394-
</div>
395-
</SelectItem>
396-
))}
397-
</SelectContent>
398-
</Select>
382+
: "Select a function signature"}
383+
</button>
384+
</PopoverTrigger>
385+
<PopoverContent
386+
className="max-h-60 w-[--radix-popover-trigger-width] overflow-y-auto p-0"
387+
align="start"
388+
>
389+
<ul className="divide-y divide-border">
390+
{functionSignatures.map((func) => (
391+
<li key={func.signature}>
392+
<button
393+
type="button"
394+
className={cn(
395+
"w-full px-4 py-2 text-left text-sm hover:bg-accent focus:bg-accent",
396+
field.value === func.signature && "bg-accent",
397+
)}
398+
onClick={() => {
399+
field.onChange(func.signature);
400+
form.setValue("sigHashAbi", func.abi || "");
401+
setFunctionPopoverOpen(false);
402+
}}
403+
>
404+
<div className="font-medium">{func.name}</div>
405+
<div className="text-muted-foreground text-xs">
406+
Selector: {func.signature}
407+
</div>
408+
</button>
409+
</li>
410+
))}
411+
</ul>
412+
</PopoverContent>
413+
</Popover>
399414
) : (
400415
<Input
401416
placeholder={

0 commit comments

Comments
 (0)