1- "use client" ;
2-
3- import { useState } from "react" ;
1+ import React , { useState } from "react" ;
42import { Button } from "@/components/ui/button" ;
53import { Badge } from "@/components/ui/badge" ;
64import { ArrowUpRight } from "lucide-react" ;
@@ -15,6 +13,19 @@ function truncateString(str: string): string {
1513 return `${ str . slice ( 0 , 5 ) } ...${ str . slice ( - 30 ) } ` ;
1614}
1715
16+ // Function to format extension type for display
17+ function formatExtensionType ( type : string ) : string {
18+ // Replace hyphens with spaces and limit length
19+ const formattedType = type . replace ( / - / g, " " ) ;
20+
21+ // If type is too long, truncate it for mobile displays
22+ if ( formattedType . length > 15 ) {
23+ return formattedType . slice ( 0 , 15 ) + "..." ;
24+ }
25+
26+ return formattedType ;
27+ }
28+
1829const getStatusColor = ( status : Extension [ "status" ] ) => {
1930 switch ( status ) {
2031 case "DEPLOYED" :
@@ -30,98 +41,6 @@ const getExplorerUrl = (txId: string) => {
3041 return `${ baseUrl } /${ txId } ${ isTestnet ? "?chain=testnet" : "" } ` ;
3142} ;
3243
33- export function DAOExtensions ( { extensions } : DAOExtensionsProps ) {
34- const [ selectedStatus , setSelectedStatus ] =
35- useState < Extension [ "status" ] > ( "DEPLOYED" ) ;
36-
37- const filteredExtensions = extensions . filter (
38- ( ext ) => ext . status === selectedStatus
39- ) ;
40-
41- const stats = {
42- active : extensions . filter ( ( e ) => e . status === "DEPLOYED" ) . length ,
43- pending : extensions . filter ( ( e ) => e . status === "pending" ) . length ,
44- } ;
45-
46- return (
47- < div className = "w-full" >
48- < div className = "mb-8" >
49- < h2 className = "text-xl sm:text-2xl font-semibold tracking-tight mb-2" >
50- Extensions
51- </ h2 >
52- < p className = "text-sm sm:text-base text-muted-foreground" >
53- Manage and monitor your DAO's active extensions and capabilities
54- </ p >
55- </ div >
56-
57- < div className = "space-y-4 sm:space-y-6 pb-12" >
58- < div className = "flex flex-wrap gap-2" >
59- < StatusButton
60- status = "DEPLOYED"
61- count = { stats . active }
62- selected = { selectedStatus === "DEPLOYED" }
63- onClick = { ( ) => setSelectedStatus ( "DEPLOYED" ) }
64- />
65- < StatusButton
66- status = "pending"
67- count = { stats . pending }
68- selected = { selectedStatus === "pending" }
69- onClick = { ( ) => setSelectedStatus ( "pending" ) }
70- />
71- </ div >
72-
73- < div className = "space-y-3 sm:space-y-4" >
74- { filteredExtensions . map ( ( extension ) => (
75- < div
76- key = { extension . id }
77- className = "group relative rounded-lg border bg-background/50 backdrop-blur-sm p-3 sm:p-4 transition-all hover:bg-background/80"
78- >
79- < div className = "flex flex-col sm:flex-row sm:items-start gap-3 sm:gap-4" >
80- < div className = "flex-1 min-w-0" >
81- < div className = "flex flex-wrap items-center gap-2 sm:gap-3 mb-1" >
82- < h3 className = "text-sm sm:text-base font-medium capitalize" >
83- { extension . type . replace ( "-" , " " ) }
84- </ h3 >
85- < Badge
86- variant = "secondary"
87- className = { `${ getStatusColor (
88- extension . status
89- ) } border capitalize text-xs`}
90- >
91- { extension . status }
92- </ Badge >
93- </ div >
94- { extension . contract_principal && (
95- < div className = "flex items-center gap-2 mb-1" >
96- < code className = "text-xs bg-muted px-2 py-1 rounded" >
97- { truncateString ( extension . contract_principal ) }
98- </ code >
99- </ div >
100- ) }
101- { extension . tx_id && (
102- < a
103- href = { getExplorerUrl ( extension . tx_id ) }
104- target = "_blank"
105- rel = "noopener noreferrer"
106- className = "inline-flex items-center gap-1 mt-1 text-xs text-muted-foreground hover:text-primary transition-colors"
107- >
108- < span > TX: { truncateString ( extension . tx_id ) } </ span >
109- < ArrowUpRight className = "h-3 w-3" />
110- </ a >
111- ) }
112- </ div >
113- < div className = "text-xs text-muted-foreground whitespace-nowrap" >
114- { new Date ( extension . created_at ) . toLocaleDateString ( ) }
115- </ div >
116- </ div >
117- </ div >
118- ) ) }
119- </ div >
120- </ div >
121- </ div >
122- ) ;
123- }
124-
12544function StatusButton ( {
12645 status,
12746 count,
@@ -148,4 +67,94 @@ function StatusButton({
14867 ) ;
14968}
15069
151- export default DAOExtensions ;
70+ export default function DAOExtensions ( { extensions } : DAOExtensionsProps ) {
71+ const [ selectedStatus , setSelectedStatus ] =
72+ useState < Extension [ "status" ] > ( "DEPLOYED" ) ;
73+
74+ const filteredExtensions = extensions . filter (
75+ ( ext ) => ext . status === selectedStatus
76+ ) ;
77+ const stats = {
78+ active : extensions . filter ( ( e ) => e . status === "DEPLOYED" ) . length ,
79+ pending : extensions . filter ( ( e ) => e . status === "pending" ) . length ,
80+ } ;
81+
82+ return (
83+ < div className = "container mx-auto px-4 py-8" >
84+ < div className = "space-y-8" >
85+ < div >
86+ < h2 className = "text-2xl font-bold tracking-tight" > Extensions</ h2 >
87+ < p className = "text-muted-foreground mt-2" >
88+ Manage and monitor your DAO's active extensions and
89+ capabilities
90+ </ p >
91+ </ div >
92+
93+ < div className = "space-y-6" >
94+ < div className = "flex flex-wrap gap-2" >
95+ < StatusButton
96+ status = "DEPLOYED"
97+ count = { stats . active }
98+ selected = { selectedStatus === "DEPLOYED" }
99+ onClick = { ( ) => setSelectedStatus ( "DEPLOYED" ) }
100+ />
101+ < StatusButton
102+ status = "pending"
103+ count = { stats . pending }
104+ selected = { selectedStatus === "pending" }
105+ onClick = { ( ) => setSelectedStatus ( "pending" ) }
106+ />
107+ </ div >
108+
109+ < div className = "space-y-4" >
110+ { filteredExtensions . map ( ( extension ) => (
111+ < div
112+ key = { extension . id }
113+ className = "group relative rounded-lg border bg-background/50 backdrop-blur-sm p-4 transition-all hover:bg-background/80"
114+ >
115+ < div className = "flex flex-col sm:flex-row sm:items-start gap-4" >
116+ < div className = "flex-1 min-w-0" >
117+ < div className = "flex flex-wrap items-center gap-3 mb-2" >
118+ < h3 className = "text-base font-medium capitalize break-all sm:break-normal" >
119+ { formatExtensionType ( extension . type ) }
120+ </ h3 >
121+ < Badge
122+ variant = "secondary"
123+ className = { `${ getStatusColor (
124+ extension . status
125+ ) } border capitalize shrink-0`}
126+ >
127+ { extension . status }
128+ </ Badge >
129+ </ div >
130+ { extension . contract_principal && (
131+ < div className = "flex items-center gap-2 mb-2" >
132+ < code className = "text-xs bg-muted px-2 py-1 rounded overflow-hidden text-ellipsis" >
133+ { truncateString ( extension . contract_principal ) }
134+ </ code >
135+ </ div >
136+ ) }
137+ { extension . tx_id && (
138+ < a
139+ href = { getExplorerUrl ( extension . tx_id ) }
140+ target = "_blank"
141+ rel = "noopener noreferrer"
142+ className = "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-primary transition-colors break-all"
143+ >
144+ < span > TX: { truncateString ( extension . tx_id ) } </ span >
145+ < ArrowUpRight className = "h-3 w-3 shrink-0" />
146+ </ a >
147+ ) }
148+ </ div >
149+ < div className = "text-xs text-muted-foreground whitespace-nowrap mt-2 sm:mt-0" >
150+ { new Date ( extension . created_at ) . toLocaleDateString ( ) }
151+ </ div >
152+ </ div >
153+ </ div >
154+ ) ) }
155+ </ div >
156+ </ div >
157+ </ div >
158+ </ div >
159+ ) ;
160+ }
0 commit comments