chore: App router migration - (/more, /maintenance, /connect-and-join, /upgrade) finish migration (#16497)

* more: extract client component into /modules folder

* maintenance: extract client component into /modules folder

* upgrade: extract client component into /modules folder

* improve WithLayout wrapper

* connect-and-join: extract client component into /modules folder

* add env vars
This commit is contained in:
Benny Joo authored and GitHub committed 2024-09-06 17:22:05 +00:00
1 parent 7bfad11ff9
commit d4b0516235
17 files changed
+259 -197

No files matched your search

+4
View File
@@ -357,6 +357,10 @@ APP_ROUTER_AUTH_SAML_ENABLED=0
APP_ROUTER_AUTH_ERROR_ENABLED=0
APP_ROUTER_AUTH_PLATFORM_ENABLED=0
APP_ROUTER_AUTH_OAUTH2_ENABLED=0
APP_ROUTER_MORE_ENABLED=0
APP_ROUTER_MAINTENANCE_ENABLED=0
APP_ROUTER_UPGRADE_ENABLED=0
APP_ROUTER_CONNECT_AND_JOIN_ENABLED=0
# disable setry server source maps
SENTRY_DISABLE_SERVER_WEBPACK_PLUGIN=1
+4
View File
@@ -28,6 +28,10 @@ const ROUTES: [URLPattern, boolean][] = [
["/bookings/:status", process.env.APP_ROUTER_BOOKINGS_STATUS_ENABLED === "1"] as const,
["/video/:path*", process.env.APP_ROUTER_VIDEO_ENABLED === "1"] as const,
["/teams", process.env.APP_ROUTER_TEAMS_ENABLED === "1"] as const,
["/more", process.env.APP_ROUTER_MORE_ENABLED === "1"] as const,
["/maintenance", process.env.APP_ROUTER_MAINTENANCE_ENABLED === "1"] as const,
["/upgrade", process.env.APP_ROUTER_UPGRADE_ENABLED === "1"] as const,
["/connect-and-join", process.env.APP_ROUTER_CONNECT_AND_JOIN_ENABLED === "1"] as const,
["/availability", process.env.APP_ROUTER_AVAILABILITY_ENABLED === "1"] as const,
].map(([pathname, enabled]) => [
new URLPattern({
+10 -1
View File
@@ -1,4 +1,13 @@
import LegacyPage from "@pages/connect-and-join";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import LegacyPage from "~/connect-and-join/connect-and-join-view";
export const generateMetadata = async () => {
return await _generateMetadata(
() => "Connect and Join",
() => ""
);
};
export default WithLayout({ getLayout: null, Page: LegacyPage })<"P">;
+3 -2
View File
@@ -1,12 +1,13 @@
import LegacyPage from "@pages/maintenance";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { APP_NAME } from "@calcom/lib/constants";
import LegacyPage from "~/maintenance/maintenance-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => `${t("under_maintenance")}`,
(t) => t("under_maintenance"),
(t) => t("under_maintenance_description", { appName: APP_NAME })
);
+10 -1
View File
@@ -1,4 +1,13 @@
import Page from "@pages/more";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import Page from "~/more/more-page-view";
export const generateMetadata = async () => {
return await _generateMetadata(
() => "More",
() => ""
);
};
export default WithLayout({ getLayout: null, Page })<"P">;
+12
View File
@@ -0,0 +1,12 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import LegacyPage from "~/upgrade/upgrade-view";
export const generateMetadata = async () =>
await _generateMetadata(
() => "Upgrade",
() => ""
);
export default WithLayout({ getLayout: null, Page: LegacyPage })<"P">;
+3 -1
View File
@@ -11,6 +11,7 @@ type WithLayoutParams<T extends Record<string, any>> = {
Page?: (props: T) => React.ReactElement | null;
getData?: (arg: GetServerSidePropsContext) => Promise<T | undefined>;
isBookingPage?: boolean;
requiresLicense?: boolean;
};
export function WithLayout<T extends Record<string, any>>({
@@ -18,6 +19,7 @@ export function WithLayout<T extends Record<string, any>>({
getData,
Page,
isBookingPage,
requiresLicense,
}: WithLayoutParams<T>) {
return async <P extends "P" | "L">(p: P extends "P" ? PageProps : LayoutProps) => {
const h = headers();
@@ -33,7 +35,7 @@ export function WithLayout<T extends Record<string, any>>({
return (
<PageWrapper
getLayout={getLayout}
requiresLicense={false}
requiresLicense={requiresLicense || !!(Page && "requiresLicense" in Page && Page.requiresLicense)}
nonce={nonce}
themeBasis={null}
isBookingPage={isBookingPage || !!(Page && "isBookingPage" in Page && Page.isBookingPage)}
@@ -0,0 +1,90 @@
"use client";
import { useSession } from "next-auth/react";
import { Trans } from "next-i18next";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { getQueryParam } from "@calcom/features/bookings/Booker/utils/query-param";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { TRPCClientError } from "@calcom/trpc/react";
import { Button, EmptyScreen, Alert } from "@calcom/ui";
function ConnectAndJoin() {
const { t } = useLocale();
const router = useRouter();
const token = getQueryParam("token");
const [meetingUrl, setMeetingUrl] = useState<string | null>(null);
const [errorMessage, setErrorMessage] = useState<string | undefined>();
const session = useSession();
const isUserPartOfOrg = session.status === "authenticated" && !!session.data.user?.org;
const mutation = trpc.viewer.connectAndJoin.useMutation({
onSuccess: (res) => {
if (res.meetingUrl && !res.isBookingAlreadyAcceptedBySomeoneElse) {
router.push(res.meetingUrl);
} else if (res.isBookingAlreadyAcceptedBySomeoneElse && res.meetingUrl) {
setMeetingUrl(res.meetingUrl);
}
},
onError: (err) => {
console.log("err", err, err instanceof TRPCClientError);
if (err instanceof TRPCClientError) {
setErrorMessage(t(err.message));
} else {
setErrorMessage(t("something_went_wrong"));
}
},
});
if (session.status === "loading") return <p>{t("loading")}</p>;
if (!token) return <p>{t("token_not_found")}</p>;
return (
<div className="mx-8 mt-12 block items-start sm:flex">
{session ? (
<EmptyScreen
headline={t("instant_tab_title")}
Icon="phone-call"
description={t("uprade_to_create_instant_bookings")}
buttonRaw={
<div className="flex flex-col items-center justify-center gap-4">
{meetingUrl ? (
<div className="text-default flex flex-col items-center gap-2 text-center text-sm font-normal">
<Trans i18nKey="some_other_host_already_accepted_the_meeting">
Some other host already accepted the meeting. Do you still want to join?
<Link className="inline-block cursor-pointer underline" href={meetingUrl}>
Continue to Meeting
</Link>
</Trans>
</div>
) : (
<Button
loading={mutation.isPending}
tooltip={isUserPartOfOrg ? t("join_meeting") : t("not_part_of_org")}
disabled={!isUserPartOfOrg}
onClick={() => {
mutation.mutate({ token });
}}>
{t("join_meeting")}
</Button>
)}
{errorMessage && <Alert severity="error" message={errorMessage} />}
</div>
}
/>
) : (
<div>{t("you_must_be_logged_in_to", { url: WEBAPP_URL })}</div>
)}
</div>
);
}
ConnectAndJoin.requiresLicense = true;
export default ConnectAndJoin;
@@ -0,0 +1,25 @@
"use client";
import Head from "next/head";
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
import { Button } from "@calcom/ui";
export default function MaintenancePage() {
return (
<div className="bg-subtle flex h-screen">
<Head>
<title>Under Maintenance | {APP_NAME}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="bg-default m-auto rounded-md p-10 text-right ltr:text-left">
<h1 className="text-emphasis text-2xl font-medium">Down for maintenance</h1>
<p className="text-default mb-6 mt-4 max-w-2xl text-sm">
The Cal.com team are performing scheduled maintenance. If you have any questions, please contact
support.
</p>
<Button href={`${WEBSITE_URL}/support`}>Contact Support</Button>
</div>
</div>
);
}
+16
View File
@@ -0,0 +1,16 @@
"use client";
import Shell, { MobileNavigationMoreItems } from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
export default function MorePage() {
const { t } = useLocale();
return (
<Shell hideHeadingOnMobile>
<div className="max-w-screen-lg">
<MobileNavigationMoreItems />
<p className="text-subtle mt-6 text-xs leading-tight md:hidden">{t("more_page_footer")}</p>
</div>
</Shell>
);
}
+59
View File
@@ -0,0 +1,59 @@
"use client";
import { useRouter } from "next/navigation";
import Shell from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import { Button, EmptyScreen } from "@calcom/ui";
import { showToast } from "@calcom/ui";
export type OrgUpgradeBannerProps = {
data: RouterOutputs["viewer"]["getUserTopBanners"]["orgUpgradeBanner"];
};
export default function UpgradePage() {
const { t } = useLocale();
const router = useRouter();
const publishOrgMutation = trpc.viewer.organizations.publish.useMutation({
onSuccess(data) {
router.push(data.url);
},
onError: (error) => {
showToast(error.message, "error");
},
});
const doesUserHaveOrgToUpgrade = trpc.viewer.organizations.checkIfOrgNeedsUpgrade.useQuery();
return (
<Shell hideHeadingOnMobile>
<div className="max-w-screen-lg">
{doesUserHaveOrgToUpgrade.data ? (
<EmptyScreen
headline="Your upgrade is here"
description="Improve your scheduling experience by upgrading to the new plan and enjoy the new features."
Icon="circle-arrow-up"
buttonRaw={
<Button
onClick={() => {
publishOrgMutation.mutate();
}}>
{t("upgrade")}
</Button>
}
/>
) : (
<EmptyScreen
headline="You are all set"
description="You are already on the latest plan. Nothing to upgrade. Enjoy the new features and reach out to us with any questions!"
Icon="circle-check"
buttonRaw={<Button href="mailto:support@cal.com">{t("contact_support")}</Button>}
/>
)}
</div>
</Shell>
);
}
+4 -89
View File
@@ -1,93 +1,8 @@
"use client";
import { useSession } from "next-auth/react";
import { Trans } from "next-i18next";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { getQueryParam } from "@calcom/features/bookings/Booker/utils/query-param";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { TRPCClientError } from "@calcom/trpc/react";
import { Button, EmptyScreen, Alert } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
function ConnectAndJoin() {
const { t } = useLocale();
const router = useRouter();
const token = getQueryParam("token");
const [meetingUrl, setMeetingUrl] = useState<string | null>(null);
const [errorMessage, setErrorMessage] = useState<string | undefined>();
import ConnectAndJoinPage from "~/connect-and-join/connect-and-join-view";
const session = useSession();
const isUserPartOfOrg = session.status === "authenticated" && !!session.data.user?.org;
const Page = () => <ConnectAndJoinPage />;
Page.PageWrapper = PageWrapper;
const mutation = trpc.viewer.connectAndJoin.useMutation({
onSuccess: (res) => {
if (res.meetingUrl && !res.isBookingAlreadyAcceptedBySomeoneElse) {
router.push(res.meetingUrl);
} else if (res.isBookingAlreadyAcceptedBySomeoneElse && res.meetingUrl) {
setMeetingUrl(res.meetingUrl);
}
},
onError: (err) => {
console.log("err", err, err instanceof TRPCClientError);
if (err instanceof TRPCClientError) {
setErrorMessage(t(err.message));
} else {
setErrorMessage(t("something_went_wrong"));
}
},
});
if (session.status === "loading") return <p>{t("loading")}</p>;
if (!token) return <p>{t("token_not_found")}</p>;
return (
<div className="mx-8 mt-12 block items-start sm:flex">
{session ? (
<EmptyScreen
headline={t("instant_tab_title")}
Icon="phone-call"
description={t("uprade_to_create_instant_bookings")}
buttonRaw={
<div className="flex flex-col items-center justify-center gap-4">
{meetingUrl ? (
<div className="text-default flex flex-col items-center gap-2 text-center text-sm font-normal">
<Trans i18nKey="some_other_host_already_accepted_the_meeting">
Some other host already accepted the meeting. Do you still want to join?
<Link className="inline-block cursor-pointer underline" href={meetingUrl}>
Continue to Meeting
</Link>
</Trans>
</div>
) : (
<Button
loading={mutation.isPending}
tooltip={isUserPartOfOrg ? t("join_meeting") : t("not_part_of_org")}
disabled={!isUserPartOfOrg}
onClick={() => {
mutation.mutate({ token });
}}>
{t("join_meeting")}
</Button>
)}
{errorMessage && <Alert severity="error" message={errorMessage} />}
</div>
}
/>
) : (
<div>{t("you_must_be_logged_in_to", { url: WEBAPP_URL })}</div>
)}
</div>
);
}
ConnectAndJoin.requiresLicense = true;
ConnectAndJoin.PageWrapper = PageWrapper;
export default ConnectAndJoin;
export default Page;
+1 -25
View File
@@ -1,25 +1 @@
"use client";
import Head from "next/head";
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
import { Button } from "@calcom/ui";
export default function MaintenancePage() {
return (
<div className="bg-subtle flex h-screen">
<Head>
<title>Under Maintenance | {APP_NAME}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="bg-default m-auto rounded-md p-10 text-right ltr:text-left">
<h1 className="text-emphasis text-2xl font-medium">Down for maintenance</h1>
<p className="text-default mb-6 mt-4 max-w-2xl text-sm">
The Cal.com team are performing scheduled maintenance. If you have any questions, please contact
support.
</p>
<Button href={`${WEBSITE_URL}/support`}>Contact Support</Button>
</div>
</div>
);
}
export { default } from "~/maintenance/maintenance-view";
+6 -17
View File
@@ -1,19 +1,8 @@
"use client";
import Shell, { MobileNavigationMoreItems } from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import PageWrapper from "@components/PageWrapper";
export default function MorePage() {
const { t } = useLocale();
return (
<Shell hideHeadingOnMobile>
<div className="max-w-screen-lg">
<MobileNavigationMoreItems />
<p className="text-subtle mt-6 text-xs leading-tight md:hidden">{t("more_page_footer")}</p>
</div>
</Shell>
);
}
MorePage.PageWrapper = PageWrapper;
import MorePage from "~/more/more-page-view";
const Page = () => <MorePage />;
Page.PageWrapper = PageWrapper;
export default Page;
+4 -58
View File
@@ -1,62 +1,8 @@
"use client";
import { useRouter } from "next/navigation";
import Shell from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import { Button, EmptyScreen } from "@calcom/ui";
import { showToast } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
export type OrgUpgradeBannerProps = {
data: RouterOutputs["viewer"]["getUserTopBanners"]["orgUpgradeBanner"];
};
import UpgradePage from "~/upgrade/upgrade-view";
export default function UpgradePage() {
const { t } = useLocale();
const Page = () => <UpgradePage />;
Page.PageWrapper = PageWrapper;
const router = useRouter();
const publishOrgMutation = trpc.viewer.organizations.publish.useMutation({
onSuccess(data) {
router.push(data.url);
},
onError: (error) => {
showToast(error.message, "error");
},
});
const doesUserHaveOrgToUpgrade = trpc.viewer.organizations.checkIfOrgNeedsUpgrade.useQuery();
return (
<Shell hideHeadingOnMobile>
<div className="max-w-screen-lg">
{doesUserHaveOrgToUpgrade.data ? (
<EmptyScreen
headline="Your upgrade is here"
description="Improve your scheduling experience by upgrading to the new plan and enjoy the new features."
Icon="circle-arrow-up"
buttonRaw={
<Button
onClick={() => {
publishOrgMutation.mutate();
}}>
{t("upgrade")}
</Button>
}
/>
) : (
<EmptyScreen
headline="You are all set"
description="You are already on the latest plan. Nothing to upgrade. Enjoy the new features and reach out to us with any questions!"
Icon="circle-check"
buttonRaw={<Button href="mailto:support@cal.com">{t("contact_support")}</Button>}
/>
)}
</div>
</Shell>
);
}
UpgradePage.PageWrapper = PageWrapper;
export default Page;
+4 -3
View File
@@ -29,18 +29,19 @@ checkRoute "$APP_ROUTER_APPS_ENABLED" app/future/apps
checkRoute "$APP_ROUTER_BOOKINGS_STATUS_ENABLED" app/future/bookings
checkRoute "$APP_ROUTER_VIDEO_ENABLED" app/future/video
checkRoute "$APP_ROUTER_TEAMS_ENABLED" app/future/teams
checkRoute "$APP_ROUTER_MORE_ENABLED" app/future/more
checkRoute "$APP_ROUTER_MAINTENANCE_ENABLED" app/future/maintenance
checkRoute "$APP_ROUTER_UPGRADE_ENABLED" app/future/upgrade
checkRoute "$APP_ROUTER_CONNECT_AND_JOIN_ENABLED" app/future/connect-and-join
# These are routes that don't have and environment variable to enable or disable them
# Will stop removing gradually as we test and confirm that they are working
rm -rf \
app/future/[user]\
app/future/booking\
app/future/connect-and-join\
app/future/d\
app/future/enterprise\
app/future/insights\
app/future/maintenance\
app/future/more\
app/future/org\
app/future/payment\
app/future/reschedule\
+4
View File
@@ -247,6 +247,10 @@
"APP_ROUTER_AUTH_ERROR_ENABLED",
"APP_ROUTER_AUTH_PLATFORM_ENABLED",
"APP_ROUTER_AUTH_OAUTH2_ENABLED",
"APP_ROUTER_MORE_ENABLED",
"APP_ROUTER_MAINTENANCE_ENABLED",
"APP_ROUTER_UPGRADE_ENABLED",
"APP_ROUTER_CONNECT_AND_JOIN_ENABLED",
"APP_ROUTER_TEAMS_ENABLED",
"APP_ROUTER_AVAILABILITY_ENABLED",
"APP_USER_NAME",