Implement photo upload enhancements

This commit is contained in:
gpt-engineer-app[bot]
2025-09-29 17:13:17 +00:00
parent 343d9c934c
commit 1542683456
4 changed files with 528 additions and 62 deletions

View File

@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
import { UppyPhotoUpload } from './UppyPhotoUpload';
import { PhotoCaptionEditor, PhotoWithCaption } from './PhotoCaptionEditor';
import { supabase } from '@/integrations/supabase/client';
import { useAuth } from '@/hooks/useAuth';
import { useToast } from '@/hooks/use-toast';
@@ -24,14 +25,28 @@ export function UppyPhotoSubmissionUpload({
rideId,
}: UppyPhotoSubmissionUploadProps) {
const [title, setTitle] = useState('');
const [caption, setCaption] = useState('');
const [uploadedUrls, setUploadedUrls] = useState<string[]>([]);
const [description, setDescription] = useState('');
const [photos, setPhotos] = useState<PhotoWithCaption[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
const { user } = useAuth();
const { toast } = useToast();
const handleUploadComplete = (urls: string[]) => {
setUploadedUrls(urls);
// Convert URLs to photo objects with empty captions
const newPhotos: PhotoWithCaption[] = urls.map((url, index) => ({
url,
caption: '',
order: photos.length + index,
}));
setPhotos(prev => [...prev, ...newPhotos]);
};
const handlePhotosChange = (updatedPhotos: PhotoWithCaption[]) => {
setPhotos(updatedPhotos);
};
const handleRemovePhoto = (index: number) => {
setPhotos(prev => prev.filter((_, i) => i !== index));
};
const handleSubmit = async () => {
@@ -44,7 +59,7 @@ export function UppyPhotoSubmissionUpload({
return;
}
if (uploadedUrls.length === 0) {
if (photos.length === 0) {
toast({
variant: 'destructive',
title: 'No Photos',
@@ -70,9 +85,11 @@ export function UppyPhotoSubmissionUpload({
submission_type: 'photo',
content: {
title: title.trim(),
caption: caption.trim(),
photos: uploadedUrls.map((url, index) => ({
url,
description: description.trim(),
photos: photos.map((photo, index) => ({
url: photo.url,
caption: photo.caption.trim(),
title: photo.title?.trim(),
order: index,
})),
context: {
@@ -97,8 +114,8 @@ export function UppyPhotoSubmissionUpload({
// Reset form
setTitle('');
setCaption('');
setUploadedUrls([]);
setDescription('');
setPhotos([]);
onSubmissionComplete?.();
} catch (error) {
console.error('Submission error:', error);
@@ -172,29 +189,29 @@ export function UppyPhotoSubmissionUpload({
</div>
<div className="space-y-2">
<Label htmlFor="caption" className="text-base font-medium">
Caption
<Label htmlFor="description" className="text-base font-medium">
Description
</Label>
<Textarea
id="caption"
value={caption}
onChange={(e) => setCaption(e.target.value)}
placeholder="Add a description or story about these photos..."
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Add a general description about these photos..."
maxLength={500}
rows={3}
className="transition-all duration-200 focus:ring-2 focus:ring-primary/20 resize-none"
/>
<p className="text-sm text-muted-foreground">
{caption.length}/500 characters
{description.length}/500 characters
</p>
</div>
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label className="text-base font-medium">Photos *</Label>
{uploadedUrls.length > 0 && (
{photos.length > 0 && (
<Badge variant="secondary" className="text-xs">
{uploadedUrls.length} photo{uploadedUrls.length !== 1 ? 's' : ''} selected
{photos.length} photo{photos.length !== 1 ? 's' : ''} selected
</Badge>
)}
</div>
@@ -204,17 +221,30 @@ export function UppyPhotoSubmissionUpload({
maxSizeMB={25}
metadata={metadata}
variant="public"
showPreview={true}
showPreview={false}
size="default"
enableDragDrop={true}
/>
</div>
{photos.length > 0 && (
<>
<Separator />
<PhotoCaptionEditor
photos={photos}
onPhotosChange={handlePhotosChange}
onRemovePhoto={handleRemovePhoto}
maxCaptionLength={200}
/>
</>
)}
<Separator />
<div className="space-y-4">
<Button
onClick={handleSubmit}
disabled={isSubmitting || !title.trim() || uploadedUrls.length === 0}
disabled={isSubmitting || !title.trim() || photos.length === 0}
className="w-full h-12 text-base font-medium photo-upload-trigger"
size="lg"
>
@@ -226,7 +256,7 @@ export function UppyPhotoSubmissionUpload({
) : (
<div className="flex items-center gap-2">
<CheckCircle className="w-5 h-5" />
Submit {uploadedUrls.length} Photo{uploadedUrls.length !== 1 ? 's' : ''}
Submit {photos.length} Photo{photos.length !== 1 ? 's' : ''}
</div>
)}
</Button>