diff options
Diffstat (limited to 'src/components/AssignLabs')
| -rw-r--r-- | src/components/AssignLabs/AssignLabs.svelte | 151 | ||||
| -rw-r--r-- | src/components/AssignLabs/LabBox.svelte | 32 | ||||
| -rw-r--r-- | src/components/AssignLabs/PTBox.svelte | 44 |
3 files changed, 227 insertions, 0 deletions
diff --git a/src/components/AssignLabs/AssignLabs.svelte b/src/components/AssignLabs/AssignLabs.svelte new file mode 100644 index 0000000..3a326ad --- /dev/null +++ b/src/components/AssignLabs/AssignLabs.svelte @@ -0,0 +1,151 @@ +<script lang="ts"> + import type PeerTeacher from "../../models/PeerTeacher"; + import { labStore, ptStore } from "../../stores"; + import Lab from "./LabBox.svelte"; + import PT from "./PTBox.svelte"; + import { onMount } from "svelte"; + import { parseDatabaseLocal } from "../../util/parser"; + + let selectedPeerTeacher: PeerTeacher | undefined; + + $: peerTeachers = [...$ptStore.values()].sort((a, b) => + a.lastname.toUpperCase() === b.lastname.toUpperCase() + ? a.firstname.toUpperCase().localeCompare(b.firstname.toUpperCase()) + : a.lastname.toUpperCase().localeCompare(b.lastname.toUpperCase()) + ); + + $: labs = [...$labStore.values()].sort((a, b) => a.id - b.id); + + $: assignedLabs = [...(selectedPeerTeacher?.labs.values() ?? [])] + .flatMap((labId) => { + const lab = $labStore.get(labId); + return lab === undefined ? [] : [lab]; + }) + .sort((a, b) => a.id - b.id); + + $: unassignedLabs = labs.filter((lab) => !lab.assigned); + + $: compatibleLabs = labs.filter( + (lab) => + // Lab not already assigned + !lab.assigned && + // PT schedule not conflict with lab + !selectedPeerTeacher?.conflictsWith(lab.event) && + // PT's labs not conflict with this lab + !assignedLabs.some((assignment) => + assignment.event.conflictsWith(lab.event) + ) + ); + + function updateReactiveDeclarations() { + selectedPeerTeacher = selectedPeerTeacher; + peerTeachers = peerTeachers; + labs = labs; + } + + function assignLab(id: number) { + const lab = $labStore.get(id); + if (lab === undefined) return; + lab.assigned = true; + selectedPeerTeacher?.labs.add(id); + updateReactiveDeclarations(); + } + + function unassignLab(id: number) { + const lab = $labStore.get(id); + if (lab === undefined) return; + lab.assigned = false; + selectedPeerTeacher?.labs.delete(id); + updateReactiveDeclarations(); + } + + // Load db from local storage so I don't have to keep uploading + onMount(() => { + const db = localStorage.getItem("db"); + if (db) { + parseDatabaseLocal(JSON.parse(db)); + } + }); +</script> + +<div + class="flex-none overflow-hidden flex-col h-[100vh] w-[80vw] px-[2vw] pt-[1vh]" +> + <!-- Top half: 3 Columns --> + <div class="flex flex-row h-[80vh]"> + <!-- PT Box --> + <div class="assign-box rounded-l-xl"> + <!-- PT Header --> + <div class="assign-box-header">Peer Teacher</div> + <!-- PT Body --> + <div class="assign-box-body"> + {#each peerTeachers as pt} + <div + class={selectedPeerTeacher == pt + ? "border-l-8 border-blue-500" + : ""} + on:click={() => { + selectedPeerTeacher = pt; + }} + > + <svelte:component this={PT} {pt} /> + </div> + {/each} + </div> + </div> + + <!-- Available Labs --> + <div class="assign-box"> + <div class="assign-box-header">Labs</div> + <div class="assign-box-body"> + {#each compatibleLabs as lab} + <svelte:component + this={Lab} + {lab} + iconName="plus-circle" + iconClick={() => { + assignLab(lab.id); + }} + /> + {/each} + </div> + </div> + + <!-- Selected PT's Labs --> + <div class="assign-box rounded-r-xl"> + <div class="assign-box-header"> + {selectedPeerTeacher?.name ?? "PT's Labs"} + </div> + <div class="assign-box-body"> + {#each assignedLabs as lab} + <svelte:component + this={Lab} + {lab} + iconName="minus-circle" + iconClick={() => { + unassignLab(lab.id); + + }} + /> + {/each} + </div> + </div> + </div> + + <!-- Bottom half: Universal unassigned labs --> + <div class="flex flex-col mt-2 text-center"> + <h1>Unassigned Labs</h1> + <div + class="flex flex-row overflow-auto border-y-4 mt-1 border-slate-500 w-full items-center text-sm" + > + {#each unassignedLabs as lab} + <div + class="hover:animate-bounce border rounded-xl hover:bg-sky-100 hover:text-black px-3 py-1 mx-2" + > + <p>{lab.course}</p> + <p>{lab.section}</p> + </div> + {/each} + </div> + </div> +</div> diff --git a/src/components/AssignLabs/LabBox.svelte b/src/components/AssignLabs/LabBox.svelte new file mode 100644 index 0000000..9805c51 --- /dev/null +++ b/src/components/AssignLabs/LabBox.svelte @@ -0,0 +1,32 @@ +<script lang="ts"> + import type Lab from "../../models/Lab"; + import Icon from "../helpers/Icon.svelte"; + export let lab: Lab; + export let iconClick = () => {}; + export let iconName: string; +</script> + +<!-- Lab box --> +<div + class="block border-b px-3 py-3 hover:bg-sky-100 hover:text-black h-20 overflow-hidden" +> + <!-- Lab content --> + <div class="flex flex-col"> + <!-- Top Half --> + <div class="flex flex-row"> + <strong class="flex-grow">CSCE {lab.course} - {lab.section}</strong> + <Icon + name={iconName} + class="h-6 w-6" + handleClick={() => { + iconClick(); + }} + /> + </div> + </div> + <!-- Bottom half --> + <div> + <p class="text-xs">{lab.event.info}</p> + <p class="text-xs">{lab.building} {lab.room}</p> + </div> +</div> diff --git a/src/components/AssignLabs/PTBox.svelte b/src/components/AssignLabs/PTBox.svelte new file mode 100644 index 0000000..3ad50d1 --- /dev/null +++ b/src/components/AssignLabs/PTBox.svelte @@ -0,0 +1,44 @@ +<script lang="ts"> + import type PeerTeacher from "../../models/PeerTeacher"; + import Icon from "../helpers/Icon.svelte"; + export let pt: PeerTeacher; + + let modalID = () => { + return `my-modal-${pt.id}`; + } +</script> + +<!-- PT Box --> +<div + class="block border-b px-3 py-3 hover:bg-sky-100 hover:text-black h-20 overflow-hidden group" +> + <!-- Top half, name and button --> + <div class="flex flex-row items-center "> + <!-- Left half, name --> + <strong class="flex-grow text-sm">{pt.name}</strong> + + <!-- Right half, button --> + <!-- The button to open modal --> + <label for={modalID()} class=""> + <Icon name="info" class="h-6 w-6" /> + </label> + + <!-- Modal PT event info --> + <input type="checkbox" id={modalID()} class="modal-toggle" /> + <label for={modalID()} class="modal cursor-pointer"> + <label class="modal-box relative bg-slate-300" for=""> + <h3 class="text-lg font-bold font-serif underline"> + {pt.name} + </h3> + {#each pt.events as e} + <p class="py-2"> + {e.info} + </p> + {/each} + </label> + </label> + </div> + + <!-- Bottom half, hours --> + <div class="">Hours: {pt.lab_hours}</div> +</div> |
