import { useState } from 'react'; import { Camera, Upload, Loader2, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent } from '@/components/ui/card'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useNostrPublish } from '@/hooks/useNostrPublish'; import { useUploadFile } from '@/hooks/useUploadFile'; import { useToast } from '@/hooks/useToast'; import { useQueryClient } from '@tanstack/react-query'; import { PHOTO_CONTRIBUTION_KIND } from '@/hooks/useSpotContributions'; import { SKATE_SPOT_KIND } from '@/lib/types'; import { LoginArea } from '@/components/auth/LoginArea'; interface AddPhotoToSpotProps { spotPubkey: string; spotIdentifier: string; spotTitle: string; } export function AddPhotoToSpot({ spotPubkey, spotIdentifier, spotTitle }: AddPhotoToSpotProps) { const { user } = useCurrentUser(); const { mutateAsync: publishEvent, isPending: isPublishing } = useNostrPublish(); const { mutateAsync: uploadFile, isPending: isUploading } = useUploadFile(); const { toast } = useToast(); const queryClient = useQueryClient(); const [open, setOpen] = useState(false); const [caption, setCaption] = useState(''); const [uploadedImage, setUploadedImage] = useState<{ url: string; mimeType?: string } | null>(null); const spotRef = `${SKATE_SPOT_KIND}:${spotPubkey}:${spotIdentifier}`; const handleImageUpload = async (e: React.ChangeEvent) => { const files = e.target.files; if (!files || files.length === 0) return; try { const file = files[0]; const tags = await uploadFile(file); const url = tags.find(([name]) => name === 'url')?.[1]; const mimeType = tags.find(([name]) => name === 'm')?.[1]; if (url) { setUploadedImage({ url, mimeType }); toast({ title: 'Photo uploaded', description: 'Add a caption and submit to contribute!', }); } } catch (error) { toast({ title: 'Upload failed', description: error instanceof Error ? error.message : 'Failed to upload photo', variant: 'destructive', }); } e.target.value = ''; }; const handleSubmit = async () => { if (!uploadedImage) { toast({ title: 'No photo', description: 'Please upload a photo first.', variant: 'destructive', }); return; } try { // Create kind 1063 file metadata event const eventTags: string[][] = [ ['url', uploadedImage.url], ['a', spotRef], ['alt', `Community photo for ${spotTitle}`], ]; if (uploadedImage.mimeType) { eventTags.push(['m', uploadedImage.mimeType]); } await publishEvent({ kind: PHOTO_CONTRIBUTION_KIND, content: caption.trim(), tags: eventTags, }); toast({ title: 'Photo contributed!', description: 'Your photo has been added to this spot.', }); // Reset and close setCaption(''); setUploadedImage(null); setOpen(false); // Invalidate the photos query queryClient.invalidateQueries({ queryKey: ['spot-photos', spotPubkey, spotIdentifier] }); } catch (error) { toast({ title: 'Failed to contribute', description: error instanceof Error ? error.message : 'Something went wrong', variant: 'destructive', }); } }; const handleClose = () => { setOpen(false); setCaption(''); setUploadedImage(null); }; return ( Add Photo to Spot Contribute a photo to help others discover this spot. {!user ? (

Log in to contribute photos

) : (
{/* Photo upload area */} {uploadedImage ? (
Uploaded
) : ( )} {/* Caption */}