Modified Assets to update the assetId in the history records when it gets changed. Changing the assetId is handy when a sticker is removed, making it possible to just alter the ID instead of re-printing the sticker.
This commit is contained in:
@@ -24,7 +24,12 @@ 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} from "react-router-dom";
|
||||
import {Link, useLocation, useNavigate, useNavigationType} from "react-router-dom";
|
||||
import {Action as NavigationType} from "@remix-run/router/history";
|
||||
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',
|
||||
@@ -37,6 +42,10 @@ const cssEditorField = {
|
||||
}
|
||||
|
||||
const AssignmentsByAsset = () => {
|
||||
const navigate = useNavigate()
|
||||
const navigateType = useNavigationType()
|
||||
const location = useLocation()
|
||||
const state = location.state
|
||||
const theme = useTheme();
|
||||
const [assetId, setAssetId] = useState("")
|
||||
|
||||
@@ -48,8 +57,7 @@ const AssignmentsByAsset = () => {
|
||||
const [unassignConditionDetails, setUnassignConditionDetails] = useState("")
|
||||
|
||||
const [assetIdInput, setAssetIdInput] = useState(undefined)
|
||||
|
||||
|
||||
|
||||
const {foundAsset} = useTracker(() => {
|
||||
let foundAsset = null;
|
||||
|
||||
@@ -65,12 +73,72 @@ const AssignmentsByAsset = () => {
|
||||
}
|
||||
|
||||
return {foundAsset}
|
||||
});
|
||||
}, [assetId]);
|
||||
|
||||
// Set a timer function to create history for the browser if the user pauses on an asset long enough.
|
||||
useEffect(() => {
|
||||
let clearTimer;
|
||||
|
||||
// Only setup the timer to update navigation if we have found an asset for the current text input, and that asset is not the same as the one already current in the browser history.
|
||||
if(foundAsset && (!state || state.assetId !== foundAsset.assetId)) {
|
||||
const prevFoundAssetId = foundAsset.assetId
|
||||
|
||||
// If the asset id doesn't change in 3 seconds then add this asset to the browser history so the back functionality works.
|
||||
const timer = setTimeout(() => {
|
||||
if(foundAsset && foundAsset.assetId === prevFoundAssetId) navigate("/assignments/byAsset", {replace: false, state: {assetId: foundAsset.assetId}});
|
||||
}, 3000)
|
||||
|
||||
clearTimer = () => clearTimeout(timer)
|
||||
}
|
||||
|
||||
return clearTimer
|
||||
}, [foundAsset])
|
||||
|
||||
const [usageData, setUsageData] = useState([])
|
||||
const [assignmentData, setAssignmentData] = useState([])
|
||||
|
||||
//This works too well. The field always gets focus anytime anything is typed anywhere.
|
||||
// useEffect(() => {
|
||||
// if(assetIdInput) assetIdInput.focus()
|
||||
// })
|
||||
// Collect the usage and assignment data when the selected person changes.
|
||||
useEffect(() => {
|
||||
try {
|
||||
if(foundAsset) {
|
||||
let query = {assetId: foundAsset.assetId}
|
||||
|
||||
console.log("Requesting asset historical data")
|
||||
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 ByAsset.jsx: " + e)}
|
||||
}, [foundAsset])
|
||||
|
||||
// Restore the state if the forward/back/refresh functionality of the browser was utilized.
|
||||
useEffect(() => {
|
||||
console.log("useEffect - navigation")
|
||||
if(!state) {
|
||||
console.log("no state")
|
||||
navigate("/assignments/byAsset", {replace: true, state: {asset: null}})
|
||||
}
|
||||
else {
|
||||
console.log(navigateType)
|
||||
console.log(state)
|
||||
if(navigateType === "POP" || navigateType === 'REPLACE' || navigateType === "PUSH") {
|
||||
setAssetId(state.assetId ? state.assetId : "")
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
|
||||
//Set focus on initial rendering.
|
||||
useEffect(() => {
|
||||
if(assetIdInput) assetIdInput.focus()
|
||||
}, [assetIdInput])
|
||||
|
||||
const unassign = (editConditionOnly) => {
|
||||
// Open the dialog to get condition and comment.
|
||||
@@ -100,6 +168,82 @@ const AssignmentsByAsset = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const [tab, setTab] = useState('assignments')
|
||||
|
||||
const RenderUsage = ({data}) => {
|
||||
return (
|
||||
<>
|
||||
<ul>
|
||||
{data.map((next, i) => (
|
||||
<li key={next._id}>
|
||||
{next.person && (
|
||||
<>
|
||||
User: <Link to={"/assignments/byPerson"} state={{search: next.person.lastName, person: next.person}}>{next.person.firstName} {next.person.lastName} {next.person.grade ? "~ " + next.person.grade : ""} ({next.email})</Link><br/>
|
||||
</>
|
||||
)}
|
||||
{!next.person && (
|
||||
<>
|
||||
User: N/A<br/>
|
||||
</>
|
||||
)}
|
||||
{/*Device ID: <Link to={"/search?deviceId=" + encodeURIComponent(next.deviceId)}>{next.deviceId}</Link><br/>*/}
|
||||
{/*{next.asset && (*/}
|
||||
{/* <>Asset ID: <Link to={"/search?assetId=" + encodeURIComponent(next.asset.assetId)}>{next.asset.assetId}</Link><br/></>*/}
|
||||
{/*)}*/}
|
||||
{/*<>Asset Type: {next.assetType ? next.assetType.name : "Unknown"}<br/></>*/}
|
||||
{/*Serial: <Link to={"/search?serial=" + encodeURIComponent(next.serial)}>{next.serial}</Link><br/>*/}
|
||||
{new Date(next.startTime).toLocaleDateString("en-US") + "-" + new Date(next.endTime).toLocaleDateString("en-US") + " @ " + new Date(next.endTime).toLocaleTimeString("en-US")} ({Math.ceil(((next.endTime ? next.endTime : new Date().getTime()) - next.startTime) / (1000*60*60*24))} days)<br/>
|
||||
{/*{next.assignedTo && (*/}
|
||||
{/* <>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.assetId}>
|
||||
{next.assignee && (
|
||||
<>
|
||||
User: <Link to={"/assignments/byPerson"} state={{search: next.assignee.lastName, person: next.assignee}}>{next.assignee.firstName} {next.assignee.lastName} {next.assignee.grade ? "~ " + next.assignee.grade : ""} ({next.assignee.email})</Link><br/>
|
||||
</>
|
||||
)}
|
||||
{/*{next.asset && (*/}
|
||||
{/* <>*/}
|
||||
{/* Asset ID: <Link to={"/search?assetId=" + encodeURIComponent(next.asset.assetId)}>{next.asset.assetId}</Link><br/>*/}
|
||||
{/* </>*/}
|
||||
{/*)}*/}
|
||||
{/*{next.assetType && (*/}
|
||||
{/* <>*/}
|
||||
{/* Asset Type: {next.assetType.name}<br/>*/}
|
||||
{/* </>*/}
|
||||
{/*)}*/}
|
||||
{/*Serial: <Link to={"/search?serial=" + encodeURIComponent(next.serial)}>{next.serial}</Link><br/>*/}
|
||||
{new Date(next.startDate).toLocaleDateString("en-US") + (next.endDate ? "-" + new Date(next.endDate).toLocaleDateString("en-US") : " - Still Assigned")} ({Math.ceil(((next.endDate ? next.endDate : new Date().getTime()) - next.startDate) / (1000*60*60*24))} days)<br/>
|
||||
{next.comment && (
|
||||
<>Comment: {next.comment}<br/></>
|
||||
)}
|
||||
Start Condition: {next.startCondition}<br/>
|
||||
{next.startConditionDetails && <>Details: {next.startConditionDetails}<br/></>}
|
||||
{next.endDate && (
|
||||
<>
|
||||
End Condition: {next.endCondition}<br/>
|
||||
{next.endConditionDetails && <>Details: {next.endConditionDetails}<br/></>}
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={openUnassignDialog} onClose={unassignDialogClosed}>
|
||||
@@ -122,24 +266,44 @@ const AssignmentsByAsset = () => {
|
||||
</Dialog>
|
||||
|
||||
<Box style={{marginTop: '1rem',...cssTwoColumnContainer}}>
|
||||
<TextField style={cssEditorField} variant="standard" label="Asset ID" inputRef={input=>setAssetIdInput(input)} value={assetId} onChange={(e) => {setAssetId(e.target.value.toUpperCase())}}/>
|
||||
<TextField style={{...cssEditorField, maxWidth: "40rem", minWidth: "10rem"}} variant="standard" label="Asset ID" inputRef={input=>setAssetIdInput(input)} value={assetId} onChange={(e) => {setAssetId(e.target.value.toUpperCase())}}/>
|
||||
{foundAsset && (
|
||||
<div>
|
||||
<h3 style={{margin: "0 0 0.5rem 0"}}>Asset ID: {foundAsset.assetId}</h3>
|
||||
<h3 style={{margin: "0 0 0.5rem 0"}}>Serial: {foundAsset.serial}</h3>
|
||||
<h3 style={{margin: "0 0 0.5rem 0"}}>Current Condition: {foundAsset.condition}</h3>
|
||||
<TabContext value={tab}>
|
||||
<Box sx={{borderBottom: 1, borderColor: 'divider'}}>
|
||||
<TabList onChange={(e, v)=>setTab(v)}>
|
||||
<Tab label="Assignments" value="assignments"/>
|
||||
<Tab label="Assignment History" value="assignmentHistory"/>
|
||||
<Tab label="Usage History" value="usageHistory"/>
|
||||
</TabList>
|
||||
</Box>
|
||||
<TabPanel value="assignments">
|
||||
<div>
|
||||
<div>Condition Details: {foundAsset.conditionDetails}</div>
|
||||
{foundAsset.assignee && (
|
||||
<>
|
||||
<div>Assigned on: {new Date(foundAsset.assignmentDate).toLocaleDateString("en-US")} ({Math.ceil((new Date().getTime() - foundAsset.assignmentDate) / (1000*60*60*24))} days)</div>
|
||||
<div>Assigned to: <Link to={"/assignments/byPerson"} state={{search: foundAsset.assignee.lastName, person: foundAsset.assignee}}>{foundAsset.assignee.firstName} {foundAsset.assignee.lastName} {foundAsset.assignee.grade && foundAsset.assignee.grade} ({foundAsset.assignee.email})</Link></div>
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(false)}>Unassign</Button>
|
||||
{" "}
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(true)}>Edit</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel value="assignmentHistory">
|
||||
<RenderAssignments data={assignmentData}/>
|
||||
</TabPanel>
|
||||
<TabPanel value="usageHistory">
|
||||
<RenderUsage data={usageData}/>
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
{foundAsset && (
|
||||
<div>
|
||||
<div>Serial: {foundAsset.serial}</div>
|
||||
<div>Condition: {foundAsset.condition}</div>
|
||||
<div>Condition Details: {foundAsset.conditionDetails}</div>
|
||||
{foundAsset.assignee && (
|
||||
<>
|
||||
<div>Assigned on: {foundAsset.assignmentDate.toString()}</div>
|
||||
<div>Assigned to: {foundAsset.assignee.firstName} {foundAsset.assignee.lastName} {foundAsset.assignee.grade && foundAsset.assignee.grade} (<Link to={"/search?email=" + encodeURIComponent(foundAsset.assignee.email)}>{foundAsset.assignee.email}</Link>)</div>
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(false)}>Unassign</Button>
|
||||
{" "}
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(true)}>Edit</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user