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 TextField from "@mui/material/TextField"; import Button from "@mui/material/Button"; import MenuItem from '@mui/material/MenuItem'; import {InputLabel, List, ListItem, ListItemButton, ListItemText, Switch} from "@mui/material"; import Box from "@mui/material/Box"; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; import {Assets, conditions} from "/imports/api/assets"; import {AssetTypes} from "/imports/api/asset-types"; import {Students} from "/imports/api/students"; import {Staff} from "/imports/api/staff"; import {Link, useLocation, useNavigate, useNavigationType} from "react-router-dom"; import { Action as NavigationType } from "@remix-run/router"; import FormControlLabel from "@mui/material/FormControlLabel"; import Tab from '@mui/material/Tab'; import TabContext from '@mui/lab/TabContext'; import TabList from '@mui/lab/TabList'; import TabPanel from '@mui/lab/TabPanel'; const cssTwoColumnContainer = { display: 'grid', gridTemplateColumns: "1fr 1fr", columnGap: '1rem', rowGap: '0.4rem', } const cssEditorField = { minWidth: '10rem' } const AssignmentsByPerson = () => { const navigate = useNavigate() const navigateType = useNavigationType() const location = useLocation() const state = location.state const theme = useTheme() // const [searchType, setSearchType] = useState("Email") const [search, setSearch] = useState(state && state.search ? state.search : "") const [includeInactive, setIncludeInactive] = useState(false) const [selectedPerson, setSelectedPerson] = useState(state && state.person ? state.person : "") const [assetId, setAssetId] = useState("") const [openAssignDialog, setOpenAssignDialog] = useState(false) const [assignCondition, setAssignCondition] = useState(conditions[2]) const [assignConditionDetails, setAssignConditionDetails] = useState("") //Dialog stuff. const [openUnassignDialog, setOpenUnassignDialog] = useState(false) const [unassignDialogEditConditionOnly, setUnassignDialogEditConditionOnly] = useState(false) const [unassignCondition, setUnassignCondition] = useState(conditions[2]) const [unassignComment, setUnassignComment] = useState("") const [unassignConditionDetails, setUnassignConditionDetails] = useState("") const [unassignAsset, setUnassignAsset] = useState(undefined) const [searchInput, setSearchInput] = useState(undefined) const {people} = useTracker(() => { let people = []; if(search && search.length > 1) { let query; query = {$or: [{email: {$regex: search, $options: 'i'}}, {firstName: {$regex: search, $options: 'i'}}, {firstNameAlias: {$regex: search, $options: 'i'}}, {lastName: {$regex: search, $options: 'i'}}]} // if(searchType === "Email") { // query = {email: {$regex: search, $options: 'i'}}; // } else if(searchType === 'First Name') { // query = {firstName: {$regex: search, $options: 'i'}} // } else { // query = {lastName: {$regex: search, $options: 'i'}} // } // Look for students/staff that are active or whose active flag is not set. if(!includeInactive) query = {$and: [query, {$or: [{active: true}, {active: {$exists: false}}]}]} const students = Students.find(query).fetch(); const staff = Staff.find(query).fetch(); for(let next of students) next.type = "Student" for(let next of staff) next.type = "Staff" people = [...staff, ...students] } return {people} }, [search]); const {assets} = useTracker(() => { let assets = []; if(selectedPerson) { assets = Assets.find({assigneeId: selectedPerson._id}).fetch(); for(let next of assets) { next.assetType = AssetTypes.findOne({_id: next.assetTypeId}) } } return {assets} }, [selectedPerson]); const {foundAsset} = useTracker(() => { let foundAsset = null; if(assetId) { foundAsset = Assets.findOne({assetId: assetId}); if(foundAsset) { foundAsset.assetType = AssetTypes.findOne({_id: foundAsset.assetTypeId}) if(foundAsset.assigneeId) foundAsset.assignee = foundAsset.assigneeType === "Student" ? Students.findOne({_id: foundAsset.assigneeId}) : Staff.findOne({_id: foundAsset.assigneeId}) } } return {foundAsset} }, [assetId]); const [usageData, setUsageData] = useState([]) const [assignmentData, setAssignmentData] = useState([]) // Collect the usage and assignment data when the selected person changes. useEffect(() => { try { if(selectedPerson) { let query = selectedPerson.type === "Student" ? {studentId: selectedPerson._id} : {staffId: selectedPerson._id} console.log("Collecting person history") console.log(query) Meteor.call('DataCollection.chromebookData', query, (err, result) => { if (err) console.error(err) else setUsageData(result) }) Meteor.call('AssetAssignmentHistory.get', query, (err, result) => { if (err) console.error(err) else setAssignmentData(result) }) } else setUsageData({}) } catch(e) {console.log("Found error in collecting chromebook history & usage in ByPerson.jsx: " + e)} }, [selectedPerson]) const getListItemStyle = (item) => { return { backgroundColor: selectedPerson === item ? '#EECFA6' : 'white' } } const assign = () => { if(foundAsset) { //Open the dialog to get condition. setAssignCondition(foundAsset.condition ? foundAsset.condition : conditions[2]) setAssignConditionDetails(foundAsset.conditionDetails || "") setOpenAssignDialog(true) } } const assignDialogClosed = (assign) => { setOpenAssignDialog(false) if(assign === true) { // Call assets.assign Meteor.call('assets.assign', foundAsset.assetId, selectedPerson.type, selectedPerson._id, assignCondition, assignConditionDetails, (err, result) => { if(err) console.error(err) else { // Clear the asset id field and set focus to it. setAssetId("") if(assetIdInput) assetIdInput.focus() } }) //document.getElementById('assetIdInput').focus() } } //Force focus to the search input field when initially rendering. useEffect(() => { if(searchInput) searchInput.focus() }, [searchInput]) const unassign = (asset, editConditionOnly) => { // Open the dialog to get condition and comment. setUnassignDialogEditConditionOnly(editConditionOnly) setUnassignAsset(asset); setUnassignComment("") setUnassignCondition(asset.condition ? asset.condition : conditions[2]) setUnassignConditionDetails(asset.conditionDetails || "") setOpenUnassignDialog(true); } const unassignDialogClosed = (unassign) => { setOpenUnassignDialog(false) if(unassign === true) { if(unassignDialogEditConditionOnly) { Meteor.call('assets.updateCondition', unassignAsset._id, unassignCondition, unassignConditionDetails, (err, result) => { if(err) console.error(err) else if(assetIdInput) assetIdInput.focus() }) } else { // Call assets.unassign(assetId, comment, condition, conditionDetails, date) Meteor.call('assets.unassign', unassignAsset.assetId, unassignComment, unassignCondition, unassignConditionDetails, (err, result) => { if(err) console.error(err) else if(assetIdInput) assetIdInput.focus() }) } } } const getAssetTileStyles = (index) => { return index % 2 ? {backgroundColor: '#FFF'} : {backgroundColor: '#d2d2d2'} } const cssAssetTile = { padding: '.8rem', userSelect: 'none', // '&:nthChild(even)': {backgroundColor: '#935e5e'} } // Changes the selected person and updates the browser history. const changeSelectedPerson = (person) => { setSelectedPerson(person) navigate("/assignments/byPerson", {replace: false, state: {person, search}}); } // Restore the state if the forward/back/refresh functionality of the browser was utilized. useEffect(() => { if(!state) navigate("/assignments/byPerson", {replace: true, state: {search: "", person: null}}) else { if(navigateType === "POP" || navigateType === 'REPLACE' || navigateType === "PUSH") { setSearch(state.search) setSelectedPerson(state.person) } } }, [state, navigateType]) const [tab, setTab] = useState('assignments') const RenderUsage = ({data}) => { return ( <> ) } const RenderAssignments = ({data}) => { return ( <> ) } return ( <> Assign Asset
{setAssignCondition(e.target.value)}}> {conditions.map((condition, i) => { return {condition} })}
{setAssignConditionDetails(e.target.value)}}/>
{unassignDialogEditConditionOnly ? "Edit Condition" : "Unassign Asset"}
{setUnassignCondition(e.target.value)}}> {conditions.map((condition, i) => { return {condition} })}
{!unassignDialogEditConditionOnly && {setUnassignComment(e.target.value)}}/>} {setUnassignConditionDetails(e.target.value)}}/>
{/*setSearchType(type)} aria-label="Search Type">*/} {/* Email*/} {/* First Name*/} {/* Last Name*/} {/**/} {setIncludeInactive(e.target.checked)}}/>} label="Inactive"/> setSearchInput(input)} value={search} onChange={(e) => {setSearch(e.target.value)}}/>
{people.map((next, i) => { return ( {changeSelectedPerson(next)}}> ) })}
{selectedPerson && ( <>

{selectedPerson.firstName + " " + (selectedPerson.firstNameAlias ? "'" + selectedPerson.firstNameAlias + "' " : "") + selectedPerson.lastName + (selectedPerson.grade ? " (" + selectedPerson.grade + ")" : "")}

setTab(v)}>
{setAssetId(e.target.value.toUpperCase())}}/>
{foundAsset && ( <>
{foundAsset && foundAsset.assetType.name}
Asset ID: {foundAsset.assetId}
Serial: {foundAsset.serial}
)} {foundAsset && foundAsset.assignee && ( <>
Assigned To: {foundAsset.assignee.firstName} {foundAsset.assignee.lastName}
Assigned: {new Date(foundAsset.assignmentDate).toLocaleDateString("en-US")} ({Math.ceil((new Date().getTime() - foundAsset.assignmentDate) / (1000*60*60*24))} days)
)}
{assets.map((next, i) => { return (
{next.assetType.name}
Asset ID: {next.assetId}
Serial: {next.serial}
Assigned: {new Date(next.assignmentDate).toLocaleDateString("en-US")} ({Math.ceil((new Date().getTime() - next.assignmentDate) / (1000*60*60*24))} days)
{" "}
) })}
)}
) } export default () => { Meteor.subscribe('students'); Meteor.subscribe('staff'); Meteor.subscribe('assetTypes'); Meteor.subscribe('assets'); return ( ) }