init
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { DashboardLayout } from '../../components/dashboard/DashboardLayout';
|
||||
import { GalleryCard } from '../../components/dashboard/GalleryCard';
|
||||
import { StudioStat } from '../../components/dashboard/StudioStat';
|
||||
import { useAuth } from '../../features/auth/useAuth';
|
||||
import { deleteGallery, getGalleries } from '../../lib/api';
|
||||
import { formatBytes } from '../../lib/format';
|
||||
import type { GallerySummary } from '../../types/gallery';
|
||||
|
||||
export default function DashboardPage() {
|
||||
const { user } = useAuth();
|
||||
const [galleries, setGalleries] = useState<GallerySummary[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
getGalleries()
|
||||
.then(setGalleries)
|
||||
.catch((reason: unknown) =>
|
||||
setError(reason instanceof Error ? reason.message : 'Could not load galleries.'),
|
||||
)
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
async function removeGallery(gallery: GallerySummary) {
|
||||
if (!window.confirm(`Delete "${gallery.title}"? This cannot be undone.`)) return;
|
||||
try {
|
||||
await deleteGallery(gallery.id);
|
||||
setGalleries((current) => current.filter((item) => item.id !== gallery.id));
|
||||
} catch (reason) {
|
||||
setError(reason instanceof Error ? reason.message : 'Could not delete gallery.');
|
||||
}
|
||||
}
|
||||
|
||||
const photos = galleries.reduce((total, gallery) => total + gallery.photoCount, 0);
|
||||
const storage = galleries.reduce((total, gallery) => total + gallery.totalBytes, 0);
|
||||
const published = galleries.filter((gallery) => gallery.status === 'published').length;
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<div className="studio-page">
|
||||
<header className="studio-page__header">
|
||||
<div>
|
||||
<p className="studio-kicker">{user?.name || 'Studio'} / overview</p>
|
||||
<h1 className="studio-display">
|
||||
Make the handoff <em>matter.</em>
|
||||
</h1>
|
||||
<p className="studio-page__lede">
|
||||
Everything your clients need, in one beautiful place.
|
||||
</p>
|
||||
</div>
|
||||
<Link className="platform-button platform-button--accent" to="/dashboard/galleries/new">
|
||||
<span>New gallery</span>
|
||||
<span aria-hidden="true">+</span>
|
||||
</Link>
|
||||
</header>
|
||||
|
||||
<section className="studio-stats" aria-label="Studio overview">
|
||||
<StudioStat
|
||||
label="Galleries"
|
||||
value={String(galleries.length).padStart(2, '0')}
|
||||
note="All your work, in one place"
|
||||
accent="coral"
|
||||
/>
|
||||
<StudioStat
|
||||
label="Published"
|
||||
value={String(published).padStart(2, '0')}
|
||||
note="Currently out in the world"
|
||||
accent="violet"
|
||||
/>
|
||||
<StudioStat
|
||||
label="Photographs"
|
||||
value={String(photos).padStart(2, '0')}
|
||||
note="Ready to be remembered"
|
||||
accent="gold"
|
||||
/>
|
||||
<StudioStat
|
||||
label="Storage used"
|
||||
value={formatBytes(storage)}
|
||||
note="Across every gallery"
|
||||
accent="ink"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="studio-section studio-section--recent">
|
||||
<div className="studio-section__heading">
|
||||
<div>
|
||||
<p className="studio-kicker">Your latest work</p>
|
||||
<h2 className="studio-heading">Recent galleries</h2>
|
||||
</div>
|
||||
<Link className="inline-link" to="/dashboard/galleries">
|
||||
View all galleries <span aria-hidden="true">↗</span>
|
||||
</Link>
|
||||
</div>
|
||||
{error && <p className="studio-alert studio-alert--error">{error}</p>}
|
||||
{loading ? (
|
||||
<div className="studio-list-loading">
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</div>
|
||||
) : galleries.length === 0 ? (
|
||||
<div className="studio-empty">
|
||||
<span className="studio-empty__mark">+</span>
|
||||
<div>
|
||||
<h3>Your first gallery starts here.</h3>
|
||||
<p>Give finished work a place that feels as considered as the work itself.</p>
|
||||
</div>
|
||||
<Link className="inline-link" to="/dashboard/galleries/new">
|
||||
Create a gallery <span aria-hidden="true">↗</span>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<div className="gallery-grid gallery-grid--dashboard">
|
||||
{galleries.slice(0, 3).map((gallery) => (
|
||||
<GalleryCard key={gallery.id} gallery={gallery} onDelete={removeGallery} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</DashboardLayout>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user