From 17b870f6a8de8081e9b47387183713699cd2c4d1 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Fri, 13 Mar 2026 16:56:29 -0700 Subject: [PATCH 1/7] Add ability to delete local Events/Ballots --- src/lib/storage/storage.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib/storage/storage.ts b/src/lib/storage/storage.ts index 739b06b..b4f2dbc 100644 --- a/src/lib/storage/storage.ts +++ b/src/lib/storage/storage.ts @@ -66,6 +66,11 @@ export class StorageManager { this.saveStorage(this.data); } + deleteBallot(ballotID: number) { + if (this.data.ballots) delete this.data.ballots[ballotID]; + this.saveStorage(this.data); + } + saveEvent(eventID: number, name: string, token: string) { if (!this.data.events) { this.data.events = {}; @@ -74,6 +79,11 @@ export class StorageManager { this.saveStorage(this.data); } + deleteEvent(eventID: number) { + if (this.data.events) delete this.data.events[eventID]; + this.saveStorage(this.data); + } + async migrate(data: StorageData): Promise> { let migratedData: StorageData = { ...data }; From 7b3dd151fd70510462be4e1e7625f9ac89cf80a9 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Fri, 13 Mar 2026 16:57:02 -0700 Subject: [PATCH 2/7] Add SavedEventList and SavedBallotList components --- src/lib/components/SavedBallotList.svelte | 54 ++++++++++++++++ src/lib/components/SavedEventList.svelte | 78 +++++++++++++++++++++++ src/routes/+page.svelte | 5 ++ 3 files changed, 137 insertions(+) create mode 100644 src/lib/components/SavedBallotList.svelte create mode 100644 src/lib/components/SavedEventList.svelte diff --git a/src/lib/components/SavedBallotList.svelte b/src/lib/components/SavedBallotList.svelte new file mode 100644 index 0000000..a2aa9be --- /dev/null +++ b/src/lib/components/SavedBallotList.svelte @@ -0,0 +1,54 @@ + + +{#snippet ballotItem(ballot: BallotItem)} + + Ballot - {ballot.eventName} + + +{/snippet} + +{#each ballots as ballot (ballot.id)} + {@render ballotItem(ballot)} +{/each} diff --git a/src/lib/components/SavedEventList.svelte b/src/lib/components/SavedEventList.svelte new file mode 100644 index 0000000..61c271f --- /dev/null +++ b/src/lib/components/SavedEventList.svelte @@ -0,0 +1,78 @@ + + +{#snippet eventItem(event: EventItem)} + {event.name} +{/snippet} + +{#each events as event (event.id)} + {@render eventItem(event)} +{/each} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 9e07075..e44e90d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,5 +1,7 @@ @@ -14,5 +16,8 @@
+ + + From e931752ee8c24247c151fb55692209f6dcef5d62 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Wed, 25 Mar 2026 12:02:06 -0700 Subject: [PATCH 3/7] Swap theme colors --- src/app.css | 40 +++++++++---------- src/lib/components/EventForm.svelte | 6 +-- .../components/registration.svelte | 2 +- .../[id=eventID]/components/voting.svelte | 2 +- src/routes/register/+page.svelte | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/app.css b/src/app.css index 80bc59b..3e8f3fa 100644 --- a/src/app.css +++ b/src/app.css @@ -5,27 +5,27 @@ @custom-variant dark (&:where(.dark, .dark *)); @theme { - --color-primary-50: #fff5f2; - --color-primary-100: #fff1ee; - --color-primary-200: #ffe4de; - --color-primary-300: #ffd5cc; - --color-primary-400: #ffbcad; - --color-primary-500: #fe795d; - --color-primary-600: #ef562f; - --color-primary-700: #eb4f27; - --color-primary-800: #cc4522; - --color-primary-900: #a5371b; + --color-primary-50: #f0f9ff; + --color-primary-100: #e0f2fe; + --color-primary-200: #bae6fd; + --color-primary-300: #7dd3fc; + --color-primary-400: #38bdf8; + --color-primary-500: #0ea5e9; + --color-primary-600: #0284c7; + --color-primary-700: #0369a1; + --color-primary-800: #075985; + --color-primary-900: #0c4a6e; - --color-secondary-50: #f0f9ff; - --color-secondary-100: #e0f2fe; - --color-secondary-200: #bae6fd; - --color-secondary-300: #7dd3fc; - --color-secondary-400: #38bdf8; - --color-secondary-500: #0ea5e9; - --color-secondary-600: #0284c7; - --color-secondary-700: #0369a1; - --color-secondary-800: #075985; - --color-secondary-900: #0c4a6e; + --color-secondary-50: #fff5f2; + --color-secondary-100: #fff1ee; + --color-secondary-200: #ffe4de; + --color-secondary-300: #ffd5cc; + --color-secondary-400: #ffbcad; + --color-secondary-500: #fe795d; + --color-secondary-600: #ef562f; + --color-secondary-700: #eb4f27; + --color-secondary-800: #cc4522; + --color-secondary-900: #a5371b; } @source '../node_modules/flowbite-svelte/dist'; diff --git a/src/lib/components/EventForm.svelte b/src/lib/components/EventForm.svelte index d9b4551..21a9b9a 100644 --- a/src/lib/components/EventForm.svelte +++ b/src/lib/components/EventForm.svelte @@ -49,7 +49,7 @@ }; -Create an Event +Host an Event
@@ -67,7 +67,7 @@ onkeydown={handleKeyPressOnDishInput} />
- +
{#if dishes.length > 0} @@ -93,5 +93,5 @@ {/each} - +
diff --git a/src/routes/event/[id=eventID]/components/registration.svelte b/src/routes/event/[id=eventID]/components/registration.svelte index 51c5835..dfa99d8 100644 --- a/src/routes/event/[id=eventID]/components/registration.svelte +++ b/src/routes/event/[id=eventID]/components/registration.svelte @@ -79,6 +79,6 @@ {/if} - diff --git a/src/routes/event/[id=eventID]/components/voting.svelte b/src/routes/event/[id=eventID]/components/voting.svelte index dcc4555..abc25f9 100644 --- a/src/routes/event/[id=eventID]/components/voting.svelte +++ b/src/routes/event/[id=eventID]/components/voting.svelte @@ -56,5 +56,5 @@ - + diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte index a8de8df..677a8a2 100644 --- a/src/routes/register/+page.svelte +++ b/src/routes/register/+page.svelte @@ -82,7 +82,7 @@
-
From 96a804162e066466c0e7928919b2b3ea4987b537 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Wed, 25 Mar 2026 12:02:23 -0700 Subject: [PATCH 4/7] Add user dashboard --- src/lib/components/SavedBallotList.svelte | 48 +++++++++++----- src/lib/components/SavedEventList.svelte | 68 +++++++++++------------ src/routes/+page.svelte | 9 ++- src/routes/user/dashboard/+page.svelte | 20 +++++++ 4 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 src/routes/user/dashboard/+page.svelte diff --git a/src/lib/components/SavedBallotList.svelte b/src/lib/components/SavedBallotList.svelte index a2aa9be..e7be2a6 100644 --- a/src/lib/components/SavedBallotList.svelte +++ b/src/lib/components/SavedBallotList.svelte @@ -2,17 +2,19 @@ import type { APIError } from '$lib/api/base'; import { EventsAPI } from '$lib/api/events'; import { getStorageContext } from '$lib/storage/storage'; - import { Alert, Button } from 'flowbite-svelte'; + import { Card, Heading, P } from 'flowbite-svelte'; import { onMount } from 'svelte'; type BallotItem = { eventName: string; eventID: number; - state: 'expired' | 'valid' | 'missing'; + state: 'closed' | 'open'; id: number; }; let ballots: BallotItem[] = $state([]); + let closedBallots: BallotItem[] = $derived(ballots.filter((ballot) => ballot.state === 'closed')); + let openBallots: BallotItem[] = $derived(ballots.filter((ballot) => ballot.state === 'open')); const storage = getStorageContext(); @@ -31,24 +33,44 @@ eventName: response.name, eventID: localBallots[keyAsNumber].eventID, id: keyAsNumber, - state: response.status == 'CL' ? 'expired' : 'valid' + state: response.status == 'CL' ? 'closed' : 'open' }); } catch (e) { - if ((e as APIError).status == 404) storage.deleteBallot(keyAsNumber); + const status = (e as APIError).status; + if (status == 404 || status == 403) storage.deleteBallot(keyAsNumber); } } }); {#snippet ballotItem(ballot: BallotItem)} - - Ballot - {ballot.eventName} - - +
  • + + {ballot.eventName} + +
  • {/snippet} -{#each ballots as ballot (ballot.id)} - {@render ballotItem(ballot)} -{/each} +{#if ballots.length === 0} +

    No past ballots found.

    +{:else} + {#if openBallots.length} + Open +
      + {#each openBallots as ballot (ballot.id)} + {@render ballotItem(ballot)} + {/each} +
    + {/if} + {#if closedBallots.length} + Closed +
      + {#each closedBallots.slice(0, 5) as ballot (ballot.id)} + {@render ballotItem(ballot)} + {/each} +
    + {/if} +{/if} diff --git a/src/lib/components/SavedEventList.svelte b/src/lib/components/SavedEventList.svelte index 61c271f..ea71b61 100644 --- a/src/lib/components/SavedEventList.svelte +++ b/src/lib/components/SavedEventList.svelte @@ -2,22 +2,19 @@ import type { APIError } from '$lib/api/base'; import { EventsAPI } from '$lib/api/events'; import { getStorageContext } from '$lib/storage/storage'; - import { Alert } from 'flowbite-svelte'; + import { Card, Heading, P } from 'flowbite-svelte'; import { onMount } from 'svelte'; type EventItem = { name: string; - state: 'expired' | 'valid' | 'missing'; + state: 'closed' | 'open' | 'missing'; id: number; }; let events: EventItem[] = $state([]); - let ballots: { - eventName: string; - state: 'expired' | 'valid' | 'missing'; - id: number; - }[] = $state([]); + let closedEvents: EventItem[] = $derived(events.filter((event) => event.state === 'closed')); + let openEvents: EventItem[] = $derived(events.filter((event) => event.state === 'open')); const storage = getStorageContext(); @@ -25,19 +22,20 @@ const eventApi = new EventsAPI(); const localEvents = storage.data.events; - const localBallots = storage.data.ballots; for (const key in localEvents) { const keyAsNumber = Number(key); + try { - await eventApi.getEvent(keyAsNumber, localEvents[keyAsNumber].token); + const event = await eventApi.getEvent(keyAsNumber, localEvents[keyAsNumber].token); events.push({ name: localEvents[keyAsNumber].name, id: keyAsNumber, - state: 'valid' + state: event.status === 'CL' ? 'closed' : 'open' }); } catch (e) { - if ((e as APIError).status == 404) { + const status = (e as APIError).status; + if (status == 404 || status == 403) { events.push({ name: localEvents[keyAsNumber].name, id: keyAsNumber, @@ -47,32 +45,34 @@ } } } - - console.log(events); - - for (const key in localBallots) { - const keyAsNumber = Number(key); - try { - const response = await eventApi.getEvent( - localBallots[keyAsNumber].eventID, - localBallots[keyAsNumber].token - ); - ballots.push({ - eventName: response.name, - id: keyAsNumber, - state: response.status == 'CL' ? 'expired' : 'valid' - }); - } catch (e) { - if ((e as APIError).status == 404) storage.deleteBallot(keyAsNumber); - } - } }); {#snippet eventItem(event: EventItem)} - {event.name} +
  • + + {event.name} + +
  • {/snippet} -{#each events as event (event.id)} - {@render eventItem(event)} -{/each} +{#if events.length === 0} +

    No past events found.

    +{:else} + {#if openEvents.length} + Open +
      + {#each openEvents as event (event.id)} + {@render eventItem(event)} + {/each} +
    + {/if} + {#if closedEvents.length} + Closed +
      + {#each closedEvents.slice(0, 5) as event (event.id)} + {@render eventItem(event)} + {/each} +
    + {/if} +{/if} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e44e90d..50cc63f 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,8 +1,6 @@
    @@ -16,8 +14,9 @@
    - - + + +
    or
    diff --git a/src/routes/user/dashboard/+page.svelte b/src/routes/user/dashboard/+page.svelte new file mode 100644 index 0000000..140a685 --- /dev/null +++ b/src/routes/user/dashboard/+page.svelte @@ -0,0 +1,20 @@ + + +
    + Your Dashboard + +
    + Events + +
    +
    + Ballots + +
    + + +
    From c9241980c9a0fb5694b93f8c80713930c73ebbc0 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Wed, 25 Mar 2026 16:45:28 -0700 Subject: [PATCH 5/7] Make minimum dish number == 2 --- src/lib/components/EventForm.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/EventForm.svelte b/src/lib/components/EventForm.svelte index 21a9b9a..86d03b5 100644 --- a/src/lib/components/EventForm.svelte +++ b/src/lib/components/EventForm.svelte @@ -13,7 +13,7 @@ let newDish = $state(''); let votingSystem: string = $state(votingSystems[0].id); - const isFormValid = $derived(eventName.trim() !== '' && dishes.length > 0); + const isFormValid = $derived(eventName.trim() !== '' && dishes.length > 1); const addDish = () => { if (newDish.trim()) { From bd54dfae497633622e9f3d334d57bca20c1aa5da Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Wed, 25 Mar 2026 16:45:44 -0700 Subject: [PATCH 6/7] Use ListGroup --- src/lib/components/SavedBallotList.svelte | 30 +++++++++++------------ src/lib/components/SavedEventList.svelte | 27 ++++++++++---------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/lib/components/SavedBallotList.svelte b/src/lib/components/SavedBallotList.svelte index e7be2a6..bf4c2dc 100644 --- a/src/lib/components/SavedBallotList.svelte +++ b/src/lib/components/SavedBallotList.svelte @@ -2,7 +2,7 @@ import type { APIError } from '$lib/api/base'; import { EventsAPI } from '$lib/api/events'; import { getStorageContext } from '$lib/storage/storage'; - import { Card, Heading, P } from 'flowbite-svelte'; + import { Heading, Listgroup, ListgroupItem, P } from 'flowbite-svelte'; import { onMount } from 'svelte'; type BallotItem = { @@ -44,33 +44,31 @@ {#snippet ballotItem(ballot: BallotItem)} -
  • - - {ballot.eventName} - -
  • + + {ballot.eventName} + {/snippet} {#if ballots.length === 0} -

    No past ballots found.

    +

    No past ballots found.

    {:else} {#if openBallots.length} - Open -
      + + Open {#each openBallots as ballot (ballot.id)} {@render ballotItem(ballot)} {/each} -
    + {/if} {#if closedBallots.length} - Closed -
      + + Closed {#each closedBallots.slice(0, 5) as ballot (ballot.id)} {@render ballotItem(ballot)} {/each} -
    + {/if} {/if} diff --git a/src/lib/components/SavedEventList.svelte b/src/lib/components/SavedEventList.svelte index ea71b61..2b6ca3b 100644 --- a/src/lib/components/SavedEventList.svelte +++ b/src/lib/components/SavedEventList.svelte @@ -2,7 +2,7 @@ import type { APIError } from '$lib/api/base'; import { EventsAPI } from '$lib/api/events'; import { getStorageContext } from '$lib/storage/storage'; - import { Card, Heading, P } from 'flowbite-svelte'; + import { Heading, Listgroup, ListgroupItem, P } from 'flowbite-svelte'; import { onMount } from 'svelte'; type EventItem = { @@ -49,30 +49,31 @@ {#snippet eventItem(event: EventItem)} -
  • - - {event.name} - -
  • + + {event.name} + {/snippet} {#if events.length === 0} -

    No past events found.

    +

    No past events found.

    {:else} {#if openEvents.length} - Open -
      + + Open {#each openEvents as event (event.id)} {@render eventItem(event)} {/each} -
    + {/if} {#if closedEvents.length} - Closed -
      + + Closed {#each closedEvents.slice(0, 5) as event (event.id)} {@render eventItem(event)} {/each} -
    + {/if} {/if} From 3dc7cb8ca31702f59aa22ca5b1e1fc12cd36f622 Mon Sep 17 00:00:00 2001 From: Jesudas Joseph Date: Wed, 25 Mar 2026 16:46:13 -0700 Subject: [PATCH 7/7] Check for existence of any ballots/events in localstorage --- src/lib/storage/storage.ts | 8 ++++++++ src/routes/+page.svelte | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/lib/storage/storage.ts b/src/lib/storage/storage.ts index b4f2dbc..db69148 100644 --- a/src/lib/storage/storage.ts +++ b/src/lib/storage/storage.ts @@ -35,6 +35,14 @@ export class StorageManager { this.data = await this.loadStorage(); }; + hasBallots() { + return !!this.data.ballots; + } + + hasEvents() { + return !!this.data.events; + } + getBallot(ballotID: number) { if (!this.data.ballots) throw new ErrorBallotNotFound(ballotID); if (ballotID in this.data.ballots) return this.data.ballots[ballotID]; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 50cc63f..2a4ee15 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,6 +1,9 @@
    @@ -14,9 +17,11 @@
    - + {#if storage.hasEvents() || storage.hasEvents()} + -
    or +
    or + {/if}