diff --git a/apps/web/pages/bookings/[status].tsx b/apps/web/pages/bookings/[status].tsx index ab7a348568..2277a195cd 100644 --- a/apps/web/pages/bookings/[status].tsx +++ b/apps/web/pages/bookings/[status].tsx @@ -5,7 +5,7 @@ import { Fragment } from "react"; import { z } from "zod"; import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components"; -import BookingLayout, { useFilterStore } from "@calcom/features/bookings/layout/BookingLayout"; +import BookingLayout from "@calcom/features/bookings/layout/BookingLayout"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { RouterInputs, RouterOutputs, trpc } from "@calcom/trpc/react"; import { Alert, Button, EmptyScreen, Icon } from "@calcom/ui"; @@ -42,7 +42,6 @@ const querySchema = z.object({ }); export default function Bookings() { - // const selectedUsers = useFilterStore((state) => state.selectedUsers); const router = useRouter(); const { status } = router.isReady ? querySchema.parse(router.query) : { status: "upcoming" as const }; const { t } = useLocale(); diff --git a/packages/features/bookings/components/TeamsMemberFilter.tsx b/packages/features/bookings/components/TeamsMemberFilter.tsx index 520b80107e..3fff594622 100644 --- a/packages/features/bookings/components/TeamsMemberFilter.tsx +++ b/packages/features/bookings/components/TeamsMemberFilter.tsx @@ -1,27 +1,15 @@ import { Fragment } from "react"; -import shallow from "zustand/shallow"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { RouterOutputs, trpc } from "@calcom/trpc/react"; +import { trpc } from "@calcom/trpc/react"; import { AnimatedPopover, Avatar } from "@calcom/ui"; -import { useFilterStore } from "../layout/BookingLayout"; - -export type ITeamMemberFilters = RouterOutputs["viewer"]["teams"]["listTeamsandMembers"]; -export type ITeamMemberFilter = ITeamMemberFilters[0]; +import { useFilterQuery } from "../lib/useFilterQuery"; export const TeamsMemberFilter = () => { - const { selectedUsers, pushSelectedUser, removeSelectedUser } = useFilterStore( - (state) => ({ - selectedUsers: state.selectedUsers, - pushSelectedUser: state.pushSelectedUser, - removeSelectedUser: state.removeSelectedUser, - }), - shallow - ); const { t } = useLocale(); + const { data: query, pop, push } = useFilterQuery(); const { data } = trpc.viewer.teams.listTeamsandMembers.useQuery(); - // Will be handled up the tree to redirect if (data?.length === 0) return null; @@ -48,17 +36,15 @@ export const TeamsMemberFilter = () => { selected.id === team.id && selected.user.id === member.user.id - ).length > 0 - } name={`${member.team.id}-${member.user.id}`} + checked={query.userIds?.includes(member.user.id) && query.teamIds?.includes(team.id)} onChange={(e) => { if (e.target.checked) { - pushSelectedUser({ id: team.id, teamName: team.name, user: member.user }); + push("userIds", member.user.id); + push("teamIds", team.id); } else if (!e.target.checked) { - removeSelectedUser(member.user.id); + pop("userIds", member.user.id); + pop("teamIds", team.id); } }} className="text-primary-600 focus:ring-primary-500 inline-flex h-4 w-4 place-self-center justify-self-end rounded border-gray-300 " diff --git a/packages/features/bookings/layout/BookingLayout.tsx b/packages/features/bookings/layout/BookingLayout.tsx index 7654e00941..b1c415e037 100644 --- a/packages/features/bookings/layout/BookingLayout.tsx +++ b/packages/features/bookings/layout/BookingLayout.tsx @@ -1,11 +1,10 @@ import React, { ComponentProps } from "react"; -import create from "zustand"; import { HorizontalTabs, Shell } from "@calcom/ui"; import { VerticalTabItemProps, HorizontalTabItemProps } from "@calcom/ui/v2"; -import { EventTypeFilter, IEventTypeFilter } from "../components/EventTypeFilter"; -import { TeamsMemberFilter, ITeamMemberFilter } from "../components/TeamsMemberFilter"; +import { EventTypeFilter} from "../components/EventTypeFilter"; +import { TeamsMemberFilter } from "../components/TeamsMemberFilter"; const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [ { @@ -30,51 +29,6 @@ const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [ }, ]; -interface BookingLayoutStoreState { - selectedEventTypes: IEventTypeFilter[]; - selectedUsers: { - id: number; - teamName: string; - user: ITeamMemberFilter["members"][0]["user"]; - }[]; -} -interface BookingLayoutStoreActions { - setSelectedEventTypes: (eventTypes: IEventTypeFilter[]) => void; - setSelectedUsers: (users: BookingLayoutStoreState["selectedUsers"]) => void; - pushSelectedEventType: (eventType: IEventTypeFilter) => void; - pushSelectedUser: (user: BookingLayoutStoreState["selectedUsers"][0]) => void; - removeSelectedEventType: (eventType: IEventTypeFilter) => void; - removeSelectedUser: (userId: number) => void; - clearState: () => void; -} - -// Since this is a layout i thought i'd be best to implement some "Global" component state -export const useFilterStore = create((set) => ({ - selectedEventTypes: [], - selectedUsers: [], - setSelectedEventTypes: (eventTypes) => set({ selectedEventTypes: eventTypes }), - setSelectedUsers: (users) => set({ selectedUsers: users }), - pushSelectedEventType: (eventType) => { - set((state) => ({ selectedEventTypes: [...state.selectedEventTypes, eventType] })); - }, - pushSelectedUser: (user) => { - set((state) => ({ selectedUsers: [...state.selectedUsers, user] })); - }, - removeSelectedEventType: (eventType) => { - set((state) => ({ - selectedEventTypes: state.selectedEventTypes.filter((type) => type.id !== eventType.id), - })); - }, - removeSelectedUser: (userId) => { - set((state) => { - return { - selectedUsers: state.selectedUsers.filter((selected) => selected.user.id !== userId), - }; - }); - }, - clearState: () => set({ selectedEventTypes: [], selectedUsers: [] }), -})); - export default function BookingLayout({ children, ...rest @@ -85,8 +39,8 @@ export default function BookingLayout({
- {/* - */} + +
{children}
diff --git a/packages/features/bookings/lib/useFilterQuery.tsx b/packages/features/bookings/lib/useFilterQuery.tsx new file mode 100644 index 0000000000..04429f3ede --- /dev/null +++ b/packages/features/bookings/lib/useFilterQuery.tsx @@ -0,0 +1,56 @@ +import { useRouter } from "next/router"; +import z from "zod"; + +// Take string and return number +export const queryNumberSchema = z.preprocess( + (a) => parseInt(z.string().parse(a), 10), + z.number().positive().array() +); +// Take array as a string and return zod array +export const queryNumberArray = z.preprocess( + (a) => + z + .string() + .parse(a) + .split(",") + .map((a) => parseInt(a, 10)), + z.number().positive().array() +); +// Take string and return return zod string array - comma separated +export const queryStringArray = z.preprocess((a) => z.string().parse(a).split(","), z.string().array()); + +const filterQuerySchema = z.object({ + teamIds: queryNumberArray.optional(), + status: queryStringArray.optional(), // Not used right now but could be implemented when/if we move status to a filter + userIds: queryNumberArray.optional(), + eventTypeIds: queryNumberArray.optional(), +}); + +type FilterQuerySchema = z.infer; +type Keys = keyof FilterQuerySchema; + +export function useFilterQuery() { + const router = useRouter(); + const data = filterQuerySchema.parse(router.query); + + // push item to key of filterQuerySchema and set new query params in url + + const push = (key: Required, item: string | number) => { + const newData = { ...data }; + const keyData = newData[key] ?? []; + // @typescript-eslint/ban-ts-comment + // @ts-ignore + newData[key] = [...keyData, item]; + router.push({ query: newData }); + }; + + const pop = (key: Required, item: string | number) => { + const newData = { ...data }; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore idk how to fix this ? + newData[key] = newData[key].filter((a) => a !== item); + router.push({ query: newData }); + }; + + return { data, push, pop }; +} diff --git a/packages/features/package.json b/packages/features/package.json index c0e2152ca0..0d220f2ce4 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -7,7 +7,6 @@ "main": "index.ts", "dependencies": { "@lexical/react": "^0.5.0", - "lexical": "^0.5.0", - "zustand": "^4.1.5" + "lexical": "^0.5.0" } }