Files
calendar/packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx
T
luzpazandGitHub 197a7ba6e9 fix: typos in packages/features (#19220)
Found via `codespell -q 3 -S "*.svg,./apps/web/public/static/locales,./packages/app-store/stripepayment/lib/currencyOptions.ts,./packages/lib/freeEmailDomainCheck/freeEmailDomains.ts" -L afterall,atleast,datea,fo,incase,ist,nam,notin,optionel,perview,reccuring`

Closes #19219
2025-02-21 05:14:57 -03:00

198 lines
7.7 KiB
TypeScript

"use client";
import { Trans } from "next-i18next";
import { useState } from "react";
import { useFormState } from "react-hook-form";
import dayjs from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import {
Button,
EmptyScreen,
Icon,
showToast,
SkeletonText,
TableBody,
TableCell,
TableNew,
TableRow,
Tooltip,
} from "@calcom/ui";
import CreateNewOutOfOfficeEntryButton from "./CreateNewOutOfOfficeEntryButton";
import { CreateOrEditOutOfOfficeEntryModal } from "./CreateOrEditOutOfOfficeModal";
import type { BookingRedirectForm } from "./CreateOrEditOutOfOfficeModal";
export const OutOfOfficeEntriesList = () => {
const { t } = useLocale();
const utils = trpc.useUtils();
const { data, isPending } = trpc.viewer.outOfOfficeEntriesList.useQuery();
const deleteOutOfOfficeEntryMutation = trpc.viewer.outOfOfficeEntryDelete.useMutation({
onSuccess: () => {
showToast(t("success_deleted_entry_out_of_office"), "success");
utils.viewer.outOfOfficeEntriesList.invalidate();
useFormState;
},
onError: () => {
showToast(`An error occurred`, "error");
},
});
const [currentlyEditingOutOfOfficeEntry, setCurrentlyEditingOutOfOfficeEntry] =
useState<BookingRedirectForm | null>(null);
const [openModal, setOpenModal] = useState(false);
const editOutOfOfficeEntry = (entry: BookingRedirectForm) => {
setCurrentlyEditingOutOfOfficeEntry(entry);
setOpenModal(true);
};
if (data === null || data?.length === 0 || (data === undefined && !isPending))
return (
<EmptyScreen
className="mt-6"
headline={t("ooo_empty_title")}
description={t("ooo_empty_description")}
buttonRaw={<CreateNewOutOfOfficeEntryButton size="sm" />}
customIcon={
<div className="mt-4 h-[102px]">
<div className="flex h-full flex-col items-center justify-center p-2 md:mt-0 md:p-0">
<div className="relative">
<div className="dark:bg-darkgray-50 absolute -left-3 -top-3 -z-20 h-[70px] w-[70px] -rotate-[24deg] rounded-3xl border-2 border-[#e5e7eb] p-8 opacity-40 dark:opacity-80">
<div className="w-12" />
</div>
<div className="dark:bg-darkgray-50 absolute -top-3 left-3 -z-10 h-[70px] w-[70px] rotate-[24deg] rounded-3xl border-2 border-[#e5e7eb] p-8 opacity-60 dark:opacity-90">
<div className="w-12" />
</div>
<div className="dark:bg-darkgray-50 text-inverted relative z-0 flex h-[70px] w-[70px] items-center justify-center rounded-3xl border-2 border-[#e5e7eb] bg-white">
<Icon name="clock" size={28} />
<div className="dark:bg-darkgray-50 absolute right-4 top-5 h-[12px] w-[12px] rotate-[56deg] bg-white text-lg font-bold" />
<span className="absolute right-4 top-3 font-sans text-sm font-extrabold">z</span>
</div>
</div>
</div>
</div>
}
/>
);
return (
<div className="border-subtle mt-6 rounded-lg border">
<TableNew className="border-0">
<TableBody>
{data?.map((item) => (
<TableRow key={item.id} data-testid={`table-redirect-${item.toUser?.username || "n-a"}`}>
<TableCell className="flex flex-row justify-between p-4">
<div className="flex flex-row items-center">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-gray-50">
{item?.reason?.emoji || "🏝️"}
</div>
<div className="ml-2 flex flex-col">
<p className="px-2 font-bold">
{dayjs.utc(item.start).format("ll")} - {dayjs.utc(item.end).format("ll")}
</p>
<p className="px-2">
{item.toUser?.username ? (
<Trans
i18nKey="ooo_forwarding_to"
values={{
username: item.toUser?.username,
}}
components={{
span: <span className="text-subtle font-bold" />,
}}
/>
) : (
<>{t("ooo_not_forwarding")}</>
)}
</p>
{item.notes && (
<p className="px-2">
<span className="text-subtle">{t("notes")}: </span>
<span data-testid={`ooo-entry-note-${item.toUser?.username || "n-a"}`}>
{item.notes}
</span>
</p>
)}
</div>
</div>
<div className="flex flex-row items-center gap-x-2">
<Tooltip content={t("edit")}>
<Button
className="self-center rounded-lg border"
type="button"
color="secondary"
variant="icon"
data-testid={`ooo-edit-${item.toUser?.username || "n-a"}`}
StartIcon="pencil"
onClick={() => {
const offset = dayjs().utcOffset();
const outOfOfficeEntryData: BookingRedirectForm = {
uuid: item.uuid,
dateRange: {
startDate: dayjs(item.start).subtract(offset, "minute").toDate(),
endDate: dayjs(item.end).subtract(offset, "minute").startOf("d").toDate(),
},
offset,
toTeamUserId: item.toUserId,
reasonId: item.reason?.id ?? 1,
notes: item.notes ?? undefined,
};
editOutOfOfficeEntry(outOfOfficeEntryData);
}}
/>
</Tooltip>
<Tooltip content={t("delete")}>
<Button
className="self-center rounded-lg border"
type="button"
color="destructive"
variant="icon"
disabled={deleteOutOfOfficeEntryMutation.isPending}
StartIcon="trash-2"
onClick={() => {
deleteOutOfOfficeEntryMutation.mutate({ outOfOfficeUid: item.uuid });
}}
/>
</Tooltip>
</div>
</TableCell>
</TableRow>
))}
{isPending && (
<>
{new Array(2).fill(0).map((_, index) => (
<TableRow key={index}>
<TableCell>
<SkeletonText className="h-12 w-full" />
</TableCell>
</TableRow>
))}
</>
)}
{!isPending && (data === undefined || data.length === 0) && (
<TableRow>
<TableCell colSpan={6} className="text-center">
<p className="text-subtle text-sm">{t("no_redirects_found")}</p>
</TableCell>
</TableRow>
)}
</TableBody>
</TableNew>
{openModal && (
<CreateOrEditOutOfOfficeEntryModal
openModal={openModal}
closeModal={() => {
setOpenModal(false);
setCurrentlyEditingOutOfOfficeEntry(null);
}}
currentlyEditingOutOfOfficeEntry={currentlyEditingOutOfOfficeEntry}
/>
)}
</div>
);
};