mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 05:51:23 -05:00
feat: Implement photo processing logic
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Camera, Upload, LogIn } from 'lucide-react';
|
||||
import { Camera, Upload, LogIn, Settings } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { UppyPhotoSubmissionUpload } from '@/components/upload/UppyPhotoSubmissionUpload';
|
||||
import { PhotoManagementDialog } from '@/components/upload/PhotoManagementDialog';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { EntityPhotoGalleryProps } from '@/types/submissions';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
|
||||
interface Photo {
|
||||
id: string;
|
||||
@@ -25,8 +27,10 @@ export function EntityPhotoGallery({
|
||||
}: EntityPhotoGalleryProps) {
|
||||
const { user } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const { isModerator } = useUserRole();
|
||||
const [photos, setPhotos] = useState<Photo[]>([]);
|
||||
const [showUpload, setShowUpload] = useState(false);
|
||||
const [showManagement, setShowManagement] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,42 +39,28 @@ export function EntityPhotoGallery({
|
||||
|
||||
const fetchPhotos = async () => {
|
||||
try {
|
||||
// Fetch approved photo submissions for this entity
|
||||
// Use separate queries for each legacy field to avoid JSONB UUID parsing issues
|
||||
let query = supabase
|
||||
.from('content_submissions')
|
||||
.select('id, content, created_at, user_id')
|
||||
.eq('status', 'approved')
|
||||
.eq('submission_type', 'photo')
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(50);
|
||||
|
||||
// Apply entity-specific filters using proper JSONB text casting
|
||||
const { data: submissions, error } = await query.or(
|
||||
`content->>entity_id.eq.${entityId},content->>park_id.eq.${entityId},content->>ride_id.eq.${entityId},content->>company_id.eq.${entityId}`
|
||||
);
|
||||
// Fetch photos directly from the photos table
|
||||
const { data: photoData, error } = await supabase
|
||||
.from('photos')
|
||||
.select('id, cloudflare_image_url, title, caption, submitted_by, created_at, order_index')
|
||||
.eq('entity_type', entityType)
|
||||
.eq('entity_id', entityId)
|
||||
.order('order_index', { ascending: true })
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Extract photos from submissions
|
||||
const extractedPhotos: Photo[] = [];
|
||||
submissions?.forEach((submission) => {
|
||||
const content = submission.content as any;
|
||||
if (content.photos && Array.isArray(content.photos)) {
|
||||
content.photos.forEach((photo: any) => {
|
||||
extractedPhotos.push({
|
||||
id: `${submission.id}-${photo.order}`,
|
||||
url: photo.url,
|
||||
caption: photo.caption,
|
||||
title: photo.title,
|
||||
user_id: submission.user_id,
|
||||
created_at: submission.created_at,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
// Map to Photo interface
|
||||
const mappedPhotos: Photo[] = photoData?.map((photo) => ({
|
||||
id: photo.id,
|
||||
url: photo.cloudflare_image_url,
|
||||
caption: photo.caption || undefined,
|
||||
title: photo.title || undefined,
|
||||
user_id: photo.submitted_by,
|
||||
created_at: photo.created_at,
|
||||
})) || [];
|
||||
|
||||
setPhotos(extractedPhotos);
|
||||
setPhotos(mappedPhotos);
|
||||
} catch (error) {
|
||||
console.error('Error fetching photos:', error);
|
||||
} finally {
|
||||
@@ -123,7 +113,7 @@ export function EntityPhotoGallery({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Upload Button */}
|
||||
{/* Header with Upload and Management Buttons */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Photo Gallery</h3>
|
||||
@@ -131,21 +121,38 @@ export function EntityPhotoGallery({
|
||||
Share your photos of {entityName}
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={handleUploadClick} className="gap-2">
|
||||
{user ? (
|
||||
<>
|
||||
<Upload className="w-4 h-4" />
|
||||
Upload Photos
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LogIn className="w-4 h-4" />
|
||||
Sign in to Upload
|
||||
</>
|
||||
<div className="flex gap-2">
|
||||
{isModerator && photos.length > 0 && (
|
||||
<Button onClick={() => setShowManagement(true)} variant="outline" className="gap-2">
|
||||
<Settings className="w-4 h-4" />
|
||||
Manage
|
||||
</Button>
|
||||
)}
|
||||
</Button>
|
||||
<Button onClick={handleUploadClick} className="gap-2">
|
||||
{user ? (
|
||||
<>
|
||||
<Upload className="w-4 h-4" />
|
||||
Upload Photos
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LogIn className="w-4 h-4" />
|
||||
Sign in to Upload
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Photo Management Dialog */}
|
||||
<PhotoManagementDialog
|
||||
entityId={entityId}
|
||||
entityType={entityType}
|
||||
open={showManagement}
|
||||
onOpenChange={setShowManagement}
|
||||
onUpdate={fetchPhotos}
|
||||
/>
|
||||
|
||||
{/* Photo Grid */}
|
||||
{photos.length > 0 ? (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user