Skip to content

Commit 4f6c364

Browse files
committed
[Dashboard] Add searchbar for Explorer (#4916)
Part of DASH-246 <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a search functionality to filter displayed functions in the `ContractFunctionsPanel`. It enhances user experience by allowing users to search for specific functions using a search input. ### Detailed summary - Added `SearchIcon` and `Input` components for search functionality. - Implemented state management for keyword search using `useState` and `useDebounce`. - Filtered functions based on the search input before rendering. - Updated the layout to include the search input at the top of the functions list. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 0e900fe commit 4f6c364

File tree

1 file changed

+63
-37
lines changed

1 file changed

+63
-37
lines changed

apps/dashboard/src/components/contract-functions/contract-function.tsx

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { Input } from "@/components/ui/input";
34
import { useDashboardRouter } from "@/lib/DashboardRouter";
45
import { cn } from "@/lib/utils";
56
import {
@@ -24,6 +25,7 @@ import {
2425
} from "@chakra-ui/react";
2526
import type { AbiEvent, AbiFunction } from "abitype";
2627
import { camelToTitle } from "contract-ui/components/solidity-inputs/helpers";
28+
import { SearchIcon } from "lucide-react";
2729
import { usePathname, useSearchParams } from "next/navigation";
2830
import { type Dispatch, type SetStateAction, useMemo, useState } from "react";
2931
import type { ThirdwebContract } from "thirdweb";
@@ -33,6 +35,7 @@ import * as ERC1155Ext from "thirdweb/extensions/erc1155";
3335
import { useReadContract } from "thirdweb/react";
3436
import { toFunctionSelector } from "thirdweb/utils";
3537
import { Badge, Button, Card, Heading, Text } from "tw-components";
38+
import { useDebounce } from "use-debounce";
3639
import { useContractFunctionSelectors } from "../../contract-ui/hooks/useContractFunctionSelectors";
3740
import {
3841
COMMANDS,
@@ -331,43 +334,53 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
331334
? 1
332335
: 0;
333336

334-
const functionSection = (e: ExtensionFunctions) => (
335-
<Flex key={e.extension} flexDir="column" mb={6}>
336-
{e.extension ? (
337-
<>
338-
<Flex alignItems="center" alignContent="center" gap={2}>
339-
<Image
340-
src="/assets/dashboard/extension-check.svg"
341-
alt="Extension detected"
342-
objectFit="contain"
343-
mb="2px"
344-
/>
345-
<Heading as="label" size="label.md">
346-
{e.extension}
347-
</Heading>
348-
</Flex>
349-
<Divider my={2} />
350-
</>
351-
) : (
352-
<>
353-
<Flex alignItems="center" alignContent="center" gap={2}>
354-
<Heading as="label" size="label.md">
355-
Other Functions
356-
</Heading>
357-
</Flex>
358-
<Divider my={2} />
359-
</>
360-
)}
361-
{e.functions.map((fn) => (
362-
<FunctionsOrEventsListItem
363-
key={`${fn.name}_${fn.type}_${fn.inputs.length}`}
364-
fn={fn}
365-
selectedFunction={selectedFunction}
366-
setSelectedFunction={setSelectedFunction}
367-
/>
368-
))}
369-
</Flex>
370-
);
337+
const [_keywordSearch, setKeywordSearch] = useState<string>("");
338+
const [keywordSearch] = useDebounce(_keywordSearch, 150);
339+
340+
const functionSection = (e: ExtensionFunctions) => {
341+
const filteredFunctions = keywordSearch
342+
? e.functions.filter((o) =>
343+
o.name.toLowerCase().includes(keywordSearch.toLowerCase()),
344+
)
345+
: e.functions;
346+
return (
347+
<Flex key={e.extension} flexDir="column" mb={6}>
348+
{e.extension ? (
349+
<>
350+
<Flex alignItems="center" alignContent="center" gap={2}>
351+
<Image
352+
src="/assets/dashboard/extension-check.svg"
353+
alt="Extension detected"
354+
objectFit="contain"
355+
mb="2px"
356+
/>
357+
<Heading as="label" size="label.md">
358+
{e.extension}
359+
</Heading>
360+
</Flex>
361+
<Divider my={2} />
362+
</>
363+
) : (
364+
<>
365+
<Flex alignItems="center" alignContent="center" gap={2}>
366+
<Heading as="label" size="label.md">
367+
Other Functions
368+
</Heading>
369+
</Flex>
370+
<Divider my={2} />
371+
</>
372+
)}
373+
{filteredFunctions.map((fn) => (
374+
<FunctionsOrEventsListItem
375+
key={`${fn.name}_${fn.type}_${fn.inputs.length}`}
376+
fn={fn}
377+
selectedFunction={selectedFunction}
378+
setSelectedFunction={setSelectedFunction}
379+
/>
380+
))}
381+
</Flex>
382+
);
383+
};
371384

372385
return (
373386
<SimpleGrid height="100%" columns={12} gap={5}>
@@ -406,6 +419,19 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
406419
</Tab>
407420
)}
408421
</TabList>
422+
423+
<div className="sticky top-0 z-[1]">
424+
<div className="relative w-full">
425+
<SearchIcon className="-translate-y-1/2 absolute top-[50%] left-3 size-4 text-muted-foreground" />
426+
<Input
427+
value={_keywordSearch}
428+
placeholder="Search"
429+
className="h-auto rounded-none border-x-0 py-3 pl-9 focus-visible:ring-0 focus-visible:ring-offset-0"
430+
onChange={(e) => setKeywordSearch(e.target.value)}
431+
/>
432+
</div>
433+
</div>
434+
409435
<TabPanels h="auto" overflow="auto">
410436
{writeFunctions.length > 0 && (
411437
<TabPanel>

0 commit comments

Comments
 (0)