write permission to the bin or team is required to make the transaction rows selectable

This commit is contained in:
csawatzky 2025-06-06 09:13:02 -06:00
parent 691b3be1f9
commit 216569b661
8 changed files with 121 additions and 27 deletions

View file

@ -18,10 +18,12 @@ import { getGrainUnit } from "utils";
interface Props {
bin: Bin
permissions: pond.Permission[]
refresh: () => void
}
export default function BinTransactions(props: Props){
const { bin } = props
const { bin, permissions, refresh } = props
const [state, setState] = useState<pond.TransactionState>(pond.TransactionState.TRANSACTION_STATE_APPROVAL_REQUIRED)
const transactionAPI = useTransactionAPI()
const binAPI = useBinAPI()
@ -67,8 +69,10 @@ export default function BinTransactions(props: Props){
let binMap: Map<string, Bin> = new Map()
resp.data.bins.map(b => {
let bin = Bin.create(b)
options.push({label: bin.name(), value: bin.key()})
binMap.set(bin.key(), bin)
if(bin.key() !== props.bin.key()){
options.push({label: bin.name(), value: bin.key(), group: bin.grainName()})
binMap.set(bin.key(), bin)
}
})
setBinOptions(options)
setBins(binMap)
@ -80,19 +84,29 @@ export default function BinTransactions(props: Props){
grainBagAPI.listGrainBags(0, 0, "asc", "name").then(resp => {
setGrainBagOptions(resp.data.grainBags.map(g => {
let grainBag = GrainBag.create(g)
return {label: grainBag.name(), value: grainBag.key()}
return {label: grainBag.name(), value: grainBag.key(), group: grainBag.grainName()}
}))
})
}
//load fields
const loadFields = useCallback(()=>{
fieldAPI.listFields(0,0, "asc", "field_name").then(resp => {
setFieldOptions(resp.data.fields.map(f => {
let field = Field.create(f)
return {label: field.name(), value: field.key(), group: field.grainName()}
}))
})
},[])
//load contracts
const loadContracts = useCallback(()=>{
contractAPI.listContracts(0,0, "asc", "name").then(resp => {
setContractOptions(resp.data.contracts.map(c => {
let contract = Contract.create(c)
return {label: contract.name(), value: contract.key(), group: contract.grainName()}
}))
})
},[])
@ -122,7 +136,6 @@ export default function BinTransactions(props: Props){
}
const submit = () => {
console.log("submitting transaction")
let transaction = cloneDeep(selectedTransaction)
if(transaction){
//use the dropdowns to update the from/to for the transaction, meaning if the user added another object it will adjust its inventory as well
@ -150,11 +163,20 @@ export default function BinTransactions(props: Props){
}).catch(err => {
openSnack("There was a problem submitting transaction approval")
})
refresh()
}
}
const reject = () => {
//reject the transaction
if(selectedTransaction){
transactionAPI.submitApproval(selectedTransaction.transaction.key, false, selectedTransaction.transaction).then(resp => {
openSnack("Transaction rejected")
}).catch(err => {
openSnack("There was a problem rejecting the transaction")
})
}
refresh()
}
const getOptions = (type: pond.ObjectType) => {
@ -163,6 +185,10 @@ export default function BinTransactions(props: Props){
return binOptions
case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
return grainBagOptions
case pond.ObjectType.OBJECT_TYPE_FIELD:
return fieldOptions
case pond.ObjectType.OBJECT_TYPE_CONTRACT:
return contractOptions
default:
return []
}
@ -198,6 +224,7 @@ export default function BinTransactions(props: Props){
options={[
pond.ObjectType.OBJECT_TYPE_BIN,
pond.ObjectType.OBJECT_TYPE_GRAIN_BAG,
pond.ObjectType.OBJECT_TYPE_FIELD
]}
getOptionLabel={(option: pond.ObjectType) => ObjectDescriber(option).name}
@ -212,7 +239,13 @@ export default function BinTransactions(props: Props){
loadBins()
}
}else if (val === pond.ObjectType.OBJECT_TYPE_GRAIN_BAG){
if(grainBagOptions.length === 0){
loadGrainbags()
}
}else if (val === pond.ObjectType.OBJECT_TYPE_FIELD){
if (fieldOptions.length === 0){
loadFields()
}
}
}}
renderInput={params => <TextField {...params} label="Type" />}
@ -260,7 +293,7 @@ export default function BinTransactions(props: Props){
options={[
pond.ObjectType.OBJECT_TYPE_BIN,
pond.ObjectType.OBJECT_TYPE_GRAIN_BAG,
pond.ObjectType.OBJECT_TYPE_CONTRACT
]}
getOptionLabel={(option: pond.ObjectType) => ObjectDescriber(option).name}
fullWidth
@ -274,7 +307,13 @@ export default function BinTransactions(props: Props){
loadBins()
}
}else if (val === pond.ObjectType.OBJECT_TYPE_GRAIN_BAG){
if(grainBagOptions.length === 0){
loadGrainbags()
}
}else if (val === pond.ObjectType.OBJECT_TYPE_CONTRACT){
if(contractOptions.length === 0){
loadContracts()
}
}
}}
renderInput={params => <TextField {...params} label="Type" />}
@ -282,6 +321,12 @@ export default function BinTransactions(props: Props){
<Autocomplete
sx={{marginY: 1}}
disabled={toDisabled}
groupBy={option => {
if (option.group) {
return option.group;
}
return "No Grain Type";
}}
id="autoFromObjects"
value={toOption}
options={getOptions(toType)}
@ -366,7 +411,15 @@ export default function BinTransactions(props: Props){
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={closeDialog}>Close</Button>
<Button variant="contained" color="error" onClick={closeDialog}>Reject</Button>
<Button
variant="contained"
color="error"
onClick={() => {
reject()
closeDialog()
}}>
Reject
</Button>
<Button
variant="contained"
disabled={requiresMatch && selectedMatch === undefined}
@ -446,14 +499,14 @@ export default function BinTransactions(props: Props){
title="Pending Transactions"
subtitle={"Select a transaction to approve"}
noDataMessage="No Pending Transactions Found"
onRowClick={(row)=> {
setSelectedTransaction(row)
setFromType(row.transaction.fromObject)
setFromOption({label: objectNames.get(row.transaction.fromKey) ?? "", value: row.transaction.fromKey})
setToType(row.transaction.toObject)
setToOption({label: objectNames.get(row.transaction.toKey) ?? "", value: row.transaction.toKey})
setOpenDialog(true)
}}
onRowClick={permissions.includes(pond.Permission.PERMISSION_WRITE) ? (row)=> {
setSelectedTransaction(row)
setFromType(row.transaction.fromObject)
setFromOption({label: objectNames.get(row.transaction.fromKey) ?? "", value: row.transaction.fromKey})
setToType(row.transaction.toObject)
setToOption({label: objectNames.get(row.transaction.toKey) ?? "", value: row.transaction.toKey})
setOpenDialog(true)
} : undefined}
rows={transactions}
handleRowsPerPageChange={(e)=>{setTablePageSize(e.target.value)}}
setPage={(page)=>{setTablePage(page)}}

View file

@ -22,7 +22,7 @@ import GrainDescriber from "grain/GrainDescriber";
import { Contract } from "models/Contract";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { useGlobalState, useTaskAPI, useContractAPI } from "providers";
import { useGlobalState, useTaskAPI, useContractAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";
import { getGrainUnit } from "utils";
@ -63,6 +63,7 @@ export default function ContractSettings(props: Props) {
const [deleteWindow, setDeleteWindow] = useState(false);
const [createDeliveryTask, setCreateDeliveryTask] = useState(false);
const [conversionValue, setConversionValue] = useState("1");
const { openSnack } = useSnackbar()
const [labels, setLabels] = useState<InputLabels>({
sizeLabel: "Size",
commodityLabel: "Commodity",
@ -174,11 +175,14 @@ export default function ContractSettings(props: Props) {
contractAPI
.updateContract(contract.key(), name, settings, as)
.then(resp => {
console.log("Updated Contract");
//console.log("Updated Contract");
openSnack("Contract Updated")
close();
})
.catch(err => {
console.log("Error updating contract");
//console.log("Error updating contract");
openSnack("Error Updating Contract")
});
} else {
let settings: pond.ContractSettings = pond.ContractSettings.create();

View file

@ -155,7 +155,7 @@ export class Bin {
return GrainDescriber(this.grain()).name;
}
} else {
return "";
return "None";
}
}

View file

@ -234,4 +234,16 @@ export class Contract {
}
return storedunitVal;
}
public grainName(): string {
if (this.grain() !== pond.Grain.GRAIN_INVALID) {
if (this.grain() === pond.Grain.GRAIN_CUSTOM) {
return this.customType();
} else {
return GrainDescriber(this.grain()).name;
}
} else {
return "None";
}
}
}

View file

@ -4,6 +4,7 @@ import { or } from "utils/types";
import area from "@turf/area";
import { Feature } from "geojson";
import { GeometryMapping } from "./GeometryMapping";
import GrainDescriber from "grain/GrainDescriber";
export class Field {
public settings: pond.FieldSettings = pond.FieldSettings.create();
@ -150,4 +151,16 @@ export class Field {
}
return coords;
}
public grainName(): string {
if (this.grain() !== pond.Grain.GRAIN_INVALID) {
if (this.grain() === pond.Grain.GRAIN_CUSTOM) {
return this.customType();
} else {
return GrainDescriber(this.grain()).name;
}
} else {
return "None";
}
}
}

View file

@ -1,3 +1,4 @@
import GrainDescriber from "grain/GrainDescriber";
import { cloneDeep } from "lodash";
import { pond } from "protobuf-ts/pond";
import { or } from "utils/types";
@ -132,4 +133,16 @@ export class GrainBag {
}
return bpt;
}
public grainName(): string {
if (this.grain() !== pond.Grain.GRAIN_INVALID) {
if (this.grain() === pond.Grain.GRAIN_CUSTOM) {
return this.customType();
} else {
return GrainDescriber(this.grain()).name;
}
} else {
return "None";
}
}
}

View file

@ -969,7 +969,7 @@ export default function Bin(props: Props) {
/>
)}
{detail === "transactions" &&
<BinTransactions bin={bin}/>
<BinTransactions bin={bin} permissions={permissions}/>
}
</Grid>
</Grid>
@ -1090,7 +1090,7 @@ export default function Bin(props: Props) {
/>
</TabPanelMine>
<TabPanelMine value={mobileTab} index={6}>
<BinTransactions bin={bin}/>
<BinTransactions bin={bin} permissions={permissions}/>
</TabPanelMine>
</Card>
);

View file

@ -38,7 +38,6 @@ export default function Contracts() {
as
)
.then(resp => {
console.log(resp)
let contracts: Contract[] = [];
let contractPermissions: Map<string, pond.Permission[]> = new Map();
resp.data.contracts.forEach(contract => {