fix: move team availability search to serverside (#17549)

* move search to severside

* transform zod stirng to lowercase
This commit is contained in:
sean-brydon
2024-11-08 15:32:08 +05:30
committed by GitHub
parent 5ae6e1e983
commit 4976e24e12
3 changed files with 57 additions and 4 deletions
@@ -1,3 +1,5 @@
"use client";
import { keepPreviousData } from "@tanstack/react-query";
import type { ColumnDef } from "@tanstack/react-table";
import { getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table";
@@ -6,6 +8,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import dayjs from "@calcom/dayjs";
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
import type { DateRange } from "@calcom/lib/date-ranges";
import { useDebounce } from "@calcom/lib/hooks/useDebounce";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { MembershipRole } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc";
@@ -64,6 +67,8 @@ export function AvailabilitySliderTable(props: { userTimeFormat: number | null;
const [browsingDate, setBrowsingDate] = useState(dayjs());
const [editSheetOpen, setEditSheetOpen] = useState(false);
const [selectedUser, setSelectedUser] = useState<SliderUser | null>(null);
const [searchString, setSearchString] = useState("");
const debouncedSearchString = useDebounce(searchString, 500);
const tbStore = createTimezoneBuddyStore({
browsingDate: browsingDate.toDate(),
@@ -75,6 +80,7 @@ export function AvailabilitySliderTable(props: { userTimeFormat: number | null;
loggedInUsersTz: dayjs.tz.guess() || "Europe/London",
startDate: browsingDate.startOf("day").toISOString(),
endDate: browsingDate.endOf("day").toISOString(),
searchString: debouncedSearchString,
},
{
getNextPageParam: (lastPage) => lastPage.nextCursor,
@@ -202,7 +208,7 @@ export function AvailabilitySliderTable(props: { userTimeFormat: number | null;
});
// This means they are not apart of any teams so we show the upgrade tip
if (!flatData.length) return <UpgradeTeamTip />;
if (!flatData.length && !data?.pages?.[0]?.meta?.isApartOfAnyTeam) return <UpgradeTeamTip />;
return (
<TBContext.Provider
@@ -223,7 +229,7 @@ export function AvailabilitySliderTable(props: { userTimeFormat: number | null;
isPending={isPending}
onScroll={(e) => fetchMoreOnBottomReached(e.target as HTMLDivElement)}>
<DataTableToolbar.Root>
<DataTableToolbar.SearchBar table={table} searchKey="member" />
<DataTableToolbar.SearchBar table={table} onSearch={(value) => setSearchString(value)} />
</DataTableToolbar.Root>
</DataTable>
</CellHighlightContainer>
@@ -25,18 +25,29 @@ async function getTeamMembers({
teamIds,
cursor,
limit,
searchString,
}: {
teamId?: number;
organizationId: number | null;
teamIds?: number[];
cursor: number | null | undefined;
limit: number;
searchString?: string | null;
}) {
const memberships = await prisma.membership.findMany({
where: {
teamId: {
in: teamId ? [teamId] : teamIds,
},
...(searchString
? {
OR: [
{ user: { username: { contains: searchString } } },
{ user: { name: { contains: searchString } } },
{ user: { email: { contains: searchString } } },
],
}
: {}),
},
select: {
id: true,
@@ -128,13 +139,22 @@ async function buildMember(member: Member, dateFrom: Dayjs, dateTo: Dayjs) {
}
async function getInfoForAllTeams({ ctx, input }: GetOptions) {
const { cursor, limit } = input;
const { cursor, limit, searchString } = input;
// Get all teamIds for the user
const teamIds = await prisma.membership
.findMany({
where: {
userId: ctx.user.id,
...(searchString
? {
OR: [
{ user: { username: { contains: searchString } } },
{ user: { name: { contains: searchString } } },
{ user: { email: { contains: searchString } } },
],
}
: {}),
},
select: {
id: true,
@@ -152,6 +172,7 @@ async function getInfoForAllTeams({ ctx, input }: GetOptions) {
organizationId: ctx.user.organizationId,
cursor,
limit,
searchString,
});
// Get total team count across all teams the user is in (for pagination)
@@ -169,7 +190,7 @@ async function getInfoForAllTeams({ ctx, input }: GetOptions) {
}
export const listTeamAvailabilityHandler = async ({ ctx, input }: GetOptions) => {
const { cursor, limit } = input;
const { cursor, limit, searchString } = input;
const teamId = input.teamId || ctx.user.organizationId;
let teamMembers: Member[] = [];
@@ -198,6 +219,15 @@ export const listTeamAvailabilityHandler = async ({ ctx, input }: GetOptions) =>
totalTeamMembers = await prisma.membership.count({
where: {
teamId: teamId,
...(searchString
? {
OR: [
{ user: { username: { contains: searchString } } },
{ user: { name: { contains: searchString } } },
{ user: { email: { contains: searchString } } },
],
}
: {}),
},
});
@@ -207,6 +237,7 @@ export const listTeamAvailabilityHandler = async ({ ctx, input }: GetOptions) =>
cursor,
limit,
organizationId: ctx.user.organizationId,
searchString,
});
}
}
@@ -224,11 +255,26 @@ export const listTeamAvailabilityHandler = async ({ ctx, input }: GetOptions) =>
const members = await Promise.all(buildMembers);
let belongsToTeam = true;
if (totalTeamMembers === 0) {
const membership = await prisma.membership.findFirst({
where: {
userId: ctx.user.id,
},
select: {
id: true,
},
});
belongsToTeam = !!membership;
}
return {
rows: members || [],
nextCursor,
meta: {
totalRowCount: totalTeamMembers,
isApartOfAnyTeam: belongsToTeam,
},
};
};
@@ -7,6 +7,7 @@ export const ZListTeamAvailaiblityScheme = z.object({
endDate: z.string(),
loggedInUsersTz: z.string(),
teamId: z.number().optional(),
searchString: z.string().toLowerCase().optional(),
});
export type TListTeamAvailaiblityScheme = z.infer<typeof ZListTeamAvailaiblityScheme>;