Files
DistrictCentral/imports/ui/Admin.svelte

361 lines
10 KiB
Svelte
Raw Normal View History

<script>
import {Meteor} from "meteor/meteor";
import {onMount} from "svelte";
import {Sites} from "../api/sites";
import GridTable from "./GridTable.svelte";
import {writable} from "svelte/store";
import TextField from '@smui/textfield';
import HelperText from '@smui/textfield/helper-text';
2022-06-20 08:24:35 -07:00
import {Students} from "../api/students";
import {Staff} from "../api/staff";
import {AssetTypes} from "../api/asset-types";
onMount(async () => {
Meteor.subscribe('sites');
2022-06-20 08:24:35 -07:00
Meteor.subscribe('assetTypes');
});
// Should not be needed now. Did not work well - had a bug somewhere.
// const fixRecords = () => {Meteor.call("admin.fixRecords");}
const siteColumns = [
{
key: "_id",
title: "ID",
value: v => v._id,
minWidth: 20,
weight: 1,
cls: "id",
}, {
key: "name",
title: "Name",
value: v => v.name,
minWidth: 100,
weight: 1,
cls: "name",
},
];
const actions = {
title: "Actions",
headerWidgets: [
{icon: "add_box", action: () => {editedSite.set({name: ""});}, tooltip: "Add a new Site."}
],
rowWidgets: [
{icon: "add_circle", action: (v) => {editedSite.set(v)}},
{icon: "delete", action: (v) => {deleteSite(v)}}
],
};
const deleteSite = site => {
//TODO:
};
// Create a holder for the site being edited. This allows us to clear the editor when the user finishes, and allows the table or parent view to setup the editor.
let editedSite = writable(null);
let dirtySite = null;
// Copy the edited site when ever it changes, set some defaults for a new site object (to make the view happy).
editedSite.subscribe(site => {dirtySite = Object.assign({name: ""}, site)});
// Load the sites (reactive).
let sites = Sites.find({});
const applySiteChanges = () => {
if(dirtySite._id)
Meteor.call("sites.update", dirtySite._id, dirtySite.name);
else
Meteor.call("sites.add", dirtySite.name);
editedSite.set(null);
}
const rejectSiteChanges = () => {
editedSite.set(null);
}
2022-06-20 08:24:35 -07:00
let selectedSite = null;
2022-06-20 08:24:35 -07:00
let students = null;
let staff = null;
$: {
if(selectedSite) {
Meteor.subscribe('students', selectedSite._id);
Meteor.subscribe('staff', selectedSite._id);
students = Students.find({siteId: selectedSite._id});
staff = Staff.find({siteId: selectedSite._id});
}
}
const onSiteSelection = (e) => {
selectedSite = Sites.findOne({_id: e.detail});
}
const uploadStudents = () => {
// console.log(files);
// console.log(selectedSite);
// console.log(selectedSite._id);
if(files && files.length) {
let file = files[0];
let reader = new FileReader();
reader.onload = (e) => {
// console.log("Sending Data");
// console.log(selectedSite._id);
// console.log(reader.result);
Meteor.call('students.loadCsv', reader.result, selectedSite._id);
}
reader.readAsText(file, "UTF-8");
}
}
let files;
const studentColumns = [
{
key: "_id",
title: "ID",
value: v => v._id,
minWidth: 20,
weight: 1,
cls: "id",
}, {
key: "email",
title: "Email",
value: v => v.email,
minWidth: 100,
weight: 1,
cls: "email",
}, {
key: "firstName",
title: "First Name",
value: v => v.firstName,
minWidth: 100,
weight: 1,
cls: "firstName",
}, {
key: "lastName",
title: "Last Name",
value: v => v.lastName,
minWidth: 100,
weight: 1,
cls: "lastName",
}, {
key: "grade",
title: "Grade",
value: v => v.grade,
minWidth: 100,
weight: 1,
cls: "grade",
},
];
let editedStudent = writable(null);
const onStudentSelection = (e) => {
}
const staffColumns = [
{
key: "_id",
title: "ID",
value: v => v._id,
minWidth: 20,
weight: 1,
cls: "id",
}, {
key: "email",
title: "Email",
value: v => v.email,
minWidth: 100,
weight: 1,
cls: "email",
}, {
key: "firstName",
title: "First Name",
value: v => v.firstName,
minWidth: 100,
weight: 1,
cls: "firstName",
}, {
key: "lastName",
title: "Last Name",
value: v => v.lastName,
minWidth: 100,
weight: 1,
cls: "lastName",
},
];
let editedStaff = writable(null);
const onStaffSelection = (e) => {
}
const assetTypesColumns = [
{
key: "_id",
title: "ID",
value: v => v._id,
minWidth: 20,
weight: 1,
cls: "id",
}, {
key: "name",
title: "Name",
value: v => v.name,
minWidth: 100,
weight: 1,
cls: "name",
}, {
key: "description",
title: "Description",
value: v => v.description,
minWidth: 100,
weight: 1,
cls: "description",
},
];
const assetTypesActions = {
title: "Actions",
headerWidgets: [
{icon: "add_box", action: () => {editedAssetType.set({name: ""});}, tooltip: "Add a new asset type."}
],
rowWidgets: [
{icon: "add_circle", action: (v) => {editedAssetType.set(v)}},
{icon: "delete", action: (v) => {deleteAssetType(v)}}
],
};
2022-06-20 08:24:35 -07:00
let editedAssetType = writable(null);
const onAssetTypeSelection = (e) => {
}
let dirtyAssetType = null;
// Copy the edited value when ever it changes, set some defaults for a new value object (to make the view happy).
editedAssetType.subscribe(v => {dirtyAssetType = Object.assign({name: "", description: ""}, v)});
2022-06-20 08:24:35 -07:00
// Load the sites (reactive).
let assetTypes = AssetTypes.find({});
const deleteAssetType = assetType => {
//TODO:
};
const applyAssetTypeChanges = () => {
if(dirtyAssetType._id)
Meteor.call("assetTypes.update", dirtyAssetType._id, dirtyAssetType.name, dirtyAssetType.description);
else
Meteor.call("assetTypes.add", dirtyAssetType.name, dirtyAssetType.description);
editedAssetType.set(null);
}
const rejectAssetTypeChanges = () => {
editedSite.set(null);
}
</script>
<div class="container">
<h2>Sites</h2>
2022-06-20 08:24:35 -07:00
<GridTable bind:rows={sites} columns="{siteColumns}" actions="{actions}" rowKey="{(v) => {return v._id}}" bind:edited="{editedSite}" on:selection={onSiteSelection}>
{#if dirtySite}
<div class="editorContainer">
<div style="grid-column: 1/span 1">
<TextField type="text" style="width: 100%" bind:value={dirtySite.name} label="Name">
<HelperText slot="helper">Provide a unique name for the site.</HelperText>
</TextField>
</div>
<button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applySiteChanges}>
check
</button>
<button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectSiteChanges}>
close
</button>
</div>
{/if}
</GridTable>
2022-06-20 08:24:35 -07:00
{#if selectedSite}
<h2>Site Students</h2>
<form on:submit|preventDefault={uploadStudents}>
<input style="display: inline-block" type="file" multiple="false" accept="text/csv" bind:files={files}/>
<input type="submit" value="Upload"/>
</form>
<GridTable bind:rows={students} columns="{studentColumns}" actions="{null}" rowKey="{(v) => {return v._id}}" bind:edited="{editedStudent}" on:selection={onStudentSelection}>
{#if dirtySite}
<div class="editorContainer">
<div style="grid-column: 1/span 1">
<TextField type="text" style="width: 100%" bind:value={dirtySite.name} label="Name">
<HelperText slot="helper">Provide a unique name for the site.</HelperText>
</TextField>
</div>
<button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applySiteChanges}>
check
</button>
<button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectSiteChanges}>
close
</button>
</div>
{/if}
</GridTable>
<h2>Site Staff</h2>
<GridTable bind:rows={staff} columns="{staffColumns}" actions="{null}" rowKey="{(v) => {return v._id}}" bind:edited="{editedStaff}" on:selection={onStaffSelection}>
{#if dirtySite}
<div class="editorContainer">
<div style="grid-column: 1/span 1">
<TextField type="text" style="width: 100%" bind:value={dirtySite.name} label="Name">
<HelperText slot="helper">Provide a unique name for the site.</HelperText>
</TextField>
</div>
<button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applySiteChanges}>
check
</button>
<button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectSiteChanges}>
close
</button>
</div>
{/if}
</GridTable>
{/if}
<h2>Asset Types</h2>
<GridTable bind:rows={assetTypes} columns="{assetTypesColumns}" actions="{assetTypesActions}" rowKey="{(v) => {return v._id}}" bind:edited="{editedAssetType}" on:selection={onAssetTypeSelection}>
{#if dirtyAssetType}
2022-06-20 08:24:35 -07:00
<div class="editorContainer">
<div style="grid-column: 1/span 1">
<TextField type="text" style="width: 100%" bind:value={dirtyAssetType.name} label="Name">
<HelperText slot="helper">Provide a unique name for the asset type.</HelperText>
</TextField>
<TextField type="text" style="width: 100%" bind:value={dirtyAssetType.description} label="Description">
<HelperText slot="helper">A detailed description.</HelperText>
2022-06-20 08:24:35 -07:00
</TextField>
</div>
<button type="button" style="grid-column: 2/span 1;" class="button accept-button material-icons material-symbols-outlined" on:click={applyAssetTypeChanges}>check</button>
<button type="button" style="grid-column: 3/span 1;" class="button reject-button material-icons material-symbols-outlined" on:click={rejectAssetTypeChanges}>close</button>
2022-06-20 08:24:35 -07:00
</div>
{/if}
</GridTable>
<!--{#each sites as site}-->
<!-- <div>{site.name}</div>-->
<!--{/each}-->
<!-- <button type="button" on:click={fixRecords}>Fix Records</button>-->
</div>
<style>
2022-06-20 08:24:35 -07:00
form {
margin: 0;
}
.editorContainer {
display: grid;
grid-template-columns: minmax(10px, 1fr) minmax(3rem, 3rem) minmax(3rem, 3rem);
}
.accept-button, .reject-button {
font-size: .8rem;
padding: .6rem;
margin: auto;
color: white;
border-radius: 50%;
border: 0;
font-weight: 800;
alignment: center;
cursor: pointer;
}
.accept-button {
background-color: rgba(61, 148, 61, 0.91);
}
.reject-button {
background-color: rgba(176, 64, 64, 0.61);
}
.accept-button:hover {
background-color: rgb(61, 148, 61);
}
.reject-button:hover {
background-color: rgb(176, 64, 64);
}
</style>