adding the harvest plan stuff to the field page
This commit is contained in:
parent
84885dc163
commit
c69636482a
8 changed files with 146 additions and 36 deletions
|
|
@ -63,8 +63,6 @@ export default function FieldActions(props: Props) {
|
||||||
removeSelf: false
|
removeSelf: false
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(permissions)
|
|
||||||
|
|
||||||
const groupMenu = () => {
|
const groupMenu = () => {
|
||||||
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
|
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
|
||||||
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
|
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,17 @@ import {
|
||||||
TextField
|
TextField
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
|
import { Option } from "common/SearchSelect";
|
||||||
import { Field, HarvestPlan, Task } from "models";
|
import { Field, HarvestPlan, Task } from "models";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useHarvestPlanAPI, useTaskAPI } from "providers";
|
import { useFieldAPI, useGlobalState, useHarvestPlanAPI, useTaskAPI } from "providers";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
fields: Field[];
|
fields?: Field[];
|
||||||
plan: HarvestPlan;
|
plan: HarvestPlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,6 +30,8 @@ export default function DuplicateHarvestPlan(props: Props) {
|
||||||
const harvestPlanAPI = useHarvestPlanAPI();
|
const harvestPlanAPI = useHarvestPlanAPI();
|
||||||
const taskAPI = useTaskAPI();
|
const taskAPI = useTaskAPI();
|
||||||
const [ready, setReady] = useState(false);
|
const [ready, setReady] = useState(false);
|
||||||
|
const [fieldOptions, setFieldOptions] = useState<Field[]>([])
|
||||||
|
const fieldAPI = useFieldAPI();
|
||||||
|
|
||||||
const loadTasks = useCallback(() => {
|
const loadTasks = useCallback(() => {
|
||||||
taskAPI.listTasks(50, 0, "asc", "start", plan.key(), undefined).then(resp => {
|
taskAPI.listTasks(50, 0, "asc", "start", plan.key(), undefined).then(resp => {
|
||||||
|
|
@ -41,9 +44,25 @@ export default function DuplicateHarvestPlan(props: Props) {
|
||||||
loadTasks();
|
loadTasks();
|
||||||
}, [loadTasks]);
|
}, [loadTasks]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(fields){
|
||||||
|
//if fields were passed in use those
|
||||||
|
setFieldOptions(fields)
|
||||||
|
}else{
|
||||||
|
//otherwise load them
|
||||||
|
fieldAPI.listFields(50, 0, "asc", "fieldName").then(resp => {
|
||||||
|
setFieldOptions(resp.data.fields.map(f => Field.create(f)))
|
||||||
|
}).catch(err => {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},[fields])
|
||||||
|
|
||||||
|
//this should load the fields here
|
||||||
|
|
||||||
const duplicate = () => {
|
const duplicate = () => {
|
||||||
let planSettings = HarvestPlan.clone(plan).settings;
|
let planSettings = HarvestPlan.clone(plan).settings;
|
||||||
planSettings.field = fields[newFieldIndex].key();
|
planSettings.field = fieldOptions[newFieldIndex].key();
|
||||||
planSettings.createDate = moment.now();
|
planSettings.createDate = moment.now();
|
||||||
if (title !== "") {
|
if (title !== "") {
|
||||||
planSettings.title = title;
|
planSettings.title = title;
|
||||||
|
|
@ -69,7 +88,7 @@ export default function DuplicateHarvestPlan(props: Props) {
|
||||||
value={newFieldIndex}
|
value={newFieldIndex}
|
||||||
onChange={e => setNewFieldIndex(+e.target.value)}
|
onChange={e => setNewFieldIndex(+e.target.value)}
|
||||||
color="primary">
|
color="primary">
|
||||||
{fields.map((option, i) => (
|
{fieldOptions.map((option, i) => (
|
||||||
<MenuItem key={option.key()} value={i}>
|
<MenuItem key={option.key()} value={i}>
|
||||||
{option.fieldName()}
|
{option.fieldName()}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
@ -98,8 +117,8 @@ export default function DuplicateHarvestPlan(props: Props) {
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={
|
disabled={
|
||||||
!ready ||
|
!ready ||
|
||||||
(fields[newFieldIndex] &&
|
(fieldOptions[newFieldIndex] &&
|
||||||
!fields[newFieldIndex].permissions.includes(pond.Permission.PERMISSION_WRITE))
|
!fieldOptions[newFieldIndex].permissions.includes(pond.Permission.PERMISSION_WRITE))
|
||||||
}>
|
}>
|
||||||
Duplicate
|
Duplicate
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import ShareObjectIcon from "@mui/icons-material/Share";
|
||||||
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
|
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
|
||||||
import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle";
|
import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import ObjectUsers from "user/ObjectUsers";
|
import ObjectUsers from "user/ObjectUsers";
|
||||||
import ShareObject from "user/ShareObject";
|
import ShareObject from "user/ShareObject";
|
||||||
import { isOffline } from "utils/environment";
|
import { isOffline } from "utils/environment";
|
||||||
|
|
@ -43,7 +43,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
interface Props {
|
interface Props {
|
||||||
plan: HarvestPlan;
|
plan: HarvestPlan;
|
||||||
planField: Field;
|
planField: Field;
|
||||||
fieldList: Field[];
|
fieldList?: Field[];
|
||||||
permissions: pond.Permission[];
|
permissions: pond.Permission[];
|
||||||
refreshCallback: (updatedPlan?: HarvestPlan) => void;
|
refreshCallback: (updatedPlan?: HarvestPlan) => void;
|
||||||
hideNew?: boolean;
|
hideNew?: boolean;
|
||||||
|
|
@ -215,7 +215,7 @@ export default function HarvestPlanActions(props: Props) {
|
||||||
setUpdatePlan(true);
|
setUpdatePlan(true);
|
||||||
setOpenState({ ...openState, settings: true });
|
setOpenState({ ...openState, settings: true });
|
||||||
}}>
|
}}>
|
||||||
<Edit /> Edit or Add Activity
|
<Edit /> Activities
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
import { Notes } from "@mui/icons-material";
|
import { Notes } from "@mui/icons-material";
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
import { Field, HarvestPlan } from "models";
|
import { Field, HarvestPlan } from "models";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getThemeType } from "theme";
|
import { getThemeType } from "theme";
|
||||||
import Chat from "chat/Chat";
|
import Chat from "chat/Chat";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
@ -23,7 +23,7 @@ interface Props {
|
||||||
permissions: pond.Permission[];
|
permissions: pond.Permission[];
|
||||||
planField: Field;
|
planField: Field;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
fieldList: Field[];
|
fieldList?: Field[];
|
||||||
changePlan: (updatedPlan?: HarvestPlan) => void;
|
changePlan: (updatedPlan?: HarvestPlan) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,7 +175,7 @@ export default function HarvestPlanDisplay(props: Props) {
|
||||||
<Typography
|
<Typography
|
||||||
variant="h5"
|
variant="h5"
|
||||||
style={{ fontWeight: 700, marginTop: "auto", marginBottom: "auto" }}>
|
style={{ fontWeight: 700, marginTop: "auto", marginBottom: "auto" }}>
|
||||||
Crop Plan{plan.key() !== "" ? " - " + plan.settings.title : " - None Found"}
|
{plan.key() !== "" ? plan.settings.title : "None Found"}
|
||||||
</Typography>
|
</Typography>
|
||||||
{!isMobile && permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
{!isMobile && permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
||||||
<HarvestPlanActions
|
<HarvestPlanActions
|
||||||
|
|
|
||||||
26
src/harvestPlan/HarvestPlanTable.tsx
Normal file
26
src/harvestPlan/HarvestPlanTable.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Box } from "@mui/material"
|
||||||
|
import ResponsiveTable from "common/ResponsiveTable"
|
||||||
|
import { useHarvestPlanAPI } from "providers"
|
||||||
|
import { useCallback, useEffect, useState } from "react"
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
field?: string
|
||||||
|
}
|
||||||
|
export default function HarvestPlanTable(props: Props){
|
||||||
|
const {field} = props
|
||||||
|
const harvestAPI = useHarvestPlanAPI()
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
const [pageSize, setPageSize] = useState(10)
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
harvestAPI.listHarvestPlans(pageSize, page*pageSize, "asc", "name", field).then(resp => {
|
||||||
|
console.log(resp)
|
||||||
|
})
|
||||||
|
},[page, pageSize, field])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { Field, HarvestPlan } from "models";
|
import { Field, fieldScope, HarvestPlan, teamScope } from "models";
|
||||||
import { useGlobalState } from "providers";
|
import { useFieldAPI, useGlobalState, useHarvestPlanAPI } from "providers";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation, useParams } from "react-router-dom";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile, useSnackbar, useUserAPI } from "hooks";
|
||||||
import { Box, Grid2, IconButton } from "@mui/material";
|
import { Box, Card, Grid2, IconButton } from "@mui/material";
|
||||||
import FieldActions from "field/FieldActions";
|
import FieldActions from "field/FieldActions";
|
||||||
import { Settings } from "@mui/icons-material";
|
import { Settings } from "@mui/icons-material";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
@ -12,28 +12,82 @@ import FieldMinimap from "field/Fieldminimap";
|
||||||
import Weather from "weather/weather";
|
import Weather from "weather/weather";
|
||||||
import TaskViewer from "tasks/TaskViewer";
|
import TaskViewer from "tasks/TaskViewer";
|
||||||
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import HarvestPlanTable from "harvestPlan/HarvestPlanTable";
|
||||||
|
|
||||||
export default function FieldPage() {
|
export default function FieldPage() {
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
//const [{ as }] = useGlobalState()
|
//const [{ as }] = useGlobalState()
|
||||||
|
const fieldAPI = useFieldAPI();
|
||||||
|
const userAPI = useUserAPI();
|
||||||
|
const [{as, user}] = useGlobalState();
|
||||||
|
const {openSnack} = useSnackbar();
|
||||||
|
const fieldID = useParams<{ fieldID: string }>()?.fieldID ?? "";
|
||||||
const [field, setField] = useState<Field>(state?.field ? Field.create(state.field) : Field.create())
|
const [field, setField] = useState<Field>(state?.field ? Field.create(state.field) : Field.create())
|
||||||
const [permissions, setPermissions] = useState<pond.Permission[]>(state?.permissions ? state.permissions : [])
|
const [permissions, setPermissions] = useState<pond.Permission[]>(state?.permissions ? state.permissions : [])
|
||||||
const isMobile = useMobile()
|
const isMobile = useMobile()
|
||||||
const [openFieldSettings, setOpenFieldSettings] = useState(false)
|
const [openFieldSettings, setOpenFieldSettings] = useState(false)
|
||||||
const [planLoading, setPlanLoading] = useState(false)
|
const [planLoading, setPlanLoading] = useState(false)
|
||||||
const [hPlan, setHPlan] = useState<HarvestPlan>(HarvestPlan.create());
|
const [hPlan, setHPlan] = useState<HarvestPlan>(HarvestPlan.create());
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const hPlanAPI = useHarvestPlanAPI();
|
||||||
|
|
||||||
const loadField = () => {
|
const loadField = useCallback(() => {
|
||||||
|
|
||||||
}
|
},[as])
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(state.field){
|
// if already loading do nothing
|
||||||
|
if(loading) return
|
||||||
|
//if the field is passed through in the state just use it
|
||||||
|
if(state?.field){
|
||||||
let field = Field.create(state.field)
|
let field = Field.create(state.field)
|
||||||
|
field.permissions = state.permissions
|
||||||
setField(field)
|
setField(field)
|
||||||
setPermissions(state.permissions)
|
setPermissions(state.permissions)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
},[state.field])
|
//otherwise load the field
|
||||||
|
setLoading(true)
|
||||||
|
fieldAPI.getField(fieldID, as).then(resp => {
|
||||||
|
setField(Field.create(resp.data))
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("Failed to load Field")
|
||||||
|
}).finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
//also get the permissions
|
||||||
|
let scope = fieldScope(fieldID);
|
||||||
|
if (as) {
|
||||||
|
scope = teamScope(as)
|
||||||
|
}
|
||||||
|
userAPI.getUser(user.id(), scope).then(resp => {
|
||||||
|
let f = cloneDeep(field)
|
||||||
|
f.permissions = resp.permissions
|
||||||
|
setField(f)
|
||||||
|
setPermissions(resp.permissions);
|
||||||
|
});
|
||||||
|
},[loadField, fieldID, as])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (field.key() !== "") {
|
||||||
|
hPlanAPI
|
||||||
|
.listHarvestPlans(1, 0, "desc", "createDate", field.key(), as)
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.data.harvestPlan.length > 0) {
|
||||||
|
let plan = resp.data.harvestPlan[0];
|
||||||
|
setHPlan(HarvestPlan.any(plan));
|
||||||
|
} else {
|
||||||
|
setHPlan(HarvestPlan.create());
|
||||||
|
}
|
||||||
|
setPlanLoading(false);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
//openSnack("Failed to load plan");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [field, as, hPlanAPI]);
|
||||||
|
|
||||||
const fieldActions = () => {
|
const fieldActions = () => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -60,14 +114,12 @@ export default function FieldPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const harvestPlans = () => {
|
const harvestPlans = () => {
|
||||||
console.log(permissions)
|
|
||||||
return (
|
return (
|
||||||
<HarvestPlanDisplay
|
<HarvestPlanDisplay
|
||||||
plan={hPlan}
|
plan={hPlan}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
planField={field}
|
planField={field}
|
||||||
loading={planLoading}
|
loading={planLoading}
|
||||||
fieldList={[field]}
|
|
||||||
changePlan={updatedPlan => {
|
changePlan={updatedPlan => {
|
||||||
if (updatedPlan) {
|
if (updatedPlan) {
|
||||||
setHPlan(updatedPlan);
|
setHPlan(updatedPlan);
|
||||||
|
|
@ -87,18 +139,31 @@ export default function FieldPage() {
|
||||||
|
|
||||||
const desktopView = () => {
|
const desktopView = () => {
|
||||||
return (
|
return (
|
||||||
<Grid2 container>
|
<Grid2 container spacing={1}>
|
||||||
<Grid2 size={4}>
|
<Grid2 size={4}>
|
||||||
|
<Card raised>
|
||||||
{map()}
|
{map()}
|
||||||
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={3}>
|
<Grid2 size={3}>
|
||||||
|
<Card raised>
|
||||||
{weather()}
|
{weather()}
|
||||||
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={5}>
|
<Grid2 size={5}>
|
||||||
|
<Card raised>
|
||||||
{tasks()}
|
{tasks()}
|
||||||
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={12}>
|
<Grid2 size={4}>
|
||||||
|
<Card raised>
|
||||||
{harvestPlans()}
|
{harvestPlans()}
|
||||||
|
</Card>
|
||||||
|
</Grid2>
|
||||||
|
<Grid2 size={8}>
|
||||||
|
<Card>
|
||||||
|
<HarvestPlanTable field={field.key()}/>
|
||||||
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
)
|
)
|
||||||
|
|
@ -116,8 +181,10 @@ export default function FieldPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
|
<Box padding={2}>
|
||||||
{fieldActions()}
|
{fieldActions()}
|
||||||
{isMobile ? mobileView() : desktopView()}
|
{isMobile ? mobileView() : desktopView()}
|
||||||
|
</Box>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import { permissionToString } from "pbHelpers/Permission";
|
||||||
|
|
||||||
export interface IFieldAPIContext {
|
export interface IFieldAPIContext {
|
||||||
addField: (field: pond.FieldSettings, otherTeam?: string) => Promise<any>;
|
addField: (field: pond.FieldSettings, otherTeam?: string) => Promise<any>;
|
||||||
getField: (fieldId: string, otherTeam?: string) => Promise<any>;
|
getField: (fieldId: string, otherTeam?: string) => Promise<AxiosResponse<pond.Field>>;
|
||||||
listFields: (
|
listFields: (
|
||||||
limit: number,
|
limit: number,
|
||||||
offset: number,
|
offset: number,
|
||||||
|
|
@ -53,8 +53,8 @@ export default function FieldProvider(props: PropsWithChildren<Props>) {
|
||||||
|
|
||||||
const getField = (fieldId: string, otherTeam?: string) => {
|
const getField = (fieldId: string, otherTeam?: string) => {
|
||||||
const view = otherTeam ? otherTeam : as
|
const view = otherTeam ? otherTeam : as
|
||||||
if (view) return get(pondURL("/field/" + fieldId + "?as=" + view));
|
if (view) return get<pond.Field>(pondURL("/field/" + fieldId + "?as=" + view));
|
||||||
return get(pondURL("/field/" + fieldId));
|
return get<pond.Field>(pondURL("/field/" + fieldId));
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeField = (key: string, otherTeam?: string) => {
|
const removeField = (key: string, otherTeam?: string) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue