Continued work on the historical pages.

This commit is contained in:
2022-09-09 08:10:19 -07:00
parent d6bd620207
commit 5c0ef1f46c
11 changed files with 512 additions and 51 deletions

View File

@@ -1,17 +0,0 @@
import { Meteor } from 'meteor/meteor';
import React, { useState, useEffect } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { useTheme } from '@mui/material/styles';
import _ from 'lodash';
import SimpleTable from "/imports/ui/util/SimpleTable";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import Select from '@mui/material/Select';
import Chip from '@mui/material/Chip';
import MenuItem from '@mui/material/MenuItem';
import {InputLabel, List, ListItem, ListItemButton, ListItemText} from "@mui/material";
import Box from "@mui/material/Box";
import OutlinedInput from '@mui/material/OutlinedInput';
import FormControl from '@mui/material/FormControl';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';

View File

@@ -0,0 +1,125 @@
import { Meteor } from 'meteor/meteor';
import React, { useState, useEffect } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { useTheme } from '@mui/material/styles';
import _ from 'lodash';
import SimpleTable from "/imports/ui/util/SimpleTable";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import Select from '@mui/material/Select';
import Chip from '@mui/material/Chip';
import MenuItem from '@mui/material/MenuItem';
import {InputLabel, List, ListItem, ListItemButton, ListItemText} from "@mui/material";
import Box from "@mui/material/Box";
import OutlinedInput from '@mui/material/OutlinedInput';
import FormControl from '@mui/material/FormControl';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import {useNavigate} from "react-router-dom";
import {Students} from "/imports/api/students";
import {Staff} from "/imports/api/staff";
import {Assets} from "/imports/api/assets";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Paper from "@mui/material/Paper";
import InputBase from "@mui/material/InputBase";
import IconButton from "@mui/material/IconButton";
import SearchIcon from "@mui/icons-material/Search";
export default () => {
const navigate = useNavigate()
const [resultType, setResultType] = useState("usage")
const [searchType, setSearchType] = useState("email")
const [value, setValue] = useState("")
const search = () => {
if(searchType === 'email' || searchType === 'firstName' || searchType === 'lastName') {
if (value && value.length > 1) {
let query = searchType === 'email' ? {email: {$regex: value, $options: 'i'}} : searchType === 'firstName' ? {firstName: {$regex: value, $options: 'i'}} : {lastName: {$regex: value, $options: 'i'}}
let students = Students.find(query).fetch()
let staff = Staff.find(query).fetch()
let all = [...staff, ...students]
if (all.length > 1) {
setPeopleToPickFrom(all)
setOpenPickPersonDialog(true)
} else if (all.length === 1) {
navigate("/history/search?resultType=" + encodeURIComponent(resultType) + "&" + (students.length ? "studentId" : 'staffId') + "=" + encodeURIComponent(all[0]._id));
}
}
}
else if(searchType === 'assetID' || searchType === 'serial') {
let asset = Assets.findOne(searchType === 'assetID' ? {assetId: value} : {serial : value});
if(asset) {
if(searchType === 'assetID')
navigate("/history/search?resultType=" + encodeURIComponent(resultType) + "&assetId=" + encodeURIComponent(asset.assetId))
else
navigate("/history/search?resultType=" + encodeURIComponent(resultType) + "&serial=" + encodeURIComponent(asset.serial))
}
}
}
Meteor.subscribe('students');
Meteor.subscribe('staff');
Meteor.subscribe('assets');
const [openPickPersonDialog, setOpenPickPersonDialog] = useState(false)
const [peopleToPickFrom, setPeopleToPickFrom] = useState([])
const pickPersonClosed = (cause, person) => {
if(openPickPersonDialog) setOpenPickPersonDialog(false)
if(person && person._id) {
navigate("/history/search?resultType=" + encodeURIComponent(resultType) + "&" + (person.grade ? "studentId" : 'staffId') + "=" + encodeURIComponent(person._id));
}
}
return (
<>
<Dialog open={openPickPersonDialog}>
<DialogTitle>Pick One</DialogTitle>
<DialogContent style={{display: 'flex', flexDirection: 'column'}}>
<List>
{peopleToPickFrom.map((next, i) => {
return (
<ListItemButton key={next._id} onClick={(e) => {pickPersonClosed("selection", next)}}>
<ListItemText primary={next.firstName + " " + next.lastName} secondary={next.email}/>
</ListItemButton>
)
})}
</List>
</DialogContent>
<DialogActions>
<Button onClick={() => pickPersonClosed("button")}>Cancel</Button>
</DialogActions>
</Dialog>
<div style={{display: "flex", flexDirection: "column"}} sx={{ p: '2px 4px', display: 'flex', alignItems: 'center', width: 400 }}>
<Paper componet='form'>
<div style={{marginBottom: "1rem", marginTop: "2rem"}}>
<ToggleButtonGroup color="primary" value={resultType} exclusive onChange={(e, type)=>setResultType(type)} aria-label="Result Type">
<ToggleButton value="usage">Usage History</ToggleButton>
<ToggleButton value="assignment">Assignment History</ToggleButton>
</ToggleButtonGroup>
</div>
<div style={{marginBottom: "1rem"}}>
<ToggleButtonGroup color="primary" value={searchType} exclusive onChange={(e, type)=>setSearchType(type)} aria-label="Search Type">
<ToggleButton value="email">Email</ToggleButton>
<ToggleButton value="firstName">First Name</ToggleButton>
<ToggleButton value="lastName">Last Name</ToggleButton>
<ToggleButton value="assetId">Asset ID</ToggleButton>
<ToggleButton value="serial">Serial</ToggleButton>
</ToggleButtonGroup>
</div>
<div>
<InputBase value={value} onChange={(e) => {setValue(e.target.value)}} sx={{ ml: 1, flex: 1 }} placeholder="Value" inputProps={{ 'aria-label': 'Search Value' }}/>
<IconButton type="button" sx={{ p: '10px' }} aria-label="search" onClick={search}>
<SearchIcon />
</IconButton>
</div>
</Paper>
</div>
</>
)
}

