From ad5d645347cb93f637b13d1defa323a335c1d939 Mon Sep 17 00:00:00 2001 From: Souptik Datta Date: Thu, 29 Aug 2024 22:58:35 +0530 Subject: [PATCH] feat: Implement editable OOO events feature (#15932) * feat: Implement edit ooo feature Signed-off-by: Souptik Datta * refactor: Refactor button text and gap between buttons Signed-off-by: Souptik Datta * fix: Fix entry create and edit edge cases Signed-off-by: Souptik Datta * chore: Change "edit ooo event" modal title Signed-off-by: Souptik Datta * chore: Add tooltips to entry eidt and delete buttons Signed-off-by: Souptik Datta * feat: Reset form on form close event Signed-off-by: Souptik Datta * refactor: Refactor reset-form function Signed-off-by: Souptik Datta * chore: Rename create or edit OOO as suggested Signed-off-by: Souptik Datta * refactor: Refactor component and function names Signed-off-by: Souptik Datta * feat: Improve ooo events email notifications Signed-off-by: Souptik Datta * fix: Fix email templates Signed-off-by: Souptik Datta * feat: Add e2e test for ooo event edit functionality Signed-off-by: Souptik Datta * refactor: Create separate test for edit ooo event Signed-off-by: Souptik Datta * fix: Remove extra user from redirect user configuration test Signed-off-by: Souptik Datta * chore: code refactor * remove log * chore: Update ooo-input-schema uuid data type Signed-off-by: Souptik Datta * fix: Address feedbacks Signed-off-by: Souptik Datta * chore: code splitting and refactor --------- Signed-off-by: Souptik Datta Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com> Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> --- .../my-account/out-of-office/index.tsx | 372 ++---------------- apps/web/playwright/out-of-office.e2e.ts | 95 ++++- apps/web/public/static/locales/en/common.json | 10 +- .../BookingRedirectEmailNotification.tsx | 32 +- .../booking-redirect-notification.ts | 11 +- .../settings/CreateOrEditOutOfOfficeModal.tsx | 243 ++++++++++++ .../settings/OutOfOfficeEntriesList.tsx | 173 ++++++++ .../server/routers/loggedInViewer/_router.tsx | 26 +- .../loggedInViewer/outOfOffice.handler.ts | 131 +++++- .../loggedInViewer/outOfOffice.schema.ts | 1 + 10 files changed, 714 insertions(+), 380 deletions(-) create mode 100644 packages/features/settings/CreateOrEditOutOfOfficeModal.tsx create mode 100644 packages/features/settings/OutOfOfficeEntriesList.tsx diff --git a/apps/web/pages/settings/my-account/out-of-office/index.tsx b/apps/web/pages/settings/my-account/out-of-office/index.tsx index dc8537fc50..b69c3daff8 100644 --- a/apps/web/pages/settings/my-account/out-of-office/index.tsx +++ b/apps/web/pages/settings/my-account/out-of-office/index.tsx @@ -1,35 +1,12 @@ -import { Trans } from "next-i18next"; import { useSearchParams } from "next/navigation"; import { useEffect, useState } from "react"; -import { Controller, useForm, useFormState } from "react-hook-form"; -import dayjs from "@calcom/dayjs"; +import { CreateOrEditOutOfOfficeEntryModal } from "@calcom/features/settings/CreateOrEditOutOfOfficeModal"; +import { OutOfOfficeEntriesList } from "@calcom/features/settings/OutOfOfficeEntriesList"; import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout"; -import { useHasTeamPlan } from "@calcom/lib/hooks/useHasPaidPlan"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery"; -import { - Button, - DateRangePicker, - Dialog, - DialogContent, - DialogFooter, - DialogHeader, - EmptyScreen, - Icon, - Meta, - Select, - showToast, - SkeletonText, - Switch, - TableBody, - TableCell, - TableNew, - TableRow, - TextArea, - UpgradeTeamsBadge, -} from "@calcom/ui"; +import { Button, Icon, Meta, SkeletonText } from "@calcom/ui"; import PageWrapper from "@components/PageWrapper"; @@ -39,328 +16,7 @@ export type BookingRedirectForm = { toTeamUserId: number | null; reasonId: number; notes?: string; -}; - -const CreateOutOfOfficeEntryModal = ({ - openModal, - closeModal, -}: { - openModal: boolean; - closeModal: () => void; -}) => { - const { t } = useLocale(); - const utils = trpc.useUtils(); - - const [selectedReason, setSelectedReason] = useState<{ label: string; value: number } | null>(null); - const [profileRedirect, setProfileRedirect] = useState(false); - const [selectedMember, setSelectedMember] = useState<{ label: string; value: number | null } | null>(null); - - const [dateRange] = useState<{ startDate: Date; endDate: Date }>({ - startDate: dayjs().utc().startOf("d").toDate(), - endDate: dayjs().utc().add(1, "d").endOf("d").toDate(), - }); - - const { hasTeamPlan } = useHasTeamPlan(); - const { data: listMembers } = trpc.viewer.teams.listMembers.useQuery({}); - const me = useMeQuery(); - const memberListOptions: { - value: number | null; - label: string; - }[] = - listMembers - ?.filter((member) => me?.data?.id !== member.id) - .map((member) => ({ - value: member.id || null, - label: member.name || "", - })) || []; - - const { handleSubmit, setValue, control, register } = useForm({ - defaultValues: { - dateRange: { - startDate: dateRange.startDate, - endDate: dateRange.endDate, - }, - offset: dayjs().utcOffset(), - toTeamUserId: null, - reasonId: 1, - }, - }); - - const createOutOfOfficeEntry = trpc.viewer.outOfOfficeCreate.useMutation({ - onSuccess: () => { - showToast(t("success_entry_created"), "success"); - utils.viewer.outOfOfficeEntriesList.invalidate(); - setProfileRedirect(false); - closeModal(); - }, - onError: (error) => { - showToast(t(error.message), "error"); - }, - }); - - const { data: outOfOfficeReasonList } = trpc.viewer.outOfOfficeReasonList.useQuery(); - - const reasonList = [ - ...(outOfOfficeReasonList || []).map((reason) => ({ - label: `${reason.emoji} ${reason.userId === null ? t(reason.reason) : reason.reason}`, - value: reason.id, - })), - ]; - - return ( - - { - event.preventDefault(); - }}> -
{ - createOutOfOfficeEntry.mutate(data); - setValue("toTeamUserId", null); - setValue("notes", ""); - setSelectedReason(null); - setSelectedMember(null); - })}> -
- -
-

{t("dates")}

-
- ( - { - onChange(values); - }} - /> - )} - /> -
-
- - {/* Reason Select */} -
-
-

{t("reason")}

-