import React, {useEffect, useRef, useState} from 'react';
import {postJson} from '../api';
import {daysBefore, localToday} from '../dates';
import CropPicker from './CropPicker';
import Modal from './Modal';
import Steps from './Steps';
import WhenPicker from './WhenPicker';
const FIELD_NAMES = {crop: 'Crop', garden: 'Garden'};
const STEPS = ['Choose a crop', 'Confirm'];
const STEPS_WITH_GARDEN = ['Choose a crop', 'Which garden?', 'Confirm'];
function humanize(field) {
return FIELD_NAMES[field] || 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 === 403) return ['You can\'t plant in this garden.'];
if (status === 401) return ['Please sign in again to plant something.'];
return ['Something went wrong saving that. Please try again.'];
}
// "Add planting", as a dialog over the garden cards. Two steps: search
// for a crop and choose it, then confirm what you chose and it is planted in the
// card's garden (today unless you say otherwise, with no other details; those
// can be added later). On success it hands back the garden's updated card.
//
// Pass gardens, more than one, to ask which of them after the crop; the garden
// is then the one chosen. Otherwise it is planted in `garden`.
//
// Pass a crop to start on the confirm step with it already chosen; Change still
// goes back to the search.
export default function PlantSomethingModal({garden: fixedGarden, gardens = [], iconUrl, crop: chosenCrop = null, onClose, onCreated}) {
const askingGarden = gardens.length > 1;
const [garden, setGarden] = useState(askingGarden ? null : fixedGarden); // where it goes; null until chosen
const [crop, setCrop] = useState(chosenCrop); // chosen, waiting for confirmation
const [when, setWhen] = useState('today'); // today, yesterday, or other (a date you enter)
const [customDate, setCustomDate] = useState('');
const [saving, setSaving] = useState(false);
const [errors, setErrors] = useState([]);
const confirmButton = useRef(null);
// Once a crop is chosen the search goes away; Enter then confirms.
useEffect(() => {
if (crop && garden && confirmButton.current) confirmButton.current.focus();
}, [crop, garden]);
const today = localToday();
const plantedOn = {today, yesterday: daysBefore(today, 1), other: customDate}[when];
function chooseWhen(choice) {
setWhen(choice);
if (choice === 'other' && !customDate) setCustomDate(today);
}
async function confirm() {
setSaving(true);
setErrors([]);
try {
// Today is left to the server, which knows what day it is where it is.
const planting = {garden_id: garden.id, crop_id: crop.id, ...(when === 'today' ? {} : {planted_at: plantedOn})};
const {ok, status, data} = await postJson('/plantings.json', {planting});
if (ok) {
onCreated(data.garden, crop); // closes this dialog
return;
}
setErrors(errorMessages(status, data));
} catch (error) {
setErrors(['Couldn\'t reach the server. Please try again.']);
}
setSaving(false);
}
const title = (
<>
{iconUrl && }
Plant something{garden && ` in ${garden.name}`}
>
);
return (
{errors.length > 0 && (
{' '}
That didn’t work.
{errors.map((message) =>
{message}
)}
Your choice is kept, so you can press Plant it to try again.