teams list now renders
This commit is contained in:
parent
17c559bdfc
commit
e95b654d7f
81 changed files with 6132 additions and 40 deletions
197
src/teams/TeamActions.tsx
Normal file
197
src/teams/TeamActions.tsx
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
import {
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import RemoveSelfIcon from "@mui/icons-material/ExitToApp";
|
||||
import MoreIcon from "@mui/icons-material/MoreVert";
|
||||
import GroupSettingsIcon from "@mui/icons-material/Settings";
|
||||
import ShareObjectIcon from "@mui/icons-material/Share";
|
||||
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
|
||||
import { Team, teamScope } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import React, { useState } from "react";
|
||||
import ObjectUsers from "user/ObjectUsers";
|
||||
import RemoveSelfFromObject from "user/RemoveSelfFromObject";
|
||||
import ShareObject from "user/ShareObject";
|
||||
import { isOffline } from "utils/environment";
|
||||
import TeamSettings from "./TeamSettings";
|
||||
import NotificationButton from "common/NotificationButton";
|
||||
import { blue } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
shareIcon: {
|
||||
color: blue["500"],
|
||||
"&:hover": {
|
||||
color: blue["600"]
|
||||
}
|
||||
},
|
||||
removeIcon: {
|
||||
color: "var(--status-alert)"
|
||||
},
|
||||
red: {
|
||||
color: "var(--status-alert)"
|
||||
}
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
team: Team;
|
||||
permissions: pond.Permission[];
|
||||
refreshCallback: () => void;
|
||||
preferences: pond.TeamPreferences;
|
||||
toggleNotificationPreference: () => void;
|
||||
}
|
||||
|
||||
interface OpenState {
|
||||
share: boolean;
|
||||
users: boolean;
|
||||
teams: boolean;
|
||||
settings: boolean;
|
||||
removeSelf: boolean;
|
||||
}
|
||||
|
||||
export default function TeamActions(props: Props) {
|
||||
const classes = useStyles();
|
||||
const { team, permissions, refreshCallback, preferences, toggleNotificationPreference } = props;
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const [openState, setOpenState] = useState<OpenState>({
|
||||
share: false,
|
||||
users: false,
|
||||
teams: false,
|
||||
settings: false,
|
||||
removeSelf: false
|
||||
});
|
||||
|
||||
const groupMenu = () => {
|
||||
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
|
||||
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
|
||||
return (
|
||||
<Menu
|
||||
id="groupMenu"
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={() => setAnchorEl(null)}
|
||||
keepMounted
|
||||
disableAutoFocusItem>
|
||||
{!isOffline() && canShare && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setOpenState({ ...openState, share: true });
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
// button
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ShareObjectIcon className={classes.shareIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Share" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isOffline() && canManageUsers && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setOpenState({ ...openState, users: true });
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
// button
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ObjectUsersIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Users" />
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setOpenState({ ...openState, removeSelf: true });
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
// button
|
||||
>
|
||||
<ListItemIcon>
|
||||
<RemoveSelfIcon className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Leave" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
const dialogs = () => {
|
||||
const key = team.key();
|
||||
const label = team.name();
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TeamSettings
|
||||
team={team}
|
||||
permissions={permissions}
|
||||
teamDialogOpen={openState.settings}
|
||||
closeTeamDialogCallback={() => {
|
||||
setOpenState({ ...openState, settings: false });
|
||||
}}
|
||||
refreshCallback={refreshCallback}
|
||||
/>
|
||||
<ShareObject
|
||||
scope={teamScope(key)}
|
||||
label={label}
|
||||
permissions={permissions}
|
||||
isDialogOpen={openState.share}
|
||||
closeDialogCallback={() => setOpenState({ ...openState, share: false })}
|
||||
/>
|
||||
<ObjectUsers
|
||||
scope={teamScope(key)}
|
||||
label={label}
|
||||
permissions={permissions}
|
||||
isDialogOpen={openState.users}
|
||||
closeDialogCallback={() => setOpenState({ ...openState, users: false })}
|
||||
refreshCallback={refreshCallback}
|
||||
/>
|
||||
<RemoveSelfFromObject
|
||||
scope={teamScope(key)}
|
||||
label={label}
|
||||
isDialogOpen={openState.removeSelf}
|
||||
closeDialogCallback={() => setOpenState({ ...openState, removeSelf: false })}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const canWrite = permissions.includes(pond.Permission.PERMISSION_WRITE);
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* <NotificationButton
|
||||
notify={preferences.notify}
|
||||
onChange={toggleNotificationPreference}
|
||||
tooltip={
|
||||
"Notifications for " +
|
||||
team.name() +
|
||||
" are " +
|
||||
(preferences.notify ? "enabled" : "disabled")
|
||||
}
|
||||
// hidden={isLoading}
|
||||
/> */}
|
||||
{canWrite && (
|
||||
<Tooltip title="Team Settings">
|
||||
<IconButton onClick={() => setOpenState({ ...openState, settings: true })}>
|
||||
<GroupSettingsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<IconButton
|
||||
aria-owns={anchorEl ? "groupMenu" : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => setAnchorEl(event.currentTarget)}>
|
||||
<MoreIcon />
|
||||
</IconButton>
|
||||
{groupMenu()}
|
||||
{dialogs()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
360
src/teams/TeamList.tsx
Normal file
360
src/teams/TeamList.tsx
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
Card,
|
||||
Theme,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemText,
|
||||
Typography,
|
||||
ListItemSecondaryAction,
|
||||
Divider,
|
||||
useTheme,
|
||||
TextField,
|
||||
InputAdornment,
|
||||
CircularProgress,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
} from "@mui/material";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useTeamAPI, useUserAPI } from "providers";
|
||||
import { Team, teamScope } from "models";
|
||||
import { useNavigate } from "react-router";
|
||||
// import TeamActions from "./TeamActions";
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import NextIcon from "@mui/icons-material/NavigateNext";
|
||||
import PrevIcon from "@mui/icons-material/NavigateBefore";
|
||||
import LastIcon from "@mui/icons-material/SkipNext";
|
||||
import FirstIcon from "@mui/icons-material/SkipPrevious";
|
||||
import TeamSettings from "./TeamSettings";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import { makeStyles, styled } from "@mui/styles";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
cardContent: {
|
||||
padding: theme.spacing(1)
|
||||
},
|
||||
clickable: {
|
||||
"&:hover": {
|
||||
textDecoration: "underline",
|
||||
cursor: "pointer"
|
||||
}
|
||||
},
|
||||
input: {
|
||||
marginLeft: "auto",
|
||||
marginRight: theme.spacing(2),
|
||||
marginTop: theme.spacing(1)
|
||||
}
|
||||
}))
|
||||
|
||||
const limits = [
|
||||
{
|
||||
value: 5,
|
||||
label: "5"
|
||||
},
|
||||
{
|
||||
value: 10,
|
||||
label: "10"
|
||||
},
|
||||
{
|
||||
value: 15,
|
||||
label: "15"
|
||||
},
|
||||
{
|
||||
value: 20,
|
||||
label: "20"
|
||||
}
|
||||
];
|
||||
|
||||
interface Props {}
|
||||
|
||||
export default function TeamList(props: Props) {
|
||||
const classes = useStyles();
|
||||
const [teams, setTeams] = useState<pond.Team[]>([]);
|
||||
const teamAPI = useTeamAPI();
|
||||
const userAPI = useUserAPI();
|
||||
const history = useNavigate();
|
||||
const theme = useTheme();
|
||||
const [{ user, as }] = useGlobalState();
|
||||
const [teamPerms, setTeamPerms] = useState<pond.Permission[][]>([]);
|
||||
const [teamPrefs, setTeamPrefs] = useState<pond.TeamPreferences[]>([]);
|
||||
const [total, setTotal] = useState<number>(0);
|
||||
const [limit, setLimit] = useState<number>(5);
|
||||
const [page, setPage] = useState<number>(0);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
const [teamDialogOpen, setTeamDialogOpen] = useState<boolean>(false);
|
||||
const [asUser, setAsUser] = useState<string | undefined>(undefined);
|
||||
const [userId, setUserId] = useState<string | undefined>(undefined);
|
||||
const [isUser, setIsUser] = useState<boolean>(true);
|
||||
|
||||
// const ColorAdd = styled(Add)((theme: Theme) => ({
|
||||
// color: theme.palette.getContrastText(theme.palette.primary.main),
|
||||
// backgroundColor: theme.palette.primary.main,
|
||||
// marginTop: 'auto',
|
||||
// marginBottom: 'auto',
|
||||
// borderRadius: '4px',
|
||||
// '&:hover': {
|
||||
// backgroundColor: theme.palette.primary.light,
|
||||
// cursor: 'pointer',
|
||||
// },
|
||||
// '&:disabled': {
|
||||
// backgroundColor: 'rgba(0,0,0,0)',
|
||||
// color: theme.palette.getContrastText(theme.palette.primary.main),
|
||||
// },
|
||||
// }));
|
||||
|
||||
useEffect(() => {
|
||||
if (as.includes("auth0")) setAsUser(as);
|
||||
}, [as]);
|
||||
|
||||
useEffect(() => {
|
||||
setUserId(user.id());
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!asUser) {
|
||||
setIsUser(true);
|
||||
return;
|
||||
}
|
||||
setIsUser(userId === asUser);
|
||||
}, [userId, asUser]);
|
||||
|
||||
const loadTeams = useCallback(() => {
|
||||
setLoading(true);
|
||||
let newTeamPerms: pond.Permission[][] = [];
|
||||
let newTeamPrefs: pond.TeamPreferences[] = [];
|
||||
let searchString = search;
|
||||
teamAPI
|
||||
.listTeams(limit, limit * page, undefined, "name", searchString, undefined, asUser)
|
||||
.then(resp => {
|
||||
setTotal(resp.data.total);
|
||||
resp.data.teams.forEach((team, index) => {
|
||||
let u = asUser ? asUser : user.id();
|
||||
if (team.settings && u !== "") {
|
||||
userAPI
|
||||
.getUser(u, teamScope(team.settings?.key))
|
||||
.then(resp => {
|
||||
newTeamPerms[index] = resp.permissions;
|
||||
newTeamPrefs[index] = resp.preferences;
|
||||
})
|
||||
.finally(() => {
|
||||
if (newTeamPerms[index]) setTeamPerms([...newTeamPerms]);
|
||||
if (newTeamPrefs[index]) setTeamPrefs(newTeamPrefs);
|
||||
});
|
||||
}
|
||||
});
|
||||
setTeams(resp.data.teams);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [user, teamAPI, userAPI, limit, page, search, asUser]);
|
||||
|
||||
useEffect(() => {
|
||||
loadTeams();
|
||||
}, [user, teamAPI, userAPI, limit, page, search, asUser, loadTeams]);
|
||||
|
||||
const drawTeams = () => {
|
||||
return (
|
||||
<List>
|
||||
{teams.map((team, index) => {
|
||||
let permissions = teamPerms[index];
|
||||
if (!permissions) {
|
||||
permissions = [];
|
||||
}
|
||||
let preferences = teamPrefs[index];
|
||||
if (!preferences) {
|
||||
preferences = pond.TeamPreferences.create();
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
onClick={() => {
|
||||
if (team.settings) history("teams/" + team.settings.key);
|
||||
}}
|
||||
src={team.settings?.avatar}
|
||||
alt=""
|
||||
className={classes.clickable}
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<div
|
||||
className={classes.clickable}
|
||||
onClick={() => {
|
||||
if (team.settings) history("teams/" + team.settings.key);
|
||||
}}>
|
||||
{team.settings?.name}
|
||||
</div>
|
||||
}
|
||||
secondary={
|
||||
<React.Fragment>
|
||||
<Typography component="span" variant="body2" color="textPrimary">
|
||||
{team.settings?.info}
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
{/* <ListItemSecondaryAction>
|
||||
<TeamActions
|
||||
team={Team.create(team)}
|
||||
permissions={permissions}
|
||||
refreshCallback={loadTeams}
|
||||
preferences={preferences}
|
||||
toggleNotificationPreference={() => {
|
||||
if (preferences) {
|
||||
let newTeamPrefs = cloneDeep(teamPrefs);
|
||||
newTeamPrefs[index].notify = !newTeamPrefs[index].notify;
|
||||
console.log(newTeamPrefs[index]);
|
||||
teamAPI
|
||||
.updatePreferences(
|
||||
Team.create(team).key(),
|
||||
newTeamPrefs[index],
|
||||
getContextKeys(),
|
||||
getContextTypes()
|
||||
)
|
||||
.then(resp => {
|
||||
setTeamPrefs(newTeamPrefs);
|
||||
});
|
||||
// setTeamPrefs(newTeamPrefs)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</ListItemSecondaryAction> */}
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
const showProgress = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
textAlign: "center"
|
||||
}}>
|
||||
<CircularProgress
|
||||
style={{
|
||||
textAlign: "center",
|
||||
marginTop: theme.spacing(12),
|
||||
marginBottom: theme.spacing(12)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const firstPage = () => {
|
||||
setPage(0);
|
||||
};
|
||||
|
||||
const lastPage = () => {
|
||||
setPage(Math.round(total / limit));
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (limit * (page + 1) < total) setPage(page + 1);
|
||||
};
|
||||
|
||||
const prevPage = () => {
|
||||
if (page > 0) setPage(page - 1);
|
||||
};
|
||||
|
||||
const handleChange = (event: any) => {
|
||||
setLimit(event.target.value);
|
||||
};
|
||||
|
||||
const showPageButtons = () => {
|
||||
return (
|
||||
<div style={{ display: "flex", float: "right", alignItems: "center" }}>
|
||||
<Typography style={{ marginRight: theme.spacing(2) }}>Teams per page:</Typography>
|
||||
<TextField
|
||||
select
|
||||
value={limit}
|
||||
onChange={handleChange}
|
||||
style={{ marginRight: theme.spacing(1) }}>
|
||||
{limits.map(option => (
|
||||
<MenuItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
<IconButton disabled={page < 1} size="small" color="inherit" onClick={firstPage}>
|
||||
<FirstIcon />
|
||||
</IconButton>
|
||||
<IconButton disabled={page < 1} size="small" color="inherit" onClick={prevPage}>
|
||||
<PrevIcon />
|
||||
</IconButton>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
style={{ marginRight: theme.spacing(1), marginLeft: theme.spacing(1) }}>
|
||||
{limit * page + 1} ‐ {limit * page + limit <= limit ? limit * page + limit : limit + 1} of{" "}
|
||||
{total}
|
||||
</Typography>
|
||||
<IconButton
|
||||
disabled={limit * (page + 1) >= total}
|
||||
size="small"
|
||||
color="inherit"
|
||||
onClick={nextPage}>
|
||||
<NextIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
disabled={limit * (page + 1) >= total}
|
||||
size="small"
|
||||
color="inherit"
|
||||
onClick={lastPage}>
|
||||
<LastIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className={classes.cardContent}>
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<Typography
|
||||
variant={"h6"}
|
||||
style={{
|
||||
marginLeft: theme.spacing(1),
|
||||
marginTop: "auto",
|
||||
marginBottom: "auto",
|
||||
marginRight: theme.spacing(2)
|
||||
}}>
|
||||
{isUser ? user.name() + "'s " : "Someone's "} Teams
|
||||
</Typography>
|
||||
<Add onClick={() => setTeamDialogOpen(true)} />
|
||||
<TextField
|
||||
className={classes.input}
|
||||
value={search}
|
||||
onChange={event => setSearch(event?.target.value)}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
)
|
||||
}}></TextField>
|
||||
</div>
|
||||
<Typography variant={"subtitle2"} style={{ marginLeft: theme.spacing(2) }}>
|
||||
{isUser ? "Viewing all teams that you are a part of" : "These are someone else's teams"}
|
||||
</Typography>
|
||||
{!loading ? drawTeams() : showProgress()}
|
||||
{showPageButtons()}
|
||||
<TeamSettings
|
||||
teamDialogOpen={teamDialogOpen}
|
||||
closeTeamDialogCallback={() => setTeamDialogOpen(false)}
|
||||
refreshCallback={loadTeams}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
265
src/teams/TeamSettings.tsx
Normal file
265
src/teams/TeamSettings.tsx
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
import {
|
||||
Box,
|
||||
Button,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { Team } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useSnackbar, useTeamAPI } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import DeleteButton from "common/DeleteButton";
|
||||
import { userRoleFromPermissions } from "pbHelpers/User";
|
||||
import { IconPicker } from "common/IconPicker";
|
||||
|
||||
interface Props {
|
||||
teamDialogOpen: boolean;
|
||||
closeTeamDialogCallback: () => void;
|
||||
refreshCallback?: () => void;
|
||||
team?: Team;
|
||||
permissions?: pond.Permission[];
|
||||
}
|
||||
|
||||
export default function TeamSettings(props: Props) {
|
||||
const theme = useTheme();
|
||||
const teamAPI = useTeamAPI();
|
||||
const { teamDialogOpen, closeTeamDialogCallback, permissions, refreshCallback } = props;
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [nameField, setNameField] = useState<string>("");
|
||||
const [infoField, setInfoField] = useState<string>("");
|
||||
const [url, setUrl] = useState<string>("");
|
||||
const snackbar = useSnackbar();
|
||||
const [tab, setTab] = useState(0);
|
||||
const [team, setTeam] = useState<Team>();
|
||||
const [teamKey, setTeamKey] = useState<string>();
|
||||
const [openDelete, setOpenDelete] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.team) {
|
||||
setTeam(props.team);
|
||||
setTeamKey(props.team.key());
|
||||
}
|
||||
}, [props.team]);
|
||||
|
||||
useEffect(() => {
|
||||
if (team) {
|
||||
setNameField(team.name());
|
||||
setInfoField(team.settings.info);
|
||||
setUrl(team.settings.avatar);
|
||||
}
|
||||
}, [team]);
|
||||
|
||||
// const ColorButton = withStyles((theme: Theme) => ({
|
||||
// root: {
|
||||
// color: theme.palette.getContrastText(theme.palette.primary.main),
|
||||
// backgroundColor: theme.palette.primary.main,
|
||||
// "&:hover": {
|
||||
// backgroundColor: theme.palette.primary.light
|
||||
// },
|
||||
// "&:disabled": {
|
||||
// backgroundColor: "rgba(0,0,0,0)",
|
||||
// color: theme.palette.getContrastText(theme.palette.primary.main)
|
||||
// }
|
||||
// }
|
||||
// }))(Button);
|
||||
|
||||
const removeTeam = () => {
|
||||
if (team?.key())
|
||||
teamAPI
|
||||
.removeTeam(team?.key())
|
||||
.then(() => {
|
||||
snackbar.info("Team removed successfully.");
|
||||
if (refreshCallback) refreshCallback();
|
||||
closeTeamDialogCallback();
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const addTeam = () => {
|
||||
let team = pond.TeamSettings.create();
|
||||
team.name = nameField;
|
||||
team.info = infoField;
|
||||
setLoading(true);
|
||||
teamAPI
|
||||
.addTeam(team)
|
||||
.then(resp => {
|
||||
snackbar.success("Team added successfully!");
|
||||
setTab(1);
|
||||
let t = pond.Team.create();
|
||||
t.settings = team;
|
||||
setTeam(Team.create(t));
|
||||
setTeamKey(resp.data.team);
|
||||
if (refreshCallback) refreshCallback();
|
||||
})
|
||||
.catch(err => {
|
||||
snackbar.error(err);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const updateTeam = () => {
|
||||
let newTeam = pond.TeamSettings.create();
|
||||
newTeam.name = nameField;
|
||||
newTeam.info = infoField;
|
||||
newTeam.avatar = url;
|
||||
if (teamKey) {
|
||||
teamAPI
|
||||
.updateTeam(teamKey, newTeam)
|
||||
.then(() => {
|
||||
snackbar.success("Team update successfully!");
|
||||
})
|
||||
.catch(err => {
|
||||
snackbar.error(err);
|
||||
})
|
||||
.finally(() => {
|
||||
if (refreshCallback) refreshCallback();
|
||||
setNameField("");
|
||||
setInfoField("");
|
||||
setUrl("");
|
||||
setTeamKey(undefined);
|
||||
setTab(0);
|
||||
closeTeamDialogCallback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const disableButton = () => {
|
||||
if (loading) return true;
|
||||
if (nameField === "" || infoField === "") return true;
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
setNameField("");
|
||||
setInfoField("");
|
||||
setUrl("");
|
||||
closeTeamDialogCallback();
|
||||
};
|
||||
|
||||
const isOwner = () => {
|
||||
if (permissions) {
|
||||
return userRoleFromPermissions(permissions) === "Owner";
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const deleteConfirmation = () => {
|
||||
return (
|
||||
<ResponsiveDialog
|
||||
open={openDelete}
|
||||
onClose={() => {
|
||||
setOpenDelete(false);
|
||||
}}>
|
||||
<DialogTitle>Delete Team</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
Performing this action will delete this team and and any file attachments associated
|
||||
with it.
|
||||
</Typography>
|
||||
<Typography>Are you sure you wish to continue.</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenDelete(false);
|
||||
}}>
|
||||
Close
|
||||
</Button>
|
||||
<DeleteButton onClick={removeTeam}>Confirm</DeleteButton>
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
};
|
||||
|
||||
const teamSettings = () => {
|
||||
return (
|
||||
<DialogContent>
|
||||
<DialogContentText style={{ margin: theme.spacing(1) }}>
|
||||
Add more info about your team, business, or company. You can have multiple teams if
|
||||
needed.
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
label="Name"
|
||||
value={nameField}
|
||||
onChange={event => setNameField(event?.target.value)}
|
||||
variant="outlined"
|
||||
style={{ margin: theme.spacing(1) }}
|
||||
fullWidth
|
||||
/>
|
||||
<div style={{ marginTop: theme.spacing(1) }} />
|
||||
<TextField
|
||||
label="Info"
|
||||
value={infoField}
|
||||
onChange={event => setInfoField(event?.target.value)}
|
||||
variant="outlined"
|
||||
style={{ margin: theme.spacing(1) }}
|
||||
fullWidth
|
||||
/>
|
||||
</DialogContent>
|
||||
);
|
||||
};
|
||||
|
||||
let disable = disableButton();
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ResponsiveDialog open={teamDialogOpen} onClose={close}>
|
||||
<DialogTitle>{team ? "Update " + team.name() + "?" : "Create New Team?"}</DialogTitle>
|
||||
<Box style={{ borderBottom: 1, borderColor: "divider" }}>
|
||||
<Tabs
|
||||
value={tab}
|
||||
onChange={(_, value) => setTab(value)}
|
||||
aria-label="basic tabs example"
|
||||
centered>
|
||||
<Tab label="Name & Info" key={1} />
|
||||
<Tab
|
||||
label="Team Icon"
|
||||
key={2}
|
||||
disabled={team?.key() === undefined || team?.key() === ""}
|
||||
/>
|
||||
</Tabs>
|
||||
</Box>
|
||||
{tab === 0 && teamSettings()}
|
||||
{tab === 1 && teamKey !== undefined && (
|
||||
<DialogContent>
|
||||
<IconPicker setUrl={setUrl} url={url} id={teamKey} />
|
||||
</DialogContent>
|
||||
)}
|
||||
<DialogActions>
|
||||
{isOwner() && (
|
||||
<DeleteButton
|
||||
onClick={() => {
|
||||
setOpenDelete(true);
|
||||
}}
|
||||
aria-label="Cancel"
|
||||
style={{ marginRight: "auto", marginLeft: theme.spacing(2) }}>
|
||||
Delete
|
||||
</DeleteButton>
|
||||
)}
|
||||
<Button onClick={close} color="primary" aria-label="Cancel">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
disabled={disable}
|
||||
onClick={teamKey ? updateTeam : addTeam}
|
||||
style={{ marginRight: theme.spacing(2) }}>
|
||||
<Typography variant="subtitle2" color="textPrimary">
|
||||
{teamKey ? "Update" : "Submit"}
|
||||
</Typography>
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
{deleteConfirmation()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue