import React, {useState} from 'react'; import {patchJson} from '../api'; import {formatDate} from '../dates'; import Modal from './Modal'; // "2026-09-21" a number of days earlier (or later, if negative), as // "2026-09-20". Worked out in UTC so the browser's time zone can't shift it. function daysBefore(iso, days) { const [year, month, day] = iso.split('-').map(Number); return new Date(Date.UTC(year, month - 1, day - days)).toISOString().slice(0, 10); } function errorMessages(status, data) { if (status === 422 && data && data.errors) { const messages = Object.entries(data.errors).flatMap(([field, list]) => list.map((m) => `${field.replace(/_/g, ' ').replace(/^./, (c) => c.toUpperCase())} ${m}`)); if (messages.length > 0) return messages; } if (status === 401) return ['Please sign in again to mark this as finished.']; if (status === 403) return ['You can\'t change this planting.']; return ['Something went wrong saving that. Please try again.']; } // Marking a planting finished, from a garden card, as a dialog over the list: // one question, when it finished, which is today unless you say otherwise. It // saves with PATCH /plantings/:slug.json and hands the garden's refreshed card // to onSaved (the planting then leaves the list), so the page is never left. // // The server needs the finish to come after the planting, so today is not offered // for a planting made today, and the date box starts the day after it was planted. export default function MarkFinishedModal({planting, iconUrl, onClose, onSaved}) { const {today, planted_at: plantedOn} = planting; const earliest = plantedOn ? daysBefore(plantedOn, -1) : undefined; const todayAllowed = !plantedOn || today > plantedOn; const [when, setWhen] = useState(todayAllowed ? 'today' : 'other'); const [customDate, setCustomDate] = useState(todayAllowed ? today : earliest); const [saving, setSaving] = useState(false); const [errors, setErrors] = useState([]); // The server's "today" is the one that counts, not the browser's. const finishedAt = when === 'today' ? today : customDate; const choices = [todayAllowed && ['today', 'Today'], ['other', 'Enter date']].filter(Boolean); async function save(event) { event.preventDefault(); setSaving(true); setErrors([]); try { const {ok, status, data} = await patchJson(planting.url, {planting: {finished: true, finished_at: finishedAt}}); if (ok) { onSaved(data.garden); // closes this dialog return; } setErrors(errorMessages(status, data)); } catch (error) { setErrors(['Couldn\'t reach the server. Please try again.']); } setSaving(false); } const title = ( <> {iconUrl && } Mark {planting.crop.name} as finished ); return (
{errors.length > 0 && (