From 86a5cd1d468c2287d33f38722326ae9a87a41fbc Mon Sep 17 00:00:00 2001 From: Donkoko Date: Fri, 6 Dec 2024 15:42:36 +0200 Subject: [PATCH] fix: base and self service users cannot see bookings - made sure that for self service and base users we are also querying bookings with teamMemberId - updated getBookings to support an OR query when both user and teamMember id are passed - added a feature that when accepting an invite, if there are any bookings attached to the team member, we update them by linking them also to the user --- app/modules/booking/service.server.ts | 24 ++++++++++++---- app/modules/invite/service.server.ts | 17 +++++++++++- app/routes/_layout+/bookings.tsx | 40 ++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/app/modules/booking/service.server.ts b/app/modules/booking/service.server.ts index 70e8a1730..a1466e7a2 100644 --- a/app/modules/booking/service.server.ts +++ b/app/modules/booking/service.server.ts @@ -594,12 +594,26 @@ export async function getBookings(params: { mode: "insensitive", }; } - if (custodianTeamMemberId) { - where.custodianTeamMemberId = custodianTeamMemberId; - } - if (custodianUserId) { - where.custodianUserId = custodianUserId; + + /** In the case both are passed, we do an OR */ + if (custodianTeamMemberId && custodianUserId) { + where.OR = [ + { + custodianTeamMemberId, + }, + { + custodianUserId, + }, + ]; + } else { + if (custodianTeamMemberId) { + where.custodianTeamMemberId = custodianTeamMemberId; + } + if (custodianUserId) { + where.custodianUserId = custodianUserId; + } } + if (statuses?.length) { where.status = { in: statuses, diff --git a/app/modules/invite/service.server.ts b/app/modules/invite/service.server.ts index 8fcc014fa..1e3588ef9 100644 --- a/app/modules/invite/service.server.ts +++ b/app/modules/invite/service.server.ts @@ -339,7 +339,22 @@ export async function updateInviteStatus({ await db.teamMember.update({ where: { id: invite.teamMemberId }, - data: { deletedAt: null, user: { connect: { id: user.id } } }, + data: { + deletedAt: null, + user: { connect: { id: user.id } }, + /** + * This handles a special case. + * If an invite is still pending, the team member is not yet linked to a user. + * However the admin is allowed to assign bookings to that team member. + * When the invite is accepted, we need to update all those bookings to also be linked to the user so they can see it on their bookings index. + */ + bookings: { + updateMany: { + where: { custodianTeamMemberId: invite.teamMemberId }, + data: { custodianUserId: user.id }, + }, + }, + }, }); } diff --git a/app/routes/_layout+/bookings.tsx b/app/routes/_layout+/bookings.tsx index 85882553f..6892426af 100644 --- a/app/routes/_layout+/bookings.tsx +++ b/app/routes/_layout+/bookings.tsx @@ -19,6 +19,7 @@ import { Filters } from "~/components/list/filters"; import { Badge } from "~/components/shared/badge"; import { Button } from "~/components/shared/button"; import { Td, Th } from "~/components/table"; +import { db } from "~/database/db.server"; import { useUserRoleHelper } from "~/hooks/user-user-role-helper"; import { getBookings } from "~/modules/booking/service.server"; import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server"; @@ -69,6 +70,40 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const cookie = await updateCookieWithPerPage(request, perPageParam); const { perPage } = cookie; + /** + * For self service and base users, we need to get the teamMember to be able to filter by it as well. + * Tis is to handle a case when a booking was assigned when there wasnt a user attached to a team member but they were later on linked. + * This is to ensure that the booking is still visible to the user that was assigned to it. + * Also this shouldn't really happen as we now have a fix implemented when accepting invites, + * to make sure it doesnt happen, hwoever its good to keep this as an extra safety thing. + * Ideally in the future we should remove this as it adds another query to the db + * @TODO this can safely be remove 3-6 months after this commit + */ + let selfServiceData = null; + if (isSelfServiceOrBase) { + const teamMember = await db.teamMember.findFirst({ + where: { + userId, + organizationId, + }, + }); + if (!teamMember) { + throw new ShelfError({ + cause: null, + title: "Team member not found", + message: + "You are not part of a team in this organization. Please contact your organization admin to resolve this", + label: "Booking", + shouldBeCaptured: false, + }); + } + selfServiceData = { + // If the user is self service, we only show bookings that belong to that user) + custodianUserId: authSession?.userId, + custodianTeamMemberId: teamMember.id, + }; + } + const { bookings, bookingCount } = await getBookings({ organizationId, page, @@ -79,10 +114,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { // If status is in the params, we filter based on it statuses: [status], }), - ...(isSelfServiceOrBase && { - // If the user is self service, we only show bookings that belong to that user) - custodianUserId: authSession?.userId, - }), + ...selfServiceData, }); const totalPages = Math.ceil(bookingCount / perPage);