({ field, onSave, onDelete, onClose }: FieldEditDialogProps)
| 19 | } |
| 20 | |
| 21 | const FieldEditDialog = ({ field, onSave, onDelete, onClose }: FieldEditDialogProps) => { |
| 22 | const [name, setName] = useState(field.name); |
| 23 | const [crop, setCrop] = useState(field.crop); |
| 24 | const [area, setArea] = useState(String(haToAcres(field.area))); |
| 25 | const [location, setLocation] = useState(field.location); |
| 26 | const [color, setColor] = useState(field.color); |
| 27 | const [group, setGroup] = useState(field.group || ""); |
| 28 | const [cropSearch, setCropSearch] = useState(""); |
| 29 | const [showCropDropdown, setShowCropDropdown] = useState(false); |
| 30 | |
| 31 | const filteredCrops = cropSearch |
| 32 | ? CROP_OPTIONS.filter(c => c.name.toLowerCase().includes(cropSearch.toLowerCase()) || c.category.toLowerCase().includes(cropSearch.toLowerCase())) |
| 33 | : CROP_OPTIONS; |
| 34 | |
| 35 | const groupedCrops = CROP_CATEGORIES.reduce((acc, cat) => { |
| 36 | const crops = filteredCrops.filter(c => c.category === cat); |
| 37 | if (crops.length > 0) acc[cat] = crops; |
| 38 | return acc; |
| 39 | }, {} as Record<string, typeof CROP_OPTIONS>); |
| 40 | |
| 41 | const handleSave = () => { |
| 42 | const areaAcres = parseFloat(area) || haToAcres(field.area); |
| 43 | const areaHa = Math.round((areaAcres / 2.47105) * 10) / 10; |
| 44 | onSave({ ...field, name, crop, cropEmoji: "", area: areaHa, location, color, group: group || undefined }); |
| 45 | }; |
| 46 | |
| 47 | return ( |
| 48 | <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm pb-[env(safe-area-inset-bottom)]"> |
| 49 | <div className="bg-card rounded-xl border border-border p-5 w-80 space-y-4 shadow-2xl animate-fade-in mx-[5px] max-h-[85vh] overflow-y-auto mb-16 sm:mb-0"> |
| 50 | <div className="flex items-center justify-between"> |
| 51 | <h3 className="text-sm font-semibold text-foreground">Edit Region</h3> |
| 52 | <button onClick={onClose} className="text-muted-foreground hover:text-foreground transition-colors"><X className="w-4 h-4" /></button> |
| 53 | </div> |
| 54 | |
| 55 | <div> |
| 56 | <label className="text-xs text-muted-foreground block mb-1">Region Name</label> |
| 57 | <input type="text" value={name} onChange={(e) => setName(e.target.value)} |
| 58 | className="w-full bg-secondary/50 border border-border rounded-lg px-3 py-2 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-ring" /> |
| 59 | </div> |
| 60 | |
| 61 | <div className="relative"> |
| 62 | <label className="text-xs text-muted-foreground block mb-1">Crop / Land Use</label> |
| 63 | <button type="button" onClick={() => setShowCropDropdown(!showCropDropdown)} |
| 64 | className="w-full bg-secondary/50 border border-border rounded-lg px-3 py-2 text-sm text-foreground text-left focus:outline-none focus:ring-1 focus:ring-ring flex items-center justify-between"> |
| 65 | <span>{crop}</span><span className="text-muted-foreground text-xs">▼</span> |
| 66 | </button> |
| 67 | {showCropDropdown && ( |
| 68 | <div className="absolute top-full mt-1 left-0 right-0 bg-card border border-border rounded-lg shadow-xl z-30 max-h-56 overflow-y-auto"> |
| 69 | <div className="sticky top-0 bg-card p-2 border-b border-border"> |
| 70 | <div className="relative"> |
| 71 | <input type="text" value={cropSearch} onChange={e => setCropSearch(e.target.value)} placeholder="Search crops..." |
| 72 | className="w-full bg-secondary/50 border border-border rounded-md px-3 py-1.5 pr-8 text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring" autoFocus /> |
| 73 | <Search className="absolute right-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" /> |
| 74 | </div> |
| 75 | </div> |
| 76 | {Object.entries(groupedCrops).map(([category, crops]) => ( |
| 77 | <div key={category}> |
| 78 | <div className="px-3 py-1.5 text-[10px] font-semibold text-muted-foreground uppercase tracking-wider bg-accent/20">{category}</div> |
nothing calls this directly
no test coverage detected