* added lockedSMS to future routes * add orgMigrations routes to future * correct metadata * small fix * add orgMigrations to future * Move components to client components * Remove tRPC element from edit user RSC * Get username for meta * Remove suspense query * Remove orgMigrations from app router * Type fix * Revert "Remove suspense query" This reverts commit eadd814f6e4a5d6856d9218342b7909c22fe62c6. * Handle suspenseQuery in app router * User edit page, fetch data server side * Update yarn.lock * Export getFixedT * Set PageWrapper as root layout for settings * Settings Layout accepts strings for shell heading * Add OOO to app router settings * Refactor layout for my-account pages * Remove instances of pages router from my-account * Refactor security pages * Add billing to app router * Add admin API link to layout * Add api keys page * Webhooks WIP * Refactor SettingsHeader to client component * Add webhook pages * Refactor API keys page * Add admin app page * Type fix * fix types * fix developer/webhooks/[id] param value type error * remove unnecessary code * do not pass t prop to CreateNewWebhookButton * fix type errors in webhook-edit-view * fix the remaining type errors * do not use prisma directly in generateMetadata * remove use client if unnecessary * Remove unused shell heading from SettingsLayoutAppDir * improve metadata * fix billing page * fix import in settings/teams * Use next `notFound()` * fix type check * fix type check * remove unused code * Fix calendar setting page * Separate settings pages into route groups * Refactor admin settings pages * Remove meta instance from billing page route * Update settings layoutAppDir * Refactor developer settings pages * Refactor out of office * Refactor my account settings * Refactor admin api page * Refactor security pages * Type fix * fix styling in settings layout --------- Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com> Co-authored-by: Omar López <zomars@me.com> Co-authored-by: Benny Joo <sldisek783@gmail.com>
154 lines
4.6 KiB
TypeScript
154 lines
4.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
|
|
import { InstallAppButton } from "@calcom/app-store/components";
|
|
import {
|
|
SelectedCalendarsSettingsWebWrapper,
|
|
DestinationCalendarSettingsWebWrapper,
|
|
} from "@calcom/atoms/monorepo";
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
import { trpc } from "@calcom/trpc/react";
|
|
import {
|
|
Button,
|
|
EmptyScreen,
|
|
List,
|
|
ShellSubHeading,
|
|
AppSkeletonLoader as SkeletonLoader,
|
|
showToast,
|
|
} from "@calcom/ui";
|
|
|
|
import { QueryCell } from "@lib/QueryCell";
|
|
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
|
|
|
import AppListCard from "@components/AppListCard";
|
|
import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections";
|
|
|
|
type Props = {
|
|
onChanged: () => unknown | Promise<unknown>;
|
|
fromOnboarding?: boolean;
|
|
destinationCalendarId?: string;
|
|
isPending?: boolean;
|
|
};
|
|
|
|
function CalendarList(props: Props) {
|
|
const { t } = useLocale();
|
|
const query = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
|
|
|
|
return (
|
|
<QueryCell
|
|
query={query}
|
|
success={({ data }) => (
|
|
<List>
|
|
{data.items.map((item) => (
|
|
<AppListCard
|
|
title={item.name}
|
|
key={item.name}
|
|
logo={item.logo}
|
|
description={item.description}
|
|
shouldHighlight
|
|
slug={item.slug}
|
|
actions={
|
|
<InstallAppButton
|
|
type={item.type}
|
|
render={(buttonProps) => (
|
|
<Button color="secondary" {...buttonProps}>
|
|
{t("connect")}
|
|
</Button>
|
|
)}
|
|
onChanged={() => props.onChanged()}
|
|
/>
|
|
}
|
|
/>
|
|
))}
|
|
</List>
|
|
)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function CalendarListContainer(props: { heading?: boolean; fromOnboarding?: boolean }) {
|
|
const { t } = useLocale();
|
|
const { heading = true, fromOnboarding } = props;
|
|
const { error, setQuery: setError } = useRouterQuery("error");
|
|
|
|
useEffect(() => {
|
|
if (error === "account_already_linked") {
|
|
showToast(t(error), "error", { id: error });
|
|
setError(undefined);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
const utils = trpc.useUtils();
|
|
const onChanged = () =>
|
|
Promise.allSettled([
|
|
utils.viewer.integrations.invalidate(
|
|
{ variant: "calendar", onlyInstalled: true },
|
|
{
|
|
exact: true,
|
|
}
|
|
),
|
|
utils.viewer.connectedCalendars.invalidate(),
|
|
]);
|
|
const query = trpc.viewer.connectedCalendars.useQuery();
|
|
const installedCalendars = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: true });
|
|
const mutation = trpc.viewer.setDestinationCalendar.useMutation({
|
|
onSuccess: () => {
|
|
utils.viewer.connectedCalendars.invalidate();
|
|
},
|
|
});
|
|
return (
|
|
<QueryCell
|
|
query={query}
|
|
customLoader={<SkeletonLoader />}
|
|
success={({ data }) => {
|
|
return (
|
|
<>
|
|
{!!data.connectedCalendars.length || !!installedCalendars.data?.items.length ? (
|
|
<>
|
|
{heading && (
|
|
<>
|
|
<DestinationCalendarSettingsWebWrapper />
|
|
<SelectedCalendarsSettingsWebWrapper
|
|
onChanged={onChanged}
|
|
fromOnboarding={fromOnboarding}
|
|
destinationCalendarId={data.destinationCalendar?.externalId}
|
|
isPending={mutation.isPending}
|
|
/>
|
|
</>
|
|
)}
|
|
</>
|
|
) : fromOnboarding ? (
|
|
<>
|
|
{!!query.data?.connectedCalendars.length && (
|
|
<ShellSubHeading
|
|
className="mt-4"
|
|
title={<SubHeadingTitleWithConnections title={t("connect_additional_calendar")} />}
|
|
/>
|
|
)}
|
|
<CalendarList onChanged={onChanged} />
|
|
</>
|
|
) : (
|
|
<EmptyScreen
|
|
Icon="calendar"
|
|
headline={t("no_category_apps", {
|
|
category: t("calendar").toLowerCase(),
|
|
})}
|
|
description={t(`no_category_apps_description_calendar`)}
|
|
buttonRaw={
|
|
<Button
|
|
color="secondary"
|
|
data-testid="connect-calendar-apps"
|
|
href="/apps/categories/calendar">
|
|
{t(`connect_calendar_apps`)}
|
|
</Button>
|
|
}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}}
|
|
/>
|
|
);
|
|
}
|