diff --git a/portal/src/components/billing/CancelSubscriptionSurveyDialog.tsx b/portal/src/components/billing/CancelSubscriptionSurveyDialog.tsx new file mode 100644 index 0000000000..c4bec4126c --- /dev/null +++ b/portal/src/components/billing/CancelSubscriptionSurveyDialog.tsx @@ -0,0 +1,58 @@ +import { + Dialog, + DialogFooter, + DialogType, + IDialogContentProps, +} from "@fluentui/react"; +import React, { useMemo } from "react"; +import { FormattedMessage } from "@oursky/react-messageformat"; +import PrimaryButton from "../../PrimaryButton"; +import DefaultButton from "../../DefaultButton"; + +interface CancelSubscriptionSurveyDialogProps { + isHidden: boolean; + onDismiss: () => void; + onConfirm: () => void; + onCancel: () => void; +} + +export function CancelSubscriptionSurveyDialog({ + isHidden, + onDismiss, + onConfirm, + onCancel, +}: CancelSubscriptionSurveyDialogProps): React.ReactElement { + const dialogContentProps: IDialogContentProps = useMemo(() => { + return { + type: DialogType.normal, + title: , + subText: ( + + ) as unknown as IDialogContentProps["subText"], + }; + }, []); + + return ( + + ); +} diff --git a/portal/src/components/billing/CurrentPlanCard.tsx b/portal/src/components/billing/CurrentPlanCard.tsx index 75851de5a8..54f1f8ce22 100644 --- a/portal/src/components/billing/CurrentPlanCard.tsx +++ b/portal/src/components/billing/CurrentPlanCard.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useMemo } from "react"; +import React, { useCallback, useContext, useMemo } from "react"; import { IButtonProps, ITooltipHostProps, @@ -35,6 +35,7 @@ import { SubscriptionUsage, Usage, } from "../../graphql/portal/globalTypes.generated"; +import { useNavigate } from "react-router-dom"; interface CurrentPlanCardProps { planName: string; @@ -420,6 +421,11 @@ function MAUUsageSection({ mauLimit: number | undefined; mauPrevious: number | undefined; }) { + const navigate = useNavigate(); + const onUpgrade = useCallback(() => { + navigate({ hash: "Subscription" }); + }, [navigate]); + return (
} + onClickUpgrade={onUpgrade} />
); @@ -461,7 +468,7 @@ function UsageMeter(props: UsageMeterProps): React.ReactElement { onClickUpgrade, } = props; const percentComplete = - current != null && limit != null ? current / limit : 0; + current != null && limit != null ? current / limit : null; const id = useId("usage-meter"); const calloutProps = useMemo(() => { return { @@ -495,14 +502,18 @@ function UsageMeter(props: UsageMeterProps): React.ReactElement { {title} - + {percentComplete != null ? ( + + ) : null} - {current != null ? `${current}` : "-"} - {" / "} - {limit != null ? `${limit}` : "-"} + {limit != null && current != null + ? `${current} / ${limit}` + : limit == null && current != null + ? `${current}` + : null} {previous != null ? ( - ) : percentComplete >= warnPercentage ? ( + ) : percentComplete != null && percentComplete >= warnPercentage ? ( diff --git a/portal/src/graphql/portal/SubscriptionScreen.tsx b/portal/src/graphql/portal/SubscriptionScreen.tsx index a2d9b01669..1d9f34357e 100644 --- a/portal/src/graphql/portal/SubscriptionScreen.tsx +++ b/portal/src/graphql/portal/SubscriptionScreen.tsx @@ -67,6 +67,7 @@ import LinkButton from "../../LinkButton"; import { useGenerateStripeCustomerPortalSessionMutationMutation } from "./mutations/generateStripeCustomerPortalSessionMutation"; import { CancelSubscriptionReminder } from "../../components/billing/CancelSubscriptionReminder"; import { extractRawID } from "../../util/graphql"; +import { CancelSubscriptionSurveyDialog } from "../../components/billing/CancelSubscriptionSurveyDialog"; const CHECK_IS_PROCESSING_SUBSCRIPTION_INTERVAL = 5000; @@ -486,6 +487,8 @@ function SubscriptionScreenContent(props: SubscriptionScreenContentProps) { const [enterpriseDialogHidden, setEnterpriseDialogHidden] = useState(true); const [cancelDialogHidden, setCancelDialogHidden] = useState(true); + const [cancelSurveyDialogHidden, setCancelSurveyDialogHidden] = + useState(true); const { selectedKey: selectedTab, onLinkClick } = usePivotNavigation([ Tab.Subscription, @@ -551,18 +554,23 @@ function SubscriptionScreenContent(props: SubscriptionScreenContentProps) { e.preventDefault(); e.stopPropagation(); await setSubscriptionCancelledStatus(true); - const projectID = extractRawID(appID); - const cancelSurveyURL = `https://oursky.typeform.com/authgear-cancel#project_id=${projectID}`; - const anchor = document.createElement("A") as HTMLAnchorElement; - anchor.href = cancelSurveyURL; - anchor.target = "_blank"; - anchor.click(); - anchor.remove(); setCancelDialogHidden(true); + setCancelSurveyDialogHidden(false); }, - [appID, setSubscriptionCancelledStatus] + [setSubscriptionCancelledStatus] ); + const onConfirmCancelSurveyDialog = useCallback(() => { + const projectID = extractRawID(appID); + const cancelSurveyURL = `https://oursky.typeform.com/authgear-cancel#project_id=${projectID}`; + const anchor = document.createElement("A") as HTMLAnchorElement; + anchor.href = cancelSurveyURL; + anchor.target = "_blank"; + anchor.click(); + anchor.remove(); + setCancelSurveyDialogHidden(true); + }, [appID]); + return ( <> + { + setCancelSurveyDialogHidden(true); + }, [])} + onConfirm={onConfirmCancelSurveyDialog} + onCancel={useCallback(() => { + setCancelSurveyDialogHidden(true); + }, [])} + />