View File

@@ -9,7 +9,6 @@ import Button from "@mui/material/Button";
import Select from '@mui/material/Select';
import Chip from '@mui/material/Chip';
import MenuItem from '@mui/material/MenuItem';
import {InputLabel, List, ListItem, ListItemButton, ListItemText} from "@mui/material";
import Paper from '@mui/material/Paper';
import InputBase from '@mui/material/InputBase';
import IconButton from '@mui/material/IconButton';
@@ -19,20 +18,76 @@ import OutlinedInput from '@mui/material/OutlinedInput';
import FormControl from '@mui/material/FormControl';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { useNavigate } from "react-router-dom";
import {Students} from "/imports/api/students";
import {Staff} from "/imports/api/staff";
import {conditions} from "/imports/api/assets";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Dialog from "@mui/material/Dialog";
import {InputLabel, List, ListItem, ListItemButton, ListItemText} from "@mui/material";
export default () => {
const navigate = useNavigate()
const [value, setValue] = useState("")
const search = () => {
if(value && value.length > 1) {
let students = Students.find({email: {$regex: value, $options: 'i'}}).fetch()
let staff = Staff.find({email: {$regex: value, $options: 'i'}}).fetch()
let all = [...staff, ...students]
if(all.length > 1) {
setPeopleToPickFrom(all)
setOpenPickPersonDialog(true)
}
else if(all.length === 1) {
navigate("/history/search?" + (students.length ? "studentId" : 'staffId') + "=" + encodeURIComponent(all[0]._id));
}
}
}
Meteor.subscribe('students');
Meteor.subscribe('staff');
const [openPickPersonDialog, setOpenPickPersonDialog] = useState(false)
const [peopleToPickFrom, setPeopleToPickFrom] = useState([])
const pickPersonClosed = (cause, person) => {
if(openPickPersonDialog) setOpenPickPersonDialog(false)
if(person && person._id) {
navigate("/history/search?" + (person.grade ? "studentId" : 'staffId') + "=" + encodeURIComponent(person._id));
}
}
return (
<div style={{display: "flex", flexDirection: "column"}} sx={{ p: '2px 4px', display: 'flex', alignItems: 'center', width: 400 }}>
<Paper componet='form'>
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="Email"
inputProps={{ 'aria-label': 'Search Email' }}
/>
<IconButton type="button" sx={{ p: '10px' }} aria-label="search">
<SearchIcon />
</IconButton>
</Paper>
</div>
<>
<Dialog open={openPickPersonDialog}>
<DialogTitle>Pick One</DialogTitle>
<DialogContent style={{display: 'flex', flexDirection: 'column'}}>
<List>
{peopleToPickFrom.map((next, i) => {
return (
<ListItemButton key={next._id} onClick={(e) => {pickPersonClosed("selection", next)}}>
<ListItemText primary={next.firstName + " " + next.lastName} secondary={next.email}/>
</ListItemButton>
)
})}
</List>
</DialogContent>
<DialogActions>
<Button onClick={() => pickPersonClosed("button")}>Cancel</Button>
</DialogActions>
</Dialog>
<div style={{display: "flex", flexDirection: "column"}} sx={{ p: '2px 4px', display: 'flex', alignItems: 'center', width: 400 }}>
<Paper componet='form'>
<InputBase value={value} onChange={(e) => {setValue(e.target.value)}} sx={{ ml: 1, flex: 1 }} placeholder="Email" inputProps={{ 'aria-label': 'Search Email' }}/>
<IconButton type="button" sx={{ p: '10px' }} aria-label="search" onClick={search}>
<SearchIcon />
</IconButton>
</Paper>
</div>
</>
)
}

