bolt.diy/app/components/app-library/ExampleLibraryApps.tsx
2025-04-26 13:04:08 -07:00

93 lines
2.8 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { type BuildAppResult, getRecentApps } from '~/lib/persistence/apps';
import styles from './ExampleLibraryApps.module.scss';
import { importChat } from '~/lib/persistence/useChatHistory';
export const ExampleLibraryApps = () => {
const [numApps, setNumApps] = useState<number>(6);
const [apps, setApps] = useState<BuildAppResult[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
async function fetchRecentApps() {
try {
setLoading(true);
const recentApps = await getRecentApps(numApps);
setApps(recentApps);
setError(null);
} catch (err) {
console.error('Failed to fetch recent apps:', err);
setError('Failed to load recent apps');
} finally {
setLoading(false);
}
}
if (apps.length < numApps) {
fetchRecentApps();
}
}, [numApps]);
if (error) {
return <div className={styles.error}>{error}</div>;
}
if (apps.length === 0) {
if (loading) {
return <div className={styles.loading}>Loading recent apps...</div>;
}
return <div className={styles.empty}>No recent apps found</div>;
}
const displayApps = apps.slice(0, numApps);
return (
<div className={styles.container}>
<div className={styles.grid}>
{displayApps.map((app) => (
<div
key={app.appId}
className={`${styles.appItem} ${app.outcome !== 'success' ? styles.appItemError : ''}`}
onClick={() => {
importChat(
app.title ?? 'Untitled App',
app.messages.filter((msg) => {
// Workaround an issue where the messages in the database include images
// (used to generate the screenshots).
if (msg.role == 'assistant' && msg.type == 'image') {
return false;
}
return true;
}),
);
}}
>
{app.imageDataURL ? (
<img src={app.imageDataURL} alt={app.title || 'App preview'} className={styles.previewImage} />
) : (
<div className={styles.placeholderImage}>{app.title || 'No preview'}</div>
)}
<div className={styles.appTitle}>{app.title || 'Untitled App'}</div>
</div>
))}
</div>
{loading && <div className={styles.loading}>Loading recent apps...</div>}
{!loading && (
<div className={styles.buttonContainer}>
<button
className={styles.loadMoreButton}
onClick={() => {
setNumApps((prev) => prev + 12);
}}
>
Load More
</button>
</div>
)}
</div>
);
};