385 lines
12 KiB
TypeScript
385 lines
12 KiB
TypeScript
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<number>(-1);
|
|
const [yearIndex, setYearIndex] = useState(0);
|
|
const [bins, setBins] = useState<Bin[]>([]);
|
|
const [fields, setFields] = useState<Field[]>([]);
|
|
const [hYears, setHYears] = useState<Map<number, HarvestYear>>(new Map<number, HarvestYear>());
|
|
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<number, HarvestYear>();
|
|
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 (
|
|
<Box>
|
|
<FormControl>
|
|
<RadioGroup value={decreaseMode} name="radio-buttons-group">
|
|
<FormControlLabel
|
|
value="correction"
|
|
control={<Radio />}
|
|
label="Correction"
|
|
onChange={() => setDecreaseMode("correction")}
|
|
/>
|
|
{/* Doesnt Actually Do Anything yet */}
|
|
{/* <FormControlLabel
|
|
value="sold"
|
|
control={<Radio />}
|
|
label="Sold"
|
|
onChange={() => setDecreaseMode("sold")}
|
|
/> */}
|
|
<FormControlLabel
|
|
value="moved"
|
|
control={<Radio />}
|
|
label="Moved"
|
|
onChange={() => setDecreaseMode("moved")}
|
|
/>
|
|
</RadioGroup>
|
|
</FormControl>
|
|
{decreaseMode === "moved" && (
|
|
<TextField
|
|
id="bins"
|
|
fullWidth
|
|
margin="normal"
|
|
select
|
|
label="Bin grain moved to"
|
|
value={binIndex}
|
|
onChange={e => setBinIndex(+e.target.value)}>
|
|
{bins.map((option, i) => (
|
|
<MenuItem key={i} value={i} disabled={option.key() === activeBinSettings.key}>
|
|
{option.name()} - {grainName(option)}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
)}
|
|
</Box>
|
|
);
|
|
} else {
|
|
return (
|
|
<Box>
|
|
<FormControl>
|
|
<RadioGroup value={increaseMode} name="radio-buttons-group">
|
|
<FormControlLabel
|
|
value="correction"
|
|
control={<Radio />}
|
|
label="Correction"
|
|
onChange={() => setIncreaseMode("correction")}
|
|
/>
|
|
{/* Doesnt Actually Do Anything yet */}
|
|
{/* <FormControlLabel
|
|
value="purchased"
|
|
control={<Radio />}
|
|
label="Purchased"
|
|
onChange={() => setIncreaseMode("purchased")}
|
|
/> */}
|
|
<FormControlLabel
|
|
value="grown"
|
|
control={<Radio />}
|
|
label="Grown"
|
|
onChange={() => setIncreaseMode("grown")}
|
|
/>
|
|
</RadioGroup>
|
|
</FormControl>
|
|
{increaseMode === "grown" && (
|
|
<Box>
|
|
<TextField
|
|
id="fields"
|
|
fullWidth
|
|
margin="normal"
|
|
select
|
|
label="Field"
|
|
helperText="Select the field that provided the grain"
|
|
value={fieldIndex}
|
|
onChange={e => setFieldIndex(+e.target.value)}>
|
|
<MenuItem key="noField" value={-1}>
|
|
No Field Selected
|
|
</MenuItem>
|
|
{fields.map((option, i) => (
|
|
<MenuItem key={i} value={i}>
|
|
{option.fieldName()}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
<TextField
|
|
id="harvestYear"
|
|
fullWidth
|
|
margin="normal"
|
|
select
|
|
label="Harvest Year"
|
|
helperText="Select which Year to track"
|
|
value={yearIndex}
|
|
onChange={e => setYearIndex(+e.target.value)}
|
|
disabled={fieldIndex < 0}>
|
|
<MenuItem key={0} value={0}>
|
|
New Harvest Year
|
|
</MenuItem>
|
|
{Array.from(hYears.values()).length > 0 &&
|
|
Array.from(hYears.values()).map(option => (
|
|
<MenuItem key={option.year()} value={option.year()}>
|
|
{option.year()}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|
|
};
|
|
|
|
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 (
|
|
<ResponsiveDialog open={dialogControl} onClose={() => closeDialog(true)}>
|
|
<DialogTitle>Grain Adjustment for {activeBinSettings.name}</DialogTitle>
|
|
<DialogContent>{dialogContent()}</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={() => closeDialog(true)} color="primary">
|
|
Cancel
|
|
</Button>
|
|
<Button onClick={setNewInventory} color="primary" disabled={disableButton()}>
|
|
Confirm
|
|
</Button>
|
|
</DialogActions>
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|