Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send notifications to KM when new booking requests are made + new booking review page #527

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
199e828
Initial concept for sending booking notifications to KM
Fiery-132 Oct 16, 2024
c0204ad
Removed unnecessary type
Fiery-132 Oct 17, 2024
dbfb5ce
Improved notification message
Fiery-132 Oct 17, 2024
cdf17cf
Fixed incorrect time when editing booking requests
Fiery-132 Oct 17, 2024
4655e6f
Added new page for accepting/denying booking requests and linked noti…
Fiery-132 Oct 17, 2024
2883d5f
Refactored identical code for accepting/rejecting booking requests to…
Fiery-132 Oct 17, 2024
b286838
Refactored code for handling accept/reject actions into one function
Fiery-132 Oct 17, 2024
4cf859a
Refactored code for getting weekly booking requests
Fiery-132 Oct 17, 2024
460a432
Changed StatusComponent.svelte to support two different modes
Fiery-132 Oct 17, 2024
fb609c5
Formatting fix and added link to inspect page from /booking/admin
Fiery-132 Oct 17, 2024
7eb27b8
Fixed incorrect date format on /booking/admin
Fiery-132 Oct 17, 2024
05db5bf
Refactored identical code for getting bookingRequest and form into sh…
Fiery-132 Oct 17, 2024
14f1bec
Removed old, unnecessary code
Fiery-132 Oct 17, 2024
03712c8
Fixed invalid bookingRequest id error
Fiery-132 Oct 17, 2024
f6488f8
Removed unused parameter
Fiery-132 Oct 17, 2024
21aa913
Removed old testing code
Fiery-132 Oct 17, 2024
78fcb8b
Added error handling for KM notifications
Fiery-132 Oct 17, 2024
5ebeea5
Merge branch 'main' of https://github.com/Dsek-LTH/web into 487-send-…
Fiery-132 Oct 17, 2024
201e03a
Removed unused variable
Fiery-132 Oct 17, 2024
6162e23
Moved sharedUtils.ts
Fiery-132 Oct 17, 2024
6ed10d4
Edited import
Fiery-132 Oct 17, 2024
54b932a
Added TODO
Fiery-132 Oct 18, 2024
082a58a
Merge branch 'main' of https://github.com/Dsek-LTH/web into 487-send-…
Fiery-132 Oct 18, 2024
4fede28
Changed the booking inspector to match the updated booking editor
Fiery-132 Oct 21, 2024
5afbecd
Update to booking inspector:
Fiery-132 Oct 21, 2024
c8d13ec
Changed notification bookable names to nameEn
Fiery-132 Oct 22, 2024
1436030
Merge branch 'Dsek-LTH:main' into 487-send-notification-to-km-when-ne…
Fiery-132 Oct 22, 2024
396d626
Fixed the calendar on review booking page so it does not display *all…
Fiery-132 Oct 22, 2024
61756e8
General refactoring
danieladugyan Nov 9, 2024
3221f9f
Merge remote-tracking branch 'origin/main' into 487-send-notification…
danieladugyan Nov 9, 2024
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 changes: 2 additions & 1 deletion src/routes/(app)/booking/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { isAuthorized } from "$lib/utils/authorization";
import { page } from "$app/stores";
import apiNames from "$lib/utils/apiNames";
import StatusComponent from "./admin/StatusComponent.svelte";
import StatusComponent from "./StatusComponent.svelte";
import dayjs from "dayjs";
import ConfirmDialog from "$lib/components/ConfirmDialog.svelte";
import BookingCalendar from "./BookingCalendar.svelte";
Expand Down Expand Up @@ -60,6 +60,7 @@
<StatusComponent
bind:bookingRequest
bind:bookingRequests={data.bookingRequests}
class="flex-col"
/>
</td>
<td>
Expand Down
73 changes: 63 additions & 10 deletions src/routes/(app)/booking/BookingEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
import type { BookingSchema } from "./schema";
import { superForm } from "$lib/utils/client/superForms";
import * as m from "$paraglide/messages";
import type { Bookable } from "@prisma/client";
import type { Bookable, BookingRequest } from "@prisma/client";
import StatusComponent from "./StatusComponent.svelte";