View File

@@ -0,0 +1,135 @@
import { Meteor } from 'meteor/meteor';
import React, { useState, useEffect } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import _ from 'lodash';
// import queryString from 'query-string'
import {Link, useSearchParams} from "react-router-dom";
const RenderUsage = ({data}) => {
return (
<>
<ul>
{data.map((next, i) => (
<li key={next._id}>
{next.person && (
<>
User: {next.person.firstName} {next.person.lastName} {next.person.grade ? "~ " + next.person.grade : ""} (<Link to={"/history/search?email=" + encodeURIComponent(next.email)}>{next.email}</Link>)<br/>
</>
)}
Device ID: <Link to={"/history/search?deviceId=" + encodeURIComponent(next.deviceId)}>{next.deviceId}</Link><br/>
Serial: <Link to={"/history/search?serial=" + encodeURIComponent(next.serial)}>{next.serial}</Link><br/>
{next.asset && (
<>
Asset ID: <Link to={"/history/search?assetId=" + encodeURIComponent(next.asset.assetId)}>{next.asset.assetId}</Link><br/>
</>
)}
{new Date(next.startTime).toLocaleDateString("en-US") + "-" + new Date(next.endTime).toLocaleDateString("en-US")}
{next.assetType && (
<>
<br/>Asset Type: {next.assetType.name}
</>
)}
{next.assignedTo && (
<>
<br/>Currently assigned to: {next.assignedTo.firstName} {next.assignedTo.lastName} {next.assignedTo.grade ? "~ " + next.assignedTo.grade : ""} ({next.assignedTo.email})
</>
)}
</li>
))}
</ul>
</>
)
}
const RenderAssignments = ({data}) => {
return (
<>
<ul>
{data.map((next, i) => (
<li key={next._id}>
{next.assignee && (
<>
User: {next.assignee.firstName} {next.assignee.lastName} {next.assignee.grade ? "~ " + next.assignee.grade : ""} (<Link to={"/history/search?email=" + encodeURIComponent(next.assignee.email)}>{next.assignee.email}</Link>)<br/>
</>
)}
Serial: <Link to={"/history/search?serial=" + encodeURIComponent(next.serial)}>{next.serial}</Link><br/>
{next.asset && (
<>
Asset ID: <Link to={"/history/search?assetId=" + encodeURIComponent(next.asset.assetId)}>{next.asset.assetId}</Link><br/>
</>
)}
{next.assetType && (
<>
Asset Type: {next.assetType.name}<br/>
</>
)}
{new Date(next.startDate).toLocaleDateString("en-US") + "-" + new Date(next.endDate).toLocaleDateString("en-US")}<br/>
Comment: {next.comment}<br/>
Start Condition: {next.startCondition}<br/>
Details: {next.startConditionDetails}<br/>
End Condition: {next.endCondition}<br/>
Details: {next.endConditionDetails}<br/>
</li>
))}
</ul>
</>
)
}
export default () => {
// const query = queryString.parse(search)
const [data, setData] = useState([])
const [search, setSearch] = useSearchParams()
useEffect(() => {
let args;
if(search.get('resultType') === 'usage') {
if(search.get('studentId')) {
args = {studentId: search.get('studentId')}
}
else if(search.get('staffId')) {
args = {staffId: search.get('staffId')}
}
else if(search.get('email')) {
args = {email: search.get('email')}
}
else if(search.get('deviceId')) {
args = {deviceId: search.get('deviceId')}
}
else if(search.get('serial')) {
args = {serial: search.get('serial')}
}
else if(search.get('assetId')) {
args = {assetId: search.get('assetId')}
}
Meteor.call('DataCollection.chromebookData', args, (err, result) => {
if (err) console.error(err)
else setData(result)
})
}
else {
if(search.get('studentId')) {
args = {studentId: search.get('studentId')}
}
else if(search.get('staffId')) {
args = {staffId: search.get('staffId')}
}
else if(search.get('serial')) {
args = {serial: search.get('serial')}
}
else if(search.get('assetId')) {
args = {assetId: search.get('assetId')}
}
Meteor.call('AssetAssignmentHistory.get', args, (err, result) => {
if (err) console.error(err)
else setData(result)
})
}
}, [search])
return (search.get('resultType') === 'usage' ? <RenderUsage data={data}/> : <RenderAssignments data={data}/>)
}