DashboardPage.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { useState } from 'react';
  2. import { useImages } from '../hooks/useImages';
  3. import { USER_BUCKET } from '../config';
  4. import ImageGrid from '../components/ImageGrid';
  5. import ImageUploader from '../components/ImageUploader';
  6. import type { ImageFile, UploadOptions } from '../types';
  7. export default function DashboardPage() {
  8. const { images, isLoading, error, uploadImage, deleteImage, fetchImages } = useImages(USER_BUCKET);
  9. const [isUploading, setIsUploading] = useState(false);
  10. const [showUploader, setShowUploader] = useState(false);
  11. const [uploadError, setUploadError] = useState<string | null>(null);
  12. const handleUpload = async (file: File, options: UploadOptions) => {
  13. setIsUploading(true);
  14. setUploadError(null);
  15. try {
  16. await uploadImage(file, options);
  17. setShowUploader(false);
  18. } catch (err) {
  19. setUploadError(err instanceof Error ? err.message : 'Upload failed');
  20. } finally {
  21. setIsUploading(false);
  22. }
  23. };
  24. const handleDelete = async (image: ImageFile) => {
  25. try {
  26. await deleteImage(image);
  27. } catch (err) {
  28. alert(err instanceof Error ? err.message : 'Delete failed');
  29. }
  30. };
  31. return (
  32. <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
  33. {/* Header */}
  34. <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-8">
  35. <div>
  36. <h1
  37. className="text-2xl font-bold"
  38. style={{ color: 'var(--text-primary)' }}
  39. >
  40. My Images
  41. </h1>
  42. <p style={{ color: 'var(--text-secondary)' }}>Manage your uploaded images</p>
  43. </div>
  44. <div className="flex gap-3">
  45. <button
  46. onClick={() => fetchImages()}
  47. className="btn btn-secondary flex items-center gap-2"
  48. >
  49. <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  50. <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" />
  51. </svg>
  52. Refresh
  53. </button>
  54. <button
  55. onClick={() => setShowUploader(!showUploader)}
  56. className="btn btn-primary flex items-center gap-2"
  57. >
  58. <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  59. <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
  60. </svg>
  61. Upload Image
  62. </button>
  63. </div>
  64. </div>
  65. {/* Upload section */}
  66. {showUploader && (
  67. <div className="card p-6 mb-8">
  68. <div className="flex justify-between items-center mb-4">
  69. <h2
  70. className="text-lg font-semibold"
  71. style={{ color: 'var(--text-primary)' }}
  72. >
  73. Upload New Image
  74. </h2>
  75. <button
  76. onClick={() => setShowUploader(false)}
  77. className="transition-colors"
  78. style={{ color: 'var(--text-muted)' }}
  79. >
  80. <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  81. <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
  82. </svg>
  83. </button>
  84. </div>
  85. {uploadError && (
  86. <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">
  87. {uploadError}
  88. </div>
  89. )}
  90. <ImageUploader
  91. onUpload={handleUpload}
  92. isUploading={isUploading}
  93. showExpiry={false}
  94. showDownloadToggle={false}
  95. compact
  96. />
  97. </div>
  98. )}
  99. {/* Error message */}
  100. {error && (
  101. <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">
  102. {error}
  103. </div>
  104. )}
  105. {/* Image grid */}
  106. <ImageGrid
  107. images={images}
  108. onDelete={handleDelete}
  109. isLoading={isLoading}
  110. emptyMessage="No images uploaded yet. Click 'Upload Image' to get started."
  111. />
  112. </div>
  113. );
  114. }