| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import { useState } from 'react';
- import { useImages } from '../hooks/useImages';
- import { USER_BUCKET } from '../config';
- import ImageGrid from '../components/ImageGrid';
- import ImageUploader from '../components/ImageUploader';
- import type { ImageFile, UploadOptions } from '../types';
- export default function DashboardPage() {
- const { images, isLoading, error, uploadImage, deleteImage, fetchImages } = useImages(USER_BUCKET);
- const [isUploading, setIsUploading] = useState(false);
- const [showUploader, setShowUploader] = useState(false);
- const [uploadError, setUploadError] = useState<string | null>(null);
- const handleUpload = async (file: File, options: UploadOptions) => {
- setIsUploading(true);
- setUploadError(null);
- try {
- await uploadImage(file, options);
- setShowUploader(false);
- } catch (err) {
- setUploadError(err instanceof Error ? err.message : 'Upload failed');
- } finally {
- setIsUploading(false);
- }
- };
- const handleDelete = async (image: ImageFile) => {
- try {
- await deleteImage(image);
- } catch (err) {
- alert(err instanceof Error ? err.message : 'Delete failed');
- }
- };
- return (
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
- {/* Header */}
- <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-8">
- <div>
- <h1
- className="text-2xl font-bold"
- style={{ color: 'var(--text-primary)' }}
- >
- My Images
- </h1>
- <p style={{ color: 'var(--text-secondary)' }}>Manage your uploaded images</p>
- </div>
- <div className="flex gap-3">
- <button
- onClick={() => fetchImages()}
- className="btn btn-secondary flex items-center gap-2"
- >
- <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
- </svg>
- Refresh
- </button>
- <button
- onClick={() => setShowUploader(!showUploader)}
- className="btn btn-primary flex items-center gap-2"
- >
- <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
- </svg>
- Upload Image
- </button>
- </div>
- </div>
- {/* Upload section */}
- {showUploader && (
- <div className="card p-6 mb-8">
- <div className="flex justify-between items-center mb-4">
- <h2
- className="text-lg font-semibold"
- style={{ color: 'var(--text-primary)' }}
- >
- Upload New Image
- </h2>
- <button
- onClick={() => setShowUploader(false)}
- className="transition-colors"
- style={{ color: 'var(--text-muted)' }}
- >
- <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
- </svg>
- </button>
- </div>
- {uploadError && (
- <div className="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg text-red-700 dark:text-red-400 text-sm">
- {uploadError}
- </div>
- )}
- <ImageUploader
- onUpload={handleUpload}
- isUploading={isUploading}
- showExpiry={false}
- showDownloadToggle={false}
- compact
- />
- </div>
- )}
- {/* Error message */}
- {error && (
- <div className="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg text-red-700 dark:text-red-400">
- {error}
- </div>
- )}
- {/* Image grid */}
- <ImageGrid
- images={images}
- onDelete={handleDelete}
- isLoading={isLoading}
- emptyMessage="No images uploaded yet. Click 'Upload Image' to get started."
- />
- </div>
- );
- }
|