import { useEffect, useMemo, useState } from 'react' import { X, Camera } from 'lucide-react' import type { Category, Location, Task, Priority, AppConfig, Asset } from '../types' import { PRIORITIES, PRIORITY_LABELS } from '../types' import { createTask, fetchTasks, uploadTaskPhoto, fetchAssets } from '../api' import AssigneeSelect, { type Assignment } from './AssigneeSelect' import { PriorityBadge, StatusBadge } from './shared' export default function NewTaskModal({ categories, locations, config, onClose, onCreated }: { categories: Category[] locations: Location[] config: AppConfig | null onClose: () => void onCreated: () => void }) { const [title, setTitle] = useState('') const [description, setDescription] = useState('') const [locationId, setLocationId] = useState('') const [assetId, setAssetId] = useState('') const [priority, setPriority] = useState('medium') const [unusable, setUnusable] = useState(false) const [dueDate, setDueDate] = useState('') const [files, setFiles] = useState([]) const [assets, setAssets] = useState([]) const [existing, setExisting] = useState([]) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const [assignment, setAssignment] = useState({ assigned_type: (config?.default_assigned_type as Assignment['assigned_type']) || 'staff', assigned_to: config?.default_assignee || null, assigned_to_name: config?.default_assignee_name || config?.default_assignee || null, contractor_id: config?.default_contractor_id ?? null, }) const locationAssets = useMemo( () => assets.filter(a => a.location_id === locationId), [assets, locationId] ) useEffect(() => { fetchAssets().then(setAssets).catch(() => {}) }, []) // Duplicate hint: existing open tasks at the chosen location useEffect(() => { if (!locationId) { setExisting([]); return } fetchTasks({ location_id: locationId as number }).then(setExisting).catch(() => setExisting([])) }, [locationId]) const grouped = useMemo(() => categories.map(c => ({ category: c, locations: locations.filter(l => l.category_id === c.id && l.active), })).filter(g => g.locations.length), [categories, locations]) async function submit() { if (!title.trim() || !locationId) { setError('Title and location are required'); return } setSaving(true) setError(null) try { const task = await createTask({ title: title.trim(), description: description.trim() || null, location_id: locationId, asset_id: assetId || null, priority, unusable, due_date: dueDate || null, assigned_type: assignment.assigned_type, assigned_to: assignment.assigned_to, assigned_to_name: assignment.assigned_to_name, contractor_id: assignment.contractor_id, }) for (const file of files) { await uploadTaskPhoto(task.id, file, 'report').catch(() => {}) } onCreated() onClose() } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create task') } finally { setSaving(false) } } return (
e.stopPropagation()}>

Report a fault

{error &&
{error}
}
setTitle(e.target.value)} placeholder="e.g. Shower dripping" autoFocus />
{existing.length > 0 && (
Already open at this location: {existing.slice(0, 4).map(t => (
{t.title}
))}
)} {locationAssets.length > 0 && (
)}