11"use client" ;
22
3- import * as React from "react" ;
4- import { IconPlay , StarRatingIcons } from "@/components/ui/icons" ;
3+ import { StarRatingIcons } from "@/components/ui/icons" ;
54import { Separator } from "@/components/ui/separator" ;
6- import BackendAPI from "@/lib/autogpt-server-api" ;
5+ import BackendAPI , { LibraryAgent } from "@/lib/autogpt-server-api" ;
76import { useRouter } from "next/navigation" ;
87import Link from "next/link" ;
98import { useToast } from "@/components/ui/use-toast" ;
109
11- import useSupabase from "@/hooks/useSupabase" ;
12- import { DownloadIcon , LoaderIcon } from "lucide-react" ;
1310import { useOnboarding } from "../onboarding/onboarding-provider" ;
11+ import { User } from "@supabase/supabase-js" ;
12+ import { cn } from "@/lib/utils" ;
13+ import { FC , useCallback , useMemo , useState } from "react" ;
14+
1415interface AgentInfoProps {
16+ user : User | null ;
1517 name : string ;
1618 creator : string ;
1719 shortDescription : string ;
@@ -22,9 +24,11 @@ interface AgentInfoProps {
2224 lastUpdated : string ;
2325 version : string ;
2426 storeListingVersionId : string ;
27+ libraryAgent : LibraryAgent | null ;
2528}
2629
27- export const AgentInfo : React . FC < AgentInfoProps > = ( {
30+ export const AgentInfo : FC < AgentInfoProps > = ( {
31+ user,
2832 name,
2933 creator,
3034 shortDescription,
@@ -35,28 +39,48 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
3539 lastUpdated,
3640 version,
3741 storeListingVersionId,
42+ libraryAgent,
3843} ) => {
3944 const router = useRouter ( ) ;
40- const api = React . useMemo ( ( ) => new BackendAPI ( ) , [ ] ) ;
41- const { user } = useSupabase ( ) ;
45+ const api = useMemo ( ( ) => new BackendAPI ( ) , [ ] ) ;
4246 const { toast } = useToast ( ) ;
4347 const { completeStep } = useOnboarding ( ) ;
44-
45- const [ downloading , setDownloading ] = React . useState ( false ) ;
46-
47- const handleAddToLibrary = async ( ) => {
48+ const [ adding , setAdding ] = useState ( false ) ;
49+ const [ downloading , setDownloading ] = useState ( false ) ;
50+
51+ const libraryAction = useCallback ( async ( ) => {
52+ setAdding ( true ) ;
53+ if ( libraryAgent ) {
54+ toast ( {
55+ description : "Redirecting to your library..." ,
56+ duration : 2000 ,
57+ } ) ;
58+ // Redirect to the library agent page
59+ router . push ( `/library/agents/${ libraryAgent . id } ` ) ;
60+ return ;
61+ }
4862 try {
4963 const newLibraryAgent = await api . addMarketplaceAgentToLibrary (
5064 storeListingVersionId ,
5165 ) ;
5266 completeStep ( "MARKETPLACE_ADD_AGENT" ) ;
5367 router . push ( `/library/agents/${ newLibraryAgent . id } ` ) ;
68+ toast ( {
69+ title : "Agent Added" ,
70+ description : "Redirecting to your library..." ,
71+ duration : 2000 ,
72+ } ) ;
5473 } catch ( error ) {
5574 console . error ( "Failed to add agent to library:" , error ) ;
75+ toast ( {
76+ title : "Error" ,
77+ description : "Failed to add agent to library. Please try again." ,
78+ variant : "destructive" ,
79+ } ) ;
5680 }
57- } ;
81+ } , [ toast , api , storeListingVersionId , completeStep , router ] ) ;
5882
59- const handleDownloadToLibrary = async ( ) => {
83+ const handleDownload = useCallback ( async ( ) => {
6084 const downloadAgent = async ( ) : Promise < void > => {
6185 setDownloading ( true ) ;
6286 try {
@@ -89,12 +113,16 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
89113 } ) ;
90114 } catch ( error ) {
91115 console . error ( `Error downloading agent:` , error ) ;
92- throw error ;
116+ toast ( {
117+ title : "Error" ,
118+ description : "Failed to download agent. Please try again." ,
119+ variant : "destructive" ,
120+ } ) ;
93121 }
94122 } ;
95123 await downloadAgent ( ) ;
96124 setDownloading ( false ) ;
97- } ;
125+ } , [ setDownloading , api , storeListingVersionId , toast ] ) ;
98126
99127 return (
100128 < div className = "w-full max-w-[396px] px-4 sm:px-6 lg:w-[396px] lg:px-0" >
@@ -105,65 +133,61 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
105133
106134 { /* Creator */ }
107135 < div className = "mb-3 flex w-full items-center gap-1.5 lg:mb-4" >
108- < div className = "font-geist text-base font-normal text-neutral-800 dark:text-neutral-200 sm:text-lg lg:text-xl" >
136+ < div className = "font-sans text-base font-normal text-neutral-800 dark:text-neutral-200 sm:text-lg lg:text-xl" >
109137 by
110138 </ div >
111139 < Link
112140 href = { `/marketplace/creator/${ encodeURIComponent ( creator ) } ` }
113- className = "font-geist text-base font-medium text-neutral-800 hover:underline dark:text-neutral-200 sm:text-lg lg:text-xl"
141+ className = "font-sans text-base font-medium text-neutral-800 hover:underline dark:text-neutral-200 sm:text-lg lg:text-xl"
114142 >
115143 { creator }
116144 </ Link >
117145 </ div >
118146
119147 { /* Short Description */ }
120- < div className = "font-geist mb-4 line-clamp-2 w-full text-base font-normal leading-normal text-neutral-600 dark:text-neutral-300 sm:text-lg lg:mb-6 lg:text-xl lg:leading-7" >
148+ < div className = "mb-4 line-clamp-2 w-full font-sans text-base font-normal leading-normal text-neutral-600 dark:text-neutral-300 sm:text-lg lg:mb-6 lg:text-xl lg:leading-7" >
121149 { shortDescription }
122150 </ div >
123151
124- { /* Run Agent Button */ }
125- < div className = "mb-4 w-full lg:mb-[60px]" >
126- { user ? (
152+ { /* Buttons */ }
153+ < div className = "mb-4 flex w-full gap-3 lg:mb-[60px]" >
154+ { user && (
127155 < button
128- onClick = { handleAddToLibrary }
129- className = "inline-flex w-full items-center justify-center gap-2 rounded-[38px] bg-violet-600 px-4 py-3 transition-colors hover:bg-violet-700 sm:w-auto sm:gap-2.5 sm:px-5 sm:py-3.5 lg:px-6 lg:py-4"
130- >
131- < IconPlay className = "h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
132- < span className = "font-poppins text-base font-medium text-neutral-50 sm:text-lg" >
133- Add To Library
134- </ span >
135- </ button >
136- ) : (
137- < button
138- onClick = { handleDownloadToLibrary }
139- className = { `inline-flex w-full items-center justify-center gap-2 rounded-[38px] px-4 py-3 transition-colors sm:w-auto sm:gap-2.5 sm:px-5 sm:py-3.5 lg:px-6 lg:py-4 ${
140- downloading
141- ? "bg-neutral-400"
142- : "bg-violet-600 hover:bg-violet-700"
143- } `}
144- disabled = { downloading }
145- >
146- { downloading ? (
147- < LoaderIcon className = "h-5 w-5 animate-spin text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
148- ) : (
149- < DownloadIcon className = "h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
156+ className = { cn (
157+ "inline-flex min-w-24 items-center justify-center rounded-full bg-violet-600 px-4 py-3" ,
158+ "transition-colors duration-200 hover:bg-violet-500 disabled:bg-zinc-400" ,
150159 ) }
151- < span className = "font-poppins text-base font-medium text-neutral-50 sm:text-lg" >
152- { downloading ? "Downloading..." : "Download Agent as File" }
160+ onClick = { libraryAction }
161+ disabled = { adding }
162+ >
163+ < span className = "justify-start font-sans text-sm font-medium leading-snug text-primary-foreground" >
164+ { libraryAgent ? "See runs" : "Add to library" }
153165 </ span >
154166 </ button >
155167 ) }
168+ < button
169+ className = { cn (
170+ "inline-flex min-w-24 items-center justify-center rounded-full bg-zinc-200 px-4 py-3" ,
171+ "transition-colors duration-200 hover:bg-zinc-200/70 disabled:bg-zinc-200/40" ,
172+ ) }
173+ onClick = { handleDownload }
174+ disabled = { downloading }
175+ >
176+ < div className = "justify-start text-center font-sans text-sm font-medium leading-snug text-zinc-800" >
177+ Download agent
178+ </ div >
179+ </ button >
156180 </ div >
157181
158182 { /* Rating and Runs */ }
159183 < div className = "mb-4 flex w-full items-center justify-between lg:mb-[44px]" >
160184 < div className = "flex items-center gap-1.5 sm:gap-2" >
161- < span className = "font-geist whitespace-nowrap text-base font-semibold text-neutral-800 dark:text-neutral-200 sm:text-lg" >
185+ < span className = "whitespace-nowrap font-sans text-base font-semibold text-neutral-800 dark:text-neutral-200 sm:text-lg" >
162186 { rating . toFixed ( 1 ) }
163187 </ span >
164188 < div className = "flex gap-0.5" > { StarRatingIcons ( rating ) } </ div >
165189 </ div >
166- < div className = "font-geist whitespace-nowrap text-base font-semibold text-neutral-800 dark:text-neutral-200 sm:text-lg" >
190+ < div className = "whitespace-nowrap font-sans text-base font-semibold text-neutral-800 dark:text-neutral-200 sm:text-lg" >
167191 { runs . toLocaleString ( ) } runs
168192 </ div >
169193 </ div >
@@ -183,14 +207,14 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
183207
184208 { /* Categories */ }
185209 < div className = "mb-4 flex w-full flex-col gap-1.5 sm:gap-2 lg:mb-[36px]" >
186- < div className = "font-geist decoration-skip-ink-none mb-1.5 text-base font-medium leading-6 text-neutral-800 dark:text-neutral-200 sm:mb-2" >
210+ < div className = "decoration-skip-ink-none mb-1.5 font-sans text-base font-medium leading-6 text-neutral-800 dark:text-neutral-200 sm:mb-2" >
187211 Categories
188212 </ div >
189213 < div className = "flex flex-wrap gap-1.5 sm:gap-2" >
190214 { categories . map ( ( category , index ) => (
191215 < div
192216 key = { index }
193- className = "font-geist decoration-skip-ink-none whitespace-nowrap rounded-full border border-neutral-600 bg-white px-2 py-0.5 text-base font-normal leading-6 text-neutral-800 underline-offset-[from-font] dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 sm:px-[16px] sm:py-[10px]"
217+ className = "decoration-skip-ink-none whitespace-nowrap rounded-full border border-neutral-600 bg-white px-2 py-0.5 font-sans text-base font-normal leading-6 text-neutral-800 underline-offset-[from-font] dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200 sm:px-[16px] sm:py-[10px]"
194218 >
195219 { category }
196220 </ div >
@@ -200,10 +224,10 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
200224
201225 { /* Version History */ }
202226 < div className = "flex w-full flex-col gap-0.5 sm:gap-1" >
203- < div className = "font-geist decoration-skip-ink-none mb-1.5 text-base font-medium leading-6 text-neutral-800 dark:text-neutral-200 sm:mb-2" >
227+ < div className = "decoration-skip-ink-none mb-1.5 font-sans text-base font-medium leading-6 text-neutral-800 dark:text-neutral-200 sm:mb-2" >
204228 Version history
205229 </ div >
206- < div className = "font-geist decoration-skip-ink-none text-base font-normal leading-6 text-neutral-600 underline-offset-[from-font] dark:text-neutral-400" >
230+ < div className = "decoration-skip-ink-none font-sans text-base font-normal leading-6 text-neutral-600 underline-offset-[from-font] dark:text-neutral-400" >
207231 Last updated { lastUpdated }
208232 </ div >
209233 < div className = "text-xs text-neutral-600 dark:text-neutral-400 sm:text-sm" >
0 commit comments