MCPcopy Create free account
hub / github.com/Thanas-R/Virdis / FieldEditDialog

Function FieldEditDialog

src/components/FieldEditDialog.tsx:21–129  ·  view source on GitHub ↗
({ field, onSave, onDelete, onClose }: FieldEditDialogProps)

Source from the content-addressed store, hash-verified

19}
20
21const 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>

Callers

nothing calls this directly

Calls 1

haToAcresFunction · 0.90

Tested by

no test coverage detected