added way for users to share all fields

This commit is contained in:
csawatzky 2025-08-27 16:06:59 -06:00
parent 4db21a3d0c
commit 3802691977
4 changed files with 173 additions and 24 deletions

View file

@ -244,14 +244,12 @@ const columns: Column<Field>[] = [
return ( return (
<Box> <Box>
{isMobile &&
<Button <Button
onClick={()=>{setShareOpen(true)}} onClick={()=>{setShareOpen(true)}}
variant="contained" variant="contained"
color="primary"> color="primary">
Share All Share All
</Button> </Button>
}
<Tabs <Tabs
value={tabValue} value={tabValue}
onChange={handleChange} onChange={handleChange}
@ -259,19 +257,6 @@ const columns: Column<Field>[] = [
<Tab label="Adaptive" /> <Tab label="Adaptive" />
<Tab label="John Deere" /> <Tab label="John Deere" />
<Tab label="Case New Holland" /> <Tab label="Case New Holland" />
{!isMobile &&
<Button
style={{
position: "absolute",
top: 0,
right: 0
}}
onClick={()=>{setShareOpen(true)}}
variant="contained"
color="primary">
Share All
</Button>
}
</Tabs> </Tabs>
{fieldTable(fields)} {fieldTable(fields)}
{/* <HarvestSettings {/* <HarvestSettings

View file

@ -1,5 +1,10 @@
import { Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material"; import { Box, Button, Checkbox, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, FormGroup, FormLabel, Grid2, Stack, Switch, TextField } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog"; import ResponsiveDialog from "common/ResponsiveDialog";
import { cloneDeep } from "lodash";
import { pond } from "protobuf-ts/pond";
import { useFieldAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";
import TeamSearch from "teams/TeamSearch";
interface Props { interface Props {
open: boolean open: boolean
@ -8,35 +13,188 @@ interface Props {
export default function ShareAllFields(props: Props) { export default function ShareAllFields(props: Props) {
const {open, close} = props const {open, close} = props
const [teamShare, setTeamShare] = useState(false)
const fieldAPI = useFieldAPI();
const { openSnack } = useSnackbar()
const [team, setTeam] = useState<string>("")
const [user, setUser] = useState<string>("")
const [sharedPermissions, setSharedPermissions] = useState<pond.Permission[]>([
pond.Permission.PERMISSION_READ
])
const share = () => { const share = () => {
if(teamShare){
//if sharing to team use shareAllByKey //if sharing to team use shareAllByKey
fieldAPI.shareAllByKey(team, sharedPermissions)
.then(resp => {
openSnack("Shared all fields to team")
}).catch(err => {
openSnack("There was a problem sharing the fields")
})
}else{
//if sharing to user use shareAll //if sharing to user use shareAll
fieldAPI.shareAll(user, sharedPermissions)
.then(resp => {
openSnack("Shared all fields to user")
}).catch(err => {
openSnack("There was a problem sharing the fields")
})
}
} }
const target = () => { const target = () => {
// toggle for whether sharing to user or team // toggle for whether sharing to user or team
return (
<React.Fragment>
<Grid2 container alignItems="center">
<Grid2>User</Grid2>
<Grid2>
<Switch
color="default"
value={teamShare}
checked={teamShare}
onChange={(_, checked) => {
setTeamShare(checked)
}}
name="storage"
/>
</Grid2>
<Grid2>Team</Grid2>
</Grid2>
{teamShare ?
<Box>
<TeamSearch label="Team" setTeamCallback={(teamKey) => {setTeam(teamKey)}}/>
</Box> :
<Box>
<TextField
label="User Email"
fullWidth
value={user}
onChange={(e) => {
setUser(e.target.value)
}}
/>
</Box>}
</React.Fragment>
)
// if sharing to user have a text field // if sharing to user have a text field
// if sharing to team have the team selector }
const changePermissions = (checked: boolean, permission: pond.Permission) => {
let currentPerms = cloneDeep(sharedPermissions)
if(checked){
//if the permissions does not include the permission add it
if(!sharedPermissions.includes(permission)) currentPerms.push(permission)
}else{
//if the permissions includes the permission remove it
if(sharedPermissions.includes(permission)) currentPerms.splice(currentPerms.indexOf(permission), 1)
}
setSharedPermissions(currentPerms)
} }
const permissions = () => { const permissions = () => {
// the checkboxes of permissions // the checkboxes of permissions
return (
<React.Fragment>
<FormControl sx={{marginTop: 2}} component="fieldset" fullWidth variant="outlined">
<FormLabel component="legend">Permissions</FormLabel>
<FormGroup>
<FormControlLabel
control={
<Checkbox
disabled={sharedPermissions.includes(pond.Permission.PERMISSION_READ)}
checked={sharedPermissions.includes(pond.Permission.PERMISSION_READ)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_READ)}}
value={pond.Permission.PERMISSION_READ as pond.Permission}
/>
}
label="View"
labelPlacement="end"
/>
<FormControlLabel
control={
<Checkbox
checked={sharedPermissions.includes(pond.Permission.PERMISSION_WRITE)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_WRITE)}}
value={pond.Permission.PERMISSION_WRITE as pond.Permission}
/>
}
label="Edit"
labelPlacement="end"
/>
<FormControlLabel
control={
<Checkbox
checked={sharedPermissions.includes(pond.Permission.PERMISSION_SHARE)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_SHARE)}}
value={pond.Permission.PERMISSION_SHARE as pond.Permission}
/>
}
label="Share"
labelPlacement="end"
/>
<FormControlLabel
control={
<Checkbox
checked={sharedPermissions.includes(pond.Permission.PERMISSION_USERS)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_USERS)}}
value={pond.Permission.PERMISSION_USERS as pond.Permission}
/>
}
label="Users"
labelPlacement="end"
/>
<FormControlLabel
control={
<Checkbox
checked={sharedPermissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_FILE_MANAGEMENT)}}
value={pond.Permission.PERMISSION_FILE_MANAGEMENT as pond.Permission}
/>
}
label="Files"
labelPlacement="end"
/>
{/* billing */}
<FormControlLabel
control={
<Checkbox
checked={sharedPermissions.includes(pond.Permission.PERMISSION_BILLING)}
onChange={(_, checked) => {changePermissions(checked, pond.Permission.PERMISSION_BILLING)}}
value={pond.Permission.PERMISSION_BILLING as pond.Permission}
/>
}
label="Billing"
labelPlacement="end"
/>
</FormGroup>
</FormControl>
</React.Fragment>
)
} }
const actions = () => { const actions = () => {
//the buttons to shaare or cancel //the buttons to shaare or cancel
return (
<React.Fragment>
<Button onClick={close}>Close</Button>
<Button onClick={share} variant="contained" color="primary">Share</Button>
</React.Fragment>
)
} }
return ( return (
<ResponsiveDialog open={open} onClose={close}> <ResponsiveDialog open={open} onClose={close}>
<DialogTitle>Share All Fields</DialogTitle> <DialogTitle>Share All Fields</DialogTitle>
<DialogContent> <DialogContent>
Content for selecting target and permissions <Box minWidth={300}>
{target()}
{permissions()}
</Box>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
Buttons for cancel and confirm {actions()}
</DialogActions> </DialogActions>
</ResponsiveDialog> </ResponsiveDialog>
) )

View file

@ -161,7 +161,7 @@ export class Field {
* @param spacing - an optional paramater that will expand the bounding area by the given long lat amount * @param spacing - an optional paramater that will expand the bounding area by the given long lat amount
* @returns LngLatBounds - an object containing the southwest and northeast coordinates of a bounding box * @returns LngLatBounds - an object containing the southwest and northeast coordinates of a bounding box
*/ */
public fieldBounds(spacing?: number): LngLatBounds { public fieldBounds(spacing?: number, squared?: boolean): LngLatBounds {
let minLong = 0; let minLong = 0;
let minLat = 0; let minLat = 0;
let maxLong = 0; let maxLong = 0;
@ -178,6 +178,12 @@ export class Field {
} }
// let southWest = [minLong,minLat] // let southWest = [minLong,minLat]
// let northEast = [maxLong,maxLat] // let northEast = [maxLong,maxLat]
if (squared){
//make sure the bounds are squared so as to fit the entire field in the map
//get the diff between the longs and the lats
//find which is narrower
//take half of the difference between the differences
}
if(spacing){ if(spacing){
minLong = minLong - spacing minLong = minLong - spacing
minLat = minLat - spacing minLat = minLat - spacing

View file

@ -103,7 +103,7 @@ export default function FieldProvider(props: PropsWithChildren<Props>) {
}; };
const shareAll = (email: string, permissions: pond.Permission[]) => { const shareAll = (email: string, permissions: pond.Permission[]) => {
let url = pondURL("/fields/shareAll") let url = pondURL("/shareAllFields")
if (as) url = url + "?as=" + as if (as) url = url + "?as=" + as
return new Promise<AxiosResponse>((resolve, reject) => { return new Promise<AxiosResponse>((resolve, reject) => {
post(url, { post(url, {
@ -118,7 +118,7 @@ export default function FieldProvider(props: PropsWithChildren<Props>) {
} }
const shareAllByKey = (key: string, permissions: pond.Permission[]) => { const shareAllByKey = (key: string, permissions: pond.Permission[]) => {
let url = pondURL("/fields/shareAllByKey") let url = pondURL("/shareAllFieldsByKey")
if (as) url = url + "?as=" + as if (as) url = url + "?as=" + as
return new Promise<AxiosResponse>((resolve, reject) => { return new Promise<AxiosResponse>((resolve, reject) => {
post(url, { post(url, {