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);
+ }, [])}
+ />