import ResponsiveDialog from "common/ResponsiveDialog"; import { Bin, Field, HarvestYear } from "models"; import React, { useCallback } from "react"; import { useFieldAPI, useBinAPI, useHarvestYearAPI, useGlobalState } from "providers"; import { Box, Button, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, MenuItem, Radio, RadioGroup, TextField } from "@mui/material"; import { useState } from "react"; import { useEffect } from "react"; import { pond } from "protobuf-ts/pond"; import { useSnackbar } from "hooks"; import moment from "moment"; import GrainDescriber from "./GrainDescriber"; interface Props { activeBinSettings: pond.BinSettings; newGrainInventory: number; dialogControl: boolean; onClose(cancel?: boolean): void; afterUpdate?(secondBin?: Bin): void; } //this component is going to be deprecated by grain transaction export default function GrainInventory(props: Props) { const { activeBinSettings, newGrainInventory, dialogControl, onClose, afterUpdate } = props; const binAPI = useBinAPI(); const fieldAPI = useFieldAPI(); const hYearAPI = useHarvestYearAPI(); const [{ as }] = useGlobalState(); const [binIndex, setBinIndex] = useState(0); const [fieldIndex, setFieldIndex] = useState(-1); const [yearIndex, setYearIndex] = useState(0); const [bins, setBins] = useState([]); const [fields, setFields] = useState([]); const [hYears, setHYears] = useState>(new Map()); const [currentBushels, setCurrentBushels] = useState(0); const { openSnack } = useSnackbar(); const [increaseMode, setIncreaseMode] = useState<"correction" | "purchased" | "grown">( "correction" ); const [decreaseMode, setDecreaseMode] = useState<"correction" | "sold" | "moved">("correction"); useEffect(() => { if (activeBinSettings.inventory && dialogControl) { setCurrentBushels(activeBinSettings.inventory.grainBushels); } }, [activeBinSettings, dialogControl]); const loadBins = useCallback(() => { if (!dialogControl) return; binAPI .listBins(50, 0, "asc", "name", undefined, as) .then(resp => { setBins(resp.data.bins.map(b => Bin.any(b))); }) .catch(); }, [binAPI, as, dialogControl]); const loadHYears = useCallback(() => { if (fields.length > 0 && fieldIndex > -1) { hYearAPI.listHarvestYears(50, 0, "asc", "year", fields[fieldIndex].fieldName()).then(resp => { let tempMap = new Map(); resp.data.harvestYear.forEach(hy => { let tempHY = HarvestYear.any(hy); tempMap.set(tempHY.year(), tempHY); }); setHYears(tempMap); }); } }, [hYearAPI, fields, fieldIndex]); useEffect(() => { loadHYears(); }, [loadHYears]); useEffect(() => { loadBins(); fieldAPI .listFields(500, 0, "asc", "fieldName", undefined, as) .then(resp => { setFields(resp.data.fields.map(f => Field.any(f))); }) .catch(); }, [loadBins, fieldAPI, as]); const grainName = (bin: Bin) => { return bin.storage() === pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN ? GrainDescriber(bin.grain()).name : bin.customType(); }; const dialogContent = () => { if (newGrainInventory < currentBushels) { return ( } label="Correction" onChange={() => setDecreaseMode("correction")} /> {/* Doesnt Actually Do Anything yet */} {/* } label="Sold" onChange={() => setDecreaseMode("sold")} /> */} } label="Moved" onChange={() => setDecreaseMode("moved")} /> {decreaseMode === "moved" && ( setBinIndex(+e.target.value)}> {bins.map((option, i) => ( {option.name()} - {grainName(option)} ))} )} ); } else { return ( } label="Correction" onChange={() => setIncreaseMode("correction")} /> {/* Doesnt Actually Do Anything yet */} {/* } label="Purchased" onChange={() => setIncreaseMode("purchased")} /> */} } label="Grown" onChange={() => setIncreaseMode("grown")} /> {increaseMode === "grown" && ( setFieldIndex(+e.target.value)}> No Field Selected {fields.map((option, i) => ( {option.fieldName()} ))} setYearIndex(+e.target.value)} disabled={fieldIndex < 0}> New Harvest Year {Array.from(hYears.values()).length > 0 && Array.from(hYears.values()).map(option => ( {option.year()} ))} )} ); } }; const increaseInv = () => { let bin = activeBinSettings; let binInv = pond.BinInventory.fromObject({ ...bin.inventory }); if (binInv.grainBushels === 0 && bin.mode === pond.BinMode.BIN_MODE_NONE) { bin.mode = pond.BinMode.BIN_MODE_STORAGE; } binInv.grainBushels = newGrainInventory; if (fields.length > 0 && fieldIndex > -1) { if (fields[fieldIndex].crop() !== activeBinSettings.inventory?.grainType) { openSnack("Grain type of this bin does not match the Field"); return; } else if (yearIndex === 0 && hYears.has(moment().year())) { openSnack("Current year already exists for this field"); return; } binInv.grainSubtype = fields[fieldIndex].subtype(); } bin.inventory = binInv; binAPI .updateBin(activeBinSettings.key, bin) .then(() => { if (increaseMode === "grown") { if (yearIndex === 0) { let hy = HarvestYear.create(); hy.settings.field = fields[fieldIndex].fieldName(); hy.settings.grain = fields[fieldIndex].crop(); hy.settings.year = moment().year(); hy.settings.bushels = newGrainInventory - currentBushels; hYearAPI.addHarvestYear(hy.settings).then(resp => { loadHYears(); }); } else { let hy = hYears.get(yearIndex); if (hy) { hy.settings.bushels = hy.totalBushels() + (newGrainInventory - currentBushels); hYearAPI.updateHarvestYear(hy.key(), hy.settings).then(resp => { loadHYears(); }); } } } else if (increaseMode === "purchased") { } }) .catch(err => { openSnack("Failed to update grain inventory"); }) .finally(() => { if (afterUpdate) { loadBins(); afterUpdate(); } closeDialog(); }); }; const decreaseInv = () => { let binFrom = activeBinSettings; let binTo: Bin; let binFromInv = pond.BinInventory.fromObject({ ...binFrom.inventory }); if (decreaseMode === "moved") { //TODO-CS: re-think the logic for moving between bins since the addition of custom types, //possibly remove restrictions and just have a confirmation for the user to change the destination bins grain type binTo = bins[binIndex]; if (binTo.settings.inventory && binTo.settings.specs) { let binToInv = binTo.settings.inventory; //check to make sure the grain types of both bins are the same if (binFromInv.grainType !== binToInv.grainType) { if ( binToInv.grainType === pond.Grain.GRAIN_NONE || binToInv.grainType === pond.Grain.GRAIN_INVALID || binToInv.grainBushels < 1 ) { binTo.settings.inventory.grainType = binFromInv.grainType; } else { openSnack("Grain types of both bins must match"); return; } } //check if the other bin has enough space to move the grain let space = binTo.settings.specs.bushelCapacity - binTo.settings.inventory.grainBushels; if (space < currentBushels - newGrainInventory) { openSnack("Bin does not have enough space"); return; } binToInv.grainBushels = binToInv.grainBushels + (currentBushels - newGrainInventory); } } binFromInv.grainBushels = newGrainInventory; binFrom.inventory = binFromInv; binAPI .updateBin(activeBinSettings.key, binFrom) .then(() => { //update inventory of the bin that the grain was moved to if it was a decrease if (decreaseMode === "moved") { binAPI .updateBin(bins[binIndex].key(), binTo.settings) .then(() => { openSnack("Grain inventory updated"); }) .catch(err => { openSnack("Failed to update grain inventory"); }) .finally(() => { if (afterUpdate) { afterUpdate(binTo); } }); } }) .catch(err => { openSnack("Failed to update grain inventory"); }) .finally(() => { if (decreaseMode !== "moved" && afterUpdate) { afterUpdate(); } closeDialog(); }); }; const setNewInventory = () => { if (currentBushels > newGrainInventory) { decreaseInv(); } else { increaseInv(); } }; const closeDialog = (useCallback?: boolean) => { onClose(useCallback); }; const disableButton = () => { if (increaseMode === "grown") { if (fields.length === 0 || fieldIndex < 0) { return true; } } return false; }; return ( closeDialog(true)}> Grain Adjustment for {activeBinSettings.name} {dialogContent()} ); }