Implement UpgradeTip in App install flow (#8968)

pull/8990/head
Hariom Balhara 2023-05-19 15:22:17 +05:30 committed by GitHub
parent b36043b637
commit bfa30aa504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 31 additions and 4 deletions

View File

@ -36,6 +36,7 @@ const Component = ({
tos,
privacy,
isProOnly,
teamsPlanRequired,
descriptionItems,
isTemplate,
dependencies,
@ -152,6 +153,7 @@ const Component = ({
type={type}
isProOnly={isProOnly}
disableInstall={disableInstall}
teamsPlanRequired={teamsPlanRequired}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {
props = {
@ -192,6 +194,7 @@ const Component = ({
type={type}
isProOnly={isProOnly}
disableInstall={disableInstall}
teamsPlanRequired={teamsPlanRequired}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {
props = {
@ -241,7 +244,9 @@ const Component = ({
</div>
<h4 className="text-emphasis mt-8 font-semibold ">{t("pricing")}</h4>
<span className="text-default">
{price === 0 ? (
{teamsPlanRequired ? (
t("teams_plan_required")
) : price === 0 ? (
t("free_to_use_apps")
) : (
<>
@ -358,6 +363,7 @@ export default function App(props: {
privacy?: string;
licenseRequired: AppType["licenseRequired"];
isProOnly: AppType["isProOnly"];
teamsPlanRequired: AppType["teamsPlanRequired"];
descriptionItems?: Array<string | { iframe: IframeHTMLAttributes<HTMLIFrameElement> }>;
isTemplate?: boolean;
disableInstall?: boolean;

View File

@ -72,6 +72,7 @@ function SingleAppPage(props: inferSSRProps<typeof getStaticProps>) {
website={data.url}
email={data.email}
licenseRequired={data.licenseRequired}
teamsPlanRequired={data.teamsPlanRequired}
isProOnly={data.isProOnly}
descriptionItems={source.data?.items as string[] | undefined}
isTemplate={data.isTemplate}

View File

@ -47,6 +47,7 @@ export default function OmniInstallAppButton({
<InstallAppButton
type={app.type}
isProOnly={app.isProOnly}
teamsPlanRequired={app.teamsPlanRequired}
wrapperClassName={classNames("[@media(max-width:260px)]:w-full", className)}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {

View File

@ -7,6 +7,7 @@ import classNames from "@calcom/lib/classNames";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { CAL_URL } from "@calcom/lib/constants";
import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType";
import { useHasTeamPlan } from "@calcom/lib/hooks/useHasPaidPlan";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import type { RouterOutputs } from "@calcom/trpc/react";
@ -49,14 +50,17 @@ export const InstallAppButtonWithoutPlanCheck = (
export const InstallAppButton = (
props: {
isProOnly?: App["isProOnly"];
teamsPlanRequired?: App["teamsPlanRequired"];
type: App["type"];
wrapperClassName?: string;
disableInstall?: boolean;
} & InstallAppButtonProps
) => {
const { isLoading, data: user } = trpc.viewer.me.useQuery();
const { isLoading: isUserLoading, data: user } = trpc.viewer.me.useQuery();
const router = useRouter();
const proProtectionElementRef = useRef<HTMLDivElement | null>(null);
const { isLoading: isTeamPlanStatusLoading, hasTeamPlan } = useHasTeamPlan();
useEffect(() => {
const el = proProtectionElementRef.current;
if (!el) {
@ -72,12 +76,19 @@ export const InstallAppButton = (
e.stopPropagation();
return;
}
if (props.teamsPlanRequired && !hasTeamPlan) {
// TODO: I think we should show the UpgradeTip in a Dialog here. This would solve the problem of no way to go back to the App page from the UpgradeTip page(except browser's back button)
router.push(props.teamsPlanRequired.upgradeUrl);
e.stopPropagation();
return;
}
},
true
);
}, [isLoading, user, router, props.isProOnly]);
}, [isUserLoading, user, router, props.isProOnly, hasTeamPlan, props.teamsPlanRequired]);
if (isLoading) {
if (isUserLoading || isTeamPlanStatusLoading) {
return null;
}

View File

@ -11,6 +11,9 @@
"publisher": "Cal.com",
"email": "help@cal.com",
"licenseRequired": true,
"teamsPlanRequired": {
"upgradeUrl": "/apps/routing-forms/forms"
},
"description": "It would allow a booker to connect with the right person or choose the right event, faster. It would work by taking inputs from the booker and using that data to route to the correct booker/event as configured by Cal user",
"__createdUsingCli": true
}

View File

@ -126,6 +126,9 @@ export interface App {
/** only required for "usage-based" billing. % of commission for paid bookings */
commission?: number;
licenseRequired?: boolean;
teamsPlanRequired?: {
upgradeUrl: string;
};
isProOnly?: boolean;
appData?: AppData;
/**

View File

@ -97,6 +97,7 @@ export function AppCard({ app, credentials, searchText }: AppCardProps) {
<InstallAppButton
type={app.type}
isProOnly={app.isProOnly}
teamsPlanRequired={app.teamsPlanRequired}
disableInstall={!!app.dependencies && !app.dependencyData?.some((data) => !data.installed)}
wrapperClassName="[@media(max-width:260px)]:w-full"
render={({ useDefaultComponent, ...props }) => {
@ -127,6 +128,7 @@ export function AppCard({ app, credentials, searchText }: AppCardProps) {
isProOnly={app.isProOnly}
wrapperClassName="[@media(max-width:260px)]:w-full"
disableInstall={!!app.dependencies && app.dependencyData?.some((data) => !data.installed)}
teamsPlanRequired={app.teamsPlanRequired}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {
props = {