11"use client" ;
22
3- import { WalletAddress } from "@/components/blocks/wallet-address" ;
4- import { CopyAddressButton } from "@/components/ui/CopyAddressButton" ;
53import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow" ;
6- import { Spinner } from "@/components/ui/Spinner/Spinner" ;
74import { Alert , AlertTitle } from "@/components/ui/alert" ;
8- import { Button } from "@/components/ui/button" ;
9- import {
10- Dialog ,
11- DialogContent ,
12- DialogDescription ,
13- DialogFooter ,
14- DialogHeader ,
15- DialogTitle ,
16- } from "@/components/ui/dialog" ;
17- import { Skeleton } from "@/components/ui/skeleton" ;
18- import { ToolTipLabel } from "@/components/ui/tooltip" ;
19- import { useMutation } from "@tanstack/react-query" ;
20- import { TransactionButton } from "components/buttons/TransactionButton" ;
21- import { CircleSlash , TrashIcon } from "lucide-react" ;
22- import { useState } from "react" ;
23- import { toast } from "sonner" ;
24- import {
25- type ContractOptions ,
26- getContract ,
27- sendTransaction ,
28- waitForReceipt ,
29- } from "thirdweb" ;
30- import { uninstallModuleByProxy } from "thirdweb/modules" ;
5+ import { CircleSlash } from "lucide-react" ;
6+ import type { ContractOptions } from "thirdweb" ;
317import type { Account } from "thirdweb/wallets" ;
32- import { useModuleContractInfo } from "./moduleContractInfo " ;
8+ import { ModuleCard } from "./module-card " ;
339
3410export const InstalledModulesTable = ( props : {
3511 contract : ContractOptions ;
@@ -43,7 +19,7 @@ export const InstalledModulesTable = (props: {
4319 const { installedModules, ownerAccount } = props ;
4420
4521 const sectionTitle = (
46- < h2 className = "mb-3 text-2xl font-bold tracking-tight" >
22+ < h2 className = "mb-3 font-bold text-2xl tracking-tight" >
4723 Installed Modules
4824 </ h2 >
4925 ) ;
@@ -67,11 +43,10 @@ export const InstalledModulesTable = (props: {
6743 { sectionTitle }
6844 < ScrollShadow scrollableClassName = "rounded-lg" >
6945 < div className = "flex flex-col gap-6" >
70- { installedModules . data ?. map ( ( e , i ) => (
71- < ModuleTemplate
72- // biome-ignore lint/suspicious/noArrayIndexKey: FIXME
73- key = { i }
74- moduleAddress = { e }
46+ { installedModules . data ?. map ( ( moduleAddress ) => (
47+ < ModuleCard
48+ key = { moduleAddress }
49+ moduleAddress = { moduleAddress }
7550 contract = { props . contract }
7651 onRemoveModule = { props . refetchModules }
7752 ownerAccount = { ownerAccount }
@@ -82,172 +57,3 @@ export const InstalledModulesTable = (props: {
8257 </ >
8358 ) ;
8459} ;
85-
86- function SkeletonModule ( ) {
87- return (
88- < div className = "h-[400px] w-full" />
89- )
90- }
91-
92-
93- function ModuleTemplate ( props : {
94- moduleAddress : string ;
95- contract : ContractOptions ;
96- onRemoveModule : ( ) => void ;
97- ownerAccount ?: Account ;
98- } ) {
99- const { contract, moduleAddress, ownerAccount } = props ;
100- const [ isUninstallModalOpen , setIsUninstallModalOpen ] = useState ( false ) ;
101-
102- const contractInfo = useModuleContractInfo (
103- getContract ( {
104- address : moduleAddress ,
105- chain : contract . chain ,
106- client : contract . client ,
107- } ) ,
108- ) ;
109-
110- const uninstallMutation = useMutation ( {
111- mutationFn : async ( account : Account ) => {
112- const uninstallTransaction = uninstallModuleByProxy ( {
113- contract,
114- chain : contract . chain ,
115- client : contract . client ,
116- moduleProxyAddress : moduleAddress ,
117- moduleData : "0x" ,
118- } ) ;
119-
120- const txResult = await sendTransaction ( {
121- transaction : uninstallTransaction ,
122- account,
123- } ) ;
124-
125- await waitForReceipt ( txResult ) ;
126- } ,
127- onSuccess ( ) {
128- toast . success ( "Module Removed successfully" ) ;
129- props . onRemoveModule ( ) ;
130- } ,
131- onError ( error ) {
132- toast . error ( "Failed to remove module" ) ;
133- console . error ( "Error during uninstallation:" , error ) ;
134- } ,
135- } ) ;
136-
137- const handleRemove = async ( ) => {
138- if ( ! ownerAccount ) {
139- return ;
140- }
141-
142- setIsUninstallModalOpen ( false ) ;
143- uninstallMutation . mutate ( ownerAccount ) ;
144- } ;
145-
146- if ( ! contractInfo ) {
147- return < SkeletonModule /> ;
148- }
149-
150- return (
151- < section >
152- < div className = "rounded-lg border border-border bg-muted/50 p-4 lg:p-6" >
153- { /* Title */ }
154- < div className = "flex justify-between" >
155- < h3 className = "text-xl font-semibold tracking-tight" >
156- { contractInfo . name || "..." }
157- </ h3 >
158-
159- < ToolTipLabel label = "Remove Module" >
160- < Button
161- onClick = { ( ) => setIsUninstallModalOpen ( true ) }
162- variant = "outline"
163- className = "rounded-xl p-3 text-red-500"
164- >
165- { uninstallMutation . isPending ? (
166- < Spinner className = "size-4" />
167- ) : (
168- < TrashIcon className = "size-4" />
169- ) }
170- </ Button >
171- </ ToolTipLabel >
172- </ div >
173-
174- { /* Description */ }
175- < p className = "text-muted-foreground" >
176- { contractInfo . description || "..." }
177- </ p >
178-
179- < div className = "h-5" />
180-
181- < div className = "flex flex-col gap-x-8 gap-y-4 md:flex-row" >
182- < div className = "flex items-center gap-2" >
183- < p className = "text-sm text-muted-foreground" >
184- Published by:{ " " }
185- </ p >
186- < WalletAddress address = { contractInfo . publisher || "" } />
187- </ div >
188-
189- < div className = "flex items-center gap-2" >
190- < p className = "text-sm text-muted-foreground" >
191- Module Address:{ " " }
192- </ p >
193- < CopyAddressButton
194- className = "text-xs"
195- address = { props . moduleAddress || "" }
196- copyIconPosition = "left"
197- variant = "outline"
198- />
199- </ div >
200- </ div >
201-
202- < div className = "h-5" />
203-
204- < Dialog
205- open = { isUninstallModalOpen }
206- onOpenChange = { setIsUninstallModalOpen }
207- >
208- < DialogContent className = "z-[10001]" dialogOverlayClassName = "z-[10000]" >
209- < form
210- onSubmit = { ( e ) => {
211- e . preventDefault ( ) ;
212- handleRemove ( ) ;
213- } }
214- >
215- < DialogHeader >
216- < DialogTitle > Uninstall Module</ DialogTitle >
217- < DialogDescription >
218- Are you sure you want to uninstall{ " " }
219- < span className = "font-medium text-foreground " >
220- { contractInfo . name }
221- </ span > { " " }
222- ?
223- </ DialogDescription >
224- </ DialogHeader >
225-
226- < DialogFooter className = "mt-10 flex-row justify-end gap-3 md:gap-1" >
227- < Button
228- type = "button"
229- onClick = { ( ) => setIsUninstallModalOpen ( false ) }
230- variant = "outline"
231- >
232- Cancel
233- </ Button >
234-
235- < TransactionButton
236- txChainID = { contract . chain . id }
237- transactionCount = { 1 }
238- isLoading = { uninstallMutation . isPending }
239- type = "submit"
240- colorScheme = "red"
241- className = "flex"
242- >
243- Uninstall
244- </ TransactionButton >
245- </ DialogFooter >
246- </ form >
247- </ DialogContent >
248- </ Dialog >
249- </ div >
250- </ section >
251- )
252- }
253-
0 commit comments