From 9f88b5c2beedd51730dbe4f2dfdd15e6bcb6e967 Mon Sep 17 00:00:00 2001
From: MananTank
Date: Wed, 2 Jul 2025 20:39:36 +0000
Subject: [PATCH] [TOOL-4951] Dashboard: Show Plan upsell on storage error in
asset creation modal (#7512)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
## PR-Codex overview
This PR introduces the `teamPlan` property to various components related to NFT and token creation, allowing the application to handle billing plans effectively. It also adds a new component for handling storage limit errors and integrates upsell reporting for plan upgrades.
### Detailed summary
- Added `teamPlan` prop to components: `CreateNFTPage`, `CreateTokenAssetPage`, `CreateNFTPageUI`, `CreateTokenAssetPageUI`, `LaunchNFT`, `LaunchTokenStatus`.
- Introduced `StorageErrorPlanUpsell` component for storage limit handling.
- Implemented upsell reporting functions: `reportUpsellShown`, `reportUpsellClicked`.
- Updated `MultiStepStatus` to use a render function for error messages.
- Changed error message type from `React.ReactNode` to `string` in `MultiStepStatus`.
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
## Summary by CodeRabbit
* **New Features**
* Introduced a tailored upsell experience when users on a free plan hit the storage limit during token or NFT creation, including a new prompt to upgrade and real-time detection of plan changes.
* Added analytics tracking for upsell prompts and upgrade link clicks.
* **Enhancements**
* Error messages in multi-step workflows can now be customized, allowing for more informative and actionable error displays.
* Components involved in token and NFT creation now accept and utilize the team's billing plan to enable conditional UI and logic.
* **Storybook**
* Updated stories to reflect storage limit scenarios and demonstrate the new upsell flow for free plan users.
---
apps/dashboard/src/@/analytics/report.ts | 29 ++++
.../multi-step-status/multi-step-status.tsx | 40 ++---
.../create/_common/storage-error-upsell.tsx | 138 ++++++++++++++++++
.../tokens/create/nft/create-nft-page-ui.tsx | 3 +
.../tokens/create/nft/create-nft-page.tsx | 2 +
.../tokens/create/nft/launch/launch-nft.tsx | 24 ++-
.../(sidebar)/tokens/create/nft/page.tsx | 1 +
.../create/token/create-token-page-impl.tsx | 3 +
.../create/token/create-token-page.client.tsx | 3 +
.../token/create-token-page.stories.tsx | 22 +++
.../create/token/launch/launch-token.tsx | 25 +++-
.../(sidebar)/tokens/create/token/page.tsx | 1 +
12 files changed, 271 insertions(+), 20 deletions(-)
create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/storage-error-upsell.tsx
diff --git a/apps/dashboard/src/@/analytics/report.ts b/apps/dashboard/src/@/analytics/report.ts
index 022cc5fcaac..71a514d27d9 100644
--- a/apps/dashboard/src/@/analytics/report.ts
+++ b/apps/dashboard/src/@/analytics/report.ts
@@ -1,6 +1,7 @@
import posthog from "posthog-js";
import type { Team } from "@/api/team";
+import type { ProductSKU } from "../types/billing";
// ----------------------------
// CONTRACTS
@@ -380,3 +381,31 @@ export function reportAssetCreationFailed(
step: properties.step,
});
}
+
+type UpsellParams = {
+ content: "storage-limit";
+ campaign: "create-coin" | "create-nft";
+ sku: Exclude;
+};
+
+/**
+ * ### Why do we need to report this event?
+ * - To track how effective the upsells are in driving users to upgrade
+ *
+ * ### Who is responsible for this event?
+ * @MananTank
+ */
+export function reportUpsellShown(properties: UpsellParams) {
+ posthog.capture("upsell shown", properties);
+}
+
+/**
+ * ### Why do we need to report this event?
+ * - To track how effective the upsells are in driving users to upgrade
+ *
+ * ### Who is responsible for this event?
+ * @MananTank
+ */
+export function reportUpsellClicked(properties: UpsellParams) {
+ posthog.capture("upsell clicked", properties);
+}
diff --git a/apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx b/apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx
index fa37f0f1149..33b6002e809 100644
--- a/apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx
+++ b/apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx
@@ -18,7 +18,7 @@ export type MultiStepState = {
}
| {
type: "error";
- message: React.ReactNode;
+ message: string;
};
label: string;
description?: string;
@@ -27,6 +27,10 @@ export type MultiStepState = {
export function MultiStepStatus(props: {
steps: MultiStepState[];
onRetry: (step: MultiStepState) => void;
+ renderError?: (
+ step: MultiStepState,
+ errorMessage: string,
+ ) => React.ReactNode;
}) {
return (
@@ -66,22 +70,24 @@ export function MultiStepStatus(props: {