From 74e6cc31e83ad570a9f06765d288e9024736e73f Mon Sep 17 00:00:00 2001 From: Furkan Sahin Date: Sat, 10 Apr 2021 21:35:13 -0500 Subject: Commit MVP --- src/App.vue | 19 ++++-- src/assets/logo.png | Bin 6849 -> 0 bytes src/components/ActionBar.vue | 75 +++++++++++++++++++++++ src/components/FileUpload.vue | 41 +++++++++++++ src/components/HelloWorld.vue | 60 ------------------ src/components/List.vue | 41 +++++++++++++ src/features/parser.js | 138 ++++++++++++++++++++++++++++++++++++++++++ src/models/EventInfo.js | 41 +++++++++++++ src/models/Lab.js | 17 ++++++ src/models/PeerTeacher.js | 29 +++++++++ src/router/index.js | 14 +++-- src/store/index.js | 22 +++++++ src/views/About.vue | 27 ++++++++- src/views/Editor.vue | 123 +++++++++++++++++++++++++++++++++++++ src/views/Home.vue | 18 ------ 15 files changed, 575 insertions(+), 90 deletions(-) delete mode 100644 src/assets/logo.png create mode 100644 src/components/ActionBar.vue create mode 100644 src/components/FileUpload.vue delete mode 100644 src/components/HelloWorld.vue create mode 100644 src/components/List.vue create mode 100644 src/features/parser.js create mode 100644 src/models/EventInfo.js create mode 100644 src/models/Lab.js create mode 100644 src/models/PeerTeacher.js create mode 100644 src/views/Editor.vue delete mode 100644 src/views/Home.vue (limited to 'src') diff --git a/src/App.vue b/src/App.vue index b964355..c3a04c9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,13 +1,22 @@ diff --git a/src/assets/logo.png b/src/assets/logo.png deleted file mode 100644 index f3d2503..0000000 Binary files a/src/assets/logo.png and /dev/null differ diff --git a/src/components/ActionBar.vue b/src/components/ActionBar.vue new file mode 100644 index 0000000..96dbaae --- /dev/null +++ b/src/components/ActionBar.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/components/FileUpload.vue b/src/components/FileUpload.vue new file mode 100644 index 0000000..b2fdb14 --- /dev/null +++ b/src/components/FileUpload.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue deleted file mode 100644 index 94ceb6b..0000000 --- a/src/components/HelloWorld.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - diff --git a/src/components/List.vue b/src/components/List.vue new file mode 100644 index 0000000..031f708 --- /dev/null +++ b/src/components/List.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/features/parser.js b/src/features/parser.js new file mode 100644 index 0000000..f91d926 --- /dev/null +++ b/src/features/parser.js @@ -0,0 +1,138 @@ +import Lab from '@/models/Lab'; +import PeerTeacher from '@/models/PeerTeacher'; +import EventInfo from '../models/EventInfo'; + +export function parseLabFile(file) { + const validCourses = [ + '110', + '111', + '121', + '206', + '221', + // '222', + '312', + '313', + // '314', + '315', + ]; + + const reader = new FileReader(); + + return new Promise((resolve, reject) => { + const result = []; + + reader.onload = (event) => { + let jsonData; + try { + jsonData = JSON.parse(event.target.result); + } catch (e) { + reject(new Error(e)); + } + const labs = jsonData.data; + + labs.forEach((lab) => { + if (validCourses.includes(lab.courseNumber)) { + const newLab = new Lab(lab.courseNumber, lab.sequenceNumber); + + if (lab.instructionalMethod !== 'Web Based') { + lab.meetingsFaculty.every((meeting) => { + const { meetingTime } = meeting; + + if (meetingTime.meetingType === 'LAB') { + let days = ''; + days += meetingTime.monday ? 'M' : ''; + days += meetingTime.tuesday ? 'T' : ''; + days += meetingTime.wednesday ? 'W' : ''; + days += meetingTime.thursday ? 'R' : ''; + days += meetingTime.friday ? 'F' : ''; + + newLab.event.days = days; + newLab.event.start = parseInt(meetingTime.beginTime, 10); + newLab.event.end = parseInt(meetingTime.endTime, 10); + + return false; + } + + return true; + }); + } + + result.push(newLab); + } + }); + + resolve(result); + }; + + reader.readAsText(file); + }); +} + +export function parsePtSchedule(file) { + const reader = new FileReader(); + + return new Promise((resolve) => { + reader.onload = (event) => { + 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()); + + lines.forEach((line) => { + const ptName = line.match(namePattern); + if (ptName) { + [, peerTeacher.firstname, peerTeacher.lastname] = ptName; + peerTeacher.uin = parseInt(ptName[3], 10); + } + + const eventMatch = line.match(eventPattern); + if (eventMatch) { + const newEvent = new EventInfo(eventMatch[1]); + newEvent.start = parseInt(eventMatch[2].replace(':', ''), 10); + newEvent.end = parseInt(eventMatch[3].replace(':', ''), 10); + peerTeacher.events.push(newEvent); + } + }); + + resolve(peerTeacher); + }; + + reader.readAsText(file); + }); +} + +export function parsePtDatabase(file) { + const reader = new FileReader(); + + return new Promise((resolve) => { + reader.onload = (event) => { + const jsonObj = JSON.parse(event.target.result); + const result = { + labs: new Map(), + peerTeachers: new Map(), + }; + + Object.keys(jsonObj.labs).forEach((key) => { + const lab = jsonObj.labs[key]; + result.labs.set(key, new Lab(lab.course, + lab.section, new EventInfo(lab.event.days, lab.event.start, lab.event.end))); + }); + + 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, + eventObj.start, eventObj.end)); + ptObj.assignedLabs = new Set(); + pt.assignedLabs.forEach((labId) => { + ptObj.assignedLabs.add(labId); + }); + result.peerTeachers.set(key, ptObj); + }); + + resolve(result); + }; + + reader.readAsText(file); + }); +} diff --git a/src/models/EventInfo.js b/src/models/EventInfo.js new file mode 100644 index 0000000..c1624a8 --- /dev/null +++ b/src/models/EventInfo.js @@ -0,0 +1,41 @@ +export default class EventInfo { + constructor(days = '', start = 0, end = 0) { + this.days = days; + this.start = start; + this.end = end; + } + + static timeToStr(time) { + let hour = Math.floor(time / 100); + let minute = time % 100; + const meridiem = (hour < 12) ? 'AM' : 'PM'; + + if (hour === 0) { + hour = 12; + } else if (hour > 12) { + hour -= 12; + } + + if (minute < 10) { + minute = `0${minute}`; + } + + return `${hour}:${minute} ${meridiem}`; + } + + conflictsWith(event) { + const daysConflict = event.days.match(new RegExp(`[${this.days}]`)); + + if (daysConflict) { + return (this.start <= event.end) && (event.start <= this.end); + } + return false; + } + + get info() { + if (this.days === '') { + return 'ONLINE'; + } + return `${this.days} ${EventInfo.timeToStr(this.start)}-${EventInfo.timeToStr(this.end)}`; + } +} diff --git a/src/models/Lab.js b/src/models/Lab.js new file mode 100644 index 0000000..2e4412d --- /dev/null +++ b/src/models/Lab.js @@ -0,0 +1,17 @@ +import EventInfo from '@/models/EventInfo'; + +export default class Lab { + constructor(course = 0, section = 0, event = new EventInfo()) { + this.course = course; + this.section = section; + this.event = event; + } + + get id() { + return `${this.course}-${this.section}`; + } + + get fullInfo() { + return `${this.id} ${this.event.info}`; + } +} diff --git a/src/models/PeerTeacher.js b/src/models/PeerTeacher.js new file mode 100644 index 0000000..00a2f0d --- /dev/null +++ b/src/models/PeerTeacher.js @@ -0,0 +1,29 @@ +export default class PeerTeacher { + constructor(firstname = '', lastname = '', uin = 0) { + this.firstname = firstname; + this.lastname = lastname; + this.uin = uin; + this.events = []; + this.assignedLabs = new Set(); + } + + conflictsWith(event) { + let conflicts = false; + this.events.every((item) => { + if (item.conflictsWith(event)) { + conflicts = true; + return false; + } + return true; + }); + return conflicts; + } + + get name() { + return `${this.firstname} ${this.lastname}`; + } + + get id() { + return this.uin; + } +} diff --git a/src/router/index.js b/src/router/index.js index 8f52523..7a598b3 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,19 +1,21 @@ import { createRouter, createWebHashHistory } from 'vue-router'; -import Home from '../views/Home.vue'; +import Editor from '../views/Editor.vue'; +import About from '../views/About.vue'; const routes = [ { path: '/', - name: 'Home', - component: Home, + name: 'About', + component: About, }, { - path: '/about', - name: 'About', + path: '/editor', + name: 'Editor', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. - component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), + // component: () => import(/* webpackChunkName: "about" */ '../views/Editor.vue'), + component: Editor, }, ]; diff --git a/src/store/index.js b/src/store/index.js index af6cee0..0c3a5c9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,8 +2,30 @@ import { createStore } from 'vuex'; export default createStore({ state: { + labs: new Map(), + peerTeachers: new Map(), }, mutations: { + setLabs(state, labs) { + state.labs = labs; + }, + setPeerTeachers(state, peerTeachers) { + state.peerTeachers = peerTeachers; + }, + importLabs(state, labs) { + state.labs.clear(); + labs.forEach((lab) => { + state.labs.set(lab.id, lab); + }); + }, + addPeerTeachers(state, peerTeachers) { + peerTeachers.forEach((pt) => { + state.peerTeachers.set(pt.id, pt); + }); + }, + deletePeerTeacher(state, id) { + state.peerTeachers.delete(id); + }, }, actions: { }, diff --git a/src/views/About.vue b/src/views/About.vue index 3fa2807..ab4725e 100644 --- a/src/views/About.vue +++ b/src/views/About.vue @@ -1,5 +1,30 @@ + + diff --git a/src/views/Editor.vue b/src/views/Editor.vue new file mode 100644 index 0000000..5ef0131 --- /dev/null +++ b/src/views/Editor.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/views/Home.vue b/src/views/Home.vue deleted file mode 100644 index e91ef23..0000000 --- a/src/views/Home.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - -- cgit v1.2.3