Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,904 changes: 1,624 additions & 2,280 deletions package-lock.json

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@
"lint": "eslint ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.3.3",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/canvas-confetti": "^1.6.4",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"autoprefixer": "^10.4.16",
"eslint": "^8.28.0",
"eslint-plugin-svelte": "^2.30.0",
"postcss": "^8.4.31",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"tailwindcss": "^3.3.5",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^5.0.0"
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/adapter-node": "^5.4.0",
"@sveltejs/kit": "^2.49.0",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tailwindcss/postcss": "^4.1.17",
"@types/canvas-confetti": "^1.9.0",
"@typescript-eslint/eslint-plugin": "^8.47.0",
"@typescript-eslint/parser": "^8.47.0",
"eslint": "^9.39.1",
"eslint-plugin-svelte": "^3.13.0",
"postcss": "^8.5.6",
"svelte": "^5.43.14",
"svelte-check": "^4.3.4",
"tailwindcss": "^4.1.17",
"tslib": "^2.8.1",
"typescript": "^5.9.3",
"vite": "^7.2.4"
},
"type": "module",
"dependencies": {
"@types/pg": "^8.10.9",
"canvas-confetti": "^1.9.2",
"date-fns": "^3.0.6",
"@types/pg": "^8.15.6",
"canvas-confetti": "^1.9.4",
"date-fns": "^4.1.0",
"html5-qrcode": "^2.3.8",
"pg": "^8.11.3",
"svelte-feather-icons": "^4.1.0",
"svelte-simple-modal": "^1.6.2"
"pg": "^8.16.3",
"svelte-feather-icons": "^4.2.0",
"svelte-simple-modal": "^2.0.0"
}
}
3 changes: 1 addition & 2 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': {},
},
}
72 changes: 69 additions & 3 deletions src/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,70 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import 'tailwindcss';

