changed the component used in the bin and component settings to the grain selector and split out the form into another component that handles just the form and passing up a grainSettings object from its fields

This commit is contained in:
csawatzky 2025-12-23 10:16:31 -06:00
parent 49aa08f232
commit 27590da78f
7 changed files with 225 additions and 151 deletions

View file

@ -1,74 +1,37 @@
import { ExpandMore } from "@mui/icons-material"
import { Accordion, AccordionDetails, AccordionSummary, Box, Button, MenuItem, TextField, Typography } from "@mui/material"
import SearchSelect, { Option } from "common/SearchSelect"
import {MenuItem, TextField } from "@mui/material"
import { cloneDeep } from "lodash"
import { pond } from "protobuf-ts/pond"
import { useGlobalState } from "providers"
import { useGrainAPI } from "providers/pond/grainAPI"
import React, { useEffect, useState } from "react"
interface Props {
initialGrain?: pond.GrainSettings
onGrainSettingsChange: (settings: pond.GrainSettings) => void
grainSettings?: pond.GrainSettings
onGrainSettingsChange: (settings: pond.GrainSettings, formValid: boolean) => void
}
export default function CustomGrainForm(props: Props) {
const {initialGrain, onGrainSettingsChange} = props
const grainAPI = useGrainAPI()
const [{as}] = useGlobalState()
const [name, setName] = useState(initialGrain ? initialGrain.name : "")
const [group, setGroup] = useState(initialGrain ? initialGrain.group : "")
const [equation, setEquation] = useState<pond.MoistureEquation>(initialGrain ? initialGrain.equation : pond.MoistureEquation.MOISTURE_EQUATION_NONE)
const [constantA, setConstantA] = useState(initialGrain ? initialGrain.a.toString() : "0")
const [constantB, setConstantB] = useState(initialGrain ? initialGrain.b.toString() : "0")
const [constantC, setConstantC] = useState(initialGrain ? initialGrain.c.toString() : "0")
const [kgPerBushel, setKgPerBushel] = useState(initialGrain ? initialGrain.kgPerBushel.toString() : "0")
const [bushelsPerTonne, setBushelsPerTonne] = useState(initialGrain ? initialGrain.bushelsPerTonne.toString() : "0")
const [newGrainSettings, setNewGrainSettings] = useState(initialGrain ?? pond.GrainSettings.create())
const [grainMap, setGrainMap] = useState<Map<string, pond.GrainObject>>(
initialGrain ?
new Map([
["Active", pond.GrainObject.create({key: "Active", name: initialGrain.name, settings: initialGrain})]
])
:
new Map())
const [grainOptions, setGrainOptions] = useState<Option[]>(
initialGrain ?
[
{
label: initialGrain.name,
value: "Active",
group: "Active"
}
]
:
[]
)
const [isNew, setIsNew] = useState(false)
const [selectedOption, setSelectedOption] = useState<Option | null>(initialGrain ? {
label: initialGrain.name,
value: "Active",
group: "Active"
} : null)
const {grainSettings, onGrainSettingsChange} = props
const [newGrainSettings, setNewGrainSettings] = useState(pond.GrainSettings.create())
const [name, setName] = useState("")
const [group, setGroup] = useState("")
const [equation, setEquation] = useState<pond.MoistureEquation>(pond.MoistureEquation.MOISTURE_EQUATION_NONE)
const [constantA, setConstantA] = useState("0")
const [constantB, setConstantB] = useState("0")
const [constantC, setConstantC] = useState("0")
const [kgPerBushel, setKgPerBushel] = useState("0")
const [bushelsPerTonne, setBushelsPerTonne] = useState("0")
useEffect(()=>{
grainAPI.listGrains(0, 0, "asc", "name", undefined, undefined, undefined, as).then(resp => {
let options: Option[] = grainOptions
let map: Map<string, pond.GrainObject> = grainMap
if (resp.data.grains){
resp.data.grains.forEach(grain => {
map.set(grain.key, grain)
options.push({
label: grain.name,
value: grain.key,
group: grain.settings?.group,
})
})
}
setGrainOptions([...options])
setGrainMap(map)
})
},[grainAPI])
if(grainSettings){
setName(grainSettings.name)
setGroup(grainSettings.group)
setEquation(grainSettings.equation)
setConstantA(grainSettings.a.toString())
setConstantB(grainSettings.b.toString())
setConstantC(grainSettings.c.toString())
setKgPerBushel(grainSettings.kgPerBushel.toString())
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
}
},[grainSettings])
const invalid = () => {
if (name === "") return true
@ -81,21 +44,12 @@ export default function CustomGrainForm(props: Props) {
return false
}
const saveGrain = () => {
// console.log(newGrainSettings)
grainAPI.addGrain(newGrainSettings, as).then(resp => {
console.log("grain added")
}).catch(err => {
console.log("err")
})
}
const settingsChanged = (newSettings: pond.GrainSettings) => {
setNewGrainSettings(newSettings)
onGrainSettingsChange(newSettings)
onGrainSettingsChange(newSettings, !invalid())
}
const newGrain = () => {
const grainForm = () => {
return (
<React.Fragment>
<TextField
@ -106,7 +60,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let name = e.target.value
setName(name)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.name = name
settingsChanged(settings)
@ -119,7 +72,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let group = e.target.value
setGroup(group)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.group = group
settingsChanged(settings)
@ -133,7 +85,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let enumVal = parseFloat(e.target.value)
setEquation(enumVal)
setIsNew(true)
let settings = cloneDeep(newGrainSettings)
settings.equation = enumVal
settingsChanged(settings)
@ -165,7 +116,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let val = e.target.value
setConstantA(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.a = parseFloat(val)
@ -183,7 +133,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let val = e.target.value
setConstantB(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.b = parseFloat(val)
@ -201,7 +150,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let val = e.target.value
setConstantC(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.c = parseFloat(val)
@ -219,7 +167,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let val = e.target.value
setKgPerBushel(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.kgPerBushel = parseFloat(val)
@ -237,7 +184,6 @@ export default function CustomGrainForm(props: Props) {
onChange={(e) => {
let val = e.target.value
setBushelsPerTonne(val)
setIsNew(true)
if(!isNaN(parseFloat(val))){
let settings = cloneDeep(newGrainSettings)
settings.bushelsPerTonne = parseFloat(val)
@ -245,77 +191,13 @@ export default function CustomGrainForm(props: Props) {
}
}}
label="Bushels per Tonne"/>
{isNew &&
<Box display='flex' justifyContent="flex-end">
<Button
variant="contained"
disabled={invalid()}
onClick={() => {
saveGrain()
setIsNew(false)
}}
color="primary">
Save Custom Grain
</Button>
</Box>
}
</React.Fragment>
)
}
const grainAccordion = () => {
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>Custom Grain Properties</AccordionSummary>
<AccordionDetails>
{newGrain()}
</AccordionDetails>
</Accordion>
)
}
return (
<React.Fragment>
{grainOptions.length === 0 ?
<Box>
<Typography sx={{marginBottom: 1}}>Custom Grain Properties</Typography>
{newGrain()}
</Box>
:
<Box>
<Box sx={{marginBottom: 2}}>
<SearchSelect
label="My Grains"
selected={selectedOption}
changeSelection={option => {
setIsNew(false)
setSelectedOption(option)
//when an option is selected set all of the state variables controlling the form entries
let grain = grainMap.get(option?.value)
if(grain && grain.settings){
//set the form values
setName(grain.name)
setGroup(grain.settings.group)
setEquation(grain.settings.equation)
setConstantA(grain.settings.a.toString())
setConstantB(grain.settings.b.toString())
setConstantC(grain.settings.c.toString())
setKgPerBushel(grain.settings.kgPerBushel.toString())
setBushelsPerTonne(grain.settings.bushelsPerTonne.toString())
//the the new grain settings object
setNewGrainSettings(grain.settings)
//pass that settings object back up
settingsChanged(grain.settings)
}
}}
group
options={grainOptions}
/>
</Box>
{grainAccordion()}
</Box>
}
{grainForm()}
</React.Fragment>
)
}

View file

@ -0,0 +1,155 @@
import { ExpandMore } from "@mui/icons-material"
import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Typography } from "@mui/material"
import SearchSelect, { Option } from "common/SearchSelect"
import { pond } from "protobuf-ts/pond"
import { useGlobalState } from "providers"
import { useGrainAPI } from "providers/pond/grainAPI"
import React, { useEffect, useState } from "react"
import CustomGrainForm from "./CustomGrainForm"
interface Props {
initialGrain?: pond.GrainSettings
onGrainSettingsChange: (settings: pond.GrainSettings) => void
}
export default function CustomGrainSelector(props: Props) {
const {initialGrain, onGrainSettingsChange} = props
const grainAPI = useGrainAPI()
const [{as}] = useGlobalState()
const [newGrainSettings, setNewGrainSettings] = useState(initialGrain ?? pond.GrainSettings.create())
const [formValid, setFormValid] = useState(true)
const [grainMap, setGrainMap] = useState<Map<string, pond.GrainObject>>(
initialGrain ?
new Map([
["Active", pond.GrainObject.create({key: "Active", name: initialGrain.name, settings: initialGrain})]
])
:
new Map())
const [grainOptions, setGrainOptions] = useState<Option[]>(
initialGrain ?
[
{
label: initialGrain.name,
value: "Active",
group: "Active"
}
]
:
[]
)
const [isNew, setIsNew] = useState(false)
const [selectedOption, setSelectedOption] = useState<Option | null>(initialGrain ? {
label: initialGrain.name,
value: "Active",
group: "Active"
} : null)
useEffect(()=>{
grainAPI.listGrains(0, 0, "asc", "name", undefined, undefined, undefined, as).then(resp => {
let options: Option[] = grainOptions
let map: Map<string, pond.GrainObject> = grainMap
if (resp.data.grains){
resp.data.grains.forEach(grain => {
map.set(grain.key, grain)
options.push({
label: grain.name,
value: grain.key,
group: grain.settings?.group,
})
})
}
setGrainOptions([...options])
setGrainMap(map)
})
},[grainAPI])
const saveGrain = () => {
// console.log(newGrainSettings)
grainAPI.addGrain(newGrainSettings, as).then(resp => {
console.log("grain added")
}).catch(err => {
console.log("err")
})
}
const settingsChanged = (newSettings: pond.GrainSettings, formValid: boolean) => {
setNewGrainSettings(newSettings)
setIsNew(true)
setFormValid(formValid)
onGrainSettingsChange(newSettings)
}
const grainAccordion = () => {
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>Custom Grain Properties</AccordionSummary>
<AccordionDetails>
<CustomGrainForm grainSettings={newGrainSettings} onGrainSettingsChange={settingsChanged}/>
{isNew &&
<Box display='flex' justifyContent="flex-end">
<Button
variant="contained"
disabled={!formValid}
onClick={() => {
setIsNew(false)
saveGrain()
}}
color="primary">
Save Custom Grain
</Button>
</Box>
}
</AccordionDetails>
</Accordion>
)
}
return (
<React.Fragment>
{grainOptions.length === 0 ?
<Box>
<Typography sx={{marginBottom: 1}}>Custom Grain Properties</Typography>
<CustomGrainForm grainSettings={newGrainSettings} onGrainSettingsChange={settingsChanged}/>
{isNew &&
<Box display='flex' justifyContent="flex-end">
<Button
variant="contained"
disabled={!formValid}
onClick={() => {
setIsNew(false)
}}
color="primary">
Save Custom Grain
</Button>
</Box>
}
</Box>
:
<Box>
<Box sx={{marginBottom: 2}}>
<SearchSelect
label="My Grains"
selected={selectedOption}
changeSelection={option => {
setIsNew(false)
setSelectedOption(option)
//when an option is selected set all of the state variables controlling the form entries
let grain = grainMap.get(option?.value)
if(grain && grain.settings){
//the the new grain settings object
setNewGrainSettings(grain.settings)
//pass that settings object back up
settingsChanged(grain.settings, true)
}
}}
group
options={grainOptions}
/>
</Box>
{grainAccordion()}
</Box>
}
</React.Fragment>
)
}