From 724ab4619d132e29739f4677169d654e68644531 Mon Sep 17 00:00:00 2001 From: "Gard.Kalland" Date: Sun, 4 May 2025 17:48:08 +0200 Subject: [PATCH 01/42] table Veiw --- .../lib/components/portal/EventTable.svelte | 316 ++++++++++++++++++ apps/www/src/lib/services/event.service.ts | 40 +++ .../lib/states/create-event-state.svelte.ts | 1 + .../portal/arrangementer/+page.server.ts | 19 +- .../routes/portal/arrangementer/+page.svelte | 61 +--- .../portal/arrangementer/[id]/+page.server.ts | 5 - .../portal/arrangementer/[id]/+page.svelte | 9 - .../arrangementer/[id]/edit/+page.server.ts | 72 ++++ .../arrangementer/[id]/edit/+page.svelte | 200 +++++++++++ 9 files changed, 645 insertions(+), 78 deletions(-) create mode 100644 apps/www/src/lib/components/portal/EventTable.svelte create mode 100644 apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts create mode 100644 apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte new file mode 100644 index 00000000..7a88df20 --- /dev/null +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -0,0 +1,316 @@ + + +
+
+ + +
+
+ + + {#if filteredEvents.length === 0} +
+ Ingen {activeTab === 'upcoming' ? 'kommende' : 'tidligere'} arrangementer å vise. +
+ {:else} +
+ + + + + + + + + + + + {#each filteredEvents as event (event.id)} + {@const status = getEventStatus(event)} + goto(`arrangementer/${event.id}`)}> + + + + + + + {/each} + +
ArrangementDatoAntall vakterStatus
{event.name}{formatDate(event.date)}{countShifts(event)}{status} + {#if $user?.role === 'board'} + + + + {/if} +
+
+ {/if} +
+
+ + diff --git a/apps/www/src/lib/services/event.service.ts b/apps/www/src/lib/services/event.service.ts index 426ffb03..5ad50887 100644 --- a/apps/www/src/lib/services/event.service.ts +++ b/apps/www/src/lib/services/event.service.ts @@ -67,6 +67,46 @@ export class EventService { return event; } + async findUpcomingEvents() { + const event = await this.#db.query.events.findMany({ + orderBy: (row, { asc }) => [asc(row.date)], + with: { + shifts: { + with: { + members: { + with: { + user: true + } + } + } + } + }, + where: (events, { gte }) => gte(events.date, new Date()) + }); + + return event; + } + + async findPastEvents() { + const event = await this.#db.query.events.findMany({ + orderBy: (row, { desc }) => [desc(row.date)], + with: { + shifts: { + with: { + members: { + with: { + user: true + } + } + } + } + }, + where: (events, { lt }) => lt(events.date, new Date()) + }); + + return event; + } + async delete(id: string) { await this.#db.delete(events).where(eq(events.id, id)); } diff --git a/apps/www/src/lib/states/create-event-state.svelte.ts b/apps/www/src/lib/states/create-event-state.svelte.ts index bc187026..b26f0070 100644 --- a/apps/www/src/lib/states/create-event-state.svelte.ts +++ b/apps/www/src/lib/states/create-event-state.svelte.ts @@ -34,6 +34,7 @@ export class CreateEventState { name: '' }); } + deleteUserFromShift(shiftIndex: number, userId: string) { const arr = this.shifts[shiftIndex].users.filter((user) => user.id !== userId); diff --git a/apps/www/src/routes/portal/arrangementer/+page.server.ts b/apps/www/src/routes/portal/arrangementer/+page.server.ts index 4e3773aa..23692af8 100644 --- a/apps/www/src/routes/portal/arrangementer/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/+page.server.ts @@ -1,21 +1,10 @@ import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ locals }) => { - const events = await locals.db.query.events.findMany({ - orderBy: (row, { asc }) => [asc(row.date)], - with: { - shifts: true - }, - where: (events, { gte }) => gte(events.date, new Date()) - }); - - const outdatedEvents = await locals.db.query.events.findMany({ - orderBy: (row, { desc }) => [desc(row.date)], - with: { - shifts: true - }, - where: (events, { lt }) => lt(events.date, new Date()) - }); + const [events, outdatedEvents] = await Promise.all([ + locals.eventService.findUpcomingEvents(), + locals.eventService.findPastEvents() + ]); return { events, diff --git a/apps/www/src/routes/portal/arrangementer/+page.svelte b/apps/www/src/routes/portal/arrangementer/+page.svelte index 8536884e..c5d6be89 100644 --- a/apps/www/src/routes/portal/arrangementer/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/+page.svelte @@ -1,59 +1,22 @@ Arrangementer -Arrangementer -{#if $user?.role == 'board'} -

- Nytt arrangement -

-{/if} - - - -
- +
+
-{#if showOutdatedEvents} -
-
    - {#each data.outdatedEvents as event} -
  • - -
  • - {:else} -

    Ingen tidligere arrangementer

    - {/each} -
-
-{/if} + diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts index 6d024e44..3ab65789 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts @@ -62,11 +62,6 @@ export const actions: Actions = { }); } - await locals.eventService.deleteUserShift({ - shiftId, - userId: locals.user.id - }); - return { success: true }; } }; diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 6ed2cba1..cec44e30 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -1,6 +1,5 @@ + + + {`Endre: ${data.event.name}`} + + +{`${data.event.name}`} + +
+ Vakt {data.event.shifts.length} + +
    + {#each data.event.shifts as shift} + {@const isInShift = shift.members.some((member) => member.userId === $user?.id)} +
  • +

    {capitalize(formatDate(shift.startAt))}

    +

    {time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))}

    +

    Ansvarlige: {shift.members.map((member) => member.user.name).join(', ')}

    + + {#if !isInShift} +
    + + +
    + {:else} +
    + + +
    + {/if} +
  • + {/each} +
+
+ +
+ {#if data.user?.role === 'board'} + Farlig +
+ +
+ {/if} +
+ + +Nytt arrangement + +{#if error} +
+

{error}

+
+{/if} + +{#if successMessage} +
+

{successMessage}

+
+{/if} + +
+ + + {#each createEventState.shifts as shift, i} + {@const shiftLength = differenceInHours(shift.endAt, shift.startAt)} +
+ +

Vakt {i + 1}

+ + + {#if shiftLength >= 4} + NB: Vakten er lengre enn 4 timer! + {/if} + Ansvarlige +
+ Alle ansvarlige vil få en e-post med kalenderinvitasjon når arrangementet opprettes. +
+ {#each createEventState.shifts[i].users as user, j (user)} +
+ user.id)} + onchange={(option) => { + const id = option?.value; + if (id) { + createEventState.shifts[i].users[j].id = id; + } + }} + options={data.users} + placeholder="Velg en bruker" + /> + +
+ {:else} +

Ingen ansvarlige. Husk å legge til.

+ {/each} + +
+ {/each} + + + From 046f5ab9799f629e0aac376ba88012dd8840ddce Mon Sep 17 00:00:00 2001 From: "Gard.Kalland" Date: Sun, 4 May 2025 17:51:44 +0200 Subject: [PATCH 02/42] added back delete --- .../lib/components/portal/EventTable.svelte | 19 ++++++++++--------- .../portal/arrangementer/[id]/+page.server.ts | 5 +++++ .../portal/arrangementer/[id]/+page.svelte | 9 +++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index 7a88df20..a01ea017 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -140,15 +140,16 @@ {countShifts(event)} {status} - {#if $user?.role === 'board'} - - - - {/if} + + + + + + + + + + {/each} diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts index 3ab65789..6d024e44 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.server.ts @@ -62,6 +62,11 @@ export const actions: Actions = { }); } + await locals.eventService.deleteUserShift({ + shiftId, + userId: locals.user.id + }); + return { success: true }; } }; diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index cec44e30..6ed2cba1 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -1,5 +1,6 @@ -
-
+
+
-
-
+
+ class="w-full py-3 pr-32 pl-4 border border-gray-300 rounded-lg text-base focus:outline-none focus:border-blue-500 focus:ring focus:ring-blue-200 focus:ring-opacity-50" - {#if $user?.role === 'board'} -
- -
- {/if} + /> -
- {#if filteredEvents.length === 0} -
- Ingen {activeTab === 'upcoming' ? 'kommende' : 'tidligere'} arrangementer å vise. -
- {:else} -
- - - - - - - - - - - - {#each filteredEvents as event (event.id)} - {@const status = getEventStatus(event)} - goto(`arrangementer/${event.id}`)}> - - - - - - - {/each} - -
ArrangementDatoAntall vakterStatus
{event.name}{formatDate(event.date)}{countShifts(event)}{status} - - {#if $user?.role === 'board'} - - - - {/if} -
-
+ {#if $user?.role === 'board'} +
+ +
{/if} +
+ + {#if filteredEvents.length === 0} +
+ Ingen {activeTab === 'upcoming' ? 'kommende' : 'tidligere'} arrangementer å vise. +
+ {:else} +
+ + + + + + + + + + + + {#each filteredEvents as event (event.id)} + {@const status = getEventStatus(event)} + goto(`arrangementer/${event.id}`)}> + + + + + + + {/each} + +
ArrangementDatoAntall vakterStatus
+ {event.name} + + {formatDate(event.date)} + + {countShifts(event)} + + {status} + + {#if $user?.role === 'board'} + + + + {/if} +
+
+ {/if}
- - From bb11759e98724b94039f45b247c745a3ed6d1493 Mon Sep 17 00:00:00 2001 From: "Gard.Kalland" Date: Thu, 8 May 2025 16:52:37 +0200 Subject: [PATCH 06/42] sort Active shift --- apps/www/src/lib/components/portal/EventTable.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index 536566a2..e63a80b6 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -50,7 +50,11 @@ const upcomingEvents = $derived([ ...events, ...outdated.filter((event: Event) => hasActiveOrUpcoming(event)) - ]); + ].sort((a, b) => { + if(hasActiveShifts(a)) return -1; + if(hasActiveShifts(b)) return 1; + return 0; + })); const pastEvnts = $derived(outdated.filter((event: Event) => !hasActiveOrUpcoming(event))); From 65a2dc155eafd443bc3617c807422c980c40b65a Mon Sep 17 00:00:00 2001 From: "Gard.Kalland" Date: Thu, 8 May 2025 22:54:01 +0200 Subject: [PATCH 07/42] =?UTF-8?q?New=20UI=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../portal/arrangementer/[id]/+page.svelte | 154 ++++++++++++++---- 1 file changed, 118 insertions(+), 36 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 6ed2cba1..2067f900 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -1,55 +1,137 @@ {data.event.name} -{data.event.name} -
- Vakter -
    - {#each data.event.shifts as shift} - {@const isInShift = shift.members.some((member) => member.userId === $user?.id)} -
  • -

    {capitalize(formatDate(shift.startAt))}

    -

    {time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))}

    -

    Ansvarlige: {shift.members.map((member) => member.user.name).join(', ')}

    - {#if !isInShift} -
    - - -
    - {:else} -
    - - -
    - {/if} -
  • - {/each} -
-
- -
- {#if data.user?.role === 'board'} - Farlig -
- -
- {/if} +
+
+
+

{data.event.name}

+

{formatDate(data.event.date)}

+
+
+ +
+
+ + +
+
+ +
+ {#if activeTab === 'details'} +
+
+
+ +
+
+

Dato

+

{formatDate(data.event.date)}

+
+
+ +
+
+ +
+
+

Antall vakter

+

+ {data.event.shifts.length} {data.event.shifts.length === 1 ? 'vakt' : 'vakter'} +

+
+
+ +
+
+ +
+
+

Ansvarlige

+
    + {#each data.event.shifts as shift, i} +
  • + Vakt {i + 1}: {shift.members.map((member) => member.user.name).join(', ') || 'Ingen ansvarlige'} +
  • + {/each} +
+
+
+
+ {:else if activeTab === 'shifts'} +
+ {#each data.event.shifts as shift, i} + {@const isInShift = shift.members.some((member) => member.userId === $user?.id)} +
+
+

Vakt {i + 1}

+
+
+
+
+

Dato

+

{capitalize(formatDate(shift.startAt))}

+
+
+

Tid

+

{time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))}

+
+
+ +
+

Ansvarlige

+

{shift.members.map((member) => member.user.name).join(', ') || 'Ingen ansvarlige'}

+
+ + {#if !isInShift} +
+ + +
+ {:else} +
+ + +
+ {/if} +
+
+ {/each} +
+ {/if} +
+
From 2e2bf434431d47000f24c188dbbd2e947fb1a2ad Mon Sep 17 00:00:00 2001 From: "Gard.Kalland" Date: Tue, 13 May 2025 13:25:47 +0200 Subject: [PATCH 08/42] =?UTF-8?q?New=20UI=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../portal/arrangementer/ny/+page.svelte | 249 +++++++++++------- 1 file changed, 156 insertions(+), 93 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index 51cbb19d..fd73f5b6 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -1,6 +1,6 @@ -
-
+
+
- -
+
+ +
{/if} -
- +
+ {#if filteredEvents.length === 0} -
+
Ingen {activeTab === 'upcoming' ? 'kommende' : 'tidligere'} arrangementer å vise.
{:else} @@ -132,38 +130,49 @@ - - - - - + + + + + {#each filteredEvents as event (event.id)} {@const status = getEventStatus(event)} - goto(`arrangementer/${event.id}`)}> - goto(`arrangementer/${event.id}`)} + > + - - - - diff --git a/apps/www/src/lib/services/event.service.ts b/apps/www/src/lib/services/event.service.ts index 5ad50887..3464574c 100644 --- a/apps/www/src/lib/services/event.service.ts +++ b/apps/www/src/lib/services/event.service.ts @@ -67,6 +67,42 @@ export class EventService { return event; } + async updateEvent(id: string, eventData: Partial<{ name: string; date: Date }>) { + const event = await this.#db + .insert(events) + .values({ + id, + ...eventData + }) + .onConflictDoUpdate({ + target: events.id, + set: eventData + }) + .returning() + .then((rows) => rows[0]); + + return event; + } + + async updateShift( + id: string, + shiftData: Partial<{ eventId: string; startAt: Date; endAt: Date }> + ) { + const shift = await this.#db + .insert(shifts) + .values({ + id, + ...shiftData + }) + .onConflictDoUpdate({ + target: shifts.id, + set: shiftData + }) + .returning() + .then((rows) => rows[0]); + return shift; + } + async findUpcomingEvents() { const event = await this.#db.query.events.findMany({ orderBy: (row, { asc }) => [asc(row.date)], @@ -110,4 +146,10 @@ export class EventService { async delete(id: string) { await this.#db.delete(events).where(eq(events.id, id)); } + + // This deletes the shift and its user_shifts + async deleteShift(id: string) { + await this.#db.delete(userShifts).where(eq(userShifts.shiftId, id)); + await this.#db.delete(shifts).where(eq(shifts.id, id)); + } } diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 2067f900..1b098ceb 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -9,7 +9,6 @@ let { data } = $props(); let user = getUser(); let activeTab = $state('details'); - @@ -17,38 +16,38 @@
- - -
-
-
-

{data.event.name}

-

{formatDate(data.event.date)}

+
+
+
+

{data.event.name}

+

{formatDate(data.event.date)}

+
-
- -
+ +
- +
{#if activeTab === 'details'}
-
-
+
+
@@ -56,21 +55,22 @@

{formatDate(data.event.date)}

- -
-
+ +
+

Antall vakter

- {data.event.shifts.length} {data.event.shifts.length === 1 ? 'vakt' : 'vakter'} + {data.event.shifts.length} + {data.event.shifts.length === 1 ? 'vakt' : 'vakter'}

- -
-
+ +
+
@@ -78,7 +78,9 @@
    {#each data.event.shifts as shift, i}
  • - Vakt {i + 1}: {shift.members.map((member) => member.user.name).join(', ') || 'Ingen ansvarlige'} + Vakt {i + 1}: + {shift.members.map((member) => member.user.name).join(', ') || + 'Ingen ansvarlige'}
  • {/each}
@@ -89,11 +91,11 @@
{#each data.event.shifts as shift, i} {@const isInShift = shift.members.some((member) => member.userId === $user?.id)} -
-
+
+

Vakt {i + 1}

-
+

Dato

@@ -101,19 +103,26 @@

Tid

-

{time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))}

+

+ {time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))} +

- +

Ansvarlige

-

{shift.members.map((member) => member.user.name).join(', ') || 'Ingen ansvarlige'}

+

+ {shift.members.map((member) => member.user.name).join(', ') || + 'Ingen ansvarlige'} +

- + {#if !isInShift}
- @@ -121,7 +130,9 @@ {:else} - @@ -132,6 +143,6 @@ {/each}
{/if} -
-
+
+
diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts index 6d024e44..7d081cc0 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts @@ -3,13 +3,20 @@ import type { Actions, PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ locals, params }) => { const event = await locals.eventService.findFullEventById(params.id); - if (!event) { throw error(404, 'Event not found'); } + const users = await locals.userService.findAll().then((users) => + users.map((user) => ({ + label: user.name, + value: user.id + })) + ); + return { - event + event, + users }; }; @@ -19,54 +26,72 @@ export const actions: Actions = { await locals.eventService.delete(params.id); throw redirect(303, '/portal/arrangementer'); } - return fail(401, { message: 'Unauthorized' }); }, - join: async ({ request, locals }) => { - if (!locals.user) { - return fail(401, { - message: 'Not logged in' - }); + + save: async ({ request, params, locals }) => { + if (locals.user?.role !== 'board') { + return fail(401, { message: 'Unauthorized' }); } const formData = await request.formData(); - const shiftId = formData.get('shiftId'); - if (!shiftId || typeof shiftId !== 'string') { - return fail(400, { - message: 'Missing shiftId' - }); - } - await locals.eventService.createUserShift({ - shiftId, - userId: locals.user.id, - status: 'accepted' + await locals.eventService.updateEvent(params.id, { + name: formData.get('name') as string, + date: new Date(formData.get('date') as string) }); - return { success: true }; - }, - leave: async ({ request, locals }) => { - if (!locals.user) { - return fail(401, { - message: 'Not logged in' - }); + for (const id of formData.getAll('deletedShiftIds')) { + await locals.eventService.deleteShift(id.toString()); } - const formData = await request.formData(); - const shiftId = formData.get('shiftId'); - if (!shiftId || typeof shiftId !== 'string') { - return fail(400, { - message: 'Missing shiftId' + const existingEvent = await locals.eventService.findFullEventById(params.id); + + const shiftsCount = parseInt(formData.get('shiftsCount')?.toString() || '0', 10); + + for (let i = 0; i < shiftsCount; i++) { + const shiftId = formData.get(`shift[${i}].id`)?.toString(); + if (!shiftId) continue; + + await locals.eventService.updateShift(shiftId, { + eventId: params.id, + startAt: new Date(formData.get(`shift[${i}].startAt`) as string), + endAt: new Date(formData.get(`shift[${i}].endAt`) as string) }); - } - await locals.eventService.deleteUserShift({ - shiftId, - userId: locals.user.id - }); + const userCount = parseInt(formData.get(`shift[${i}].userCount`)?.toString() || '0', 10); + const currentUserIds = []; + + for (let j = 0; j < userCount; j++) { + const userId = formData.get(`shift[${i}].user[${j}].id`)?.toString(); + if (userId?.trim()) currentUserIds.push(userId); + } + + const existingShift = existingEvent.shifts.find((s) => s.id === shiftId); + const existingUserIds = existingShift?.members.map((m) => m.user.id) || []; + + for (const userId of currentUserIds) { + if (!existingUserIds.includes(userId)) { + await locals.eventService.createUserShift({ + shiftId, + userId, + status: 'accepted' + }); + } + } + + for (const existingId of existingUserIds) { + if (!currentUserIds.includes(existingId)) { + await locals.eventService.deleteUserShift({ + shiftId, + userId: existingId + }); + } + } + } - return { success: true }; + return { success: true, message: 'Arrangementet ble oppdatert' }; } }; diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index 469bf71a..fbb5d542 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -1,198 +1,237 @@ - {`Endre: ${data.event.name}`} + Rediger arrangement: {eventName} -{`${data.event.name}`} - -
- Vakt {data.event.shifts.length} - -
    - {#each data.event.shifts as shift} - {@const isInShift = shift.members.some((member) => member.userId === $user?.id)} -
  • -

    {capitalize(formatDate(shift.startAt))}

    -

    {time(subHours(shift.startAt, 2))} - {time(subHours(shift.endAt, 2))}

    -

    Ansvarlige: {shift.members.map((member) => member.user.name).join(', ')}

    - - {#if !isInShift} - - - - - {:else} -
    - - - - {/if} -
  • - {/each} -
-
- -
- {#if data.user?.role === 'board'} - Farlig -
- - - {/if} -
+ -Nytt arrangement +
+ Rediger arrangement -{#if error} -
-

{error}

-
-{/if} + +
+ + +
-{#if successMessage} -
-

{successMessage}

+
+
+

Arrangement detaljer

-{/if} - -
- - - {#each createEventState.shifts as shift, i} - {@const shiftLength = differenceInHours(shift.endAt, shift.startAt)} -
- -

Vakt {i + 1}

- - - {#if shiftLength >= 4} - NB: Vakten er lengre enn 4 timer! - {/if} - Ansvarlige -
- Alle ansvarlige vil få en e-post med kalenderinvitasjon når arrangementet opprettes. +

{form.message}

- {#each createEventState.shifts[i].users as user, j (user)} -
- user.id)} - onchange={(option) => { - const id = option?.value; - if (id) { - createEventState.shifts[i].users[j].id = id; - } - }} - options={data.users} - placeholder="Velg en bruker" + {/if} + + + + + {#each deletedShiftIds as id} + + {/each} + {#each removedUserShifts as keyValue} + + {/each} + + +
+
+ + -
+ + +
+
+

Vakter

+ + + Legg til vakt +
- {:else} -

Ingen ansvarlige. Husk å legge til.

- {/each} - -
- {/each} - - - + + {#each shifts as shift, i} +
+
+

Vakt {i + 1}

+ +
+ + + +
+ + +
+ +
+
+

Ansvarlige

+ +
+ + + + {#if shift.users.length === 0} +

Ingen ansvarlige

+ {:else} +
+ {#each shift.users as user, j} +
+ { + if (option?.value) { + user.id = option.value; + user.name = option.label; + } + }} + placeholder="Velg en bruker" + /> + + +
+ {/each} +
+ {/if} +
+
+ {/each} +
+ +
+
+
+ + + + +
+
+ +
+
From 5f97f022c51c77d24f7f6e6b4994d8d1566eac41 Mon Sep 17 00:00:00 2001 From: Gard Date: Mon, 19 May 2025 17:51:28 +0200 Subject: [PATCH 10/42] format --- apps/www/src/lib/services/event.service.ts | 8 +-- .../arrangementer/[id]/edit/+page.server.ts | 53 +++++++++++++------ .../arrangementer/[id]/edit/+page.svelte | 10 ++-- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/apps/www/src/lib/services/event.service.ts b/apps/www/src/lib/services/event.service.ts index 3464574c..1bd7eb64 100644 --- a/apps/www/src/lib/services/event.service.ts +++ b/apps/www/src/lib/services/event.service.ts @@ -67,7 +67,7 @@ export class EventService { return event; } - async updateEvent(id: string, eventData: Partial<{ name: string; date: Date }>) { + async updateEvent(id: string, eventData: { name: string; date: Date }) { const event = await this.#db .insert(events) .values({ @@ -84,10 +84,7 @@ export class EventService { return event; } - async updateShift( - id: string, - shiftData: Partial<{ eventId: string; startAt: Date; endAt: Date }> - ) { + async updateShift(id: string, shiftData: { eventId: string; startAt: Date; endAt: Date }) { const shift = await this.#db .insert(shifts) .values({ @@ -147,7 +144,6 @@ export class EventService { await this.#db.delete(events).where(eq(events.id, id)); } - // This deletes the shift and its user_shifts async deleteShift(id: string) { await this.#db.delete(userShifts).where(eq(userShifts.shiftId, id)); await this.#db.delete(shifts).where(eq(shifts.id, id)); diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts index 7d081cc0..cbb5e362 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts @@ -37,31 +37,44 @@ export const actions: Actions = { } const formData = await request.formData(); + const eventId = params.id; - await locals.eventService.updateEvent(params.id, { - name: formData.get('name') as string, - date: new Date(formData.get('date') as string) + const updatedEvent = await locals.eventService.updateEvent(eventId, { + name: String(formData.get('name') || ''), + date: new Date(String(formData.get('date') || '')) }); - for (const id of formData.getAll('deletedShiftIds')) { - await locals.eventService.deleteShift(id.toString()); + if (!updatedEvent) { + return fail(500, { message: 'Kunne ikkje oppdatere arrangementet' }); } - const existingEvent = await locals.eventService.findFullEventById(params.id); + const deletedShiftIds = formData.getAll('deletedShiftIds').map((id) => String(id)); + for (const shiftId of deletedShiftIds) { + await locals.eventService.deleteShift(shiftId); + } + + const existingEvent = await locals.eventService.findFullEventById(eventId); + if (!existingEvent) { + return fail(404, { message: 'Kunne ikkje finne arrangementet' }); + } - const shiftsCount = parseInt(formData.get('shiftsCount')?.toString() || '0', 10); + const shiftsCount = parseInt(String(formData.get('shiftsCount') || '0'), 10); for (let i = 0; i < shiftsCount; i++) { const shiftId = formData.get(`shift[${i}].id`)?.toString(); if (!shiftId) continue; - await locals.eventService.updateShift(shiftId, { - eventId: params.id, - startAt: new Date(formData.get(`shift[${i}].startAt`) as string), - endAt: new Date(formData.get(`shift[${i}].endAt`) as string) + const updatedShift = await locals.eventService.updateShift(shiftId, { + eventId, + startAt: new Date(String(formData.get(`shift[${i}].startAt`))), + endAt: new Date(String(formData.get(`shift[${i}].endAt`))) }); - const userCount = parseInt(formData.get(`shift[${i}].userCount`)?.toString() || '0', 10); + if (!updatedShift) { + return fail(500, { message: `Kunne ikkje oppdatere vakten: ${shiftId}` }); + } + + const userCount = parseInt(String(formData.get(`shift[${i}].userCount`) || '0'), 10); const currentUserIds = []; for (let j = 0; j < userCount; j++) { @@ -74,19 +87,25 @@ export const actions: Actions = { for (const userId of currentUserIds) { if (!existingUserIds.includes(userId)) { - await locals.eventService.createUserShift({ + const result = await locals.eventService.createUserShift({ shiftId, userId, status: 'accepted' }); + + if (!result) { + return fail(500, { + message: `Kunne ikkje legge til bruker ${userId} til vakten ${shiftId}` + }); + } } } - for (const existingId of existingUserIds) { - if (!currentUserIds.includes(existingId)) { - await locals.eventService.deleteUserShift({ + for (const userId of existingUserIds) { + if (!currentUserIds.includes(userId)) { + const result = await locals.eventService.deleteUserShift({ shiftId, - userId: existingId + userId }); } } diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index fbb5d542..51320bca 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -1,5 +1,5 @@ @@ -47,7 +46,6 @@
Rediger arrangement -
- {#each shifts as shift, i} + {#each eventState.shifts as shift, i}

Vakt {i + 1}

@@ -135,15 +124,20 @@ type="button" class="rounded-full p-1 text-red-400 hover:text-red-600" onclick={() => { - if (shift.id) deletedShiftIds = [...deletedShiftIds, shift.id]; - shifts = shifts.filter((s) => s !== shift); + // For existing shifts, track deletion + if (i < originalShifts.length) { + deletedShiftIds = [...deletedShiftIds, originalShifts[i].id]; + } + eventState.deleteShift(i); }} >
- + {#if i < originalShifts.length} + + {/if}
(shift.users = [...shift.users, { id: '', name: '' }])} + onclick={() => eventState.addUserToShift(i)} > Legg til @@ -188,6 +182,9 @@ class="flex-1" bind:value={user.name} options={data.users} + disabledOptions={eventState.shifts[i].users + .filter(u => u.id && u.id !== user.id) + .map(u => u.id)} onchange={(option) => { if (option?.value) { user.id = option.value; @@ -201,10 +198,10 @@ type="button" class="flex h-10 w-10 items-center justify-center rounded-lg border hover:text-red-500" onclick={() => { - if (user.id && shift.id) { - removedUserShifts = [...removedUserShifts, `${shift.id}|${user.id}`]; + if (i < originalShifts.length && user.id) { + removedUserShifts = [...removedUserShifts, `${originalShifts[i].id}|${user.id}`]; } - shift.users = shift.users.filter((u) => u !== user); + eventState.deleteUserFromShift(i, user.id); }} > @@ -224,7 +221,7 @@ - diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index fd73f5b6..b423e751 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -7,6 +7,7 @@ import Combobox from '$lib/components/ui/Combobox.svelte'; import { CreateEventState } from '$lib/states/create-event-state.svelte'; import { differenceInHours } from 'date-fns'; + import { goto } from '$app/navigation'; let { data } = $props(); let error = $state(''); @@ -201,7 +202,7 @@
- + - -
-
-
+
+

Arrangement detaljer

+
+ +
@@ -89,9 +77,14 @@ {/each} -
+
- + {#each eventState.shifts as shift, i} -
+

Vakt {i + 1}

-
+

Ansvarlige

- @@ -182,9 +170,9 @@ class="flex-1" bind:value={user.name} options={data.users} - disabledOptions={eventState.shifts[i].users - .filter(u => u.id && u.id !== user.id) - .map(u => u.id)} + disabledOptions={eventState.shifts[i].users + .filter((u) => u.id && u.id !== user.id) + .map((u) => u.id)} onchange={(option) => { if (option?.value) { user.id = option.value; @@ -196,10 +184,13 @@
-
+
diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index b423e751..12c6b9bb 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -7,7 +7,7 @@ import Combobox from '$lib/components/ui/Combobox.svelte'; import { CreateEventState } from '$lib/states/create-event-state.svelte'; import { differenceInHours } from 'date-fns'; - import { goto } from '$app/navigation'; + import { goto } from '$app/navigation'; let { data } = $props(); let error = $state(''); @@ -55,12 +55,11 @@ Nytt arrangement -Nytt arrangement -
-
+
+
+

Nytt arrangement

+
{#if error}
@@ -101,7 +100,7 @@ {@const endDate = shift.endAt ? new Date(shift.endAt) : new Date()} {@const shiftLength = differenceInHours(endDate, startDate)}

Vakt {i + 1}

@@ -202,7 +201,9 @@
- + - +
+ +
- {#if form?.message} -
-

{form.message}

-
- {/if} + {#if form?.message} +
+

{form.message}

+
+ {/if}
{#each deletedShiftIds as id} @@ -78,12 +77,7 @@
- + Nytt arrangement -

Nytt arrangement

-
+
{#if error}
From 1ac803ebb97263fab204d3ad5ce81f4d37c3b339 Mon Sep 17 00:00:00 2001 From: Gard Date: Mon, 26 May 2025 15:07:44 +0200 Subject: [PATCH 15/42] added unsaved message --- .../arrangementer/[id]/edit/+page.server.ts | 201 ++++++++++-------- .../arrangementer/[id]/edit/+page.svelte | 61 +++++- 2 files changed, 165 insertions(+), 97 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts index 15010b89..8cd65006 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts @@ -21,96 +21,113 @@ export const load: PageServerLoad = async ({ locals, params }) => { }; export const actions: Actions = { - delete: async ({ params, locals }) => { - if (locals.user?.role === 'board') { - await locals.eventService.delete(params.id); - throw redirect(303, '/portal/arrangementer'); - } - return fail(401, { - message: 'Unauthorized' - }); - }, - - save: async ({ request, params, locals }) => { - if (locals.user?.role !== 'board') { - return fail(401, { message: 'Unauthorized' }); - } - - const formData = await request.formData(); - const eventId = params.id; - - const updatedEvent = await locals.eventService.updateEvent(eventId, { - name: String(formData.get('name') || ''), - date: new Date(String(formData.get('date') || '')) - }); - - if (!updatedEvent) { - return fail(500, { - message: 'Failed to update event' - }); - } - - const deletedShiftIds = formData.getAll('deletedShiftIds').map((id) => String(id)); - for (const shiftId of deletedShiftIds) { - await locals.eventService.deleteShift(shiftId); - } - - const existingEvent = await locals.eventService.findFullEventById(eventId); - if (!existingEvent) { - return fail(404, { - message: 'Event not found' - }); - } - - const shiftsCount = parseInt(String(formData.get('shiftsCount') || '0'), 10); - - for (let i = 0; i < shiftsCount; i++) { - const shiftId = formData.get(`shift[${i}].id`)?.toString(); - if (!shiftId) continue; - - await locals.eventService.updateShift(shiftId, { - eventId: params.id, - startAt: new Date(String(formData.get(`shift[${i}].startAt`))), - endAt: new Date(String(formData.get(`shift[${i}].endAt`))) - }); - - const userCount = parseInt(String(formData.get(`shift[${i}].userCount`) || '0'), 10); - const currentUserIds = []; - - for (let j = 0; j < userCount; j++) { - const userId = formData.get(`shift[${i}].user[${j}].id`)?.toString(); - if (userId?.trim()) currentUserIds.push(userId); - } - - const existingShift = existingEvent.shifts.find((s) => s.id === shiftId); - const existingUserIds = existingShift?.members.map((m) => m.user.id) || []; - - for (const userId of currentUserIds) { - if (!existingUserIds.includes(userId)) { - const result = await locals.eventService.createUserShift({ - shiftId, - userId, - status: 'accepted' - }); - - if (!result) { - return fail(500, { - message: `Failed to add user to event` - }); - } - } - } - - for (const userId of existingUserIds) { - if (!currentUserIds.includes(userId)) { - const result = await locals.eventService.deleteUserShift({ - shiftId, - userId - }); - } - } - } - - return { success: true, message: 'Event has been updated' }; - } + delete: async ({ params, locals }) => { + if (locals.user?.role !== 'board') { + return fail(401, { message: 'Unauthorized' }); + } + + await locals.eventService.delete(params.id); + throw redirect(303, '/portal/arrangementer'); + }, + + + save: async ({ request, params, locals }) => { + if (locals.user?.role !== 'board') { + return fail(401, { message: 'Unauthorized' }); + } + + const formData = await request.formData(); + const eventId = params.id; + + const updated = await locals.eventService.updateEvent(params.id, { + name: String(formData.get('name') || ''), + date: new Date(String(formData.get('date') || '')) + }); + + const deletedShiftIds = formData.getAll('deletedShiftIds').map(id => String(id)); + for (const shiftId of deletedShiftIds) { + await locals.eventService.deleteShift(shiftId); + } + + const removedUserShifts = formData.getAll('removedUserShifts').map(kv => String(kv)); + for (const userShift of removedUserShifts) { + const [shiftId, userId] = userShift.split('|'); + if (shiftId && userId) { + await locals.eventService.deleteUserShift({ shiftId, userId }); + } + } + + const existingEvent = await locals.eventService.findFullEventById(eventId); + if (!existingEvent) { + return fail(404, { message: 'Event not found' }); + } + + const shiftsCount = parseInt(String(formData.get('shiftsCount') || '0'), 10); + const processedShifts = []; + + for (let i = 0; i < shiftsCount; i++) { + const shiftId = formData.get(`shift[${i}].id`)?.toString(); + const startAt = new Date(String(formData.get(`shift[${i}].startAt`))); + const endAt = new Date(String(formData.get(`shift[${i}].endAt`))); + + let shift; + + if (shiftId) { + shift = await locals.eventService.updateShift(shiftId, { + eventId, + startAt, + endAt + }); + } else { + const shifts = await locals.eventService.createShifts([{ + eventId, + startAt, + endAt + }]); + shift = shifts?.[0]; + } + + if (!shift) { + return fail(500, { message: 'Failed to create/update shift' }); + } + + processedShifts.push({ + shiftId: shift.id, + index: i + }); + } + + for (const { shiftId, index } of processedShifts) { + const userCount = parseInt(String(formData.get(`shift[${index}].userCount`) || '0'), 10); + + const existingShift = existingEvent.shifts.find(s => s.id === shiftId); + const existingUserIds = existingShift?.members.map(m => m.user.id) || []; + + const newUserIds = []; + for (let j = 0; j < userCount; j++) { + const userId = formData.get(`shift[${index}].user[${j}].id`)?.toString(); + if (userId?.trim()) { + newUserIds.push(userId); + } + } + + const usersToAdd = newUserIds.filter(userId => !existingUserIds.includes(userId)); + + const usersToRemove = existingUserIds.filter(userId => !newUserIds.includes(userId)); + + if (usersToAdd.length > 0) { + const userShiftsToCreate = usersToAdd.map(userId => ({ + shiftId, + userId + })); + await locals.eventService.createUserShifts(userShiftsToCreate); + } + + for (const userId of usersToRemove) { + await locals.eventService.deleteUserShift({ shiftId, userId }); + } + } + + return { success: true, message: 'Vakten har blitt oppdatert' }; + } }; diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index 81b54665..cb905399 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -6,10 +6,12 @@ import { enhance } from '$app/forms'; import { CreateEventState } from '$lib/states/create-event-state.svelte'; import { ISOStandard } from '$lib/date'; + import { beforeNavigate } from '$app/navigation'; let { data, form } = $props(); let showDeleteConfirm = $state(false); + let deletedShifts = $state(['']) const eventState = new CreateEventState(); @@ -30,6 +32,14 @@ let originalShifts = $state(data.event.shifts.map((shift) => ({ id: shift.id }))); let deletedShiftIds = $state([] as string[]); let removedUserShifts = $state([] as string[]); + + beforeNavigate(({ cancel }) => { + if (deletedShiftIds.length > 0 || removedUserShifts.length > 0) { + if (!confirm('Du har ulagrede endringer. Er du sikker på at du vil forlate siden?')) { + cancel(); + } + } + }); @@ -66,7 +76,32 @@

{form.message}

{/if} - + + {#if deletedShiftIds.length > 0 || removedUserShifts.length > 0} +
+

Ulagrede endringer:

+
    + {#if deletedShiftIds.length > 0} +
  • • {deletedShiftIds.length} vakt{deletedShiftIds.length > 1 ? 'er' : ''} vil bli slettet
  • + {/if} + {#if removedUserShifts.length > 0} +
  • • {removedUserShifts.length} bruker{removedUserShifts.length > 1 ? 'e' : ''} vil bli fjernet
  • + {/if} +
+
+ {/if} + + + + { + return async ({ result, update }) => { + if (result.type === 'success') { + deletedShiftIds = []; + removedUserShifts = []; + } + await update(); + }; + }}> {#each deletedShiftIds as id} @@ -103,16 +138,22 @@
{#each eventState.shifts as shift, i} -
+

Vakt {i + 1}

@@ -200,7 +245,13 @@
-
+
+ {#if deletedShiftIds.length > 0 || removedUserShifts.length > 0} + + {deletedShiftIds.length + removedUserShifts.length} ulagrede endringer + + {/if} +
From 82778843788c580e61eb33f1490649f066c76ca3 Mon Sep 17 00:00:00 2001 From: Gard Date: Mon, 26 May 2025 16:09:49 +0200 Subject: [PATCH 16/42] styling --- .../src/routes/portal/arrangementer/[id]/edit/+page.server.ts | 3 +-- .../www/src/routes/portal/arrangementer/[id]/edit/+page.svelte | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts index 8cd65006..a27d4f12 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts @@ -103,7 +103,7 @@ export const actions: Actions = { const existingShift = existingEvent.shifts.find(s => s.id === shiftId); const existingUserIds = existingShift?.members.map(m => m.user.id) || []; - const newUserIds = []; + const newUserIds: string[] = []; for (let j = 0; j < userCount; j++) { const userId = formData.get(`shift[${index}].user[${j}].id`)?.toString(); if (userId?.trim()) { @@ -112,7 +112,6 @@ export const actions: Actions = { } const usersToAdd = newUserIds.filter(userId => !existingUserIds.includes(userId)); - const usersToRemove = existingUserIds.filter(userId => !newUserIds.includes(userId)); if (usersToAdd.length > 0) { diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index cb905399..c9f06bb2 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -32,6 +32,7 @@ let originalShifts = $state(data.event.shifts.map((shift) => ({ id: shift.id }))); let deletedShiftIds = $state([] as string[]); let removedUserShifts = $state([] as string[]); + beforeNavigate(({ cancel }) => { if (deletedShiftIds.length > 0 || removedUserShifts.length > 0) { From 02ae704ef3ea3624de16bcc03fdf2884519a3055 Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 19:54:47 +0200 Subject: [PATCH 17/42] removing multiple shift --- .../arrangementer/[id]/edit/+page.svelte | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index c9f06bb2..b0686ac4 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -11,7 +11,6 @@ let { data, form } = $props(); let showDeleteConfirm = $state(false); - let deletedShifts = $state(['']) const eventState = new CreateEventState(); @@ -32,7 +31,7 @@ let originalShifts = $state(data.event.shifts.map((shift) => ({ id: shift.id }))); let deletedShiftIds = $state([] as string[]); let removedUserShifts = $state([] as string[]); - + beforeNavigate(({ cancel }) => { if (deletedShiftIds.length > 0 || removedUserShifts.length > 0) { @@ -41,6 +40,7 @@ } } }); + @@ -146,18 +146,16 @@ type="button" class="rounded-full p-1 text-red-400 hover:text-red-600" onclick={() => { - - if (i < originalShifts.length) { - deletedShiftIds = [...deletedShiftIds, `${originalShifts[i].id}`]; - } - - deletedShifts.push(); - {console.log(deletedShifts)} + if (i < originalShifts.length) { + deletedShiftIds.push(originalShifts[i].id); + } + eventState.deleteShift(i); - - eventState.deleteShift(i); - }} - > + if (i < originalShifts.length) { + originalShifts.splice(i, 1); + } + }} + >
@@ -246,13 +244,6 @@
-
- {#if deletedShiftIds.length > 0 || removedUserShifts.length > 0} - - {deletedShiftIds.length + removedUserShifts.length} ulagrede endringer - - {/if} -
From f7902c35ca19211f39c9fb484a4804a2784135a0 Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 19:55:21 +0200 Subject: [PATCH 18/42] UI fix --- apps/www/src/routes/portal/arrangementer/+page.svelte | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/+page.svelte b/apps/www/src/routes/portal/arrangementer/+page.svelte index c5d6be89..f3afd13f 100644 --- a/apps/www/src/routes/portal/arrangementer/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/+page.svelte @@ -8,15 +8,6 @@ Arrangementer -
+
- - From 76b5af1f2a7893fa83085f33760264b778c367cc Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 21:47:54 +0200 Subject: [PATCH 19/42] Cant join past events --- .../portal/arrangementer/[id]/+page.svelte | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index c0f7edd2..73487d65 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -9,6 +9,14 @@ let { data } = $props(); let user = getUser(); let activeTab = $state('details'); + let isPastEvent = $state(false) + $effect(() => { + const today = formatDate(new Date()); + const eventDate = formatDate(data.event.date); + isPastEvent = eventDate < today; + }); + + @@ -25,7 +33,6 @@

{formatDate(data.event.date)}

-
-

Ansvarlige

@@ -116,27 +122,28 @@ 'Ingen ansvarlige'}

- - {#if !isInShift} - - - - - {:else} -
- - - + {#if !isPastEvent} + {#if !isInShift} +
+ + + + {:else} +
+ + + + {/if} {/if}
From 5cef44ab7f642db59a69deaa29a49deee91ea64b Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 23:06:02 +0200 Subject: [PATCH 20/42] Mobile layout --- .../lib/components/portal/EventTable.svelte | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index 02dd545e..f27e2af5 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -89,32 +89,69 @@ return ''; } } + + +let isMobile = $state(false); + +$effect(() => { + const updateLayout = () => { + isMobile = window.innerWidth < 768; + }; + + updateLayout(); + window.addEventListener('resize', updateLayout); + + return () => { + window.removeEventListener('resize', updateLayout); + }; +});
-
+
+ + + {#if isMobile && $user?.role === 'board'} + + {/if}
+
- - {#if $user?.role === 'board'} + + {#if !isMobile && $user?.role === 'board'}
From 9e112201175b84f7df92529e765eac248cd57f65 Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 23:07:03 +0200 Subject: [PATCH 21/42] Diff redir --- .../portal/arrangementer/[id]/edit/+page.svelte | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index b0686ac4..6a815195 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -94,15 +94,7 @@ -
{ - return async ({ result, update }) => { - if (result.type === 'success') { - deletedShiftIds = []; - removedUserShifts = []; - } - await update(); - }; - }}> + {#each deletedShiftIds as id} @@ -245,7 +237,7 @@
- +
-
- + - {#if !isMobile && $user?.role === 'board'} -
-
{/if}
@@ -197,7 +195,7 @@ $effect(() => { {countShifts(event)}
From 16f535fc3e3ae62be9b469fe82b53b67f2c17aa1 Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 28 May 2025 23:46:34 +0200 Subject: [PATCH 23/42] format --- .../lib/components/portal/EventTable.svelte | 65 +++--- .../routes/portal/arrangementer/+page.svelte | 2 +- .../portal/arrangementer/[id]/+page.svelte | 58 +++-- .../arrangementer/[id]/edit/+page.server.ts | 217 +++++++++--------- .../arrangementer/[id]/edit/+page.svelte | 38 ++- 5 files changed, 186 insertions(+), 194 deletions(-) diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index a245ba58..0f05cbae 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -5,7 +5,7 @@ import { getUser } from '$lib/context/user.context'; import Button from '../ui/Button.svelte'; import Input from '$lib/components/ui/Input.svelte'; - + type Event = { id: string; name: string; @@ -91,50 +91,47 @@ } } + let isMobile = $state(false); + + $effect(() => { + const updateLayout = () => { + isMobile = window.innerWidth < 546; + }; + + updateLayout(); + window.addEventListener('resize', updateLayout); -let isMobile = $state(false); - -$effect(() => { - const updateLayout = () => { - isMobile = window.innerWidth < 546; - }; - - updateLayout(); - window.addEventListener('resize', updateLayout); - - return () => { - window.removeEventListener('resize', updateLayout); - }; -}); + return () => { + window.removeEventListener('resize', updateLayout); + }; + });
-
+
- + - + {#if isMobile && $user?.role === 'board'} + {/if}
@@ -195,7 +190,9 @@ $effect(() => { {countShifts(event)}
diff --git a/apps/www/src/routes/portal/arrangementer/+page.svelte b/apps/www/src/routes/portal/arrangementer/+page.svelte index f3afd13f..6eacb672 100644 --- a/apps/www/src/routes/portal/arrangementer/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/+page.svelte @@ -8,6 +8,6 @@ Arrangementer -
+
diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 73487d65..1964298c 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -9,14 +9,12 @@ let { data } = $props(); let user = getUser(); let activeTab = $state('details'); - let isPastEvent = $state(false) - $effect(() => { - const today = formatDate(new Date()); - const eventDate = formatDate(data.event.date); - isPastEvent = eventDate < today; - }); - - + let isPastEvent = $state(false); + $effect(() => { + const today = formatDate(new Date()); + const eventDate = formatDate(data.event.date); + isPastEvent = eventDate < today; + }); @@ -122,28 +120,28 @@ 'Ingen ansvarlige'}

- {#if !isPastEvent} - {#if !isInShift} - - - - - {:else} -
- - - - {/if} + {#if !isPastEvent} + {#if !isInShift} +
+ + + + {:else} +
+ + + + {/if} {/if} diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts index a27d4f12..ac8231ca 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.server.ts @@ -21,112 +21,113 @@ export const load: PageServerLoad = async ({ locals, params }) => { }; export const actions: Actions = { - delete: async ({ params, locals }) => { - if (locals.user?.role !== 'board') { - return fail(401, { message: 'Unauthorized' }); - } - - await locals.eventService.delete(params.id); - throw redirect(303, '/portal/arrangementer'); - }, - - - save: async ({ request, params, locals }) => { - if (locals.user?.role !== 'board') { - return fail(401, { message: 'Unauthorized' }); - } - - const formData = await request.formData(); - const eventId = params.id; - - const updated = await locals.eventService.updateEvent(params.id, { - name: String(formData.get('name') || ''), - date: new Date(String(formData.get('date') || '')) - }); - - const deletedShiftIds = formData.getAll('deletedShiftIds').map(id => String(id)); - for (const shiftId of deletedShiftIds) { - await locals.eventService.deleteShift(shiftId); - } - - const removedUserShifts = formData.getAll('removedUserShifts').map(kv => String(kv)); - for (const userShift of removedUserShifts) { - const [shiftId, userId] = userShift.split('|'); - if (shiftId && userId) { - await locals.eventService.deleteUserShift({ shiftId, userId }); - } - } - - const existingEvent = await locals.eventService.findFullEventById(eventId); - if (!existingEvent) { - return fail(404, { message: 'Event not found' }); - } - - const shiftsCount = parseInt(String(formData.get('shiftsCount') || '0'), 10); - const processedShifts = []; - - for (let i = 0; i < shiftsCount; i++) { - const shiftId = formData.get(`shift[${i}].id`)?.toString(); - const startAt = new Date(String(formData.get(`shift[${i}].startAt`))); - const endAt = new Date(String(formData.get(`shift[${i}].endAt`))); - - let shift; - - if (shiftId) { - shift = await locals.eventService.updateShift(shiftId, { - eventId, - startAt, - endAt - }); - } else { - const shifts = await locals.eventService.createShifts([{ - eventId, - startAt, - endAt - }]); - shift = shifts?.[0]; - } - - if (!shift) { - return fail(500, { message: 'Failed to create/update shift' }); - } - - processedShifts.push({ - shiftId: shift.id, - index: i - }); - } - - for (const { shiftId, index } of processedShifts) { - const userCount = parseInt(String(formData.get(`shift[${index}].userCount`) || '0'), 10); - - const existingShift = existingEvent.shifts.find(s => s.id === shiftId); - const existingUserIds = existingShift?.members.map(m => m.user.id) || []; - - const newUserIds: string[] = []; - for (let j = 0; j < userCount; j++) { - const userId = formData.get(`shift[${index}].user[${j}].id`)?.toString(); - if (userId?.trim()) { - newUserIds.push(userId); - } - } - - const usersToAdd = newUserIds.filter(userId => !existingUserIds.includes(userId)); - const usersToRemove = existingUserIds.filter(userId => !newUserIds.includes(userId)); - - if (usersToAdd.length > 0) { - const userShiftsToCreate = usersToAdd.map(userId => ({ - shiftId, - userId - })); - await locals.eventService.createUserShifts(userShiftsToCreate); - } - - for (const userId of usersToRemove) { - await locals.eventService.deleteUserShift({ shiftId, userId }); - } - } - - return { success: true, message: 'Vakten har blitt oppdatert' }; - } + delete: async ({ params, locals }) => { + if (locals.user?.role !== 'board') { + return fail(401, { message: 'Unauthorized' }); + } + + await locals.eventService.delete(params.id); + throw redirect(303, '/portal/arrangementer'); + }, + + save: async ({ request, params, locals }) => { + if (locals.user?.role !== 'board') { + return fail(401, { message: 'Unauthorized' }); + } + + const formData = await request.formData(); + const eventId = params.id; + + const updated = await locals.eventService.updateEvent(params.id, { + name: String(formData.get('name') || ''), + date: new Date(String(formData.get('date') || '')) + }); + + const deletedShiftIds = formData.getAll('deletedShiftIds').map((id) => String(id)); + for (const shiftId of deletedShiftIds) { + await locals.eventService.deleteShift(shiftId); + } + + const removedUserShifts = formData.getAll('removedUserShifts').map((kv) => String(kv)); + for (const userShift of removedUserShifts) { + const [shiftId, userId] = userShift.split('|'); + if (shiftId && userId) { + await locals.eventService.deleteUserShift({ shiftId, userId }); + } + } + + const existingEvent = await locals.eventService.findFullEventById(eventId); + if (!existingEvent) { + return fail(404, { message: 'Event not found' }); + } + + const shiftsCount = parseInt(String(formData.get('shiftsCount') || '0'), 10); + const processedShifts = []; + + for (let i = 0; i < shiftsCount; i++) { + const shiftId = formData.get(`shift[${i}].id`)?.toString(); + const startAt = new Date(String(formData.get(`shift[${i}].startAt`))); + const endAt = new Date(String(formData.get(`shift[${i}].endAt`))); + + let shift; + + if (shiftId) { + shift = await locals.eventService.updateShift(shiftId, { + eventId, + startAt, + endAt + }); + } else { + const shifts = await locals.eventService.createShifts([ + { + eventId, + startAt, + endAt + } + ]); + shift = shifts?.[0]; + } + + if (!shift) { + return fail(500, { message: 'Failed to create/update shift' }); + } + + processedShifts.push({ + shiftId: shift.id, + index: i + }); + } + + for (const { shiftId, index } of processedShifts) { + const userCount = parseInt(String(formData.get(`shift[${index}].userCount`) || '0'), 10); + + const existingShift = existingEvent.shifts.find((s) => s.id === shiftId); + const existingUserIds = existingShift?.members.map((m) => m.user.id) || []; + + const newUserIds: string[] = []; + for (let j = 0; j < userCount; j++) { + const userId = formData.get(`shift[${index}].user[${j}].id`)?.toString(); + if (userId?.trim()) { + newUserIds.push(userId); + } + } + + const usersToAdd = newUserIds.filter((userId) => !existingUserIds.includes(userId)); + const usersToRemove = existingUserIds.filter((userId) => !newUserIds.includes(userId)); + + if (usersToAdd.length > 0) { + const userShiftsToCreate = usersToAdd.map((userId) => ({ + shiftId, + userId + })); + await locals.eventService.createUserShifts(userShiftsToCreate); + } + + for (const userId of usersToRemove) { + await locals.eventService.deleteUserShift({ shiftId, userId }); + } + } + + return { success: true, message: 'Vakten har blitt oppdatert' }; + } }; diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index 6a815195..b1b06af2 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -32,7 +32,6 @@ let deletedShiftIds = $state([] as string[]); let removedUserShifts = $state([] as string[]); - beforeNavigate(({ cancel }) => { if (deletedShiftIds.length > 0 || removedUserShifts.length > 0) { if (!confirm('Du har ulagrede endringer. Er du sikker på at du vil forlate siden?')) { @@ -40,7 +39,6 @@ } } }); - @@ -83,17 +81,19 @@

Ulagrede endringer:

    {#if deletedShiftIds.length > 0} -
  • • {deletedShiftIds.length} vakt{deletedShiftIds.length > 1 ? 'er' : ''} vil bli slettet
  • +
  • + • {deletedShiftIds.length} vakt{deletedShiftIds.length > 1 ? 'er' : ''} vil bli slettet +
  • {/if} {#if removedUserShifts.length > 0} -
  • • {removedUserShifts.length} bruker{removedUserShifts.length > 1 ? 'e' : ''} vil bli fjernet
  • +
  • + • {removedUserShifts.length} bruker{removedUserShifts.length > 1 ? 'e' : ''} vil bli fjernet +
  • {/if}
{/if} - -
{#each deletedShiftIds as id} @@ -138,16 +138,16 @@ type="button" class="rounded-full p-1 text-red-400 hover:text-red-600" onclick={() => { - if (i < originalShifts.length) { - deletedShiftIds.push(originalShifts[i].id); - } - eventState.deleteShift(i); - - if (i < originalShifts.length) { - originalShifts.splice(i, 1); - } - }} - > + if (i < originalShifts.length) { + deletedShiftIds.push(originalShifts[i].id); + } + eventState.deleteShift(i); + + if (i < originalShifts.length) { + originalShifts.splice(i, 1); + } + }} + > @@ -176,11 +176,7 @@

Ansvarlige

- From 51fbbc1a9d13d21449ab55dea625b1c5c9712071 Mon Sep 17 00:00:00 2001 From: Gard Date: Fri, 30 May 2025 14:51:57 +0200 Subject: [PATCH 24/42] sort users by name --- apps/www/src/routes/portal/admin/+page.svelte | 4 +++- apps/www/src/routes/portal/brukere/+page.svelte | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/www/src/routes/portal/admin/+page.svelte b/apps/www/src/routes/portal/admin/+page.svelte index 5c1ab9ea..5779a000 100644 --- a/apps/www/src/routes/portal/admin/+page.svelte +++ b/apps/www/src/routes/portal/admin/+page.svelte @@ -15,12 +15,14 @@ data.users.filter((user: User) => { return user.role === 'board' && user.name.toLowerCase().includes(search.toLowerCase()); }) + .sort((a, b) => a.name.localeCompare(b.name)) ); let normalMembers = $derived.by(() => data.users.filter((user: User) => { return user.role === 'normal' && user.name.toLowerCase().includes(search.toLowerCase()); - }) + }) + .sort((a, b) => a.name.localeCompare(b.name)) ); function closeModal() { diff --git a/apps/www/src/routes/portal/brukere/+page.svelte b/apps/www/src/routes/portal/brukere/+page.svelte index af75a7a5..d9150ac7 100644 --- a/apps/www/src/routes/portal/brukere/+page.svelte +++ b/apps/www/src/routes/portal/brukere/+page.svelte @@ -16,6 +16,7 @@ data.users.filter((user) => { return user.name.toLowerCase().includes(search.toLowerCase()); }) + .sort((a, b) => a.name.localeCompare(b.name)) ); From 97b3c8e247213925322fe30ef29242c432e684cc Mon Sep 17 00:00:00 2001 From: Gard Date: Fri, 30 May 2025 14:57:20 +0200 Subject: [PATCH 25/42] format' ' --- apps/www/src/routes/portal/admin/+page.svelte | 18 ++++++++++-------- .../routes/portal/arrangementer/+page.svelte | 2 +- .../www/src/routes/portal/brukere/+page.svelte | 9 +++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/www/src/routes/portal/admin/+page.svelte b/apps/www/src/routes/portal/admin/+page.svelte index 5779a000..93d3984b 100644 --- a/apps/www/src/routes/portal/admin/+page.svelte +++ b/apps/www/src/routes/portal/admin/+page.svelte @@ -12,17 +12,19 @@ let isModalOpen = $state(false); let boardMembers = $derived.by(() => - data.users.filter((user: User) => { - return user.role === 'board' && user.name.toLowerCase().includes(search.toLowerCase()); - }) - .sort((a, b) => a.name.localeCompare(b.name)) + data.users + .filter((user: User) => { + return user.role === 'board' && user.name.toLowerCase().includes(search.toLowerCase()); + }) + .sort((a, b) => a.name.localeCompare(b.name)) ); let normalMembers = $derived.by(() => - data.users.filter((user: User) => { - return user.role === 'normal' && user.name.toLowerCase().includes(search.toLowerCase()); - }) - .sort((a, b) => a.name.localeCompare(b.name)) + data.users + .filter((user: User) => { + return user.role === 'normal' && user.name.toLowerCase().includes(search.toLowerCase()); + }) + .sort((a, b) => a.name.localeCompare(b.name)) ); function closeModal() { diff --git a/apps/www/src/routes/portal/arrangementer/+page.svelte b/apps/www/src/routes/portal/arrangementer/+page.svelte index 6eacb672..8e6ba441 100644 --- a/apps/www/src/routes/portal/arrangementer/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/+page.svelte @@ -8,6 +8,6 @@ Arrangementer -
+
diff --git a/apps/www/src/routes/portal/brukere/+page.svelte b/apps/www/src/routes/portal/brukere/+page.svelte index d9150ac7..8771fb08 100644 --- a/apps/www/src/routes/portal/brukere/+page.svelte +++ b/apps/www/src/routes/portal/brukere/+page.svelte @@ -13,10 +13,11 @@ let search = $state(''); let filteredUsers = $derived.by(() => - data.users.filter((user) => { - return user.name.toLowerCase().includes(search.toLowerCase()); - }) - .sort((a, b) => a.name.localeCompare(b.name)) + data.users + .filter((user) => { + return user.name.toLowerCase().includes(search.toLowerCase()); + }) + .sort((a, b) => a.name.localeCompare(b.name)) ); From 8bb9ac00f611cc91c6ad0d575b87a90c794d13da Mon Sep 17 00:00:00 2001 From: Gard Date: Fri, 30 May 2025 15:47:49 +0200 Subject: [PATCH 26/42] fixed colu mn --- .../lib/components/portal/EventTable.svelte | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index 0f05cbae..2fce8c39 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -157,14 +157,19 @@
{:else}
-
ArrangementDatoAntall vakterStatusArrangementDatoAntall vakterStatus
+
{event.name} + {formatDate(event.date)} + {countShifts(event)} + {status} + {#if $user?.role === 'board'} - - - + + + {/if}
{status} {status}
+
+ + + + + + - - - - - - + + + + + @@ -175,22 +180,22 @@ onclick={() => goto(`arrangementer/${event.id}`)} > {#each filteredEvents as event (event.id)} {@const status = getEventStatus(event)} - goto(`arrangementer/${event.id}`)} - > + {#if isMobile} @@ -215,7 +204,7 @@ {#if $user?.role === 'board'} From 71d2cd80db29747a2633da739be5d6b786b1564b Mon Sep 17 00:00:00 2001 From: Gard Date: Wed, 4 Jun 2025 14:58:20 +0200 Subject: [PATCH 42/42] effect to derived --- apps/www/src/routes/portal/arrangementer/[id]/+page.svelte | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index bb779545..fd0036ef 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -9,12 +9,7 @@ let { data } = $props(); let user = getUser(); let activeTab = $state('details'); - let isPastEvent = $state(false); - $effect(() => { - const today = new Date(); - const eventDate = new Date(data.event.date); - isPastEvent = today > eventDate; - }); + let isPastEvent = $derived(new Date() > new Date(data.event.date));
ArrangementDatoAntall vakterStatus
ArrangementDatoAntall vakterStatus
{event.name} {formatDate(event.date)} {countShifts(event)} From 181ccf8f7add251f83d3d65b2678430d6ac9ecd7 Mon Sep 17 00:00:00 2001 From: Gard Date: Fri, 30 May 2025 15:48:50 +0200 Subject: [PATCH 27/42] format --- apps/www/src/routes/portal/arrangementer/ny/+page.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index 90f02ed2..6217d6af 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -1,7 +1,6 @@ + + + Nytt arrangement + + +
+
+

Nytt arrangement

+
+
+ {#if error} +
+

{error}

+
+ {/if} + + {#if successMessage} +
+

{successMessage}

+
+ {/if} + + +
+
+ + +
+
+ +
+

Vakter

+ {#each createEventState.shifts as shift, i} + {@const startDate = shift.startAt ? new Date(shift.startAt) : new Date()} + {@const endDate = shift.endAt ? new Date(shift.endAt) : new Date()} + {@const shiftLength = differenceInHours(endDate, startDate)} +
+
+

Vakt {i + 1}

+ +
+ +
+ + +
+ + {#if shiftLength >= 4} +
+ + NB: Vakten er lengre enn 4 timer! +
+ {/if} + +
+
+

Ansvarlige

+ +
+

+ Alle ansvarlige vil få en e-post med kalenderinvitasjon når arrangementet + oppdateres. +

+ +
+ {#each createEventState.shifts[i].users as user, j (user)} +
+ user.id)} + onchange={(option) => { + const id = option?.value; + if (id) { + createEventState.shifts[i].users[j].id = id; + } + }} + options={data.users} + placeholder="Velg en bruker" + /> + +
+ {:else} +

+ Ingen ansvarlige. Husk å legge til. +

+ {/each} +
+
+
+ {/each} + + +
+ +
+ + + + + + + +
+ +
+
diff --git a/apps/www/src/lib/components/portal/EventTable.svelte b/apps/www/src/lib/components/portal/EventTable.svelte index 2a5e1c38..98a0a9e7 100644 --- a/apps/www/src/lib/components/portal/EventTable.svelte +++ b/apps/www/src/lib/components/portal/EventTable.svelte @@ -1,6 +1,5 @@ - - - Nytt arrangement - - -
-
-

Nytt arrangement

-
-
- {#if error} -
-

{error}

-
- {/if} - - {#if successMessage} -
-

{successMessage}

-
- {/if} - -
-
-
- - -
-
- -
-

Vakter

- {#each createEventState.shifts as shift, i} - {@const startDate = shift.startAt ? new Date(shift.startAt) : new Date()} - {@const endDate = shift.endAt ? new Date(shift.endAt) : new Date()} - {@const shiftLength = differenceInHours(endDate, startDate)} -
-
-

Vakt {i + 1}

- -
- -
- - -
- - {#if shiftLength >= 4} -
- - NB: Vakten er lengre enn 4 timer! -
- {/if} - -
-
-

Ansvarlige

- -
-

- Alle ansvarlige vil få en e-post med kalenderinvitasjon når arrangementet - oppdateres. -

- -
- {#each createEventState.shifts[i].users as user, j (user)} -
- user.id)} - onchange={(option) => { - const id = option?.value; - if (id) { - createEventState.shifts[i].users[j].id = id; - } - }} - options={data.users} - placeholder="Velg en bruker" - /> - -
- {:else} -

- Ingen ansvarlige. Husk å legge til. -

- {/each} -
-
-
- {/each} - - -
- -
- - - - - - - -
-
-
-
From 99e20d1cba6338af313915a9b9e5e70409c1d45a Mon Sep 17 00:00:00 2001 From: Gard Date: Sat, 31 May 2025 17:39:57 +0200 Subject: [PATCH 36/42] styling --- apps/www/src/routes/portal/arrangementer/[id]/+page.svelte | 2 +- .../src/routes/portal/arrangementer/[id]/edit/+page.svelte | 4 ++-- apps/www/src/routes/portal/arrangementer/ny/+page.svelte | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 4f4f1863..9d3b9f5c 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -33,7 +33,7 @@
diff --git a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte index 988f0d41..2e6bb06b 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/edit/+page.svelte @@ -45,7 +45,7 @@ Rediger arrangement: {eventState.name} -
+

Arrangement detaljer

@@ -234,7 +234,7 @@
- + {/if}
-
-
-
+
+
-

{data.event.name}

+

{data.event.name}

-
+
-
+

Ansvarlige

-
+
diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index 22835726..345b03d7 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -53,8 +53,8 @@ Nytt arrangement -
-
+
+

Nytt arrangement

@@ -71,7 +71,7 @@ {/if} -
+
+
-

Vakt {i + 1}

+

Vakt {i + 1}

-
+
From 14cadb49ce744271e7bc40c573173e228fd10499 Mon Sep 17 00:00:00 2001 From: Gard Date: Sun, 1 Jun 2025 00:48:05 +0200 Subject: [PATCH 38/42] fixed time check --- apps/www/src/routes/portal/arrangementer/[id]/+page.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte index 8e18c57e..bb779545 100644 --- a/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/[id]/+page.svelte @@ -11,9 +11,9 @@ let activeTab = $state('details'); let isPastEvent = $state(false); $effect(() => { - const today = formatDate(new Date()); - const eventDate = formatDate(data.event.date); - isPastEvent = eventDate < today; + const today = new Date(); + const eventDate = new Date(data.event.date); + isPastEvent = today > eventDate; }); From 0eb0cd639359b6fa8b5b5e81a636b99645320322 Mon Sep 17 00:00:00 2001 From: Gard Date: Sun, 1 Jun 2025 00:51:56 +0200 Subject: [PATCH 39/42] styling --- apps/www/src/routes/portal/arrangementer/ny/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte index 345b03d7..50a3ce68 100644 --- a/apps/www/src/routes/portal/arrangementer/ny/+page.svelte +++ b/apps/www/src/routes/portal/arrangementer/ny/+page.svelte @@ -71,7 +71,7 @@ {/if} -
+
+

Vakt {i + 1}

+
- {#if isMobile && $user?.role === 'board'} -
- + -
- {#if !isMobile && $user?.role === 'board'} - - - - {/if}
{#if filteredEvents.length === 0} @@ -189,11 +179,10 @@
+ {event.name}