teams list now uses responsive container
This commit is contained in:
parent
7ee06c4e19
commit
c94b8093ff
5 changed files with 147 additions and 261 deletions
|
|
@ -50,7 +50,7 @@ export interface Column<T> {
|
||||||
interface Props<T> {
|
interface Props<T> {
|
||||||
rows: T[],
|
rows: T[],
|
||||||
columns?: Column<T>[],
|
columns?: Column<T>[],
|
||||||
title?: string;
|
title?: string | JSX.Element;
|
||||||
total: number,
|
total: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
page: number,
|
page: number,
|
||||||
|
|
@ -63,6 +63,7 @@ interface Props<T> {
|
||||||
rowsPerPageOptions?: number[];
|
rowsPerPageOptions?: number[];
|
||||||
noDataMessage?: string;
|
noDataMessage?: string;
|
||||||
renderMobile?: (row: T) => JSX.Element;
|
renderMobile?: (row: T) => JSX.Element;
|
||||||
|
hideKeys?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
|
|
@ -82,6 +83,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
rowsPerPageOptions,
|
rowsPerPageOptions,
|
||||||
noDataMessage,
|
noDataMessage,
|
||||||
renderMobile,
|
renderMobile,
|
||||||
|
hideKeys,
|
||||||
} = props
|
} = props
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
|
|
@ -169,7 +171,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
)
|
)
|
||||||
if (title) return (
|
if (title) return (
|
||||||
<Box className={classes.title}>
|
<Box className={classes.title}>
|
||||||
title
|
{title}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
@ -185,16 +187,16 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
)
|
)
|
||||||
if (columns) {
|
if (columns) {
|
||||||
return (
|
return (
|
||||||
<Grid2 container direction={"row"} spacing={2} padding={2}>
|
<Grid2 container direction={"row"} spacing={1} >
|
||||||
{columns.map((column, index) => {
|
{columns.map((column, index) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={"mobile-row-column-"+index}>
|
<React.Fragment key={"mobile-row-column-"+index}>
|
||||||
<Grid2 size={{ xs: 3 }} alignContent={"center"}>
|
{ !hideKeys && <Grid2 size={{ xs: 3 }} alignContent={"center"}>
|
||||||
<Typography fontWeight={"bold"} >
|
<Typography fontWeight={"bold"} >
|
||||||
{column.title+": "}
|
{column.title+": "}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid2>
|
</Grid2>}
|
||||||
<Grid2 size={{ xs: 9 }} alignContent={"center"}>
|
<Grid2 size={{ xs: hideKeys ? 12 : 9 }} alignContent={"center"} >
|
||||||
{column.render(row)}
|
{column.render(row)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
@ -294,7 +296,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
</Typography>
|
</Typography>
|
||||||
:
|
:
|
||||||
title && <Box className={classes.title}>
|
title && <Box className={classes.title}>
|
||||||
title
|
{title}
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
@ -306,7 +308,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
{ !hideKeys && <TableRow>
|
||||||
{ renderGutter && <TableCell></TableCell>}
|
{ renderGutter && <TableCell></TableCell>}
|
||||||
{ columns ?
|
{ columns ?
|
||||||
columns.map((column, index) => {
|
columns.map((column, index) => {
|
||||||
|
|
@ -325,7 +327,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{ isLoading ?
|
{ isLoading ?
|
||||||
|
|
@ -340,14 +342,14 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
rows.map((row, index) => {
|
rows.map((row, index) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={"row-"+index}>
|
<React.Fragment key={"row-"+index}>
|
||||||
<TableRow>
|
<TableRow >
|
||||||
{renderGutter &&
|
{renderGutter &&
|
||||||
<TableCell width={1}>
|
<TableCell width={1}>
|
||||||
<IconButton sx={{
|
<IconButton sx={{
|
||||||
transform: openGutters.includes(index) ?
|
transform: openGutters.includes(index) ?
|
||||||
'rotate(90deg)' : 'rotate(0deg)',
|
'rotate(90deg)' : 'rotate(0deg)',
|
||||||
transition: 'transform 0.3s ease',
|
transition: 'transform 0.3s ease',
|
||||||
marginRight: -1
|
marginRight: isMobile ? -1 : 0
|
||||||
}}
|
}}
|
||||||
onClick={() => handleCollapse(index)}>
|
onClick={() => handleCollapse(index)}>
|
||||||
<ChevronRight/>
|
<ChevronRight/>
|
||||||
|
|
@ -357,7 +359,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
{columns ?
|
{columns ?
|
||||||
columns.map((column, j) => {
|
columns.map((column, j) => {
|
||||||
if (column.render) return (
|
if (column.render) return (
|
||||||
<TableCell key={"row-"+index+"cell-"+j} sx={column.cellStyle}>
|
<TableCell key={"row-"+index+"cell-"+j} sx={{ padding: 0}} >
|
||||||
{column.render(row)}
|
{column.render(row)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)
|
)
|
||||||
|
|
@ -369,9 +371,10 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
})
|
})
|
||||||
:
|
:
|
||||||
Object.values(row).map((value, j) => {
|
Object.values(row).map((value, j) => {
|
||||||
|
console
|
||||||
return (
|
return (
|
||||||
<TableCell key={"row-"+index+"cell-"+j}>
|
<TableCell key={"row-"+index+"cell-"+j}>
|
||||||
{value.toString()}
|
{value ? value.toString() : ""}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,10 @@
|
||||||
import { Box } from "@mui/material";
|
|
||||||
import { useMobile } from "hooks";
|
|
||||||
import PageContainer from "pages/PageContainer";
|
import PageContainer from "pages/PageContainer";
|
||||||
import TeamList from "teams/TeamList";
|
import TeamList from "teams/TeamList";
|
||||||
|
|
||||||
export default function Teams() {
|
export default function Teams() {
|
||||||
const isMobile = useMobile();
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<Box paddingY={isMobile ? 1 : 1.5} paddingX={isMobile ? 1 : 2}>
|
<TeamList />
|
||||||
<TeamList />
|
|
||||||
</Box>
|
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ export default function Users() {
|
||||||
</Avatar>
|
</Avatar>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<ListItem style={{ padding: 0 }}>
|
<ListItem sx={{ padding: 0 }}>
|
||||||
<ListItemAvatar>{avatar}</ListItemAvatar>
|
<ListItemAvatar>{avatar}</ListItemAvatar>
|
||||||
<ListItemText primary={user.name()} secondary={user.settings.email} />
|
<ListItemText primary={user.name()} secondary={user.settings.email} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
@ -252,7 +252,7 @@ export default function Users() {
|
||||||
render: user => {
|
render: user => {
|
||||||
const actions = user.settings.actions;
|
const actions = user.settings.actions;
|
||||||
return (
|
return (
|
||||||
<Grid2 container spacing={1} className={classes.chipContainer}>
|
<Grid2 container spacing={1} className={classes.chipContainer} padding={1}>
|
||||||
{actions.slice(0, 2).map(action => flagChip(action))}
|
{actions.slice(0, 2).map(action => flagChip(action))}
|
||||||
{actions.length > 3 && flagChip("+" + (actions.length - 3) + " more")}
|
{actions.length > 3 && flagChip("+" + (actions.length - 3) + " more")}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
@ -265,7 +265,7 @@ export default function Users() {
|
||||||
render: user => {
|
render: user => {
|
||||||
const features = user.settings.features;
|
const features = user.settings.features;
|
||||||
return (
|
return (
|
||||||
<Grid2 container spacing={1} className={classes.chipContainer}>
|
<Grid2 container spacing={1} className={classes.chipContainer} padding={1}>
|
||||||
{features.slice(0, 2).map(feature => flagChip(feature))}
|
{features.slice(0, 2).map(feature => flagChip(feature))}
|
||||||
{features.length > 3 && flagChip("+" + (features.length - 3) + " more")}
|
{features.length > 3 && flagChip("+" + (features.length - 3) + " more")}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,27 @@
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Card,
|
|
||||||
Theme,
|
Theme,
|
||||||
List,
|
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemAvatar,
|
ListItemAvatar,
|
||||||
Avatar,
|
Avatar,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
Typography,
|
Typography,
|
||||||
ListItemSecondaryAction,
|
ListItemButton,
|
||||||
Divider,
|
Box,
|
||||||
useTheme,
|
|
||||||
TextField,
|
|
||||||
InputAdornment,
|
|
||||||
CircularProgress,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
MenuItem,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useTeamAPI, useUserAPI } from "providers";
|
import { useGlobalState, useTeamAPI, useUserAPI } from "providers";
|
||||||
import { Team, teamScope } from "models";
|
import { Team, teamScope } from "models";
|
||||||
import { useNavigate } from "react-router";
|
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 { AddBox } from "@mui/icons-material";
|
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import TeamActions from "./TeamActions";
|
import TeamActions from "./TeamActions";
|
||||||
|
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||||
|
import { useMobile } from "hooks";
|
||||||
|
import { AddBox } from "@mui/icons-material";
|
||||||
|
import TeamSettings from "./TeamSettings";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
cardContent: {
|
cardContent: {
|
||||||
|
|
@ -54,96 +43,63 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
height: theme.spacing(6),
|
height: theme.spacing(6),
|
||||||
marginTop: "auto",
|
marginTop: "auto",
|
||||||
marginBottom: "auto"
|
marginBottom: "auto"
|
||||||
|
},
|
||||||
|
titleBox: {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const limits = [
|
|
||||||
{
|
|
||||||
value: 5,
|
|
||||||
label: "5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 10,
|
|
||||||
label: "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 15,
|
|
||||||
label: "15"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 20,
|
|
||||||
label: "20"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function TeamList() {
|
export default function TeamList() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [teams, setTeams] = useState<pond.Team[]>([]);
|
const [teams, setTeams] = useState<Team[]>([]);
|
||||||
const teamAPI = useTeamAPI();
|
const teamAPI = useTeamAPI();
|
||||||
const userAPI = useUserAPI();
|
const userAPI = useUserAPI();
|
||||||
const history = useNavigate();
|
const history = useNavigate();
|
||||||
const theme = useTheme();
|
const isMobile = useMobile()
|
||||||
const [{ user, as }] = useGlobalState();
|
const [{ user, as }] = useGlobalState();
|
||||||
const [teamPerms, setTeamPerms] = useState<pond.Permission[][]>([]);
|
const [teamPerms, setTeamPerms] = useState<Map<string | number, pond.Permission[]>>(new Map());
|
||||||
const [teamPrefs, setTeamPrefs] = useState<pond.TeamPreferences[]>([]);
|
const [teamPrefs, setTeamPrefs] = useState<Map<string | number, pond.TeamPreferences> >(new Map());
|
||||||
const [total, setTotal] = useState<number>(0);
|
const [total, setTotal] = useState<number>(0);
|
||||||
const [limit, setLimit] = useState<number>(5);
|
const [limit, setLimit] = useState<number>(5);
|
||||||
const [page, setPage] = useState<number>(0);
|
const [page, setPage] = useState<number>(0);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [search, setSearch] = useState<string>("");
|
const [search, setSearch] = useState<string>("");
|
||||||
const [teamDialogOpen, setTeamDialogOpen] = useState<boolean>(false);
|
|
||||||
const [asUser, setAsUser] = useState<string | undefined>(undefined);
|
const [asUser, setAsUser] = useState<string | undefined>(undefined);
|
||||||
const [userId, setUserId] = useState<string | undefined>(undefined);
|
const [teamDialogOpen, setTeamDialogOpen] = useState<boolean>(false);
|
||||||
const [isUser, setIsUser] = useState<boolean>(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (as.includes("auth0")) setAsUser(as);
|
if (as.includes("auth0")) setAsUser(as);
|
||||||
}, [as]);
|
}, [as]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setUserId(user.id());
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!asUser) {
|
|
||||||
setIsUser(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsUser(userId === asUser);
|
|
||||||
}, [userId, asUser]);
|
|
||||||
|
|
||||||
// Convert string array to valid Permission[] array
|
|
||||||
// const convertToPermissions = (permissions: any[]): pond.Permission[] => {
|
|
||||||
// return permissions
|
|
||||||
// .map(p => p as any as pond.Permission) // Type assertion to treat strings as Permission
|
|
||||||
// .filter(p => Object.entries(pond.Permission).includes(p)); // Filter to ensure valid Permission values
|
|
||||||
// };
|
|
||||||
|
|
||||||
const loadTeams = useCallback(() => {
|
const loadTeams = useCallback(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let newTeamPerms: pond.Permission[][] = [];
|
let newTeamPerms: Map<string | number, pond.Permission[]> = new Map();
|
||||||
let newTeamPrefs: pond.TeamPreferences[] = [];
|
let newTeamPrefs: Map<string | number, pond.TeamPreferences> = new Map();
|
||||||
let searchString = search;
|
let searchString = search;
|
||||||
teamAPI
|
teamAPI
|
||||||
.listTeams(limit, limit * page, undefined, "name", searchString, undefined, asUser)
|
.listTeams(limit, limit * page, undefined, "name", searchString, undefined, asUser)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
setTotal(resp.data.total);
|
setTotal(resp.data.total ? resp.data.total : 0);
|
||||||
resp.data.teams.forEach((team, index) => {
|
let newTeams: Team[] = []
|
||||||
|
resp.data.teams.forEach(team => {
|
||||||
let u = asUser ? asUser : user.id();
|
let u = asUser ? asUser : user.id();
|
||||||
|
let t = Team.create(team)
|
||||||
if (team.settings && u !== "") {
|
if (team.settings && u !== "") {
|
||||||
userAPI
|
userAPI
|
||||||
.getUser(u, teamScope(team.settings?.key))
|
.getUser(u, teamScope(team.settings.key))
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
newTeamPerms[index] = resp.permissions;
|
newTeamPerms.set(t.key(), resp.permissions)
|
||||||
newTeamPrefs[index] = resp.preferences;
|
newTeamPrefs.set(t.key(), resp.preferences)
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (newTeamPerms[index]) setTeamPerms([...newTeamPerms]);
|
setTeamPerms(newTeamPerms);
|
||||||
if (newTeamPrefs[index]) setTeamPrefs(newTeamPrefs);
|
setTeamPrefs(newTeamPrefs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
newTeams.push(Team.create(team))
|
||||||
});
|
});
|
||||||
setTeams(resp.data.teams);
|
setTeams(newTeams);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -154,49 +110,58 @@ export default function TeamList() {
|
||||||
loadTeams();
|
loadTeams();
|
||||||
}, [user, teamAPI, userAPI, limit, page, search, asUser, loadTeams]);
|
}, [user, teamAPI, userAPI, limit, page, search, asUser, loadTeams]);
|
||||||
|
|
||||||
const drawTeams = () => {
|
const columns = (): Column<Team>[] => {
|
||||||
return (
|
return [
|
||||||
<List>
|
{
|
||||||
{teams.map((team, index) => {
|
title: "",
|
||||||
let permissions = teamPerms[index];
|
render: team => {
|
||||||
|
let permissions = teamPerms.get(team.settings?.key);
|
||||||
if (!permissions) {
|
if (!permissions) {
|
||||||
permissions = [];
|
permissions = [];
|
||||||
}
|
}
|
||||||
let preferences = teamPrefs[index];
|
let preferences = teamPrefs.get(team.id());
|
||||||
if (!preferences) {
|
if (!preferences) {
|
||||||
preferences = pond.TeamPreferences.create();
|
preferences = pond.TeamPreferences.create();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={index}>
|
<ListItem
|
||||||
<ListItem
|
alignItems="flex-start"
|
||||||
alignItems="flex-start"
|
disablePadding={!isMobile}
|
||||||
secondaryAction={
|
secondaryAction={
|
||||||
<TeamActions
|
<TeamActions
|
||||||
team={Team.create(team)}
|
team={team}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
refreshCallback={loadTeams}
|
refreshCallback={loadTeams}
|
||||||
removeSelfCallback={loadTeams}
|
removeSelfCallback={loadTeams}
|
||||||
preferences={preferences}
|
preferences={preferences}
|
||||||
toggleNotificationPreference={() => {
|
toggleNotificationPreference={() => {
|
||||||
if (preferences) {
|
if (preferences) {
|
||||||
let newTeamPrefs = cloneDeep(teamPrefs);
|
let newTeamPrefs = cloneDeep(teamPrefs);
|
||||||
newTeamPrefs[index].notify = !newTeamPrefs[index].notify;
|
let prefs = newTeamPrefs.get(team.id()) ?? pond.TeamPreferences.create()
|
||||||
teamAPI
|
console.log(prefs)
|
||||||
.updatePreferences(
|
prefs.notify = !newTeamPrefs.get(team.id())?.notify
|
||||||
Team.create(team).key(),
|
newTeamPrefs.set(team.id(), prefs)
|
||||||
newTeamPrefs[index],
|
teamAPI
|
||||||
getContextKeys(),
|
.updatePreferences(
|
||||||
getContextTypes()
|
team.key(),
|
||||||
)
|
prefs,
|
||||||
.then(() => {
|
getContextKeys(),
|
||||||
setTeamPrefs(newTeamPrefs);
|
getContextTypes()
|
||||||
});
|
)
|
||||||
}
|
.then(() => {
|
||||||
}}
|
setTeamPrefs(newTeamPrefs);
|
||||||
/>
|
});
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton
|
||||||
|
onClick={() => {
|
||||||
|
if (team.settings) history(team.settings.key);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar sx={{ marginLeft: isMobile ? -2 : 0 }}>
|
||||||
<Avatar
|
<Avatar
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (team.settings) history(team.settings.key);
|
if (team.settings) history(team.settings.key);
|
||||||
|
|
@ -208,152 +173,73 @@ export default function TeamList() {
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
<div
|
<Typography fontWeight={"bold"}>
|
||||||
className={classes.clickable}
|
|
||||||
onClick={() => {
|
|
||||||
if (team.settings) history(team.settings.key);
|
|
||||||
}}>
|
|
||||||
{team.settings?.name}
|
{team.settings?.name}
|
||||||
</div>
|
</Typography>
|
||||||
}
|
}
|
||||||
secondary={
|
secondary={
|
||||||
<React.Fragment>
|
!isMobile && <React.Fragment>
|
||||||
<Typography component="span" variant="body2" color="textPrimary">
|
<Typography component="span" variant="body2" color="textSecondary">
|
||||||
{team.settings?.info}
|
{team.settings?.info}
|
||||||
</Typography>
|
</Typography>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItemButton>
|
||||||
<Divider variant="inset" component="li" />
|
</ListItem>
|
||||||
</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) => {
|
const handleChange = (event: any) => {
|
||||||
setLimit(event.target.value);
|
setLimit(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showPageButtons = () => {
|
const renderGutter = (team: Team) => {
|
||||||
return (
|
return(
|
||||||
<div style={{ display: "flex", float: "right", alignItems: "center" }}>
|
<Typography variant="body2" color="textSecondary" sx={{ padding: 1 }}>
|
||||||
<Typography style={{ marginRight: theme.spacing(2) }}>Teams per page:</Typography>
|
{team.settings.info}
|
||||||
<TextField
|
</Typography>
|
||||||
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 (
|
const renderTitle = () => {
|
||||||
<Card className={classes.cardContent}>
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<Box className={classes.titleBox}>
|
||||||
<Typography
|
<Typography variant="h5">
|
||||||
variant={"h6"}
|
Teams
|
||||||
style={{
|
|
||||||
marginLeft: theme.spacing(1),
|
|
||||||
marginTop: "auto",
|
|
||||||
marginBottom: "auto",
|
|
||||||
marginRight: theme.spacing(2)
|
|
||||||
}}>
|
|
||||||
{isUser ? user.name() + "'s " : "Someone's "} Teams
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton onClick={() => setTeamDialogOpen(true)} color="primary" className={classes.button}>
|
<IconButton onClick={() => setTeamDialogOpen(true)} color="primary" className={classes.button}>
|
||||||
<AddBox/>
|
<AddBox/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<TextField
|
</Box>
|
||||||
className={classes.input}
|
)
|
||||||
value={search}
|
}
|
||||||
onChange={event => setSearch(event?.target.value)}
|
|
||||||
InputProps={{
|
return (
|
||||||
startAdornment: (
|
<>
|
||||||
<InputAdornment position="start">
|
<ResponsiveTable<Team>
|
||||||
<SearchIcon />
|
title={renderTitle()}
|
||||||
</InputAdornment>
|
rows={teams}
|
||||||
)
|
columns={columns()}
|
||||||
}}></TextField>
|
handleRowsPerPageChange={handleChange}
|
||||||
</div>
|
total={total}
|
||||||
<Typography variant={"subtitle2"} style={{ marginLeft: theme.spacing(2) }}>
|
pageSize={limit}
|
||||||
{isUser ? "Viewing all teams that you are a part of" : "These are someone else's teams"}
|
page={page}
|
||||||
</Typography>
|
setPage={setPage}
|
||||||
{!loading ? drawTeams() : showProgress()}
|
setSearchText={setSearch}
|
||||||
{showPageButtons()}
|
isLoading={loading}
|
||||||
<TeamSettings
|
renderGutter={isMobile ? renderGutter : undefined}
|
||||||
teamDialogOpen={teamDialogOpen}
|
hideKeys
|
||||||
closeTeamDialogCallback={() => setTeamDialogOpen(false)}
|
/>
|
||||||
refreshCallback={loadTeams}
|
<TeamSettings
|
||||||
/>
|
teamDialogOpen={teamDialogOpen}
|
||||||
</Card>
|
closeTeamDialogCallback={() => setTeamDialogOpen(false)}
|
||||||
);
|
refreshCallback={loadTeams}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -247,13 +247,15 @@ export default function TeamSettings(props: Props) {
|
||||||
</DeleteButton>
|
</DeleteButton>
|
||||||
)}
|
)}
|
||||||
<Button onClick={close} color="primary" aria-label="Cancel">
|
<Button onClick={close} color="primary" aria-label="Cancel">
|
||||||
Cancel
|
<Typography variant="subtitle2" color="textPrimary">
|
||||||
|
Cancel
|
||||||
|
</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={disable}
|
disabled={disable}
|
||||||
onClick={teamKey ? updateTeam : addTeam}
|
onClick={teamKey ? updateTeam : addTeam}
|
||||||
style={{ marginRight: theme.spacing(2) }}>
|
style={{ marginRight: theme.spacing(2) }}>
|
||||||
<Typography variant="subtitle2" color="textPrimary">
|
<Typography variant="subtitle2" color="primary">
|
||||||
{teamKey ? "Update" : "Submit"}
|
{teamKey ? "Update" : "Submit"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue