Skip to content

Commit 62105e1

Browse files
committed
replace date range text input with date pickers and fix yield field validation
- split single dateRange text field into Start Date / End Date inputs with type="date" - end date min is set to start date to prevent invalid ranges - colorScheme: dark applied to date inputs for dark mode calendar picker - yield field changed from text to type="number" min="0" to block negative values - dates format to "Mon D - Mon D" string on submit for display consistency
1 parent 3101ffb commit 62105e1

1 file changed

Lines changed: 69 additions & 21 deletions

File tree

src/components/KitchenandInventory/GardenManagement/GardenManagement.jsx

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,14 @@ const calendarSections = [
119119

120120
// --- Add Event Modal ---
121121

122-
const eventShape = PropTypes.shape({
123-
crop: PropTypes.string,
124-
dateRange: PropTypes.string,
125-
location: PropTypes.string,
126-
yield: PropTypes.string,
127-
status: PropTypes.string,
128-
});
122+
const formatDateDisplay = dateStr => {
123+
if (!dateStr) return '';
124+
const [year, month, day] = dateStr.split('-').map(Number);
125+
return new Date(year, month - 1, day).toLocaleDateString('en-US', {
126+
month: 'short',
127+
day: 'numeric',
128+
});
129+
};
129130

130131
function AddEventModal({ sectionTitle, newEvent, setNewEvent, darkMode, onClose, onAdd }) {
131132
const dm = darkMode ? styles.dark : '';
@@ -145,15 +146,29 @@ function AddEventModal({ sectionTitle, newEvent, setNewEvent, darkMode, onClose,
145146
placeholder="e.g. Tomatoes"
146147
/>
147148

148-
<label htmlFor="gm-dateRange" className={`${styles.modalLabel} ${dm}`}>
149-
Date Range *
149+
<label htmlFor="gm-fromDate" className={`${styles.modalLabel} ${dm}`}>
150+
Start Date *
150151
</label>
151152
<input
152-
id="gm-dateRange"
153+
id="gm-fromDate"
154+
type="date"
153155
className={`${styles.modalInput} ${dm}`}
154-
value={newEvent.dateRange}
155-
onChange={e => setNewEvent({ ...newEvent, dateRange: e.target.value })}
156-
placeholder="e.g. Jun 1 - Jun 15"
156+
value={newEvent.fromDate}
157+
onChange={e => setNewEvent({ ...newEvent, fromDate: e.target.value })}
158+
style={darkMode ? { colorScheme: 'dark' } : {}}
159+
/>
160+
161+
<label htmlFor="gm-toDate" className={`${styles.modalLabel} ${dm}`}>
162+
End Date *
163+
</label>
164+
<input
165+
id="gm-toDate"
166+
type="date"
167+
className={`${styles.modalInput} ${dm}`}
168+
value={newEvent.toDate}
169+
min={newEvent.fromDate || undefined}
170+
onChange={e => setNewEvent({ ...newEvent, toDate: e.target.value })}
171+
style={darkMode ? { colorScheme: 'dark' } : {}}
157172
/>
158173

159174
<label htmlFor="gm-location" className={`${styles.modalLabel} ${dm}`}>
@@ -168,14 +183,17 @@ function AddEventModal({ sectionTitle, newEvent, setNewEvent, darkMode, onClose,
168183
/>
169184

170185
<label htmlFor="gm-yield" className={`${styles.modalLabel} ${dm}`}>
171-
Est. Yield
186+
Est. Yield (kg)
172187
</label>
173188
<input
174189
id="gm-yield"
190+
type="number"
191+
min="0"
192+
step="0.1"
175193
className={`${styles.modalInput} ${dm}`}
176-
value={newEvent.yield}
177-
onChange={e => setNewEvent({ ...newEvent, yield: e.target.value })}
178-
placeholder="e.g. Est. 40 kg"
194+
value={newEvent.yieldKg}
195+
onChange={e => setNewEvent({ ...newEvent, yieldKg: e.target.value })}
196+
placeholder="e.g. 40"
179197
/>
180198

181199
<label htmlFor="gm-status" className={`${styles.modalLabel} ${dm}`}>
@@ -206,7 +224,14 @@ function AddEventModal({ sectionTitle, newEvent, setNewEvent, darkMode, onClose,
206224

207225
AddEventModal.propTypes = {
208226
sectionTitle: PropTypes.string,
209-
newEvent: eventShape.isRequired,
227+
newEvent: PropTypes.shape({
228+
crop: PropTypes.string,
229+
fromDate: PropTypes.string,
230+
toDate: PropTypes.string,
231+
location: PropTypes.string,
232+
yieldKg: PropTypes.string,
233+
status: PropTypes.string,
234+
}).isRequired,
210235
setNewEvent: PropTypes.func.isRequired,
211236
darkMode: PropTypes.bool,
212237
onClose: PropTypes.func.isRequired,
@@ -215,7 +240,14 @@ AddEventModal.propTypes = {
215240

216241
// --- Main Component ---
217242

218-
const emptyEvent = { crop: '', dateRange: '', location: '', yield: '', status: 'upcoming' };
243+
const emptyEvent = {
244+
crop: '',
245+
fromDate: '',
246+
toDate: '',
247+
location: '',
248+
yieldKg: '',
249+
status: 'upcoming',
250+
};
219251

220252
function GardenManagement() {
221253
const darkMode = useSelector(state => state.theme.darkMode);
@@ -232,11 +264,27 @@ function GardenManagement() {
232264
const closeModal = () => setAddModal(null);
233265

234266
const handleAddEvent = () => {
235-
if (!newEvent.crop || !newEvent.dateRange || !newEvent.location) return;
267+
if (!newEvent.crop || !newEvent.fromDate || !newEvent.toDate || !newEvent.location) return;
268+
const from = formatDateDisplay(newEvent.fromDate);
269+
const to = formatDateDisplay(newEvent.toDate);
270+
const yieldDisplay = newEvent.yieldKg ? `Est. ${newEvent.yieldKg} kg` : '';
236271
setSections(prev =>
237272
prev.map(s => {
238273
if (s.id !== addModal) return s;
239-
return { ...s, events: [...s.events, { ...newEvent, id: Date.now() }] };
274+
return {
275+
...s,
276+
events: [
277+
...s.events,
278+
{
279+
id: Date.now(),
280+
crop: newEvent.crop,
281+
dateRange: `${from}${to}`,
282+
location: newEvent.location,
283+
yield: yieldDisplay,
284+
status: newEvent.status,
285+
},
286+
],
287+
};
240288
}),
241289
);
242290
closeModal();

0 commit comments

Comments
 (0)