import React, {useEffect, useState} from 'react'; import {getJson, patchJson} from '../api'; import CropPicker from './CropPicker'; import Modal from './Modal'; import StarRating from './StarRating'; function humanize(field) { return field.replace(/_/g, ' ').replace(/^./, (c) => c.toUpperCase()); } function errorMessages(status, data) { if (status === 422 && data && data.errors) { const messages = Object.entries(data.errors).flatMap(([field, list]) => list.map((m) => `${humanize(field)} ${m}`)); if (messages.length > 0) return messages; } if (status === 401) return ['Please sign in again to save this planting.']; if (status === 403) return ['You can\'t change this planting.']; return ['Something went wrong saving that. Please try again.']; } // The same fields as the planting edit page, in a dialog over the garden list. // It loads the planting's current values from /plantings/:slug/edit.json, saves // with PATCH, and hands the refreshed garden card to onSaved, so the list // updates in place and the page is never left. export default function EditPlantingModal({planting, onClose, onSaved}) { const [form, setForm] = useState(null); // {planting, planted_from_values, sunniness_values} const [values, setValues] = useState(null); const [loadError, setLoadError] = useState(false); const [changingCrop, setChangingCrop] = useState(false); const [saving, setSaving] = useState(false); const [errors, setErrors] = useState([]); const cropName = planting.crop.name; useEffect(() => { const controller = new AbortController(); (async () => { try { const {ok, data} = await getJson(`${planting.url}/edit.json`, {signal: controller.signal}); if (!ok) throw new Error('load failed'); setForm(data); setValues(data.planting); } catch (error) { if (error.name !== 'AbortError') setLoadError(true); } })(); return () => controller.abort(); }, [planting.url]); const set = (field) => (event) => { const {type, checked, value} = event.target; setValues((current) => ({...current, [field]: type === 'checkbox' ? checked : value})); }; // As the edit page does: un-ticking "finished" clears the finished date. function setFinished(event) { const finished = event.target.checked; setValues((current) => ({...current, finished, finished_at: finished ? current.finished_at : ''})); } async function save(event) { event.preventDefault(); setSaving(true); setErrors([]); const {crop, planted_at: plantedAt, planted_from: plantedFrom, sunniness, quantity, overall_rating: rating, description, finished, finished_at: finishedAt, failed} = values; const attributes = { crop_id: crop.id, planted_at: plantedAt, planted_from: plantedFrom, sunniness, quantity, overall_rating: rating, description, finished, finished_at: finishedAt, failed, }; try { const {ok, status, data} = await patchJson(planting.url, {planting: attributes}); 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 titleId = `edit-planting-title-${planting.id}`; return ( {loadError && (
Couldn’t load this planting. Please close this and try again.
)} {!loadError && !values && (