import { useState } from "react"; import { Controller, useForm } from "react-hook-form"; import dayjs from "@calcom/dayjs"; import { classNames } from "@calcom/lib"; import { useDebounce } from "@calcom/lib/hooks/useDebounce"; import { useHasTeamPlan } from "@calcom/lib/hooks/useHasPaidPlan"; import { useInViewObserver } from "@calcom/lib/hooks/useInViewObserver"; 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, Select, showToast, Switch, TextArea, UpgradeTeamsBadge, Label, Input, } from "@calcom/ui"; export type BookingRedirectForm = { dateRange: { startDate: Date; endDate: Date }; offset: number; toTeamUserId: number | null; reasonId: number; notes?: string; uuid?: string | null; }; type Option = { value: number; label: string }; export const CreateOrEditOutOfOfficeEntryModal = ({ openModal, closeModal, currentlyEditingOutOfOfficeEntry, }: { openModal: boolean; closeModal: () => void; currentlyEditingOutOfOfficeEntry: BookingRedirectForm | null; }) => { const { t } = useLocale(); const utils = trpc.useUtils(); const [searchText, setSearchText] = useState(""); const debouncedSearch = useDebounce(searchText, 500); const members = trpc.viewer.teams.legacyListMembers.useInfiniteQuery( { limit: 10, searchText: debouncedSearch }, { enabled: true, getNextPageParam: (lastPage) => lastPage.nextCursor, } ); const me = useMeQuery(); const memberListOptions: { value: number; label: string; avatarUrl: string | null; }[] = members?.data?.pages .flatMap((page) => page.members) ?.filter((member) => me?.data?.id !== member.id) .map((member) => ({ value: member.id, label: member.name || member.username || "", avatarUrl: member.avatarUrl, })) || []; const { ref: observerRef } = useInViewObserver(() => { if (members.hasNextPage && !members.isFetching) { members.fetchNextPage(); } }, document.querySelector('[role="dialog"]')); 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, })); const [profileRedirect, setProfileRedirect] = useState(!!currentlyEditingOutOfOfficeEntry?.toTeamUserId); const { hasTeamPlan } = useHasTeamPlan(); const { handleSubmit, setValue, control, register, watch, formState: { isSubmitting }, } = useForm({ defaultValues: currentlyEditingOutOfOfficeEntry ? currentlyEditingOutOfOfficeEntry : { dateRange: { startDate: dayjs().startOf("d").toDate(), endDate: dayjs().startOf("d").add(2, "d").toDate(), }, offset: dayjs().utcOffset(), toTeamUserId: null, reasonId: 1, }, }); const watchedTeamUserId = watch("toTeamUserId"); const createOrEditOutOfOfficeEntry = trpc.viewer.outOfOfficeCreateOrUpdate.useMutation({ onSuccess: () => { showToast( currentlyEditingOutOfOfficeEntry ? t("success_edited_entry_out_of_office") : t("success_entry_created"), "success" ); utils.viewer.outOfOfficeEntriesList.invalidate(); closeModal(); }, onError: (error) => { showToast(t(error.message), "error"); }, }); return ( { if (!open) { closeModal(); } }}> { event.preventDefault(); }}>
{ if (!data.dateRange.endDate) { showToast(t("end_date_not_selected"), "error"); } else { createOrEditOutOfOfficeEntry.mutate(data); } })}>

{t("dates")}

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

{t("reason")}

( className="mb-0 mt-1 text-white" name="reason" data-testid="reason_select" value={reasonList.find((reason) => reason.value === value)} placeholder={t("ooo_select_reason")} options={reasonList} onChange={(selectedOption) => { if (selectedOption?.value) { onChange(selectedOption.value); } }} /> )} />
{/* Notes input */}

{t("notes")}