fix: move team availability search to serverside (#17549)
* move search to severside * transform zod stirng to lowercase
This commit is contained in:
@@ -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>
|
||||
|
||||
+48
-2
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user