336 lines
10 KiB
TypeScript
336 lines
10 KiB
TypeScript
import { Avatar, Box, Button, Card, Grid2 as Grid, Switch, Tab, Tabs, Tooltip, Typography } from "@mui/material";
|
|
import { Group } from "@mui/icons-material";
|
|
//import MaterialTable from "material-table";
|
|
import { Site, User } from "models";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import { useGlobalState, useSiteAPI } from "providers";
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
import PageContainer from "./PageContainer";
|
|
//import { getTableIcons } from "common/ResponsiveTable";
|
|
//import { useHistory } from "react-router";
|
|
import { useMobile } from "hooks";
|
|
import JobsiteIcon from "products/Construction/JobSiteIcon";
|
|
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { cloneDeep } from "lodash";
|
|
|
|
interface SiteWithData {
|
|
site: Site;
|
|
users: User[];
|
|
heaterData: pond.ObjectHeaterData[];
|
|
}
|
|
|
|
interface TabPanelProps {
|
|
children?: React.ReactNode;
|
|
index: any;
|
|
value: any;
|
|
}
|
|
|
|
export default function Sites() {
|
|
const siteAPI = useSiteAPI();
|
|
const [loading, setLoading] = useState(false);
|
|
const [{ as }] = useGlobalState();
|
|
//const history = useHistory();
|
|
const navigate = useNavigate()
|
|
const [sites, setSites] = useState<SiteWithData[]>([]);
|
|
const isMobile = useMobile();
|
|
const [currentTab, setCurrentTab] = useState(0);
|
|
const [tablePage, setTablePage] = useState(0);
|
|
const [pageSize, setPageSize] = useState(10);
|
|
const [total, setTotal] = useState(0)
|
|
|
|
const loadSites = useCallback(() => {
|
|
if (loading) return;
|
|
setLoading(true);
|
|
//make a site api that gets an array of objects that contain the site, its devices, and teams
|
|
siteAPI
|
|
.listSitesPageData(pageSize, tablePage * pageSize, "asc", "siteName", undefined, as)
|
|
.then(resp => {
|
|
setTotal(resp.data.total);
|
|
setSites(buildTableData(resp.data.sites));
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
});
|
|
}, [as, siteAPI, pageSize, tablePage]); //eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
const buildTableData = (siteData: pond.SiteData[]) => {
|
|
let data: SiteWithData[] = [];
|
|
siteData.forEach(site => {
|
|
if (site.site?.settings?.siteName) {
|
|
let newTableData: SiteWithData = {
|
|
site: Site.any(site.site),
|
|
users: [],
|
|
heaterData: []
|
|
};
|
|
if (site.users) {
|
|
newTableData.users = site.users.map(u => User.any(u));
|
|
}
|
|
if (site.heaterData) {
|
|
newTableData.heaterData = site.heaterData;
|
|
}
|
|
data.push(newTableData);
|
|
}
|
|
});
|
|
return data;
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadSites();
|
|
}, [loadSites]);
|
|
|
|
const siteInfoDisplay = (site: SiteWithData) => {
|
|
return (
|
|
<Grid container direction="column">
|
|
<Grid>
|
|
<Typography style={{ fontWeight: 650 }}>{site.site.siteName()}</Typography>
|
|
</Grid>
|
|
<Grid>
|
|
{site.heaterData.length + (site.heaterData.length > 1 ? " Heaters" : " Heater")}
|
|
</Grid>
|
|
</Grid>
|
|
);
|
|
};
|
|
|
|
const goToSite = (jobsite: SiteWithData) => {
|
|
// let path = "/jobsites/" + jobsite.site.settings.key;
|
|
// history.push(path, {});
|
|
let path = "/jobsites/" + jobsite.site.key();
|
|
navigate(path, { state: jobsite.site })
|
|
};
|
|
|
|
const updateActive = (active: boolean, site: Site) => {
|
|
site.settings.active = active;
|
|
siteAPI
|
|
.updateSite(site.key(), site.settings, undefined, as)
|
|
.then(resp => {})
|
|
.catch(err => {});
|
|
setSites([...sites]);
|
|
};
|
|
|
|
const desktopColumns = (): Column<SiteWithData>[] => {
|
|
return ([
|
|
{
|
|
title: "Site",
|
|
render: row => (
|
|
<Box padding={2}>
|
|
<Typography>
|
|
{row.site.siteName()}
|
|
</Typography>
|
|
</Box>
|
|
)
|
|
},
|
|
{
|
|
title: "Heaters",
|
|
render: row => (
|
|
<Grid container spacing={1}>
|
|
{row.heaterData.map((hd: pond.ObjectHeaterData) => (
|
|
<Grid key={hd.heater?.key}>
|
|
{hd.heater?.name}
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
)
|
|
},
|
|
{
|
|
title: "Users",
|
|
render: row => (
|
|
<Grid container spacing={1}>
|
|
{row.users.map((user: User) => (
|
|
<Grid key={user.id()}>
|
|
<Tooltip title={user.name()}>
|
|
{user.settings.avatar ? (
|
|
<Avatar alt={user.settings.name} src={user.settings.avatar} />
|
|
) : (
|
|
<Avatar alt={user.settings.name}>
|
|
<Group />
|
|
</Avatar>
|
|
)}
|
|
</Tooltip>
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
)
|
|
},
|
|
{
|
|
title: "Active",
|
|
render: row => (
|
|
<React.Fragment>
|
|
<Switch
|
|
checked={row.site.settings.active}
|
|
onClick={e => {
|
|
e.stopPropagation();
|
|
}}
|
|
onChange={e => {
|
|
updateActive(e.target.checked, row.site);
|
|
}}
|
|
/>
|
|
</React.Fragment>
|
|
),
|
|
}
|
|
])
|
|
}
|
|
|
|
const handleTablePage = (event: any) => {
|
|
setPageSize(event.target.value);
|
|
};
|
|
|
|
const desktopView = () => {
|
|
return (
|
|
<ResponsiveTable<SiteWithData>
|
|
title={"Jobsites"}
|
|
page={tablePage}
|
|
pageSize={pageSize}
|
|
columns={desktopColumns}
|
|
setPage={(newPage) => {setTablePage(newPage)}}
|
|
total={total}
|
|
rows={sites}
|
|
handleRowsPerPageChange={handleTablePage}
|
|
onRowClick={goToSite}
|
|
loadMore={()=>{
|
|
let current = cloneDeep(sites)
|
|
setLoading(true);
|
|
siteAPI
|
|
.listSitesPageData(pageSize, current.length, "asc", "siteName", undefined, as)
|
|
.then(resp => {
|
|
let newData = buildTableData(resp.data.sites);
|
|
setSites(current.concat(newData))
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
});
|
|
}}
|
|
/>
|
|
)
|
|
};
|
|
|
|
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 handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
|
|
setCurrentTab(newValue);
|
|
};
|
|
|
|
const loadMore = () => {
|
|
let current = cloneDeep(sites)
|
|
setLoading(true);
|
|
siteAPI
|
|
.listSitesPageData(pageSize, current.length, "asc", "siteName", undefined, as)
|
|
.then(resp => {
|
|
let newData = buildTableData(resp.data.sites);
|
|
setSites(current.concat(newData))
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
});
|
|
}
|
|
|
|
const mobileView = () => {
|
|
return (
|
|
<React.Fragment>
|
|
<Tabs
|
|
value={currentTab}
|
|
indicatorColor="primary"
|
|
textColor="primary"
|
|
onChange={handleChange}
|
|
centered
|
|
style={{
|
|
marginLeft: "auto"
|
|
}}>
|
|
<Tab label="Active" />
|
|
<Tab label="Inactive" />
|
|
</Tabs>
|
|
<TabPanelMine value={currentTab} index={0}>
|
|
{sites.map(site => {
|
|
let siteCards: JSX.Element[] = [];
|
|
if (site.site.settings.active) {
|
|
siteCards.push(
|
|
<Card
|
|
key={site.site.key()}
|
|
style={{ margin: 10, padding: 5 }}
|
|
onClick={() => {
|
|
goToSite(site);
|
|
}}>
|
|
<Grid container alignContent="center" alignItems="center">
|
|
<Grid size={2} style={{ textAlign: "center" }}>
|
|
<JobsiteIcon size={50} />
|
|
</Grid>
|
|
<Grid size={7}>
|
|
{/* information (site name, number of devices, teams in site) */}
|
|
{siteInfoDisplay(site)}
|
|
</Grid>
|
|
<Grid size={3}>
|
|
<Switch
|
|
defaultChecked={site.site.settings.active}
|
|
onClick={e => {
|
|
e.stopPropagation();
|
|
}}
|
|
onChange={e => {
|
|
updateActive(e.target.checked, site.site);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</Card>
|
|
);
|
|
}
|
|
return siteCards;
|
|
})}
|
|
</TabPanelMine>
|
|
<TabPanelMine value={currentTab} index={1}>
|
|
{sites.map(site => {
|
|
let siteCards: JSX.Element[] = [];
|
|
if (!site.site.settings.active) {
|
|
siteCards.push(
|
|
<Card
|
|
key={site.site.key()}
|
|
style={{ margin: 10, padding: 5 }}
|
|
onClick={() => {
|
|
goToSite(site);
|
|
}}>
|
|
<Grid container alignContent="center" alignItems="center">
|
|
<Grid size={2} style={{ textAlign: "center" }}>
|
|
<JobsiteIcon size={50} />
|
|
</Grid>
|
|
<Grid size={7}>
|
|
{/* information (site name, number of devices, teams in site) */}
|
|
{siteInfoDisplay(site)}
|
|
</Grid>
|
|
<Grid size={3}>
|
|
<Switch
|
|
defaultChecked={site.site.settings.active}
|
|
onClick={e => {
|
|
e.stopPropagation();
|
|
}}
|
|
onChange={e => {
|
|
updateActive(e.target.checked, site.site);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</Card>
|
|
);
|
|
}
|
|
return siteCards;
|
|
})}
|
|
</TabPanelMine>
|
|
{sites.length < total &&
|
|
<Button onClick={loadMore} variant="contained" color="primary" fullWidth>Load More</Button>
|
|
}
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
return <PageContainer>{isMobile ? mobileView() : desktopView()}</PageContainer>;
|
|
}
|