Skip to content

Commit

Permalink
Merge pull request #759 from Shelf-nu/bookings-notes
Browse files Browse the repository at this point in the history
Bookings notes
  • Loading branch information
DonKoko authored Feb 20, 2024
2 parents dedc965 + 86bd5df commit 79f0716
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 16 deletions.
24 changes: 24 additions & 0 deletions app/modules/asset/service.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ export async function updateAssetMainImage({
});
}

/** Creates a singular note */
export async function createNote({
content,
type,
Expand Down Expand Up @@ -868,6 +869,29 @@ export async function createNote({
});
}

/** Creates multiple notes with the same content */
export async function createNotes({
content,
type,
userId,
assetIds,
}: Pick<Note, "content"> & {
type?: Note["type"];
userId: User["id"];
assetIds: Asset["id"][];
}) {
const data = assetIds.map((id) => ({
content,
type: type || "COMMENT",
userId,
assetId: id,
}));

return db.note.createMany({
data,
});
}

export async function deleteNote({
id,
userId,
Expand Down
2 changes: 1 addition & 1 deletion app/modules/booking/email-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const sendCheckinReminder = async (
heading: `Your booking is due for checkin in ${getTimeRemainingMessage(
new Date(booking.to!),
new Date()
)} minutes.`,
)}.`,
assetCount,
hints,
}),
Expand Down
33 changes: 29 additions & 4 deletions app/modules/booking/service.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
sendCheckinReminder,
} from "./email-helpers";
import type { ClientHint, SchedulerData } from "./types";
import { createNotes } from "../asset";
import { getOrganizationAdminsEmails } from "../organization";

/** Includes needed for booking to have all data required for emails */
Expand Down Expand Up @@ -271,7 +272,7 @@ export const upsertBooking = async (
/** We need to invoke this function separately for the admin email as the footer of emails is different */
html: bookingUpdatesTemplateString({
booking: res,
heading: `Booking reservation for ${custodian}`,
heading: `Booking reservation request for ${custodian}`,
assetCount: res.assets.length,
hints,
isAdminEmail: true,
Expand Down Expand Up @@ -515,9 +516,19 @@ export async function getBookings({
return { bookings, bookingCount };
}

export const removeAssets = async (
booking: Pick<Booking, "id"> & { assetIds: Asset["id"][] }
) => {
export const removeAssets = async ({
booking,
firstName,
lastName,
userId,
}: {
booking: Pick<Booking, "id"> & {
assetIds: Asset["id"][];
};
firstName: string;
lastName: string;
userId: string;
}) => {
const { assetIds, id } = booking;
const b = await db.booking.update({
// First, disconnect the assets from the booking
Expand Down Expand Up @@ -549,6 +560,15 @@ export const removeAssets = async (
});
}

createNotes({
content: `**${firstName?.trim()} ${lastName?.trim()}** removed asset from booking **[${
b.name
}](/bookings/${b.id})**.`,
type: "UPDATE",
userId,
assetIds,
});

return b;
};

Expand All @@ -575,6 +595,11 @@ export const deleteBooking = async (
include: {
...commonInclude,
...bookingIncludeForEmails,
assets: {
select: {
id: true,
},
},
},
});

Expand Down
9 changes: 8 additions & 1 deletion app/modules/user/service.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ export async function getUserByEmail(email: User["email"]) {
}

export async function getUserByID(id: User["id"]) {
return db.user.findUnique({ where: { id } });
try {
return db.user.findUnique({ where: { id } });
} catch (cause) {
throw new ShelfStackError({
message: "Failed to get user",
cause,
});
}
}

export async function getUserByIDWithOrg(id: User["id"]) {
Expand Down
32 changes: 27 additions & 5 deletions app/routes/_layout+/bookings.$bookingId.add-assets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import { AddAssetForm } from "~/components/location/add-asset-form";
import { Button } from "~/components/shared";

import { Td } from "~/components/table";
import { getPaginatedAndFilterableAssets } from "~/modules/asset";
import { createNote, getPaginatedAndFilterableAssets } from "~/modules/asset";
import { getBooking, removeAssets, upsertBooking } from "~/modules/booking";
import { getUserByID } from "~/modules/user";
import { getRequiredParam, isFormProcessing } from "~/utils";
import { getClientHint } from "~/utils/client-hints";
import { ShelfStackError } from "~/utils/error";
Expand Down Expand Up @@ -92,7 +93,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
};

export const action = async ({ request, params }: ActionFunctionArgs) => {
await requirePermision(
const { authSession } = await requirePermision(
request,
PermissionEntity.booking,
PermissionAction.update
Expand All @@ -102,18 +103,39 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
const formData = await request.formData();
const assetId = formData.get("assetId") as string;
const isChecked = formData.get("isChecked") === "yes";
const user = await getUserByID(authSession.userId);
if (!user) {
throw new ShelfStackError({ message: "User not found" });
}

if (isChecked) {
await upsertBooking(
const b = await upsertBooking(
{
id: bookingId,
assetIds: [assetId],
},
getClientHint(request)
);
/** We check the ids again after updating, and if they were sent, that means assets are being added
* So we create notes for the assets that were added
*/
await createNote({
content: `**${user?.firstName?.trim()} ${user?.lastName?.trim()}** added asset to booking **[${
b.name
}](/bookings/${b.id})**.`,
type: "UPDATE",
userId: authSession.userId,
assetId,
});
} else {
await removeAssets({
id: bookingId,
assetIds: [assetId],
booking: {
id: bookingId,
assetIds: [assetId],
},
firstName: user.firstName ? user.firstName : "",
lastName: user.lastName ? user.lastName : "",
userId: authSession.userId,
});
}

Expand Down
57 changes: 52 additions & 5 deletions app/routes/_layout+/bookings.$bookingId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Header from "~/components/layout/header";
import type { HeaderData } from "~/components/layout/header/types";
import { Badge } from "~/components/shared";
import { db } from "~/database";
import { createNotes } from "~/modules/asset";
import { commitAuthSession } from "~/modules/auth";
import {
deleteBooking,
Expand Down Expand Up @@ -215,6 +216,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
);
const id = getRequiredParam(params, "bookingId");
const isSelfService = role === OrganizationRoles.SELF_SERVICE;
const user = await getUserByID(authSession.userId);

switch (intent) {
case "save":
Expand Down Expand Up @@ -316,7 +318,20 @@ export async function action({ request, params }: ActionFunctionArgs) {
}
}

await deleteBooking({ id }, getClientHint(request));
const deletedBooking = await deleteBooking(
{ id },
getClientHint(request)
);

createNotes({
content: `**${user?.firstName?.trim()} ${user?.lastName?.trim()}** deleted booking **${
deletedBooking.name
}**.`,
type: "UPDATE",
userId: authSession.userId,
assetIds: deletedBooking.assets.map((a) => a.id),
});

sendNotification({
title: "Booking deleted",
message: "Your booking has been deleted successfully",
Expand All @@ -331,16 +346,20 @@ export async function action({ request, params }: ActionFunctionArgs) {
});
case "removeAsset":
const assetId = formData.get("assetId");
// @ts-ignore @TODO we need to fix this. Not sure how
var booking = await removeAssets({ id, assetIds: [assetId as string] });
var b = await removeAssets({
booking: { id, assetIds: [assetId as string] },
firstName: user?.firstName || "",
lastName: user?.lastName || "",
userId: authSession.userId,
});
sendNotification({
title: "Asset removed",
message: "Your asset has been removed from the booking",
icon: { name: "success", variant: "success" },
senderId: authSession.userId,
});
return json(
{ booking },
{ booking: b },
{
status: 200,
headers: [
Expand All @@ -354,6 +373,16 @@ export async function action({ request, params }: ActionFunctionArgs) {
{ id, status: BookingStatus.ONGOING },
getClientHint(request)
);

createNotes({
content: `**${user?.firstName?.trim()} ${user?.lastName?.trim()}** checked out asset with **[${
booking.name
}](/bookings/${booking.id})**.`,
type: "UPDATE",
userId: authSession.userId,
assetIds: booking.assets.map((a) => a.id),
});

sendNotification({
title: "Booking checked-out",
message: "Your booking has been checked-out successfully",
Expand All @@ -377,6 +406,15 @@ export async function action({ request, params }: ActionFunctionArgs) {
},
getClientHint(request)
);
/** Create check-in notes for all assets */
createNotes({
content: `**${user?.firstName?.trim()} ${user?.lastName?.trim()}** checked in asset with **[${
booking.name
}](/bookings/${booking.id})**.`,
type: "UPDATE",
userId: authSession.userId,
assetIds: booking.assets.map((a) => a.id),
});
sendNotification({
title: "Booking checked-in",
message: "Your booking has been checked-in successfully",
Expand Down Expand Up @@ -413,10 +451,19 @@ export async function action({ request, params }: ActionFunctionArgs) {
}
);
case "cancel":
await upsertBooking(
const cancelledBooking = await upsertBooking(
{ id, status: BookingStatus.CANCELLED },
getClientHint(request)
);

createNotes({
content: `**${user?.firstName?.trim()} ${user?.lastName?.trim()}** cancelled booking **[${
cancelledBooking.name
}](/bookings/${cancelledBooking.id})**.`,
type: "UPDATE",
userId: authSession.userId,
assetIds: cancelledBooking.assets.map((a) => a.id),
});
sendNotification({
title: "Booking canceled",
message: "Your booking has been canceled successfully",
Expand Down

0 comments on commit 79f0716

Please sign in to comment.