Skip to content

Commit 5234124

Browse files
committed
Replace Select with Popover in webhook signature selection UI (#7219)
## [Dashboard] Feature: Replace Select with Popover for Event and Function Signature Selection ## Notes for the reviewer This PR replaces the Select component with a Popover component for both event and function signature selection in the webhook filter details step. The change improves the user experience by providing a more customizable dropdown interface. Key changes: - Replaced Select/SelectContent/SelectItem with Popover/PopoverContent/PopoverTrigger - Added state hooks to manage popover open states - Improved styling and layout of signature selection options - Maintained existing functionality for selecting signatures and updating form values ## How to test Test the webhook creation flow, specifically when selecting event or function signatures. Verify that: 1. The popover opens and closes correctly 2. Selecting a signature properly updates the form 3. The selected signature displays correctly in the trigger button 4. The signature details (name, hash/selector) are properly displayed <!-- start pr-codex --> --- ## PR-Codex overview This PR refactors the `FilterDetailsStep` component to replace the `Select` dropdowns with a new `SignatureDropdown` component, enhancing the UI interaction by using a `Popover` for selecting event and function signatures. ### Detailed summary - Removed `Select` dropdowns for event and function signatures. - Introduced `SignatureDropdown` component for better UI/UX. - Integrated `Popover` for displaying signature options. - Updated state management for selected signatures and ABIs. - Added new props for `SignatureDropdown` to handle selection and display. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new dropdown for selecting event and function signatures, offering a clearer and more interactive selection experience. - **Style** - Updated the signature selection interface to use a popover-based dropdown for improved usability and consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent ac4ade6 commit 5234124

File tree

1 file changed

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

1 file changed

+94
-94
lines changed

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

Lines changed: 94 additions & 94 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";
@@ -48,6 +48,74 @@ interface FilterDetailsStepProps {
4848
supportedChainIds: Array<number>;
4949
}
5050

51+
interface SignatureDropdownProps {
52+
signatures: Array<{ name: string; signature: string; abi?: string }>;
53+
value: string;
54+
onChange: (val: string) => void;
55+
setAbi: (abi: string) => void;
56+
buttonLabel: string;
57+
secondaryTextFormatter: (sig: { name: string; signature: string }) => string;
58+
disabled?: boolean;
59+
}
60+
61+
function SignatureDropdown({
62+
signatures,
63+
value,
64+
onChange,
65+
setAbi,
66+
buttonLabel,
67+
secondaryTextFormatter,
68+
disabled,
69+
}: SignatureDropdownProps) {
70+
const [open, setOpen] = useState(false);
71+
return (
72+
<Popover modal open={open} onOpenChange={setOpen}>
73+
<PopoverTrigger asChild>
74+
<button
75+
type="button"
76+
className={cn(
77+
"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",
78+
!value && "text-muted-foreground",
79+
)}
80+
disabled={disabled}
81+
>
82+
{value
83+
? signatures.find((sig) => sig.signature === value)?.name || ""
84+
: buttonLabel}
85+
</button>
86+
</PopoverTrigger>
87+
<PopoverContent
88+
className="max-h-60 w-[--radix-popover-trigger-width] overflow-y-auto p-0"
89+
align="start"
90+
>
91+
<ul className="divide-y divide-border">
92+
{signatures.map((sig) => (
93+
<li key={sig.signature}>
94+
<button
95+
type="button"
96+
className={cn(
97+
"w-full px-4 py-2 text-left text-sm hover:bg-accent focus:bg-accent",
98+
value === sig.signature && "bg-accent",
99+
)}
100+
onClick={() => {
101+
onChange(sig.signature);
102+
setAbi(sig.abi || "");
103+
setOpen(false);
104+
}}
105+
>
106+
<div className="font-medium">{sig.name}</div>
107+
<div className="text-muted-foreground text-xs">
108+
{secondaryTextFormatter(sig)}
109+
</div>
110+
</button>
111+
</li>
112+
))}
113+
</ul>
114+
</PopoverContent>
115+
</Popover>
116+
);
117+
}
118+
51119
export function FilterDetailsStep({
52120
form,
53121
eventSignatures,
@@ -305,97 +373,29 @@ export function FilterDetailsStep({
305373
{watchFilterType === "event" &&
306374
Object.keys(fetchedAbis).length > 0 &&
307375
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-
}}
319-
>
320-
<SelectTrigger>
321-
<SelectValue placeholder="Select an event signature">
322-
{field.value
323-
? eventSignatures.find(
324-
(sig) => sig.signature === field.value,
325-
)?.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>
376+
<SignatureDropdown
377+
signatures={eventSignatures}
378+
value={field.value || ""}
379+
onChange={field.onChange}
380+
setAbi={(abi) => form.setValue("sigHashAbi", abi)}
381+
buttonLabel="Select an event signature"
382+
secondaryTextFormatter={(sig) =>
383+
`Signature: ${truncateMiddle(sig.signature, 6, 4)}`
384+
}
385+
/>
355386
) : watchFilterType === "transaction" &&
356387
Object.keys(fetchedTxAbis).length > 0 &&
357388
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-
}}
369-
>
370-
<SelectTrigger className="max-w-full">
371-
<SelectValue placeholder="Select a function signature">
372-
{field.value
373-
? functionSignatures.find(
374-
(sig) => sig.signature === field.value,
375-
)?.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>
389+
<SignatureDropdown
390+
signatures={functionSignatures}
391+
value={field.value || ""}
392+
onChange={field.onChange}
393+
setAbi={(abi) => form.setValue("sigHashAbi", abi)}
394+
buttonLabel="Select a function signature"
395+
secondaryTextFormatter={(sig) =>
396+
`Selector: ${sig.signature}`
397+
}
398+
/>
399399
) : (
400400
<Input
401401
placeholder={

0 commit comments

Comments
 (0)