From 6df994389bedec9df59b7ce2fb345f35d04cf889 Mon Sep 17 00:00:00 2001 From: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Tue, 22 Oct 2024 03:52:09 +0100 Subject: [PATCH] feat: round robin handover to specific host (#17215) * frontend dialog * handler + fe calling handler * reafctors + start work on fix hosts tests * restore rr * update tests + fixing types * use a getRRHostsToReasign handler + error handle + i18n * typefixes * assert type * fix: adds missing translation * Update roundRobinManualReassignment.ts * Update roundRobinManualReassignment.ts * Update apps/web/components/dialog/ReassignDialog.tsx Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> * Update roundRobinManualReassignment.ts --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: zomars Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> --- apps/web/components/dialog/ReassignDialog.tsx | 134 +++++- apps/web/public/static/locales/en/common.json | 7 +- .../roundRobinManualReassignment.test.ts | 250 ++++++++++ .../roundRobinManualReassignment.ts | 433 ++++++++++++++++++ .../ee/round-robin/roundRobinReassignment.ts | 88 +--- .../ee/round-robin/utils/bookingSelect.ts | 26 ++ .../utils/getDestinationCalendar.ts | 36 ++ .../ee/round-robin/utils/getTeamMembers.ts | 79 ++++ .../server/routers/viewer/teams/_router.tsx | 20 + .../getRoundRobinHostsToReasign.handler.ts | 61 +++ .../getRoundRobinHostsToReasign.schema.ts | 10 + .../roundRobinManualReassign.handler.ts | 31 ++ .../roundRobinManualReassign.schema.ts | 8 + 13 files changed, 1104 insertions(+), 79 deletions(-) create mode 100644 packages/features/ee/round-robin/roundRobinManualReassignment.test.ts create mode 100644 packages/features/ee/round-robin/roundRobinManualReassignment.ts create mode 100644 packages/features/ee/round-robin/utils/bookingSelect.ts create mode 100644 packages/features/ee/round-robin/utils/getDestinationCalendar.ts create mode 100644 packages/features/ee/round-robin/utils/getTeamMembers.ts create mode 100644 packages/trpc/server/routers/viewer/teams/roundRobin/getRoundRobinHostsToReasign.handler.ts create mode 100644 packages/trpc/server/routers/viewer/teams/roundRobin/getRoundRobinHostsToReasign.schema.ts create mode 100644 packages/trpc/server/routers/viewer/teams/roundRobin/roundRobinManualReassign.handler.ts create mode 100644 packages/trpc/server/routers/viewer/teams/roundRobin/roundRobinManualReassign.schema.ts diff --git a/apps/web/components/dialog/ReassignDialog.tsx b/apps/web/components/dialog/ReassignDialog.tsx index d402624448..ebf03e9c84 100644 --- a/apps/web/components/dialog/ReassignDialog.tsx +++ b/apps/web/components/dialog/ReassignDialog.tsx @@ -1,9 +1,24 @@ +import { useAutoAnimate } from "@formkit/auto-animate/react"; import type { Dispatch, SetStateAction } from "react"; +import { useMemo } from "react"; +import { useForm } from "react-hook-form"; +import { classNames } from "@calcom/lib"; import { ErrorCode } from "@calcom/lib/errorCodes"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { Button, Dialog, DialogClose, DialogContent, DialogFooter, showToast } from "@calcom/ui"; +import { + Button, + Form, + Label, + Dialog, + DialogClose, + DialogContent, + DialogFooter, + showToast, + Select, + RadioGroup as RadioArea, +} from "@calcom/ui"; type ReassignDialog = { isOpenDialog: boolean; @@ -12,9 +27,44 @@ type ReassignDialog = { bookingId: number; }; +type FormValues = { + reassignType: "round_robin" | "team_member"; + teamMemberId?: number; +}; + export const ReassignDialog = ({ isOpenDialog, setIsOpenDialog, teamId, bookingId }: ReassignDialog) => { const { t } = useLocale(); const utils = trpc.useUtils(); + const [animationParentRef] = useAutoAnimate({ + duration: 150, + easing: "ease-in-out", + }); + // Were using legacy list members here because we don't currently have an easy way to paginate a select via infinite scroll + const teamMembers = trpc.viewer.teams.getRoundRobinHostsToReassign.useQuery({ + bookingId, + exclude: "fixedHosts", + }); + + const teamMemberOptions = useMemo(() => { + if (teamMembers.isLoading) + return [ + { + label: "Loading...", + value: 0, + }, + ]; + + return teamMembers.data?.map((member) => ({ + label: member.name, + value: member.id, + })); + }, [teamMembers]); + + const form = useForm({ + defaultValues: { + reassignType: "round_robin", + }, + }); const roundRobinReassignMutation = trpc.viewer.teams.roundRobinReassign.useMutation({ onSuccess: async () => { @@ -31,6 +81,33 @@ export const ReassignDialog = ({ isOpenDialog, setIsOpenDialog, teamId, bookingI }, }); + const roundRobinManualReassignMutation = trpc.viewer.teams.roundRobinManualReassign.useMutation({ + onSuccess: async () => { + await utils.viewer.bookings.get.invalidate(); + setIsOpenDialog(false); + showToast(t("booking_reassigned"), "success"); + }, + onError: async (error) => { + if (error.message.includes(ErrorCode.NoAvailableUsersFound)) { + showToast(t("no_available_hosts"), "error"); + } else { + showToast(t(error.message), "error"); + } + }, + }); + + const handleSubmit = (values: FormValues) => { + if (values.reassignType === "round_robin") { + roundRobinReassignMutation.mutate({ teamId, bookingId }); + } else { + if (values.teamMemberId) { + roundRobinManualReassignMutation.mutate({ bookingId, teamMemberId: values.teamMemberId }); + } + } + }; + + const watchedReassignType = form.watch("reassignType"); + return ( {/* TODO add team member reassignment*/} - - - - +
+ { + form.setValue("reassignType", val as "team_member" | "round_robin"); + }} + className={classNames("mt-1 flex flex-col gap-4")}> + + {t("round_robin")} +

{t("round_robin_reassign_description")}

+
+ + {t("team_member_round_robin_reassign")} +

{t("team_member_round_robin_reassign_description")}

+
+
+ + {watchedReassignType === "team_member" && ( +
+ +