type BookingRequestWithBookables = BookingRequest & { bookables: Bookable[] };
export let data: {
form: SuperValidated<Infer<BookingSchema>>;
bookables: Bookable[];
booking?: BookingRequestWithBookables;
allBookingRequests?: BookingRequestWithBookables[];
};

$: bookingRequest = data.booking;

const { form, errors, enhance, constraints } = superForm(data.form);
export let mode: "create" | "edit" = "create";
export let mode: "create" | "edit" | "review" = "create";

let start = $form.start;
let end = $form.end;
Expand Down Expand Up @@ -60,6 +66,23 @@
</script>

<form method="POST" use:enhance class="form-control mx-auto max-w-5xl gap-4">
{#if mode === "review"}
<div class="flex flex-col gap-5">
<div class="w-fit">
<a class="btn" href="/booking/admin">
<span class="i-mdi-arrow-expand-left" />
{m.booking_goBack()}
</a>
</div>
{#if bookingRequest && data.allBookingRequests}
<StatusComponent
bind:bookingRequest
bind:bookingRequests={data.allBookingRequests}
class="flex-row"
/>
{/if}
</div>
{/if}
<fieldset
class="input-bordered grid grid-cols-[repeat(auto-fit,minmax(300px,1fr))] rounded-xl border px-6 py-2"
class:border-error={$errors.bookables?._errors ?? 0 > 0}
Expand All @@ -73,6 +96,7 @@
name="bookables"
value={bookable.id}
bind:group={$form.bookables}
disabled={mode === "review"}
/>
<span class="label-text">{bookable.name}</span>
</label>
Expand All @@ -89,6 +113,7 @@
bind:value={start}
on:change={handleStartChange}
{...$constraints.start}
disabled={mode === "review"}
/>
</label>

Expand All @@ -103,6 +128,7 @@
bind:value={end}
on:change={handleEndChange}
{...$constraints.end}
disabled={mode === "review"}
/>
</label>

Expand All @@ -114,15 +140,42 @@
class="input input-bordered w-full"
bind:value={$form.name}
{...$constraints.name}
disabled={mode === "review"}
/>
</label>

<div class="flex *:flex-1">
<a class="btn" href="/booking">{m.booking_goBack()}</a>
{#if mode === "edit"}
<button class="btn btn-primary">{m.save()}</button>
{:else if mode === "create"}
<button class="btn btn-primary">{m.booking_create()}</button>
{/if}
</div>
{#if mode === "review" && bookingRequest}
<div class="flex *:flex-1">
<input hidden name="id" type="text" bind:value={bookingRequest.id} />
<button
formaction="?/accept"
class="btn btn-outline btn-success"
class:btn-disabled={bookingRequest.status === "ACCEPTED"}
aria-label={m.booking_accept()}
>
{m.booking_accept()}
<span class="i-mdi-check" />
</button>
<button
formaction="?/reject"
class="btn btn-outline btn-error"
class:btn-disabled={bookingRequest.status === "DENIED"}
aria-label={m.booking_deny()}
>
{m.booking_deny()}
<span class="i-mdi-close" />
</button>
</div>
{/if}

{#if mode !== "review"}
<div class="flex *:flex-1">
<a class="btn" href="/booking">{m.booking_goBack()}</a>
{#if mode === "edit"}
<button class="btn btn-primary">{m.save()}</button>
{:else if mode === "create"}
<button class="btn btn-primary">{m.booking_create()}</button>
{/if}
</div>
{/if}
</form>
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
import type { Bookable, BookingRequest } from "@prisma/client";
import dayjs from "dayjs";
import * as m from "$paraglide/messages";
import { twMerge } from "tailwind-merge";

type T = BookingRequest & { bookables: Bookable[] };
export let bookingRequest: T;
export let bookingRequests: T[];
let clazz: string | undefined = undefined;
export { clazz as class };

$: otherBookingRequests = bookingRequests.filter(
(br) => br.id !== bookingRequest.id && br.status !== "DENIED",
);
Expand All @@ -29,7 +33,7 @@
$: conflictWarning = conflict && !conflictError;
</script>

<div class="flex flex-col gap-1">
<div class={twMerge("flex gap-1", clazz)}>
{#if bookingRequest.status === "ACCEPTED"}
<div class="badge badge-success">
<span class="i-mdi-check-circle mr-1" />{m.booking_accepted()}
Expand Down
25 changes: 3 additions & 22 deletions src/routes/(app)/booking/[id]/edit/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,14 @@ import { redirect } from "$lib/utils/redirect";
import * as m from "$paraglide/messages";
import { isAuthorized } from "$lib/utils/authorization";
import apiNames from "$lib/utils/apiNames";
import { error } from "@sveltejs/kit";
import dayjs from "dayjs";
import { getBookingRequestOrThrow, getSuperValidatedForm } from "../../utils";

export const load = async ({ locals, params }) => {
const { prisma } = locals;
const bookables = await prisma.bookable.findMany();

const bookingRequest = await prisma.bookingRequest.findUnique({
where: { id: params.id },
include: { bookables: true },
});

if (!bookingRequest) {
throw error(404, m.booking_errors_notFound());
}

const initialData = {
name: bookingRequest.event ?? undefined,
start: bookingRequest.start
? dayjs(bookingRequest.start).format("YYYY-MM-DDTHH:MM")
: undefined,
end: bookingRequest.end
? dayjs(bookingRequest.end).format("YYYY-MM-DDTHH:MM")
: undefined,
bookables: bookingRequest.bookables?.map((bookable) => bookable.id),
};
const form = await superValidate(initialData, zod(bookingSchema));
const bookingRequest = await getBookingRequestOrThrow(prisma, params.id);
const form = await getSuperValidatedForm(bookingRequest);

return { bookables, form, booking: bookingRequest };
};
Expand Down
89 changes: 5 additions & 84 deletions src/routes/(app)/booking/admin/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,94 +1,15 @@
import apiNames from "$lib/utils/apiNames";
import { authorize } from "$lib/utils/authorization";
import sendNotification from "$lib/utils/notifications";
import { NotificationType } from "$lib/utils/notifications/types";
import dayjs from "dayjs";
import type { Actions, PageServerLoad } from "./$types";
import type { PageServerLoad } from "./$types";
import { actions, getUpcomingBookingRequests } from "../utils";

export const load: PageServerLoad = async ({ locals }) => {
const { prisma, user } = locals;
authorize(apiNames.BOOKINGS.UPDATE, user);

const bookingRequests = await prisma.bookingRequest.findMany({
where: {
start: {
gte: dayjs().subtract(1, "week").toDate(),
},
},
orderBy: [{ start: "asc" }, { end: "asc" }, { status: "asc" }],
include: {
bookables: true,
booker: true,
},
});
const bookingRequests = await getUpcomingBookingRequests(prisma);

return { bookingRequests };
};

export const actions: Actions = {
accept: async (event) => {
const { request, locals } = event;
const { prisma, user } = locals;
const formData = await request.formData();
const id = formData.get("id");
if (id && typeof id === "string") {
await prisma.bookingRequest.update({
where: { id },
data: {
status: "ACCEPTED",
},
});
const request = await prisma.bookingRequest.findFirst({
where: {
id,
},
select: {
bookerId: true,
event: true,
},
});
if (request && request.bookerId != null && user && user.memberId) {
sendNotification({
title: "Booking request accepted",
message: `Your booking request for ${request.event} has been accepted`,
type: NotificationType.BOOKING_REQUEST,
link: "/booking",
memberIds: [request.bookerId],
fromMemberId: user.memberId,
});
}
}
},
reject: async (event) => {
const { request, locals } = event;
const { prisma, user } = locals;
const formData = await request.formData();
const id = formData.get("id");
if (id && typeof id === "string") {
await prisma.bookingRequest.update({
where: { id },
data: {
status: "DENIED",
},
});
const request = await prisma.bookingRequest.findFirst({
where: {
id,
},
select: {
bookerId: true,
event: true,
},
});
if (request && request.bookerId != null && user && user.memberId) {
sendNotification({
title: "Booking request denied",
message: `Your booking request for ${request.event} has been denied`,
type: NotificationType.BOOKING_REQUEST,
link: "/booking",
memberIds: [request.bookerId],
fromMemberId: user.memberId,
});
}
}
},
};
export { actions };
16 changes: 12 additions & 4 deletions src/routes/(app)/booking/admin/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import dayjs from "dayjs";
import StatusComponent from "./StatusComponent.svelte";
import StatusComponent from "../StatusComponent.svelte";
import { enhance } from "$app/forms";
import { getFullName } from "$lib/utils/client/member";
import MemberAvatar from "$lib/components/socials/MemberAvatar.svelte";
Expand Down Expand Up @@ -48,9 +48,16 @@
<p class="min-w-max">{bookable}</p>
{/each}
</td>
<td>{dayjs(bookingRequest.start).format("YYYY-MM-DD HH:MM")}</td>
<td>{dayjs(bookingRequest.end).format("YYYY-MM-DD HH:MM")}</td>
<td>{bookingRequest.event}</td>
<td>{dayjs(bookingRequest.start).format("YYYY-MM-DD HH:mm")}</td>
<td>{dayjs(bookingRequest.end).format("YYYY-MM-DD HH:mm")}</td>
<td>
<a
href="/booking/admin/{bookingRequest.id}"
class="link-hover link"
>
{bookingRequest.event}
</a>
</td>
<td>
<div class="flex items-center gap-2">
{#if bookingRequest.booker}
Expand All @@ -70,6 +77,7 @@
<StatusComponent
bind:bookingRequest
bind:bookingRequests={data.bookingRequests}
class="flex-col"
/>
</td>
<td>
Expand Down
40 changes: 40 additions & 0 deletions src/routes/(app)/booking/admin/[id]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { authorize } from "$lib/utils/authorization";
import apiNames from "$lib/utils/apiNames";
import dayjs from "dayjs";
import {
actions,
getUpcomingBookingRequests,
getBookingRequestOrThrow,
getSuperValidatedForm,
} from "../../utils";

export const load = async ({ locals, params }) => {
const { prisma, user } = locals;
authorize(apiNames.BOOKINGS.UPDATE, user);
const bookables = await prisma.bookable.findMany();

const allBookingRequests = await prisma.bookingRequest.findMany({
where: {
start: {
gte: dayjs().subtract(1, "week").toDate(),
},
},
orderBy: [{ start: "asc" }, { end: "asc" }, { status: "asc" }],
include: {
bookables: true,
},
});

const bookingRequest = await getBookingRequestOrThrow(prisma, params.id);
const form = await getSuperValidatedForm(bookingRequest);

return {
bookables,
form,
booking: bookingRequest,
allBookingRequests,
bookingRequests: await getUpcomingBookingRequests(prisma),
};
};

export { actions };
15 changes: 15 additions & 0 deletions src/routes/(app)/booking/admin/[id]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import type { PageData } from "./$types";
import SetPageTitle from "$lib/components/nav/SetPageTitle.svelte";
import BookingCalendar from "../../BookingCalendar.svelte";
import BookingEditor from "../../BookingEditor.svelte";
import * as m from "$paraglide/messages";

export let data: PageData;
</script>

<SetPageTitle title={m.booking_reviewBooking()} />

<BookingEditor {data} mode="review" />

<BookingCalendar {...data} class="mt-16" />
Loading
Loading