Initial check in; All but the history pages working.
This commit is contained in:
113
imports/ui/pages/Admin/AssetTypes.jsx
Normal file
113
imports/ui/pages/Admin/AssetTypes.jsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
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 MenuItem from '@mui/material/MenuItem';
|
||||
import {AssetTypes} from "/imports/api/asset-types";
|
||||
|
||||
const cssFieldColumnContainer = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#DDD',
|
||||
padding: '0.5rem',
|
||||
border: '1px solid #999',
|
||||
borderRadius: '0.2rem'
|
||||
}
|
||||
const cssEditorField = {
|
||||
marginTop: '0.6rem',
|
||||
}
|
||||
const cssGridFieldContainer = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
columnGap: '1rem',
|
||||
rowGap: '0.4rem',
|
||||
marginBottom: '1.5rem'
|
||||
}
|
||||
const cssButtonContainer = {
|
||||
display: 'flex',
|
||||
gap: '1rem',
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
|
||||
const AssetTypeEditor = ({value, close}) => {
|
||||
const [year, setYear] = useState(value.year || "")
|
||||
const [name, setName] = useState(value.name || "")
|
||||
const [description, setDescription] = useState(value.description || "")
|
||||
|
||||
const applyChanges = () => {
|
||||
close()
|
||||
//TODO Should invert this and only close if there was success on the server.
|
||||
if(value._id)
|
||||
Meteor.call("assetType.update", value._id, name, description, year);
|
||||
else
|
||||
Meteor.call("assetType.add", name, description, year);
|
||||
}
|
||||
const rejectChanges = () => {
|
||||
close()
|
||||
}
|
||||
const change = (e) => {
|
||||
console.log(e);
|
||||
|
||||
setYear(e.target.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={cssFieldColumnContainer}>
|
||||
<h1>Asset Type Editor</h1>
|
||||
<div style={cssGridFieldContainer}>
|
||||
<TextField variant="standard" style={cssEditorField} label="Year" value={year} onChange={(e) => change}/>
|
||||
<TextField variant="standard" style={cssEditorField} label="Name" value={name} onChange={(e) => {setName(e.target.value)}}/>
|
||||
<TextField variant="outlined" style={{gridColumn: '1 / span 2',...cssEditorField}} multiline rows={4} label="Description" value={description} onChange={(e) => {setDescription(e.target.value)}}/>
|
||||
</div>
|
||||
<div style={cssButtonContainer}>
|
||||
<Button variant="contained" className="button accept-button" onClick={applyChanges}>Accept</Button>
|
||||
<Button variant="outlined" className="button reject-button" onClick={rejectChanges}>Reject</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
Meteor.subscribe('assetTypes');
|
||||
|
||||
const {assetTypes} = useTracker(() => {
|
||||
let assetTypes = AssetTypes.find().fetch();
|
||||
|
||||
return {assetTypes}
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "Year",
|
||||
value: (row) => row.year,
|
||||
},
|
||||
{
|
||||
name: "Name",
|
||||
value: (row) => row.name,
|
||||
},
|
||||
{
|
||||
name: "Description",
|
||||
value: (row) => row.description,
|
||||
},
|
||||
]
|
||||
|
||||
const options = {
|
||||
key: (row) => row._id,
|
||||
editor: (row, close) => {return (<AssetTypeEditor value={row} close={close}/>)},
|
||||
add: true,
|
||||
maxHeight: '40rem',
|
||||
keyHandler: (e, selected) => {
|
||||
if(selected && selected._id && e.key === "Delete") {
|
||||
Meteor.call("assetType.remove", selected._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SimpleTable rows={assetTypes} columns={columns} options={options}/>
|
||||
)
|
||||
}
|
||||
6
imports/ui/pages/Admin/Functions.jsx
Normal file
6
imports/ui/pages/Admin/Functions.jsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default () => {return (<div>None</div>)}
|
||||
90
imports/ui/pages/Admin/Sites.jsx
Normal file
90
imports/ui/pages/Admin/Sites.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
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 MenuItem from '@mui/material/MenuItem';
|
||||
import {Sites} from "/imports/api/sites";
|
||||
|
||||
const cssEditorField = {
|
||||
margin: '0.6rem 0',
|
||||
}
|
||||
const cssFieldContainer = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#DDD',
|
||||
padding: '0.5rem',
|
||||
border: '1px solid #999',
|
||||
borderRadius: '0.2rem',
|
||||
}
|
||||
const cssButtonContainer = {
|
||||
display: 'flex',
|
||||
gap: '1rem',
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
|
||||
const SiteEditor = ({value, close}) => {
|
||||
const [name, setName] = useState(value.name || "")
|
||||
|
||||
const applyChanges = () => {
|
||||
close()
|
||||
//TODO Should invert this and only close if there was success on the server.
|
||||
if(value._id)
|
||||
Meteor.call("sites.update", value._id, name);
|
||||
else
|
||||
Meteor.call("sites.add", name);
|
||||
}
|
||||
const rejectChanges = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={cssFieldContainer}>
|
||||
<h1>Site Editor</h1>
|
||||
<TextField style={cssEditorField} variant="standard" label="Name" value={name} onChange={(e) => {setName(e.target.value)}}/>
|
||||
<div style={cssButtonContainer}>
|
||||
<Button variant="contained" className="button accept-button" onClick={applyChanges}>Accept</Button>
|
||||
<Button variant="outlined" className="button reject-button" onClick={rejectChanges}>Reject</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
Meteor.subscribe('sites');
|
||||
|
||||
const {sites} = useTracker(() => {
|
||||
const sites = Sites.find({}).fetch();
|
||||
return {
|
||||
sites
|
||||
}
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "Name",
|
||||
value: (row) => row.name,
|
||||
},
|
||||
]
|
||||
|
||||
const options = {
|
||||
key: (row) => row._id,
|
||||
editor: (row, close) => {return (<SiteEditor value={row} close={close}/>)},
|
||||
add: true,
|
||||
maxHeight: '40rem',
|
||||
keyHandler: (e, selected) => {
|
||||
if(selected && selected._id && e.key === "Delete") {
|
||||
Meteor.call("sites.remove", selected._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SimpleTable rows={sites} columns={columns} options={options}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
153
imports/ui/pages/Admin/Staff.jsx
Normal file
153
imports/ui/pages/Admin/Staff.jsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
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 MenuItem from '@mui/material/MenuItem';
|
||||
import {Staff} from "/imports/api/staff";
|
||||
import {Sites} from "/imports/api/sites";
|
||||
|
||||
const cssSitesSelect = {
|
||||
margin: '0.6rem 0',
|
||||
minWidth: '20rem',
|
||||
}
|
||||
const cssFieldColumnContainer = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#DDD',
|
||||
padding: '0.5rem',
|
||||
border: '1px solid #999',
|
||||
borderRadius: '0.2rem'
|
||||
}
|
||||
const cssGridFieldContainer = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
columnGap: '1rem',
|
||||
rowGap: '0.4rem',
|
||||
marginBottom: '1.5rem'
|
||||
}
|
||||
const cssButtonContainer = {
|
||||
display: 'flex',
|
||||
gap: '1rem',
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
|
||||
const StaffEditor = ({value, close, defaultSiteId}) => {
|
||||
const [email, setEmail] = useState(value.email || "")
|
||||
const [id, setId] = useState(value.id || "")
|
||||
const [firstName, setFirstName] = useState(value.firstName || "")
|
||||
const [lastName, setLastName] = useState(value.lastName || "")
|
||||
const [siteId, setSiteId] = useState(value.siteId ? value.siteId : defaultSiteId)
|
||||
|
||||
const {sites} = useTracker(() => {
|
||||
let sites = Sites.find({}).fetch();
|
||||
|
||||
return {sites}
|
||||
});
|
||||
|
||||
if(!siteId && sites && sites.length > 0) {
|
||||
setSiteId(sites[0]._id)
|
||||
}
|
||||
|
||||
const applyChanges = () => {
|
||||
close()
|
||||
//TODO Should invert this and only close if there was success on the server.
|
||||
if(value._id)
|
||||
Meteor.call("staff.update", value._id, id, firstName, lastName, email, siteId);
|
||||
else
|
||||
Meteor.call("staff.add", id, firstName, lastName, email, siteId);
|
||||
}
|
||||
const rejectChanges = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={cssFieldColumnContainer}>
|
||||
<h1>Staff Editor</h1>
|
||||
<div style={cssGridFieldContainer}>
|
||||
<TextField variant="standard" label="ID" value={id} onChange={(e) => {setId(e.target.value)}}/>
|
||||
<TextField variant="standard" label="Email" value={email} onChange={(e) => {setEmail(e.target.value)}}/>
|
||||
<div/>
|
||||
<TextField variant="standard" label="First Name" value={firstName} onChange={(e) => {setFirstName(e.target.value)}}/>
|
||||
<TextField variant="standard" label="Last Name" value={lastName} onChange={(e) => {setLastName(e.target.value)}}/>
|
||||
<TextField select variant="standard" label="Site" value={siteId} onChange={(e) => {setSiteId(e.target.value)}}>
|
||||
{sites.map((next, i) => {
|
||||
return <MenuItem key={next._id} value={next._id}>{next.name}</MenuItem>
|
||||
})}
|
||||
</TextField>
|
||||
</div>
|
||||
<div style={cssButtonContainer}>
|
||||
<Button variant="contained" className="button accept-button" onClick={applyChanges}>Accept</Button>
|
||||
<Button variant="outlined" className="button reject-button" onClick={rejectChanges}>Reject</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const siteAll = {_id: 0, name: "All"}
|
||||
const [site, setSite] = useState(siteAll._id)
|
||||
|
||||
Meteor.subscribe('sites');
|
||||
Meteor.subscribe('staff');
|
||||
|
||||
const {sites} = useTracker(() => {
|
||||
const sites = Sites.find({}).fetch();
|
||||
|
||||
sites.push(siteAll);
|
||||
|
||||
return {sites}
|
||||
});
|
||||
|
||||
const {staff} = useTracker(() => {
|
||||
const staffQuery = site === siteAll._id ? {} : {siteId: site}
|
||||
let staff = Staff.find(staffQuery).fetch();
|
||||
|
||||
return {staff}
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "ID",
|
||||
value: (row) => row.id,
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
value: (row) => row.email,
|
||||
},
|
||||
{
|
||||
name: "First Name",
|
||||
value: (row) => row.firstName,
|
||||
},
|
||||
{
|
||||
name: "Last Name",
|
||||
value: (row) => row.lastName,
|
||||
},
|
||||
]
|
||||
|
||||
const options = {
|
||||
key: (row) => row._id,
|
||||
editor: (row, close) => {return (<StaffEditor value={row} close={close} defaultSiteId={site}/>)},
|
||||
add: true,
|
||||
maxHeight: '40rem',
|
||||
keyHandler: (e, selected) => {
|
||||
if(selected && selected._id && e.key === "Delete") {
|
||||
Meteor.call("staff.remove", selected._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextField label="Site" style={cssSitesSelect} select variant="standard" value={site} onChange={(e)=>{setSite(e.target.value)}}>
|
||||
{sites.map((next, i) => {
|
||||
return <MenuItem key={next._id} value={next._id}>{next.name}</MenuItem>
|
||||
})}
|
||||
</TextField>
|
||||
<SimpleTable rows={staff} columns={columns} options={options}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
158
imports/ui/pages/Admin/Students.jsx
Normal file
158
imports/ui/pages/Admin/Students.jsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState } from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
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 MenuItem from '@mui/material/MenuItem';
|
||||
import {Students} from "/imports/api/students";
|
||||
import {Sites} from "/imports/api/sites";
|
||||
|
||||
const cssSitesSelect = {
|
||||
margin: '0.6rem 0',
|
||||
minWidth: '20rem',
|
||||
}
|
||||
const cssFieldColumnContainer = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#DDD',
|
||||
padding: '0.5rem',
|
||||
border: '1px solid #999',
|
||||
borderRadius: '0.2rem'
|
||||
}
|
||||
const cssGridFieldContainer = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
columnGap: '1rem',
|
||||
rowGap: '0.4rem',
|
||||
marginBottom: '1.5rem'
|
||||
}
|
||||
const cssButtonContainer = {
|
||||
display: 'flex',
|
||||
gap: '1rem',
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
|
||||
const StudentEditor = ({value, close, defaultSiteId}) => {
|
||||
const [email, setEmail] = useState(value.email || "")
|
||||
const [id, setId] = useState(value.id || "")
|
||||
const [firstName, setFirstName] = useState(value.firstName || "")
|
||||
const [lastName, setLastName] = useState(value.lastName || "")
|
||||
const [grade, setGrade] = useState(value.grade || "")
|
||||
const [siteId, setSiteId] = useState(value.siteId ? value.siteId : defaultSiteId)
|
||||
|
||||
const {sites} = useTracker(() => {
|
||||
let sites = Sites.find({}).fetch();
|
||||
|
||||
return {sites}
|
||||
});
|
||||
|
||||
if(!siteId && sites && sites.length > 0) {
|
||||
setSiteId(sites[0]._id)
|
||||
}
|
||||
|
||||
const applyChanges = () => {
|
||||
close()
|
||||
//TODO Should invert this and only close if there was success on the server.
|
||||
if(value._id)
|
||||
Meteor.call("students.update", value._id, id, firstName, lastName, email, siteId, grade);
|
||||
else
|
||||
Meteor.call("students.add", id, firstName, lastName, email, siteId, grade);
|
||||
}
|
||||
const rejectChanges = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={cssFieldColumnContainer}>
|
||||
<h1>Student Editor</h1>
|
||||
<div style={cssGridFieldContainer}>
|
||||
<TextField variant="standard" label="ID" value={id} onChange={(e) => {setId(e.target.value)}}/>
|
||||
<TextField variant="standard" label="Email" value={email} onChange={(e) => {setEmail(e.target.value)}}/>
|
||||
<TextField variant="standard" label="Grade" value={grade} onChange={(e) => {setGrade(e.target.value)}}/>
|
||||
<TextField variant="standard" label="First Name" value={firstName} onChange={(e) => {setFirstName(e.target.value)}}/>
|
||||
<TextField variant="standard" label="Last Name" value={lastName} onChange={(e) => {setLastName(e.target.value)}}/>
|
||||
<TextField select variant="standard" label="Site" value={siteId} onChange={(e) => {setSiteId(e.target.value)}}>
|
||||
{sites.map((next, i) => {
|
||||
return <MenuItem key={next._id} value={next._id}>{next.name}</MenuItem>
|
||||
})}
|
||||
</TextField>
|
||||
</div>
|
||||
<div style={cssButtonContainer}>
|
||||
<Button variant="contained" className="button accept-button" onClick={applyChanges}>Accept</Button>
|
||||
<Button variant="outlined" className="button reject-button" onClick={rejectChanges}>Reject</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const siteAll = {_id: 0, name: "All"}
|
||||
const [site, setSite] = useState(siteAll._id)
|
||||
|
||||
Meteor.subscribe('sites');
|
||||
Meteor.subscribe('students');
|
||||
|
||||
const {sites} = useTracker(() => {
|
||||
const sites = Sites.find({}).fetch();
|
||||
|
||||
sites.push(siteAll);
|
||||
|
||||
return {sites}
|
||||
});
|
||||
|
||||
const {students} = useTracker(() => {
|
||||
const studentQuery = site === siteAll._id ? {} : {siteId: site}
|
||||
let students = Students.find(studentQuery).fetch();
|
||||
|
||||
return {students}
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "ID",
|
||||
value: (row) => row.id,
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
value: (row) => row.email,
|
||||
},
|
||||
{
|
||||
name: "First Name",
|
||||
value: (row) => row.firstName,
|
||||
},
|
||||
{
|
||||
name: "Last Name",
|
||||
value: (row) => row.lastName,
|
||||
},
|
||||
{
|
||||
name: "GRD",
|
||||
value: (row) => row.grade,
|
||||
},
|
||||
]
|
||||
|
||||
const options = {
|
||||
key: (row) => row._id,
|
||||
editor: (row, close) => {return (<StudentEditor value={row} close={close} defaultSiteId={site}/>)},
|
||||
add: true,
|
||||
maxHeight: '40rem',
|
||||
keyHandler: (e, selected) => {
|
||||
if(selected && selected._id && e.key === "Delete") {
|
||||
Meteor.call("students.remove", selected._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextField label="Site" style={cssSitesSelect} select variant="standard" value={site} onChange={(e)=>{setSite(e.target.value)}}>
|
||||
{sites.map((next, i) => {
|
||||
return <MenuItem key={next._id} value={next._id}>{next.name}</MenuItem>
|
||||
})}
|
||||
</TextField>
|
||||
<SimpleTable rows={students} columns={columns} options={options}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user