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:
@@ -22,6 +22,10 @@ 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',
|
||||
@@ -56,7 +60,7 @@ const AssignmentsByPerson = () => {
|
||||
const [unassignConditionDetails, setUnassignConditionDetails] = useState("")
|
||||
const [unassignAsset, setUnassignAsset] = useState(undefined)
|
||||
|
||||
const [assetIdInput, setAssetIdInput] = useState(undefined)
|
||||
const [searchInput, setSearchInput] = useState(undefined)
|
||||
|
||||
const {people} = useTracker(() => {
|
||||
let people = [];
|
||||
@@ -86,7 +90,7 @@ const AssignmentsByPerson = () => {
|
||||
}
|
||||
|
||||
return {people}
|
||||
});
|
||||
}, [search]);
|
||||
|
||||
const {assets} = useTracker(() => {
|
||||
let assets = [];
|
||||
@@ -100,7 +104,7 @@ const AssignmentsByPerson = () => {
|
||||
}
|
||||
|
||||
return {assets}
|
||||
});
|
||||
}, [selectedPerson]);
|
||||
|
||||
const {foundAsset} = useTracker(() => {
|
||||
let foundAsset = null;
|
||||
@@ -117,7 +121,32 @@ const AssignmentsByPerson = () => {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -150,10 +179,10 @@ const AssignmentsByPerson = () => {
|
||||
}
|
||||
}
|
||||
|
||||
//This works too well. The field always gets focus anytime anything is typed anywhere.
|
||||
// useEffect(() => {
|
||||
// if(assetIdInput) 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.
|
||||
@@ -193,19 +222,93 @@ const AssignmentsByPerson = () => {
|
||||
// '&:nthChild(even)': {backgroundColor: '#935e5e'}
|
||||
}
|
||||
|
||||
// Changes the selected person and updates the browser history.
|
||||
const changeSelectedPerson = (person) => {
|
||||
setSelectedPerson(person)
|
||||
navigate("/assignments", {replace: false, state: {person, search}});
|
||||
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 === NavigationType.Pop) {
|
||||
if(navigateType === "POP" || navigateType === 'REPLACE' || navigateType === "PUSH") {
|
||||
setSearch(state.search)
|
||||
setSelectedPerson(state.person)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [state, navigateType])
|
||||
|
||||
const [tab, setTab] = useState('assignments')
|
||||
|
||||
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={"/search?email=" + encodeURIComponent(next.email)}>{next.email}</Link>)<br/>*/}
|
||||
{/* </>*/}
|
||||
{/*)}*/}
|
||||
{/*Device ID: <Link to={"/search?deviceId=" + encodeURIComponent(next.deviceId)}>{next.deviceId}</Link><br/>*/}
|
||||
{next.asset && (
|
||||
<>Asset ID: <Link to={"/assignments/byAsset"} state={{assetId: next.asset.assetId}}>{next.asset.assetId}</Link><br/></>
|
||||
)}
|
||||
<>Asset Type: {next.assetType ? next.assetType.name : "Unknown"}<br/></>
|
||||
Serial: {next.serial}<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: {next.assignee.firstName} {next.assignee.lastName} {next.assignee.grade ? "~ " + next.assignee.grade : ""} (<Link to={"/search?email=" + encodeURIComponent(next.assignee.email)}>{next.assignee.email}</Link>)<br/>*/}
|
||||
{/* </>*/}
|
||||
{/*)}*/}
|
||||
{next.asset && (
|
||||
<>
|
||||
Asset ID: <Link to={"/assignments/byAsset"} state={{assetId: next.asset.assetId}}>{next.asset.assetId}</Link><br/>
|
||||
</>
|
||||
)}
|
||||
{next.assetType && (
|
||||
<>
|
||||
Asset Type: {next.assetType.name}<br/>
|
||||
</>
|
||||
)}
|
||||
Serial: {next.serial}<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 (
|
||||
<>
|
||||
@@ -253,7 +356,7 @@ const AssignmentsByPerson = () => {
|
||||
{/* <ToggleButton value="Last Name">Last Name</ToggleButton>*/}
|
||||
{/*</ToggleButtonGroup>*/}
|
||||
<FormControlLabel sx={{marginTop: '0.7rem'}} control={<Switch variant="standard" checked={includeInactive} onChange={(e) => {setIncludeInactive(e.target.checked)}}/>} label="Inactive"/>
|
||||
<TextField style={cssEditorField} variant="standard" label="Search" value={search} onChange={(e) => {setSearch(e.target.value)}}/>
|
||||
<TextField style={cssEditorField} variant="standard" label="Search" inputRef={input=>setSearchInput(input)} value={search} onChange={(e) => {setSearch(e.target.value)}}/>
|
||||
</Box>
|
||||
<Box style={{...cssTwoColumnContainer, gridTemplateColumns: "24rem 1fr"}}>
|
||||
<div style={{maxHeight: '26rem', overflowY:'auto', minWidth: '10rem', minHeight: '10rem', maxWidth: '40rem'}}>
|
||||
@@ -271,44 +374,55 @@ const AssignmentsByPerson = () => {
|
||||
{selectedPerson && (
|
||||
<>
|
||||
<h3 style={{margin: "0 0 0.5rem 0"}}>{selectedPerson.firstName + " " + (selectedPerson.firstNameAlias ? "'" + selectedPerson.firstNameAlias + "' " : "") + selectedPerson.lastName + (selectedPerson.grade ? " (" + selectedPerson.grade + ")" : "")}</h3>
|
||||
<div style={{...cssAssetTile, paddingTop: "0"}}>
|
||||
<div style={{marginBottom: '1rem'}}><TextField id='assetIdInput' inputRef={input=>setAssetIdInput(input)} style={cssEditorField} variant="standard" label="Asset ID" value={assetId} onChange={(e) => {setAssetId(e.target.value.toUpperCase())}}/></div>
|
||||
<div>{foundAsset && foundAsset.assetType.name}</div>
|
||||
<div>{foundAsset && <Link to={"/search?assetId=" + encodeURIComponent(foundAsset.assetId)}>{foundAsset.assetId}</Link>}</div>
|
||||
<div>{foundAsset && <Link to={"/search?serial=" + encodeURIComponent(foundAsset.serial)}>{foundAsset.serial}</Link>}</div>
|
||||
{foundAsset && foundAsset.assignee && (
|
||||
<div>Assigned To: {foundAsset.assignee.firstName} {foundAsset.assignee.lastName}</div>
|
||||
)}
|
||||
<Button variant="contained" color='primary' className="button" disabled={!foundAsset || foundAsset.assignee !== undefined} onClick={()=>assign()}>Assign</Button>
|
||||
</div>
|
||||
<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 style={{...cssAssetTile, paddingTop: "0"}}>
|
||||
<div style={{marginBottom: '1rem'}}><TextField id='assetIdInput' style={cssEditorField} variant="standard" label="Asset ID" value={assetId} onChange={(e) => {setAssetId(e.target.value.toUpperCase())}}/></div>
|
||||
{foundAsset && (
|
||||
<>
|
||||
<div>{foundAsset && foundAsset.assetType.name}</div>
|
||||
<div>Asset ID: <Link to={"/search?assetId=" + encodeURIComponent(foundAsset.assetId)}>{foundAsset.assetId}</Link></div>
|
||||
<div>Serial: <Link to={"/search?serial=" + encodeURIComponent(foundAsset.serial)}>{foundAsset.serial}</Link></div>
|
||||
</>
|
||||
)}
|
||||
{foundAsset && foundAsset.assignee && (
|
||||
<>
|
||||
<div>Assigned To: {foundAsset.assignee.firstName} {foundAsset.assignee.lastName}</div>
|
||||
<div>Assigned: {new Date(foundAsset.assignmentDate).toLocaleDateString("en-US")} ({Math.ceil((new Date().getTime() - foundAsset.assignmentDate) / (1000*60*60*24))} days)</div>
|
||||
</>
|
||||
)}
|
||||
<Button variant="contained" color='primary' className="button" disabled={!foundAsset || foundAsset.assignee !== undefined} onClick={()=>assign()}>Assign</Button>
|
||||
</div>
|
||||
{assets.map((next, i) => {
|
||||
return (
|
||||
<div key={next._id} style={{...getAssetTileStyles(i), ...cssAssetTile}}>
|
||||
<div style={{fontWeight: 800}}>{next.assetType.name}</div>
|
||||
<div>Asset ID: <Link to={"/assignments/byAsset"} state={{assetId: next.assetId}}>{next.assetId}</Link></div>
|
||||
<div>Serial: {next.serial}</div>
|
||||
<div>Assigned: {new Date(next.assignmentDate).toLocaleDateString("en-US")} ({Math.ceil((new Date().getTime() - next.assignmentDate) / (1000*60*60*24))} days)</div>
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(next, false)}>Unassign</Button>
|
||||
{" "}
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(next, true)}>Edit</Button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</TabPanel>
|
||||
<TabPanel value="assignmentHistory">
|
||||
<RenderAssignments data={assignmentData}/>
|
||||
</TabPanel>
|
||||
<TabPanel value="usageHistory">
|
||||
<RenderUsage data={usageData}/>
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</>
|
||||
)}
|
||||
{assets.map((next, i) => {
|
||||
return (
|
||||
<div key={next._id} style={{...getAssetTileStyles(i), ...cssAssetTile}}>
|
||||
<div>{next.assetType.name}</div>
|
||||
<div><Link to={"/search?assetId=" + encodeURIComponent(next.assetId)}>{next.assetId}</Link></div>
|
||||
<div><Link to={"/search?serial=" + encodeURIComponent(next.serial)}>{next.serial}</Link></div>
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(next, false)}>Unassign</Button>
|
||||
{" "}
|
||||
<Button variant="contained" color='secondary' className="button" onClick={()=>unassign(next, true)}>Edit</Button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{/*<div style={{display: 'flex', flexDirection: 'row'}}>*/}
|
||||
{/* <TextField style={cssEditorField} variant="standard" label="Asset ID" value={assetId} onChange={(e) => {setAssetId(e.target.value)}}/>*/}
|
||||
{/* <TextField style={cssEditorField} variant="standard" label="Serial" value={serial} onChange={(e) => {setSerial(e.target.value)}}/>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div style={{display: 'flex', flexDirection: 'row'}}>*/}
|
||||
{/* <TextField style={cssEditorField} select variant="standard" label="Condition" value={condition} onChange={(e)=>{setCondition(e.target.value)}}>*/}
|
||||
{/* {conditions.map((condition, i) => {*/}
|
||||
{/* return <MenuItem key={i} value={condition}>{condition}</MenuItem>*/}
|
||||
{/* })}*/}
|
||||
{/* </TextField>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div style={{display: 'flex', flexDirection: 'row'}}>*/}
|
||||
{/* <TextField style={{width: '100%', margin: '1rem'}} multiline variant="outlined" rows={4} label="Condition Details" value={conditionDetails} onChange={(e) => {setConditionDetails(e.target.value)}}/>*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
</Box>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user