fix: improve filters at /bookings (#18581)
* fix: improve filters at /bookings * fix type
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { Fragment, useMemo, useState } from "react";
|
||||
|
||||
import {
|
||||
FilterCheckboxField,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { FilterSearchField } from "@calcom/ui";
|
||||
import { AnimatedPopover, Divider, Icon } from "@calcom/ui";
|
||||
|
||||
import { groupBy } from "../groupBy";
|
||||
@@ -33,6 +34,7 @@ export const EventTypeFilter = () => {
|
||||
const { t } = useLocale();
|
||||
const { data: user } = useSession();
|
||||
const { data: query, pushItemToKey, removeItemByKeyAndValue, removeAllQueryParams } = useFilterQuery();
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const eventTypes = trpc.viewer.eventTypes.listWithTeam.useQuery(undefined, {
|
||||
enabled: !!user,
|
||||
@@ -68,6 +70,11 @@ export const EventTypeFilter = () => {
|
||||
<AnimatedPopover text={getTextForPopover()} prefix={`${t("event_type")}: `}>
|
||||
{!isEmpty ? (
|
||||
<FilterCheckboxFieldsContainer>
|
||||
<FilterSearchField
|
||||
placeholder={t("search")}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
<FilterCheckboxField
|
||||
id="all"
|
||||
icon={<Icon name="link" className="h-4 w-4" />}
|
||||
@@ -82,20 +89,22 @@ export const EventTypeFilter = () => {
|
||||
<div className="text-subtle px-4 py-2 text-xs font-medium uppercase leading-none">
|
||||
{teamName === "user_own_event_types" ? t("individual") : teamName}
|
||||
</div>
|
||||
{groupedEventTypes[teamName].map((eventType) => (
|
||||
<FilterCheckboxField
|
||||
key={eventType.id}
|
||||
checked={query.eventTypeIds?.includes(eventType.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
pushItemToKey("eventTypeIds", eventType.id);
|
||||
} else if (!e.target.checked) {
|
||||
removeItemByKeyAndValue("eventTypeIds", eventType.id);
|
||||
}
|
||||
}}
|
||||
label={eventType.title}
|
||||
/>
|
||||
))}
|
||||
{groupedEventTypes[teamName]
|
||||
.filter((eventType) => eventType.title.toLowerCase().includes(search.toLowerCase()))
|
||||
.map((eventType) => (
|
||||
<FilterCheckboxField
|
||||
key={eventType.id}
|
||||
checked={query.eventTypeIds?.includes(eventType.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
pushItemToKey("eventTypeIds", eventType.id);
|
||||
} else if (!e.target.checked) {
|
||||
removeItemByKeyAndValue("eventTypeIds", eventType.id);
|
||||
}
|
||||
}}
|
||||
label={eventType.title}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</FilterCheckboxFieldsContainer>
|
||||
|
||||
@@ -24,7 +24,7 @@ export const PeopleFilter = () => {
|
||||
const debouncedSearch = useDebounce(searchText, 500);
|
||||
|
||||
const queryMembers = trpc.viewer.teams.legacyListMembers.useInfiniteQuery(
|
||||
{ limit: 10, searchText: debouncedSearch },
|
||||
{ limit: 10, searchText: debouncedSearch, includeEmail: true },
|
||||
{
|
||||
enabled: true,
|
||||
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ZGetUserConnectedAppsInputSchema } from "./getUserConnectedApps.schema"
|
||||
import { ZHasEditPermissionForUserSchema } from "./hasEditPermissionForUser.schema";
|
||||
import { ZInviteMemberInputSchema } from "./inviteMember/inviteMember.schema";
|
||||
import { ZInviteMemberByTokenSchemaInputSchema } from "./inviteMemberByToken.schema";
|
||||
import { ZListMembersInputSchema as ZLegegacyListMembers } from "./legacyListMembers.schema";
|
||||
import { ZLegacyListMembersInputSchema } from "./legacyListMembers.schema";
|
||||
import { ZGetListSchema } from "./list.schema";
|
||||
import { ZListMembersInputSchema } from "./listMembers.schema";
|
||||
import { hasTeamPlan } from "./procedures/hasTeamPlan";
|
||||
@@ -121,7 +121,7 @@ export const viewerTeamsRouter = router({
|
||||
const handler = await importHandler(namespaced("listMembers"), () => import("./listMembers.handler"));
|
||||
return handler(opts);
|
||||
}),
|
||||
legacyListMembers: authedProcedure.input(ZLegegacyListMembers).query(async (opts) => {
|
||||
legacyListMembers: authedProcedure.input(ZLegacyListMembersInputSchema).query(async (opts) => {
|
||||
const handler = await importHandler(
|
||||
namespaced("legacyListMembers"),
|
||||
() => import("./legacyListMembers.handler")
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import type { Prisma } from "@prisma/client";
|
||||
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import type { TListMembersInputSchema } from "./legacyListMembers.schema";
|
||||
import type { TLegacyListMembersInputSchema } from "./legacyListMembers.schema";
|
||||
|
||||
type ListMembersOptions = {
|
||||
ctx: {
|
||||
user: NonNullable<TrpcSessionUser>;
|
||||
prisma: PrismaClient;
|
||||
};
|
||||
input: TListMembersInputSchema;
|
||||
input: TLegacyListMembersInputSchema;
|
||||
};
|
||||
|
||||
export const legacyListMembers = async ({ ctx, input }: ListMembersOptions) => {
|
||||
@@ -57,6 +59,15 @@ export const legacyListMembers = async ({ ctx, input }: ListMembersOptions) => {
|
||||
};
|
||||
}
|
||||
|
||||
const searchTextClauses: Prisma.UserWhereInput[] = [
|
||||
{ name: { contains: input.searchText, mode: "insensitive" } },
|
||||
{ username: { contains: input.searchText, mode: "insensitive" } },
|
||||
];
|
||||
|
||||
if (input.includeEmail) {
|
||||
searchTextClauses.push({ email: { contains: input.searchText, mode: "insensitive" } });
|
||||
}
|
||||
|
||||
// Fetch unique users through memberships
|
||||
const memberships = await prisma.membership.findMany({
|
||||
where: {
|
||||
@@ -64,10 +75,7 @@ export const legacyListMembers = async ({ ctx, input }: ListMembersOptions) => {
|
||||
teamId: { in: teamsToQuery },
|
||||
user: input.searchText?.trim()?.length
|
||||
? {
|
||||
OR: [
|
||||
{ name: { contains: input.searchText, mode: "insensitive" } },
|
||||
{ username: { contains: input.searchText, mode: "insensitive" } },
|
||||
],
|
||||
OR: searchTextClauses,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
@@ -80,6 +88,7 @@ export const legacyListMembers = async ({ ctx, input }: ListMembersOptions) => {
|
||||
name: true,
|
||||
username: true,
|
||||
avatarUrl: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,4 +7,9 @@ export const ZListMembersInputSchema = z.object({
|
||||
cursor: z.number().nullish(),
|
||||
});
|
||||
|
||||
export const ZLegacyListMembersInputSchema = ZListMembersInputSchema.extend({
|
||||
includeEmail: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type TListMembersInputSchema = z.infer<typeof ZListMembersInputSchema>;
|
||||
export type TLegacyListMembersInputSchema = z.infer<typeof ZLegacyListMembersInputSchema>;
|
||||
|
||||
Reference in New Issue
Block a user