@theme {
--color-thpink: rgb(252, 148, 187);

--font-sans:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI,
Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji,
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
--font-poppins: Poppins, sans-serif;
--font-roboto: Roboto, sans-serif;

--animate-wiggle0: wiggle 1s ease-in-out 0.05s infinite;
--animate-wiggle1: wiggle 1s ease-in-out 0.1s infinite;
--animate-wiggle2: wiggle 1s ease-in-out 0.15s infinite;
--animate-wiggle3: wiggle 1s ease-in-out 0.2s infinite;
--animate-wiggle4: wiggle 1s ease-in-out 0.25s infinite;
--animate-wiggle5: wiggle 1s ease-in-out 0.3s infinite;
--animate-wiggle6: wiggle 1s ease-in-out 0.35s infinite;
--animate-wiggle7: wiggle 1s ease-in-out 0.4s infinite;
--animate-wiggle8: wiggle 1s ease-in-out 0.45s infinite;
--animate-wiggle9: wiggle 1s ease-in-out 0.5s infinite;
--animate-fade-in: fadeIn 0.1s;
--animate-pop-in: popIn 0.2s;

@keyframes wiggle {
0%,
100% {
left: -20px;
}
50% {
left: 20px;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes popIn {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
}

/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.

If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}

18 changes: 11 additions & 7 deletions src/lib/historyModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
import { XIcon, InfoIcon } from "svelte-feather-icons";
import type { Participant } from "./slitherTypes";

export let modalOpen: boolean;
export let scannedParticipantHistory: Participant[];
export let onHistoricalScan: (participant: Participant) => void;
interface Props {
modalOpen: boolean;
scannedParticipantHistory: Participant[];
onHistoricalScan: (participant: Participant) => void;
}

let { modalOpen = $bindable(), scannedParticipantHistory, onHistoricalScan }: Props = $props();

</script>

<div class="z-10 animate-fadeIn fixed left-0 top-0 w-full h-full overflow-auto bg-[#00000088] {modalOpen ? "block" : "hidden"}">
<div class="animate-popIn bg-white rounded-xl fixed left-auto right-auto top-auto bottom-0 m-4 p-4 w-11/12 shadow-md max-w-2xl">
<button class="ml-auto block" on:click={() => modalOpen = false}><XIcon size="36" /></button>
<div class="z-10 animate-fade-in fixed left-0 top-0 w-full h-full overflow-auto bg-[#00000088] {modalOpen ? "block" : "hidden"}">
<div class="animate-pop-in bg-white rounded-xl fixed left-auto right-auto top-auto bottom-0 m-4 p-4 w-11/12 shadow-md max-w-2xl">
<button class="ml-auto block" onclick={() => modalOpen = false}><XIcon size="36" /></button>

<div>
<p class="text-2xl mb-3">Scan History:</p>
Expand All @@ -22,7 +26,7 @@
<p class="font-semibold">{historicalScan.firstName} {historicalScan.lastName}</p>
<p class="text-sm">{historicalScan.email}</p>
</div>
<button on:click={() => {onHistoricalScan(historicalScan);}} class="p-1"><InfoIcon /></button>
<button onclick={() => {onHistoricalScan(historicalScan);}} class="p-1"><InfoIcon /></button>
</div>
{/each}
</div>
Expand Down
83 changes: 47 additions & 36 deletions src/lib/scanModal.svelte
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@

<script lang="ts">
import { run } from 'svelte/legacy';

import { getMealCode, type Participant, type ScanningForType } from "./slitherTypes";
import { LoaderIcon, XIcon } from "svelte-feather-icons";
import { formatDistanceToNow } from "date-fns";
import { suspiciousLastScanWindows } from "./slitherConfig";
import { getAuthHeader } from "./slitherAuth";

export let modalOpen: boolean;
export let scannedParticipant: Participant | null;
export let selectedScanningForOption: string;
export let selectedScanningForType: ScanningForType;
interface Props {
modalOpen: boolean;
scannedParticipant: Participant | null;
selectedScanningForOption: string;
selectedScanningForType: ScanningForType;
}

let {
modalOpen = $bindable(),
scannedParticipant = $bindable(),
selectedScanningForOption,
selectedScanningForType
}: Props = $props();

let postFetching = false;
let scanDone = false;
let lastScannedParticipantEmail: string | null = null;
let postFetching = $state(false);
let scanDone = $state(false);
let lastScannedParticipantEmail: string | null = $state(null);
let lastSelectedScanningForOption: string | null = null;
$: {
run(() => {
if (scannedParticipant !== null && (scannedParticipant.email !== lastScannedParticipantEmail || selectedScanningForOption !== lastSelectedScanningForOption)) {
lastScannedParticipantEmail = scannedParticipant.email;
scanDone = false;
}
}
});

async function checkIn() {
if (scannedParticipant === null || postFetching || scanDone) {
Expand Down Expand Up @@ -115,9 +126,9 @@

</script>

<div class="z-10 animate-fadeIn fixed left-0 top-0 w-full h-full overflow-auto bg-[#00000088] {modalOpen ? "block" : "hidden"}">
<div class="animate-popIn bg-white rounded-xl fixed left-auto right-auto top-auto bottom-0 m-4 p-4 w-11/12 shadow-md max-w-2xl">
<button class="ml-auto block mb-3" on:click={() => modalOpen = false}><XIcon size="36" /></button>
<div class="z-10 animate-fade-in fixed left-0 top-0 w-full h-full overflow-auto bg-[#00000088] {modalOpen ? "block" : "hidden"}">
<div class="animate-pop-in bg-white rounded-xl fixed left-auto right-auto top-auto bottom-0 m-4 p-4 w-11/12 shadow-md max-w-2xl">
<button class="ml-auto block mb-3" onclick={() => modalOpen = false}><XIcon size="36" /></button>

<div>
{#if scannedParticipant === null}
Expand Down Expand Up @@ -171,7 +182,7 @@
{/if}

{#if selectedScanningForType === "Check-in" && scannedParticipant.checkinStatus !== "Checked In"}
<button on:click={checkIn} class="block w-full py-2 mt-6 rounded-md bg-blue-400 text-white font-bold text-2xl">
<button onclick={checkIn} class="block w-full py-2 mt-6 rounded-md bg-blue-400 text-white font-bold text-2xl">
{#if postFetching}
<LoaderIcon class="animate-spin mx-auto" size="32" />
{:else}
Expand All @@ -190,7 +201,7 @@
<p class="mt-4">Dietary restrictions: <span class="font-bold">{scannedParticipant.dietaryRestrictions}</span></p>
{/if}
<p class="mt-4">Meal group: <span class="font-bold">{scannedParticipant.mealGroup}</span></p>
<button on:click={scanMeal} class="block w-full py-2 mt-6 rounded-md text-white font-bold text-2xl {scanDone ? "bg-green-600" : "bg-blue-400"}">
<button onclick={scanMeal} class="block w-full py-2 mt-6 rounded-md text-white font-bold text-2xl {scanDone ? "bg-green-600" : "bg-blue-400"}">
{#if postFetching}
<LoaderIcon class="animate-spin mx-auto" size="32" />
{:else if scanDone}
Expand All @@ -200,28 +211,28 @@
{/if}
</button>
{:else if selectedScanningForType === "Workshop"}
{#if scannedParticipant.mealGroup === "Judge/Mentor" || scannedParticipant.isJudgeMentor}
<p class="font-bold text-xl text-orange-600 text-center mt-4">Judges and mentors don't need to scan for workshops</p>
{:else}
<p>Last workshop scan:
{#if scannedParticipant.lastWorkshopScan === null}
never
{:else if workshopScanIsSuspiciouslyRecent()}
<span class="font-bold text-red-700">{formatDistanceToNow(scannedParticipant.lastWorkshopScan, { addSuffix: true })} ⚠</span>
{:else}
{formatDistanceToNow(scannedParticipant.lastWorkshopScan, { addSuffix: true })}
{/if}
</p>
<button on:click={scanWorkshop} class="block w-full py-2 mt-6 rounded-md text-white font-bold text-2xl {scanDone ? "bg-green-600" : "bg-blue-400"}">
{#if postFetching}
<LoaderIcon class="animate-spin mx-auto" size="32" />
{:else if scanDone}
Log Successful!
{:else}
Log Workshop
{/if}
</button>
{/if}
{#if scannedParticipant.mealGroup === "Judge/Mentor" || scannedParticipant.isJudgeMentor}
<p class="font-bold text-xl text-orange-600 text-center mt-4">Judges and mentors don't need to scan for workshops</p>
{:else}
<p>Last workshop scan:
{#if scannedParticipant.lastWorkshopScan === null}
never
{:else if workshopScanIsSuspiciouslyRecent()}
<span class="font-bold text-red-700">{formatDistanceToNow(scannedParticipant.lastWorkshopScan, { addSuffix: true })} ⚠</span>
{:else}
{formatDistanceToNow(scannedParticipant.lastWorkshopScan, { addSuffix: true })}
{/if}
</p>
<button onclick={scanWorkshop} class="block w-full py-2 mt-6 rounded-md text-white font-bold text-2xl {scanDone ? "bg-green-600" : "bg-blue-400"}">
{#if postFetching}
<LoaderIcon class="animate-spin mx-auto" size="32" />
{:else if scanDone}
Log Successful!
{:else}
Log Workshop
{/if}
</button>
{/if}
{/if}
{:else}
<p class="animate-pulse">Fetching participant info...</p>
Expand Down
10 changes: 7 additions & 3 deletions src/lib/scanner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@

const SCANNER_HTML_ID = "slither-scanner-reader";

export let onScan: (email: string) => void;
interface Props {
onScan: (email: string) => void;
}

let { onScan }: Props = $props();

let scannerOpen = false;
let scannerOpen = $state(false);

function onScanSuccess(decodedText: string, decodedResult: Html5QrcodeResult) {
let email = "";
Expand Down Expand Up @@ -48,7 +52,7 @@
<div>

{#if !scannerOpen}
<button class="text-4xl bg-thpink hover:bg-pink-400 text-white rounded-lg py-2 px-[21px] mx-auto block" on:click={() => {scannerOpen = true; makeScanner();}}>Start Scanning</button>
<button class="text-4xl bg-thpink hover:bg-pink-400 text-white rounded-lg py-2 px-[21px] mx-auto block" onclick={() => {scannerOpen = true; makeScanner();}}>Start Scanning</button>
{/if}

<div id={SCANNER_HTML_ID} class="w-full max-w-2xl mx-auto"></div>
Expand Down
7 changes: 6 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<script lang="ts">
import "../app.css";
interface Props {
children?: import('svelte').Snippet;
}

let { children }: Props = $props();
</script>

<svelte:head>
Expand All @@ -16,4 +21,4 @@
/>
</svelte:head>

<slot />
{@render children?.()}
20 changes: 10 additions & 10 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
import { browser } from "$app/environment";
import HistoryModal from "$lib/historyModal.svelte";

let authorized = false;
let fetchingLoggedIn = true;
let selectedScanningForOption = Object.keys(scanningForOptions)[0];
$: selectedScanningForType = scanningForOptions[selectedScanningForOption];
let scanModalOpen = false;
let historyModalOpen = false;
let scannedParticipant: Participant | null = null;
let scannedParticipantHistory: Participant[] = [];
let authorized = $state(false);
let fetchingLoggedIn = $state(true);
let selectedScanningForOption = $state(Object.keys(scanningForOptions)[0]);
let selectedScanningForType = $derived(scanningForOptions[selectedScanningForOption]);
let scanModalOpen = $state(false);
let historyModalOpen = $state(false);
let scannedParticipant: Participant | null = $state(null);
let scannedParticipantHistory: Participant[] = $state([]);

function getAuthorizedStaff(email: string): Participant | null {
return AUTHORIZED_STAFF.find(staff => staff.email.toLowerCase() === email.toLowerCase()) || null;
Expand Down Expand Up @@ -292,15 +292,15 @@ async function fetchJudgeMentorInfo(email: string): Promise<Participant | null>

<div class="flex flex-row justify-center gap-2 mb-4">
<button
on:click={() => {
onclick={() => {
scanModalOpen = true;
fetchScannedParticipantInfo();
}}
class="block border-[3px] border-thpink hover:border-pink-400 px-2 py-1 text-xl rounded-lg mt-5"
>Re-open Last Scan</button
>
<button
on:click={() => {
onclick={() => {
historyModalOpen = true;
}}
class="block border-[3px] border-thpink hover:border-pink-400 px-2 py-1 text-xl rounded-lg mt-5"
Expand Down
Loading