import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '@clerk/clerk-react'; import { PhotoUpload, type PhotoMetadata } from './PhotoUpload'; import { LocationSelector } from './LocationSelector'; import { reportService } from '@/services/reportService'; import type { LitterType, QuantityLevel, LocationSource, Coordinates } from '@/types'; interface EnvironmentalConcern { type: string; severity: 'low' | 'medium' | 'high' | 'critical'; description: string; } interface FormData { photos: PhotoMetadata[]; location: Coordinates | null; locationSource: LocationSource | null; locationAccuracy?: number; litterType: LitterType | ''; quantity: QuantityLevel | ''; description: string; environmentalConcerns: EnvironmentalConcern[]; } interface FormErrors { photos?: string; location?: string; litterType?: string; quantity?: string; } const LITTER_TYPES: { value: LitterType; label: string; description: string }[] = [ { value: 'plastic', label: 'Plastic', description: 'Bottles, bags, packaging, microplastics' }, { value: 'metal', label: 'Metal', description: 'Cans, foil, wire, metal fragments' }, { value: 'glass', label: 'Glass', description: 'Bottles, broken glass, jars' }, { value: 'organic', label: 'Organic', description: 'Food waste, natural debris' }, { value: 'hazardous', label: 'Hazardous', description: 'Chemicals, batteries, medical waste' }, { value: 'other', label: 'Other', description: 'Mixed or unclassified litter' }, ]; const QUANTITY_LEVELS: { value: QuantityLevel; label: string; description: string }[] = [ { value: 'minimal', label: 'Minimal', description: '1-10 items, scattered' }, { value: 'moderate', label: 'Moderate', description: '11-50 items, noticeable' }, { value: 'significant', label: 'Significant', description: '51-200 items, concentrated' }, { value: 'severe', label: 'Severe', description: '200+ items, heavily polluted' }, ]; const CONCERN_TYPES = [ 'Wildlife hazard', 'Water contamination', 'Beach access blocked', 'Sharp objects', 'Chemical spill', 'Other', ]; export function ReportForm() { const navigate = useNavigate(); const { isSignedIn, isLoaded } = useAuth(); const [currentStep, setCurrentStep] = useState(1); const [formData, setFormData] = useState({ photos: [], location: null, locationSource: null, litterType: '', quantity: '', description: '', environmentalConcerns: [], }); const [errors, setErrors] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); const [submitError, setSubmitError] = useState(null); const [uploadProgress, setUploadProgress] = useState(''); const totalSteps = 4; const handlePhotosChange = (photos: PhotoMetadata[]) => { setFormData(prev => ({ ...prev, photos })); if (photos.length > 0 && errors.photos) { setErrors(prev => ({ ...prev, photos: undefined })); } }; const handleLocationChange = (location: Coordinates, source: LocationSource, accuracy?: number) => { setFormData(prev => ({ ...prev, location, locationSource: source, locationAccuracy: accuracy, })); if (errors.location) { setErrors(prev => ({ ...prev, location: undefined })); } }; const validateStep = (step: number): boolean => { const newErrors: FormErrors = {}; if (step === 1) { if (formData.photos.length === 0) { newErrors.photos = 'At least one photo is required'; } } if (step === 2) { if (!formData.location) { newErrors.location = 'Location is required'; } } if (step === 3) { if (!formData.litterType) { newErrors.litterType = 'Please select a litter type'; } if (!formData.quantity) { newErrors.quantity = 'Please select a quantity level'; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleNext = () => { if (validateStep(currentStep)) { setCurrentStep(prev => Math.min(prev + 1, totalSteps)); } }; const handleBack = () => { setCurrentStep(prev => Math.max(prev - 1, 1)); }; const handleSubmit = async () => { if (!validateStep(currentStep)) { return; } if (!formData.location || !formData.locationSource || !formData.litterType || !formData.quantity) { setSubmitError('Please complete all required fields'); return; } setIsSubmitting(true); setSubmitError(null); try { // Step 1: Upload photos setUploadProgress('Uploading photos...'); const photoUrls: string[] = []; for (let i = 0; i < formData.photos.length; i++) { const photo = formData.photos[i]; if (!photo) continue; setUploadProgress(`Uploading photo ${i + 1} of ${formData.photos.length}...`); const uploadResult = await reportService.uploadPhoto(photo.file); photoUrls.push(uploadResult.url); } // Step 2: Submit report setUploadProgress('Creating report...'); const reportData = { latitude: formData.location!.latitude, longitude: formData.location!.longitude, locationSource: formData.locationSource!, litterType: formData.litterType as LitterType, quantity: formData.quantity as QuantityLevel, description: formData.description || undefined, photoUrls, photoTimestamp: formData.photos[0]?.timestamp?.toISOString(), environmentalConcerns: formData.environmentalConcerns.length > 0 ? formData.environmentalConcerns.filter(c => c.type && c.description) : undefined, }; await reportService.createReport(reportData); setUploadProgress('Report submitted successfully!'); // Show success message setTimeout(() => { // Reset form setFormData({ photos: [], location: null, locationSource: null, litterType: '', quantity: '', description: '', environmentalConcerns: [], }); setCurrentStep(1); setUploadProgress(''); // Navigate to map page to see the new report navigate('/map'); }, 1500); } catch (error) { console.error('Error submitting report:', error); setSubmitError(error instanceof Error ? error.message : 'Failed to submit report. Please try again.'); setUploadProgress(''); } finally { setIsSubmitting(false); } }; const addEnvironmentalConcern = () => { setFormData(prev => ({ ...prev, environmentalConcerns: [ ...prev.environmentalConcerns, { type: '', severity: 'medium', description: '' }, ], })); }; const updateEnvironmentalConcern = (index: number, field: keyof EnvironmentalConcern, value: string) => { setFormData(prev => ({ ...prev, environmentalConcerns: prev.environmentalConcerns.map((concern, i) => i === index ? { ...concern, [field]: value } : concern ), })); }; const removeEnvironmentalConcern = (index: number) => { setFormData(prev => ({ ...prev, environmentalConcerns: prev.environmentalConcerns.filter((_, i) => i !== index), })); }; return (
{/* Authentication Warning */} {isLoaded && !isSignedIn && (

Authentication Required

You must be signed in to submit a report. Please{' '} sign in {' '} or{' '} create an account {' '} to continue.

)} {/* Progress Indicator */}
{[1, 2, 3, 4].map((step) => (
{step < currentStep ? ( ) : ( step )}
{step === 1 && 'Photos'} {step === 2 && 'Location'} {step === 3 && 'Details'} {step === 4 && 'Review'}
{step < totalSteps && (
)}
))}
{/* Form Content */}
{/* Step 1: Photos */} {currentStep === 1 && (

Upload Photos

Take or upload photos of the litter. Photos with GPS data will auto-populate the location.

{errors.photos && (

{errors.photos}

)}
)} {/* Step 2: Location */} {currentStep === 2 && (

Select Location

Confirm or select the location where the litter was found.

{errors.location && (

{errors.location}

)}
)} {/* Step 3: Litter Details */} {currentStep === 3 && (

Litter Details

Provide information about the type and quantity of litter.

{/* Litter Type */}
{LITTER_TYPES.map((type) => ( ))}
{errors.litterType && (

{errors.litterType}

)}
{/* Quantity Level */}
{QUANTITY_LEVELS.map((level, index) => ( ))}
{errors.quantity && (

{errors.quantity}

)}
{/* Description */}