aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.vue21
-rw-r--r--src/components/EditorLists.vue96
-rw-r--r--src/features/parser.ts (renamed from src/features/parser.js)49
-rw-r--r--src/main.ts (renamed from src/main.js)0
-rw-r--r--src/models/EventInfo.ts (renamed from src/models/EventInfo.js)17
-rw-r--r--src/models/Lab.ts (renamed from src/models/Lab.js)6
-rw-r--r--src/models/PeerTeacher.ts (renamed from src/models/PeerTeacher.js)14
-rw-r--r--src/router/index.ts (renamed from src/router/index.js)0
-rw-r--r--src/shims-vue.d.ts6
-rw-r--r--src/store/index.ts (renamed from src/store/index.js)12
-rw-r--r--src/views/About.vue9
-rw-r--r--src/views/Editor.vue105
-rw-r--r--src/vuex-shim.d.ts17
13 files changed, 191 insertions, 161 deletions
diff --git a/src/App.vue b/src/App.vue
index c3a04c9..34945a9 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -15,25 +15,4 @@ html {
height: 100vh;
max-height: 100vh;
}
-
-/* #app {
- font-family: Avenir, Helvetica, Arial, sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- text-align: center;
- color: #2c3e50;
-}
-
-#nav {
- padding: 30px;
-}
-
-#nav a {
- font-weight: bold;
- color: #2c3e50;
-}
-
-#nav a.router-link-exact-active {
- color: #42b983;
-} */
</style>
diff --git a/src/components/EditorLists.vue b/src/components/EditorLists.vue
new file mode 100644
index 0000000..ae0aa22
--- /dev/null
+++ b/src/components/EditorLists.vue
@@ -0,0 +1,96 @@
+<template>
+ <div id="editor">
+ <div class="column">
+ <list :items="peerTeachers" @selection-changed="handlePtClick" #default="pt">
+ {{ pt.item.name }} <button @click.stop="deletePeerTeacher(pt.item.id)">X</button>
+ </list>
+ </div>
+ <div class="column">
+ <list :items="compatibleLabs" #default="lab">
+ {{ lab.item.fullInfo }} <button @click.stop="assignLab(lab.item.id)">+</button>
+ </list>
+ </div>
+ <div class="column">
+ <list :items="selectedPeerTeacherAssignments" #default="lab">
+ {{ lab.item.fullInfo }} <button @click.stop="unassignLab(lab.item.id)">X</button>
+ </list>
+ </div>
+ </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, PropType } from 'vue';
+import List from '@/components/List.vue';
+import PeerTeacher from '@/models/PeerTeacher';
+import Lab from '@/models/Lab';
+
+export default defineComponent({
+ name: 'EditorLists',
+ components: {
+ List,
+ },
+ props: {
+ peerTeachers: {
+ type: Array as PropType<PeerTeacher[]>,
+ default: [],
+ },
+ labs: {
+ type: Array as PropType<Lab[]>,
+ default: [],
+ },
+ },
+ computed: {
+ compatibleLabs(): Lab[] {
+ const temp = this.labs.filter((lab) => (!this.selectedPeerTeacher.assignedLabs.has(lab.id)
+ && !this.selectedPeerTeacher.conflictsWith(lab.event)));
+
+ const currentAssignments = this.selectedPeerTeacherAssignments;
+ return temp.filter((lab) => !currentAssignments
+ .some((assignedLab) => lab.event.conflictsWith(assignedLab.event)));
+ },
+ selectedPeerTeacherAssignments(): Lab[] {
+ return Array.from(this.selectedPeerTeacher.assignedLabs.values())
+ .flatMap((id) => {
+ const lab = this.$store.state.labs.get(id);
+ return (lab === undefined) ? [] : [lab];
+ }).sort((a, b) => a.course - b.course || a.section - b.section);
+ },
+ },
+ data() {
+ return {
+ selectedPeerTeacher: new PeerTeacher(),
+ };
+ },
+ methods: {
+ handlePtClick(peerTeacher: PeerTeacher) {
+ this.selectedPeerTeacher = peerTeacher;
+ },
+ deletePeerTeacher(id: number) {
+ if (this.selectedPeerTeacher.id === id) {
+ this.selectedPeerTeacher = new PeerTeacher();
+ }
+ this.$store.commit('deletePeerTeacher', id);
+ },
+ assignLab(id: string) {
+ if (this.selectedPeerTeacher.id !== 0) {
+ this.selectedPeerTeacher.assignedLabs.add(id);
+ }
+ },
+ unassignLab(id: string) {
+ this.selectedPeerTeacher.assignedLabs.delete(id);
+ },
+ },
+});
+</script>
+
+<style>
+#editor {
+ display: flex;
+ max-height: inherit;
+}
+
+.column {
+ flex: 1;
+ overflow: auto;
+}
+</style>
diff --git a/src/features/parser.js b/src/features/parser.ts
index f91d926..7839564 100644
--- a/src/features/parser.js
+++ b/src/features/parser.ts
@@ -2,7 +2,7 @@ import Lab from '@/models/Lab';
import PeerTeacher from '@/models/PeerTeacher';
import EventInfo from '../models/EventInfo';
-export function parseLabFile(file) {
+export function parseLabFile(file: File): Promise<Lab[]> {
const validCourses = [
'110',
'111',
@@ -16,26 +16,24 @@ export function parseLabFile(file) {
'315',
];
- const reader = new FileReader();
-
return new Promise((resolve, reject) => {
- const result = [];
+ const result: Lab[] = [];
- reader.onload = (event) => {
+ file.text().then((text) => {
let jsonData;
try {
- jsonData = JSON.parse(event.target.result);
+ jsonData = JSON.parse(text);
} catch (e) {
reject(new Error(e));
}
const labs = jsonData.data;
- labs.forEach((lab) => {
+ labs.forEach((lab: any) => {
if (validCourses.includes(lab.courseNumber)) {
const newLab = new Lab(lab.courseNumber, lab.sequenceNumber);
if (lab.instructionalMethod !== 'Web Based') {
- lab.meetingsFaculty.every((meeting) => {
+ lab.meetingsFaculty.every((meeting: any) => {
const { meetingTime } = meeting;
if (meetingTime.meetingType === 'LAB') {
@@ -62,21 +60,17 @@ export function parseLabFile(file) {
});
resolve(result);
- };
-
- reader.readAsText(file);
+ });
});
}
-export function parsePtSchedule(file) {
- const reader = new FileReader();
-
+export function parsePtSchedule(file: File): Promise<PeerTeacher> {
return new Promise((resolve) => {
- reader.onload = (event) => {
+ file.text().then((text) => {
const peerTeacher = new PeerTeacher();
const namePattern = /^(.*)\s(.*)\s(\d{9})/;
const eventPattern = /^(M?T?W?R?F?)\s(\d{1,2}:\d{2})\s?-\s?(\d{1,2}:\d{2})/;
- const lines = event.target.result.split('\n').filter((line) => line.trim());
+ const lines = text.split('\n').filter((line) => line.trim());
lines.forEach((line) => {
const ptName = line.match(namePattern);
@@ -95,18 +89,17 @@ export function parsePtSchedule(file) {
});
resolve(peerTeacher);
- };
-
- reader.readAsText(file);
+ });
});
}
-export function parsePtDatabase(file) {
- const reader = new FileReader();
-
+export function parsePtDatabase(file: File): Promise<{
+ labs: Map<string, Lab>,
+ peerTeachers: Map<number, PeerTeacher>
+}> {
return new Promise((resolve) => {
- reader.onload = (event) => {
- const jsonObj = JSON.parse(event.target.result);
+ file.text().then((text) => {
+ const jsonObj = JSON.parse(text);
const result = {
labs: new Map(),
peerTeachers: new Map(),
@@ -121,18 +114,16 @@ export function parsePtDatabase(file) {
Object.keys(jsonObj.peerTeachers).forEach((key) => {
const pt = jsonObj.peerTeachers[key];
const ptObj = new PeerTeacher(pt.firstname, pt.lastname, pt.uin);
- ptObj.events = pt.events.map((eventObj) => new EventInfo(eventObj.days,
+ ptObj.events = pt.events.map((eventObj: any) => new EventInfo(eventObj.days,
eventObj.start, eventObj.end));
ptObj.assignedLabs = new Set();
- pt.assignedLabs.forEach((labId) => {
+ pt.assignedLabs.forEach((labId: string) => {
ptObj.assignedLabs.add(labId);
});
result.peerTeachers.set(key, ptObj);
});
resolve(result);
- };
-
- reader.readAsText(file);
+ });
});
}
diff --git a/src/main.js b/src/main.ts
index c673f53..c673f53 100644
--- a/src/main.js
+++ b/src/main.ts
diff --git a/src/models/EventInfo.js b/src/models/EventInfo.ts
index c1624a8..4493162 100644
--- a/src/models/EventInfo.js
+++ b/src/models/EventInfo.ts
@@ -1,13 +1,19 @@
export default class EventInfo {
- constructor(days = '', start = 0, end = 0) {
+ days: string;
+
+ start: number;
+
+ end: number;
+
+ constructor(days: string = '', start = 0, end = 0) {
this.days = days;
this.start = start;
this.end = end;
}
- static timeToStr(time) {
+ static timeToStr(time: number) {
let hour = Math.floor(time / 100);
- let minute = time % 100;
+ const minute = time % 100;
const meridiem = (hour < 12) ? 'AM' : 'PM';
if (hour === 0) {
@@ -17,13 +23,12 @@ export default class EventInfo {
}
if (minute < 10) {
- minute = `0${minute}`;
+ return `${hour}:0${minute} ${meridiem}`;
}
-
return `${hour}:${minute} ${meridiem}`;
}
- conflictsWith(event) {
+ conflictsWith(event: EventInfo) {
const daysConflict = event.days.match(new RegExp(`[${this.days}]`));
if (daysConflict) {
diff --git a/src/models/Lab.js b/src/models/Lab.ts
index 2e4412d..a6972ef 100644
--- a/src/models/Lab.js
+++ b/src/models/Lab.ts
@@ -1,6 +1,12 @@
import EventInfo from '@/models/EventInfo';
export default class Lab {
+ course: number;
+
+ section: number;
+
+ event: EventInfo;
+
constructor(course = 0, section = 0, event = new EventInfo()) {
this.course = course;
this.section = section;
diff --git a/src/models/PeerTeacher.js b/src/models/PeerTeacher.ts
index 00a2f0d..f387431 100644
--- a/src/models/PeerTeacher.js
+++ b/src/models/PeerTeacher.ts
@@ -1,4 +1,16 @@
+import EventInfo from './EventInfo';
+
export default class PeerTeacher {
+ firstname: string;
+
+ lastname: string;
+
+ uin: number;
+
+ events: EventInfo[];
+
+ assignedLabs: Set<string>;
+
constructor(firstname = '', lastname = '', uin = 0) {
this.firstname = firstname;
this.lastname = lastname;
@@ -7,7 +19,7 @@ export default class PeerTeacher {
this.assignedLabs = new Set();
}
- conflictsWith(event) {
+ conflictsWith(event: EventInfo) {
let conflicts = false;
this.events.every((item) => {
if (item.conflictsWith(event)) {
diff --git a/src/router/index.js b/src/router/index.ts
index 7a598b3..7a598b3 100644
--- a/src/router/index.js
+++ b/src/router/index.ts
diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts
new file mode 100644
index 0000000..3804a43
--- /dev/null
+++ b/src/shims-vue.d.ts
@@ -0,0 +1,6 @@
+/* eslint-disable */
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/src/store/index.js b/src/store/index.ts
index 0c3a5c9..e63e257 100644
--- a/src/store/index.js
+++ b/src/store/index.ts
@@ -1,3 +1,5 @@
+import Lab from '@/models/Lab';
+import PeerTeacher from '@/models/PeerTeacher';
import { createStore } from 'vuex';
export default createStore({
@@ -6,24 +8,24 @@ export default createStore({
peerTeachers: new Map(),
},
mutations: {
- setLabs(state, labs) {
+ setLabs(state, labs: Map<string, Lab>) {
state.labs = labs;
},
- setPeerTeachers(state, peerTeachers) {
+ setPeerTeachers(state, peerTeachers: Map<number, PeerTeacher>) {
state.peerTeachers = peerTeachers;
},
- importLabs(state, labs) {
+ importLabs(state, labs: Lab[]) {
state.labs.clear();
labs.forEach((lab) => {
state.labs.set(lab.id, lab);
});
},
- addPeerTeachers(state, peerTeachers) {
+ addPeerTeachers(state, peerTeachers: PeerTeacher[]) {
peerTeachers.forEach((pt) => {
state.peerTeachers.set(pt.id, pt);
});
},
- deletePeerTeacher(state, id) {
+ deletePeerTeacher(state, id: number) {
state.peerTeachers.delete(id);
},
},
diff --git a/src/views/About.vue b/src/views/About.vue
index ab4725e..ac2bde1 100644
--- a/src/views/About.vue
+++ b/src/views/About.vue
@@ -7,18 +7,19 @@
</div>
</template>
-<script>
+<script lang="ts">
+import { defineComponent } from 'vue';
import FileUpload from '../components/FileUpload.vue';
import { parsePtDatabase } from '../features/parser';
-export default {
+export default defineComponent({
name: 'About',
components: {
FileUpload,
},
methods: {
- handleDatabaseChange(files) {
+ handleDatabaseChange(files: File[]) {
parsePtDatabase(files[0]).then((result) => {
this.$store.commit('setLabs', result.labs);
this.$store.commit('setPeerTeachers', result.peerTeachers);
@@ -26,5 +27,5 @@ export default {
});
},
},
-};
+});
</script>
diff --git a/src/views/Editor.vue b/src/views/Editor.vue
index 5ef0131..b4a2e8e 100644
--- a/src/views/Editor.vue
+++ b/src/views/Editor.vue
@@ -1,123 +1,38 @@
<template>
<div id="home">
<action-bar />
- <div id="editor">
- <div class="column">
- <list :items="peerTeachers" @selection-changed="handlePtClick" #default="pt">
- {{ pt.item.name }} <button @click.stop="deletePeerTeacher(pt.item.id)">X</button>
- </list>
- </div>
- <div class="column">
- <list :items="compatibleLabs" #default="lab">
- {{ lab.item.fullInfo }} <button @click.stop="assignLab(lab.item.id)">+</button>
- </list>
- </div>
- <div class="column">
- <list :items="selectedPeerTeacherAssignments" #default="lab">
- {{ lab.item.fullInfo }} <button @click.stop="unassignLab(lab.item.id)">X</button>
- </list>
- </div>
- </div>
+ <editor-lists :peerTeachers="peerTeachers" :labs="labs" />
</div>
</template>
-<script>
+<script lang="ts">
+import { defineComponent } from 'vue';
import ActionBar from '@/components/ActionBar.vue';
-import List from '@/components/List.vue';
+import EditorLists from '@/components/EditorLists.vue';
import PeerTeacher from '@/models/PeerTeacher';
+import Lab from '@/models/Lab';
-export default {
+export default defineComponent({
name: 'Editor',
components: {
ActionBar,
- List,
+ EditorLists,
},
computed: {
- labs() {
+ labs(): Lab[] {
return Array.from(this.$store.state.labs.values()).sort((a, b) => a.id
.localeCompare(b.id));
},
- peerTeachers() {
+ peerTeachers(): PeerTeacher[] {
return Array.from(this.$store.state.peerTeachers.values()).sort((a, b) => a.lastname
.toUpperCase().localeCompare(b.lastname.toUpperCase()));
},
- compatibleLabs() {
- const temp = this.labs.filter((lab) => (!this.selectedPeerTeacher.assignedLabs.has(lab.id)
- && !this.selectedPeerTeacher.conflictsWith(lab.event)));
-
- const currentAssignments = this.selectedPeerTeacherAssignments;
- return temp.filter((lab) => {
- let compatible = true;
- currentAssignments.every((assignedLab) => {
- if (lab.event.conflictsWith(assignedLab.event)) {
- compatible = false;
- return false;
- }
- return true;
- });
- return compatible;
- });
- },
- selectedPeerTeacherAssignments() {
- return [...this.selectedPeerTeacher.assignedLabs.values()].map((id) => this.$store.state.labs
- .get(id)).sort((a, b) => {
- if (a.course < b.course) {
- return -1;
- }
- if (b.course < a.course) {
- return 1;
- }
-
- if (a.section < b.section) {
- return -1;
- }
- if (b.section < a.section) {
- return 1;
- }
-
- return 0;
- });
- },
- },
- data() {
- return {
- selectedPeerTeacher: new PeerTeacher(),
- };
- },
- methods: {
- handlePtClick(peerTeacher) {
- this.selectedPeerTeacher = peerTeacher;
- },
- deletePeerTeacher(id) {
- if (this.selectedPeerTeacher.id === id) {
- this.selectedPeerTeacher = new PeerTeacher();
- }
- this.$store.commit('deletePeerTeacher', id);
- },
- assignLab(id) {
- if (this.selectedPeerTeacher.id !== 0) {
- this.selectedPeerTeacher.assignedLabs.add(id);
- }
- },
- unassignLab(id) {
- this.selectedPeerTeacher.assignedLabs.delete(id);
- },
},
-};
+});
</script>
<style>
#home {
max-height: inherit;
}
-
-#editor {
- display: flex;
- max-height: inherit;
-}
-
-.column {
- flex: 1;
- overflow: auto;
-}
</style>
diff --git a/src/vuex-shim.d.ts b/src/vuex-shim.d.ts
new file mode 100644
index 0000000..c8a55f9
--- /dev/null
+++ b/src/vuex-shim.d.ts
@@ -0,0 +1,17 @@
+import { Store } from 'vuex';
+
+import PeerTeacher from './models/PeerTeacher';
+import Lab from './models/Lab';
+
+declare module '@vue/runtime-core' {
+ // declare your own store states
+ interface State {
+ peerTeachers: Map<number, PeerTeacher>,
+ labs: Map<string, Lab>
+ }
+
+ // provide typings for `this.$store`
+ interface ComponentCustomProperties {
+ $store: Store<State>
+ }
+}