326 lines
11 KiB
TypeScript
326 lines
11 KiB
TypeScript
import {
|
|
Box,
|
|
Button,
|
|
Card,
|
|
Drawer,
|
|
Grid2 as Grid,
|
|
IconButton,
|
|
LinearProgress,
|
|
Theme,
|
|
Typography
|
|
} from "@mui/material";
|
|
import ContractTransactionGraph from "contract/contractTransactionGraph";
|
|
import ContractVisualizer from "contract/contractVisualizer";
|
|
import { useMobile, useThemeType } from "hooks";
|
|
// import { MatchParams } from "navigation/Routes";
|
|
import { useContractAPI } from "providers/pond/contractAPI";
|
|
import React, { useEffect, useState } from "react";
|
|
// import { Redirect, useRouteMatch } from "react-router";
|
|
import PageContainer from "./PageContainer";
|
|
import { Contract as IContract } from "models/Contract";
|
|
import ObjectControls from "common/ObjectControls";
|
|
import ContractActions from "contract/contractActions";
|
|
import { useGlobalState, useUserAPI } from "providers";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import { Scope } from "models";
|
|
import { Transaction } from "models/Transaction";
|
|
import ContractTransactionTable from "contract/contractTransactionTable";
|
|
import GrainTransaction from "grain/GrainTransaction";
|
|
import NotesIcon from "@mui/icons-material/Notes";
|
|
import Chat from "chat/Chat";
|
|
import ContractsIcon from "products/CommonIcons/contractIcon";
|
|
import { makeStyles } from "@mui/styles";
|
|
import { useParams } from "react-router-dom";
|
|
|
|
interface TabPanelProps {
|
|
children?: React.ReactNode;
|
|
index: any;
|
|
value: any;
|
|
}
|
|
|
|
function TabPanelMine(props: TabPanelProps) {
|
|
const { children, value, index, ...other } = props;
|
|
|
|
return (
|
|
<div
|
|
role="tabpanel"
|
|
hidden={value !== index}
|
|
aria-labelledby={`simple-tab-${index}`}
|
|
{...other}>
|
|
{value === index && <React.Fragment>{children}</React.Fragment>}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const useStyles = makeStyles((theme: Theme) => {
|
|
const themeType = useThemeType();
|
|
return ({
|
|
inactiveButton: {
|
|
color: themeType === "light" ? theme.palette.common.black : theme.palette.common.white,
|
|
backgroundColor: "transparent",
|
|
width: theme.spacing(5),
|
|
height: theme.spacing(5),
|
|
border: "1px solid",
|
|
borderColor: theme.palette.divider
|
|
},
|
|
activeButton: {
|
|
color: themeType === "light" ? theme.palette.common.black : theme.palette.common.white,
|
|
backgroundColor: theme.palette.primary.main,
|
|
width: theme.spacing(5),
|
|
height: theme.spacing(5),
|
|
border: "1px solid",
|
|
borderColor: theme.palette.divider
|
|
},
|
|
drawerPaper: {
|
|
height: "100%",
|
|
width: "30%"
|
|
}
|
|
});
|
|
});
|
|
|
|
export default function Contract() {
|
|
// const match = useRouteMatch<MatchParams>();
|
|
// const contractKey = match.params.contractKey;
|
|
const contractKey = useParams<{ contractKey: string }>()?.contractKey ?? "";
|
|
|
|
const classes = useStyles();
|
|
const contractAPI = useContractAPI();
|
|
const isMobile = useMobile();
|
|
const [contract, setContract] = useState<IContract>(IContract.create());
|
|
const [validTransactions, setValidTransactions] = useState<Map<string, Transaction>>(new Map());
|
|
//have to use this as the array passed to the bar graph, for whatever reason getting the array from the values of the map causes the labels to not appear
|
|
const [transArray, setTransArray] = useState<Transaction[]>([]);
|
|
const [openGrainTransactionDialog, setOpenGrainTransactionDialog] = useState(false);
|
|
const [displayTab, setDisplayTab] = useState(0);
|
|
const [openNoteDrawer, setOpenNoteDrawer] = useState(false);
|
|
//const [revokedTransactions, setRevokedTransactions] = useState<Transaction[]>([]);
|
|
const userAPI = useUserAPI();
|
|
const [{ user, as }] = useGlobalState();
|
|
const [permissions, setPermissions] = useState<pond.Permission[]>([]);
|
|
const [objectMap, setObjectMap] = useState<Map<string, string>>(new Map());
|
|
const [loading, setLoading] = useState(false);
|
|
// const [invalid, setInvalid] = useState(false);
|
|
|
|
useEffect(() => {
|
|
let key = contractKey;
|
|
let kind = "contract";
|
|
if (as) {
|
|
key = as;
|
|
kind = "team";
|
|
}
|
|
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
|
setPermissions(resp.permissions);
|
|
});
|
|
}, [as, contractKey, userAPI, user]);
|
|
|
|
useEffect(() => {
|
|
if (!loading) {
|
|
setLoading(true);
|
|
contractAPI
|
|
.getContractPageData(contractKey, as)
|
|
.then(resp => {
|
|
setContract(IContract.any(resp.data.contract));
|
|
//setValidTransactions(resp.data.transactions.map(t => Transaction.create(t)));
|
|
let valid: Map<string, Transaction> = new Map();
|
|
let tArray: Transaction[] = [];
|
|
resp.data.transactions.forEach(transaction => {
|
|
let t = Transaction.create(transaction);
|
|
if (
|
|
t.transaction.state === pond.TransactionState.TRANSACTION_STATE_VALID ||
|
|
t.transaction.state === pond.TransactionState.TRANSACTION_STATE_CORRECTION
|
|
) {
|
|
valid.set(t.transaction.key, t);
|
|
tArray.push(t);
|
|
}
|
|
// else {
|
|
// revoked.push(t);
|
|
// }
|
|
});
|
|
setValidTransactions(valid);
|
|
setTransArray(tArray);
|
|
//setRevokedTransactions(revoked);
|
|
let tempMap: Map<string, string> = new Map();
|
|
Object.keys(resp.data.nameMap).forEach(key => {
|
|
tempMap.set(key, resp.data.nameMap[key]);
|
|
});
|
|
setObjectMap(tempMap);
|
|
setLoading(false);
|
|
})
|
|
.catch(err => {
|
|
//setInvalid(true);
|
|
});
|
|
}
|
|
}, [contractKey, contractAPI, as]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
const contractDisplay = () => {
|
|
return (
|
|
<React.Fragment>
|
|
{isMobile ? (
|
|
<Grid
|
|
container
|
|
alignContent="center"
|
|
alignItems="center"
|
|
direction="row"
|
|
style={{ marginBottom: 15 }}>
|
|
<Grid size={9}>
|
|
<Typography style={{ paddingRight: 20, fontSize: 30, fontWeight: 650 }} noWrap>
|
|
{contract.name()}
|
|
</Typography>
|
|
</Grid>
|
|
<Grid size={3}>
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)}
|
|
onClick={e => {
|
|
setOpenGrainTransactionDialog(true);
|
|
}}>
|
|
+ Add Delivery
|
|
</Button>
|
|
</Grid>
|
|
</Grid>
|
|
) : (
|
|
<Box display="flex" flexDirection="row" marginBottom={2}>
|
|
<Typography style={{ paddingRight: 20, fontSize: 30, fontWeight: 650 }} noWrap>
|
|
{contract.name()}
|
|
</Typography>
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)}
|
|
onClick={e => {
|
|
setOpenGrainTransactionDialog(true);
|
|
}}>
|
|
+ Add Delivery
|
|
</Button>
|
|
</Box>
|
|
)}
|
|
|
|
<Grid container spacing={2} direction={"row"}>
|
|
<Grid size={isMobile ? 12 : 4} style={{ height: isMobile ? 300 : 400 }}>
|
|
<ContractVisualizer contract={contract} />
|
|
</Grid>
|
|
<Grid size={isMobile ? 12 : 8} style={{ height: isMobile ? 300 : 400 }}>
|
|
<ContractTransactionGraph contract={contract} transactions={transArray} />
|
|
</Grid>
|
|
<Grid size={12}>
|
|
<ContractTransactionTable
|
|
permissions={permissions}
|
|
contract={contract}
|
|
transactions={transArray}
|
|
objectNames={objectMap}
|
|
transactionRevokedCallback={t => {
|
|
let vt = validTransactions;
|
|
vt.delete(t);
|
|
setValidTransactions(vt);
|
|
setTransArray(Array.from(vt.values()));
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<PageContainer>
|
|
<ObjectControls
|
|
actions={
|
|
<ContractActions
|
|
contract={contract}
|
|
permissions={permissions}
|
|
refreshCallback={() => {}}
|
|
/>
|
|
}
|
|
objectButton={
|
|
<IconButton
|
|
size="small"
|
|
style={{
|
|
marginTop: "0.3625rem",
|
|
marginBottom: "0.3625rem",
|
|
marginRight: "0.5rem"
|
|
}}
|
|
onClick={() => {
|
|
setDisplayTab(0);
|
|
}}
|
|
className={displayTab === 0 ? classes.activeButton : classes.inactiveButton}
|
|
component="span">
|
|
<ContractsIcon />
|
|
</IconButton>
|
|
}
|
|
notesButton={
|
|
<IconButton
|
|
onClick={() => {
|
|
if (isMobile) {
|
|
setDisplayTab(1);
|
|
} else {
|
|
setOpenNoteDrawer(true);
|
|
}
|
|
}}
|
|
size="small"
|
|
style={{
|
|
marginTop: "0.3625rem",
|
|
marginBottom: "0.3625rem",
|
|
marginRight: "0.5rem"
|
|
}}
|
|
className={displayTab === 1 ? classes.activeButton : classes.inactiveButton}
|
|
component="span">
|
|
<NotesIcon />
|
|
</IconButton>
|
|
}
|
|
/>
|
|
<Box margin={2} marginTop={0}>
|
|
{loading ? (
|
|
<LinearProgress />
|
|
) : (
|
|
<React.Fragment>
|
|
<TabPanelMine value={displayTab} index={0}>
|
|
{contractDisplay()}
|
|
</TabPanelMine>
|
|
<TabPanelMine value={displayTab} index={1}>
|
|
<Typography style={{ paddingRight: 20, fontSize: 30, fontWeight: 650 }}>
|
|
{contract.name()} - Notes
|
|
</Typography>
|
|
<Card style={{ padding: 10, marginTop: 15 }}>
|
|
<Chat objectKey={contract.key()} type={pond.NoteType.NOTE_TYPE_CONTRACT} />
|
|
</Card>
|
|
</TabPanelMine>
|
|
</React.Fragment>
|
|
)}
|
|
</Box>
|
|
<GrainTransaction
|
|
open={openGrainTransactionDialog}
|
|
mainObject={contract}
|
|
allowAttachmentUploads
|
|
restrictMatching
|
|
asDestination
|
|
close={() => {
|
|
setOpenGrainTransactionDialog(false);
|
|
}}
|
|
callback={t => {
|
|
setOpenGrainTransactionDialog(false);
|
|
if (t) {
|
|
let transactions = validTransactions;
|
|
transactions.set(t.key, Transaction.create(t));
|
|
setValidTransactions(transactions);
|
|
setTransArray(Array.from(transactions.values()));
|
|
}
|
|
}}
|
|
/>
|
|
<Drawer
|
|
open={openNoteDrawer}
|
|
onClose={() => {
|
|
setOpenNoteDrawer(false);
|
|
}}
|
|
anchor="right"
|
|
classes={{ paper: classes.drawerPaper }}>
|
|
<Box padding={2}>
|
|
<Typography>Notes</Typography>
|
|
<Card style={{ padding: 10 }}>
|
|
<Chat objectKey={contract.key()} type={pond.NoteType.NOTE_TYPE_CONTRACT} />
|
|
</Card>
|
|
</Box>
|
|
</Drawer>
|
|
</PageContainer>
|
|
);
|
|
}
|