diff --git a/frontend/__snapshots__/scenes-other-onboarding--onboarding-billing.png b/frontend/__snapshots__/scenes-other-onboarding--onboarding-billing.png new file mode 100644 index 00000000000000..02c01ec5002fcf Binary files /dev/null and b/frontend/__snapshots__/scenes-other-onboarding--onboarding-billing.png differ diff --git a/frontend/__snapshots__/scenes-other-onboarding--onboarding-other-products.png b/frontend/__snapshots__/scenes-other-onboarding--onboarding-other-products.png new file mode 100644 index 00000000000000..a5a8a431f0cd48 Binary files /dev/null and b/frontend/__snapshots__/scenes-other-onboarding--onboarding-other-products.png differ diff --git a/frontend/__snapshots__/scenes-other-onboarding--onboarding-sd-ks.png b/frontend/__snapshots__/scenes-other-onboarding--onboarding-sd-ks.png new file mode 100644 index 00000000000000..a5a8a431f0cd48 Binary files /dev/null and b/frontend/__snapshots__/scenes-other-onboarding--onboarding-sd-ks.png differ diff --git a/frontend/__snapshots__/scenes-other-products--products.png b/frontend/__snapshots__/scenes-other-products--products.png new file mode 100644 index 00000000000000..af7c42bef746ce Binary files /dev/null and b/frontend/__snapshots__/scenes-other-products--products.png differ diff --git a/frontend/src/mocks/fixtures/_billing_unsubscribed.json b/frontend/src/mocks/fixtures/_billing_unsubscribed.json new file mode 100644 index 00000000000000..d640aac7c7ea84 --- /dev/null +++ b/frontend/src/mocks/fixtures/_billing_unsubscribed.json @@ -0,0 +1,1923 @@ +{ + "available_features": [ + "surveys_unlimited_surveys", + "surveys_all_question_types", + "surveys_user_targeting", + "surveys_user_sampling", + "surveys_api_mode", + "surveys_results_analysis", + "surveys_templates", + "surveys_data_retention", + "zapier", + "slack_integration", + "microsoft_teams_integration", + "discord_integration", + "apps", + "boolean_flags", + "persist_flags_cross_authentication", + "feature_flag_payloads", + "multiple_release_conditions", + "release_condition_overrides", + "targeting_by_group", + "local_evaluation_and_bootstrapping", + "flag_usage_stats", + "feature_flags_data_retention", + "console_logs", + "recordings_playlists", + "session_replay_data_retention", + "dashboards", + "funnels", + "graphs_trends", + "paths", + "product_analytics_data_retention", + "tracked_users", + "team_members", + "organizations_projects", + "api_access", + "social_sso", + "community_support", + "terms_and_conditions" + ], + "license": { + "plan": "dev" + }, + "customer_id": "cus_OfAfHKf4QiD0rs", + "deactivated": false, + "has_active_subscription": false, + "billing_period": { + "current_period_start": "2023-11-17T23:19:00.444Z", + "current_period_end": "2023-12-17T23:19:00.444Z", + "interval": "month" + }, + "available_product_features": [ + { + "key": "surveys_unlimited_surveys", + "name": "Unlimited surveys", + "description": "Create as many surveys as you want.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_all_question_types", + "name": "All question types", + "description": "Rating scale (for NPS and the like), multiple choice, single choice, emoji rating, link, free text.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_targeting", + "name": "User property targeting", + "description": "Target users based on any of their user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_sampling", + "name": "User sampling", + "description": "Sample users to only survey a portion of the users who match the criteria.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_api_mode", + "name": "API mode", + "description": "Create surveys via the API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_results_analysis", + "name": "Results analysis", + "description": "Analyze your survey results including completion rates and drop offs.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_templates", + "name": "Templates", + "description": "Use our templates to get started quickly with NPS, customer satisfaction surveys, user interviews, and more.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + }, + { + "key": "zapier", + "name": "Zapier", + "description": "Zapier lets you connect PostHog with thousands of the most popular apps, so you can automate your work and have more time for what matters most—no code required.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "slack_integration", + "name": "Slack", + "description": "Get notified about new actions in Slack.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "microsoft_teams_integration", + "name": "Microsoft Teams", + "description": "Get notified about new actions in Microsoft Teams.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "discord_integration", + "name": "Discord", + "description": "Get notified about new actions in Discord.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "apps", + "name": "CDP + Apps library", + "description": "Connect your data with 50+ apps including BigQuery, Redshift, and more.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "boolean_flags", + "name": "Boolean feature flags", + "description": "Turn features on and off for specific users.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "persist_flags_cross_authentication", + "name": "Persist flags across authentication", + "description": "Persist feature flags across authentication events so that flag values don't change when an anonymous user logs in and becomes identified.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flag_payloads", + "name": "Payloads", + "description": "Send additional pieces of information (any valid JSON) to your app when a flag is matched for a user.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "multiple_release_conditions", + "name": "Multiple release conditions", + "description": "Target multiple groups of users with different release conditions for the same feature flag.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "release_condition_overrides", + "name": "Release condition overrides", + "description": "For any release condition, specify which flag value the users or groups in that condition should receive.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "targeting_by_group", + "name": "Flag targeting by groups", + "description": "Target feature flag release conditions by group properties, not just user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "local_evaluation_and_bootstrapping", + "name": "Local evaluation & bootstrapping", + "description": "Bootstrap flags on initialization so all flags are available immediately, without having to make extra network requests.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "flag_usage_stats", + "name": "Flag usage stats", + "description": "See how many times a flag has been evaluated, how many times each variant has been returned, and what values users received.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flags_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + }, + { + "key": "console_logs", + "name": "Console logs", + "description": "Diagnose issues by inspecting errors in the user's network console", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "recordings_playlists", + "name": "Recording playlists", + "description": "Create playlists of certain session recordings to easily find and watch them again in the future.", + "unit": "playlists", + "limit": 5, + "note": null + }, + { + "key": "session_replay_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "month", + "limit": 1, + "note": null + }, + { + "key": "dashboards", + "name": "Dashboards", + "description": "Save trends, funnels, and other insights for easy reference by your whole team.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "funnels", + "name": "Funnels", + "description": "Visualize user dropoff between a sequence of events.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "graphs_trends", + "name": "Graphs & trends", + "description": "Plot any number of events or actions over time.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "paths", + "name": "Paths", + "description": "Limited paths excludes: customizing path insights by setting the maximum number of paths, number of people on each path, how path names appear", + "unit": null, + "limit": null, + "note": "Limited" + }, + { + "key": "product_analytics_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + }, + { + "key": "tracked_users", + "name": "Tracked users", + "description": "Track users across devices and sessions.", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "team_members", + "name": "Team members", + "description": "PostHog doesn't charge per seat add your entire team!", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "organizations_projects", + "name": "Projects", + "description": "Create silos of data within PostHog. All data belongs to a single project and all queries are project-specific.", + "unit": "project", + "limit": 1, + "note": null + }, + { + "key": "api_access", + "name": "API access", + "description": "Access your data via our developer-friendly API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "social_sso", + "name": "SSO via Google, Github, or Gitlab", + "description": "Log in to PostHog with your Google, Github, or Gitlab account.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "community_support", + "name": "Community support", + "description": "Get help from other users and PostHog team members in our Community forums.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "terms_and_conditions", + "name": "Terms and conditions", + "description": "Terms and conditions", + "unit": null, + "limit": null, + "note": "Standard" + } + ], + "current_total_amount_usd": null, + "current_total_amount_usd_after_discount": null, + "products": [ + { + "name": "Product analytics + data stack", + "description": "Trends, funnels, path analysis, CDP + more.", + "price_description": null, + "usage_key": "events", + "image_url": "https://posthog.com/images/product/product-icons/product-analytics.svg", + "icon_key": "IconGraph", + "docs_url": "https://posthog.com/docs/product-analytics", + "subscribed": false, + "plans": [ + { + "plan_key": "free-20230117", + "product_key": "product_analytics", + "name": "Product analytics + data stack", + "description": "Trends, funnels, path analysis, CDP + more.", + "image_url": "https://posthog.com/images/product/product-icons/product-analytics.svg", + "docs_url": "https://posthog.com/docs/product-analytics", + "note": null, + "unit": "event", + "free_allocation": 1000000, + "features": [ + { + "key": "dashboards", + "name": "Dashboards", + "description": "Save trends, funnels, and other insights for easy reference by your whole team.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "funnels", + "name": "Funnels", + "description": "Visualize user dropoff between a sequence of events.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "graphs_trends", + "name": "Graphs & trends", + "description": "Plot any number of events or actions over time.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "paths", + "name": "Paths", + "description": "Limited paths excludes: customizing path insights by setting the maximum number of paths, number of people on each path, how path names appear", + "unit": null, + "limit": null, + "note": "Limited" + }, + { + "key": "product_analytics_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + } + ], + "tiers": null, + "current_plan": true, + "included_if": null + }, + { + "plan_key": "paid-20230509", + "product_key": "product_analytics", + "name": "Product analytics + data stack", + "description": "Trends, funnels, path analysis, CDP + more.", + "image_url": "https://posthog.com/images/product/product-icons/product-analytics.svg", + "docs_url": "https://posthog.com/docs/product-analytics", + "note": null, + "unit": "event", + "free_allocation": null, + "features": [ + { + "key": "dashboards", + "name": "Dashboards", + "description": "Save trends, funnels, and other insights for easy reference by your whole team.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "funnels", + "name": "Funnels", + "description": "Visualize user dropoff between a sequence of events.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "graphs_trends", + "name": "Graphs & trends", + "description": "Plot any number of events or actions over time.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "paths", + "name": "Paths", + "description": "Limited paths excludes: customizing path insights by setting the maximum number of paths, number of people on each path, how path names appear", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "subscriptions", + "name": "Insight & dashboard subscriptions", + "description": "Create a subscription for any insight or dashboard in PostHog to receive regular reports with their updates.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "paths_advanced", + "name": "Advanced paths", + "description": "Customize your path insights by setting the maximum number of paths, number of people on each path, and how path names should appear.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "dashboard_permissioning", + "name": "Dashboard permissions", + "description": "Restrict access to dashboards within the organization to only those who need it.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "dashboard_collaboration", + "name": "Tags & text cards", + "description": "Keep organized by adding tags to your dashboards, cohorts and more. Add text cards and descriptions to your dashboards to provide context to your team.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "ingestion_taxonomy", + "name": "Ingestion taxonomy", + "description": "Ingestion taxonomy", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "correlation_analysis", + "name": "Correlation analysis", + "description": "Automatically highlight significant factors that affect the conversion rate of users within a funnel.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "tagging", + "name": "Dashboard tags", + "description": "Organize dashboards with tags.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "behavioral_cohort_filtering", + "name": "Lifecycle cohorts", + "description": "Group users based on their long term behavior, such as whether they frequently performed an event, or have recently stopped performing an event.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "product_analytics_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "years", + "limit": 7, + "note": null + } + ], + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 1000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0003068", + "up_to": 2000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.00013", + "up_to": 15000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000819", + "up_to": 50000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000455", + "up_to": 100000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000234", + "up_to": 250000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000052", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "current_plan": false, + "included_if": null + } + ], + "type": "product_analytics", + "free_allocation": 1000000, + "tiers": null, + "tiered": true, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 1000000, + "has_exceeded_limit": false, + "percentage_usage": 0.0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": "event", + "addons": [ + { + "name": "Group analytics", + "description": "Associate events with a group or entity - such as a company, community, or project. Analyze these events as if they were sent by that entity itself. Great for B2B, marketplaces, and more.", + "price_description": null, + "image_url": "https://posthog.com/images/product/product-icons/group-analytics.svg", + "icon_key": "IconPeople", + "docs_url": "https://posthog.com/docs/product-analytics/group-analytics", + "type": "group_analytics", + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 1000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000708", + "up_to": 2000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.00003", + "up_to": 15000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000189", + "up_to": 50000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000105", + "up_to": 100000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000054", + "up_to": 250000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000012", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "tiered": true, + "included_with_main_product": false, + "subscribed": false, + "unit": "event", + "unit_amount_usd": null, + "current_amount_usd": null, + "current_usage": 0, + "projected_usage": 0, + "projected_amount_usd": null, + "plans": [ + { + "plan_key": "addon-20230509", + "product_key": "group_analytics", + "name": "Group analytics", + "description": "Associate events with a group or entity - such as a company, community, or project. Analyze these events as if they were sent by that entity itself. Great for B2B, marketplaces, and more.", + "image_url": "https://posthog.com/images/product/product-icons/group-analytics.svg", + "docs_url": "https://posthog.com/docs/product-analytics/group-analytics", + "note": null, + "unit": "event", + "free_allocation": null, + "features": [ + { + "key": "group_analytics", + "name": "Group analytics", + "description": "Associate events with a group - such as a company, community, or project - and analyze them in that context.", + "unit": null, + "limit": null, + "note": null + } + ], + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 1000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000708", + "up_to": 2000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.00003", + "up_to": 15000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000189", + "up_to": 50000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000105", + "up_to": 100000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000054", + "up_to": 250000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0000012", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "current_plan": false, + "included_if": null + } + ], + "contact_support": false + } + ], + "contact_support": false, + "inclusion_only": false + }, + { + "name": "Session replay", + "description": "Searchable recordings of people using your app or website with console logs and behavioral bucketing.", + "price_description": null, + "usage_key": "recordings", + "image_url": "https://posthog.com/images/product/product-icons/session-replay.svg", + "icon_key": "IconRewindPlay", + "docs_url": "https://posthog.com/docs/session-replay", + "subscribed": false, + "plans": [ + { + "plan_key": "free-20230117", + "product_key": "session_replay", + "name": "Session replay", + "description": "Searchable recordings of people using your app or website with console logs and behavioral bucketing.", + "image_url": "https://posthog.com/images/product/product-icons/session-replay.svg", + "docs_url": "https://posthog.com/docs/session-replay", + "note": null, + "unit": "recording", + "free_allocation": 15000, + "features": [ + { + "key": "console_logs", + "name": "Console logs", + "description": "Diagnose issues by inspecting errors in the user's network console", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "recordings_playlists", + "name": "Recording playlists", + "description": "Create playlists of certain session recordings to easily find and watch them again in the future.", + "unit": "playlists", + "limit": 5, + "note": null + }, + { + "key": "session_replay_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "month", + "limit": 1, + "note": null + } + ], + "tiers": null, + "current_plan": true, + "included_if": null + }, + { + "plan_key": "paid-20230117", + "product_key": "session_replay", + "name": "Session replay", + "description": "Searchable recordings of people using your app or website with console logs and behavioral bucketing.", + "image_url": "https://posthog.com/images/product/product-icons/session-replay.svg", + "docs_url": "https://posthog.com/docs/session-replay", + "note": null, + "unit": "recording", + "free_allocation": null, + "features": [ + { + "key": "console_logs", + "name": "Console logs", + "description": "Diagnose issues by inspecting errors in the user's network console", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "recordings_playlists", + "name": "Recording playlists", + "description": "Create playlists of certain session recordings to easily find and watch them again in the future.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "recordings_performance", + "name": "Network performance on recordings", + "description": "See your end-user's network performance and information alongside session recordings.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "recordings_file_export", + "name": "Recordings file export", + "description": "Save session recordings as a file to your local filesystem.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "session_replay_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "months", + "limit": 3, + "note": null + } + ], + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 15000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.005", + "up_to": 50000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0045", + "up_to": 150000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.004", + "up_to": 500000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0035", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "current_plan": false, + "included_if": null + } + ], + "type": "session_replay", + "free_allocation": 15000, + "tiers": null, + "tiered": true, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 15000, + "has_exceeded_limit": false, + "percentage_usage": 0.0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": "recording", + "addons": [], + "contact_support": false, + "inclusion_only": false + }, + { + "name": "Feature flags & A/B testing", + "description": "Safely roll out new features and run experiments on changes.", + "price_description": null, + "usage_key": "feature_flag_requests", + "image_url": "https://posthog.com/images/product/product-icons/feature-flags.svg", + "icon_key": "IconToggle", + "docs_url": "https://posthog.com/docs/feature-flags", + "subscribed": false, + "plans": [ + { + "plan_key": "free-20230117", + "product_key": "feature_flags", + "name": "Feature flags & A/B testing", + "description": "Safely roll out new features and run experiments on changes.", + "image_url": "https://posthog.com/images/product/product-icons/feature-flags.svg", + "docs_url": "https://posthog.com/docs/feature-flags", + "note": null, + "unit": "request", + "free_allocation": 1000000, + "features": [ + { + "key": "boolean_flags", + "name": "Boolean feature flags", + "description": "Turn features on and off for specific users.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "persist_flags_cross_authentication", + "name": "Persist flags across authentication", + "description": "Persist feature flags across authentication events so that flag values don't change when an anonymous user logs in and becomes identified.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flag_payloads", + "name": "Payloads", + "description": "Send additional pieces of information (any valid JSON) to your app when a flag is matched for a user.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "multiple_release_conditions", + "name": "Multiple release conditions", + "description": "Target multiple groups of users with different release conditions for the same feature flag.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "release_condition_overrides", + "name": "Release condition overrides", + "description": "For any release condition, specify which flag value the users or groups in that condition should receive.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "targeting_by_group", + "name": "Flag targeting by groups", + "description": "Target feature flag release conditions by group properties, not just user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "local_evaluation_and_bootstrapping", + "name": "Local evaluation & bootstrapping", + "description": "Bootstrap flags on initialization so all flags are available immediately, without having to make extra network requests.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "flag_usage_stats", + "name": "Flag usage stats", + "description": "See how many times a flag has been evaluated, how many times each variant has been returned, and what values users received.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flags_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + } + ], + "tiers": null, + "current_plan": true, + "included_if": null + }, + { + "plan_key": "paid-20230623", + "product_key": "feature_flags", + "name": "Feature flags & A/B testing", + "description": "Safely roll out new features and run experiments on changes.", + "image_url": "https://posthog.com/images/product/product-icons/feature-flags.svg", + "docs_url": "https://posthog.com/docs/feature-flags", + "note": null, + "unit": "request", + "free_allocation": null, + "features": [ + { + "key": "boolean_flags", + "name": "Boolean feature flags", + "description": "Turn features on and off for specific users.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "multivariate_flags", + "name": "Multivariate feature flags & experiments", + "description": "Create three or more variants of a feature flag to test or release different versions of a feature.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "persist_flags_cross_authentication", + "name": "Persist flags across authentication", + "description": "Persist feature flags across authentication events so that flag values don't change when an anonymous user logs in and becomes identified.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flag_payloads", + "name": "Payloads", + "description": "Send additional pieces of information (any valid JSON) to your app when a flag is matched for a user.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "multiple_release_conditions", + "name": "Multiple release conditions", + "description": "Target multiple groups of users with different release conditions for the same feature flag.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "release_condition_overrides", + "name": "Release condition overrides", + "description": "For any release condition, specify which flag value the users or groups in that condition should receive.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "targeting_by_group", + "name": "Flag targeting by groups", + "description": "Target feature flag release conditions by group properties, not just user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "local_evaluation_and_bootstrapping", + "name": "Local evaluation & bootstrapping", + "description": "Bootstrap flags on initialization so all flags are available immediately, without having to make extra network requests.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "flag_usage_stats", + "name": "Flag usage stats", + "description": "See how many times a flag has been evaluated, how many times each variant has been returned, and what values users received.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "experimentation", + "name": "A/B testing", + "description": "Test changes to your product and evaluate the impacts those changes make.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "group_experiments", + "name": "Group experiments", + "description": "Target experiments to specific groups of users so everyone in the same group gets the same variant.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "funnel_experiments", + "name": "Funnel & trend experiments", + "description": "Measure the impact of a change on a aggregate values or a series of events, like a signup flow.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "secondary_metrics", + "name": "Secondary experiment metrics", + "description": "Track additional metrics to see how your experiment affects other parts of your app or different flows.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "statistical_analysis", + "name": "Statistical analysis", + "description": "Get a statistical analysis of your experiment results to see if the results are significant, or if they're likely just due to chance.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "feature_flags_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "years", + "limit": 7, + "note": null + } + ], + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 1000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.0001", + "up_to": 2000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.000045", + "up_to": 10000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.000025", + "up_to": 50000000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.00001", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "current_plan": false, + "included_if": null + } + ], + "type": "feature_flags", + "free_allocation": 1000000, + "tiers": null, + "tiered": true, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 1000000, + "has_exceeded_limit": false, + "percentage_usage": 0.0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": "request", + "addons": [], + "contact_support": false, + "inclusion_only": false + }, + { + "name": "Surveys", + "description": "Collect feedback from your users. Multiple choice, rating, open text, and more.", + "price_description": null, + "usage_key": "survey_responses", + "image_url": "https://posthog.com/images/product/product-icons/surveys.svg", + "icon_key": "IconMessage", + "docs_url": "https://posthog.com/docs/surveys", + "subscribed": false, + "plans": [ + { + "plan_key": "free-20230928", + "product_key": "surveys", + "name": "Surveys", + "description": "Collect feedback from your users. Multiple choice, rating, open text, and more.", + "image_url": "https://posthog.com/images/product/product-icons/surveys.svg", + "docs_url": "https://posthog.com/docs/surveys", + "note": null, + "unit": "survey response", + "free_allocation": 250, + "features": [ + { + "key": "surveys_unlimited_surveys", + "name": "Unlimited surveys", + "description": "Create as many surveys as you want.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_all_question_types", + "name": "All question types", + "description": "Rating scale (for NPS and the like), multiple choice, single choice, emoji rating, link, free text.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_targeting", + "name": "User property targeting", + "description": "Target users based on any of their user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_sampling", + "name": "User sampling", + "description": "Sample users to only survey a portion of the users who match the criteria.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_api_mode", + "name": "API mode", + "description": "Create surveys via the API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_results_analysis", + "name": "Results analysis", + "description": "Analyze your survey results including completion rates and drop offs.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_templates", + "name": "Templates", + "description": "Use our templates to get started quickly with NPS, customer satisfaction surveys, user interviews, and more.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "year", + "limit": 1, + "note": null + } + ], + "tiers": null, + "current_plan": true, + "included_if": null + }, + { + "plan_key": "paid-20230928", + "product_key": "surveys", + "name": "Surveys", + "description": "Collect feedback from your users. Multiple choice, rating, open text, and more.", + "image_url": "https://posthog.com/images/product/product-icons/surveys.svg", + "docs_url": "https://posthog.com/docs/surveys", + "note": null, + "unit": "survey response", + "free_allocation": null, + "features": [ + { + "key": "surveys_unlimited_surveys", + "name": "Unlimited surveys", + "description": "Create as many surveys as you want.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_all_question_types", + "name": "All question types", + "description": "Rating scale (for NPS and the like), multiple choice, single choice, emoji rating, link, free text.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_multiple_questions", + "name": "Multiple questions", + "description": "Create multiple questions in a single survey.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_targeting", + "name": "User property targeting", + "description": "Target users based on any of their user properties.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_user_sampling", + "name": "User sampling", + "description": "Sample users to only survey a portion of the users who match the criteria.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_styling", + "name": "Custom colors & positioning", + "description": "Customize the colors of your surveys to match your brand and set survey position.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_text_html", + "name": "Custom HTML text", + "description": "Add custom HTML to your survey text.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_api_mode", + "name": "API mode", + "description": "Create surveys via the API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_results_analysis", + "name": "Results analysis", + "description": "Analyze your survey results including completion rates and drop offs.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_templates", + "name": "Templates", + "description": "Use our templates to get started quickly with NPS, customer satisfaction surveys, user interviews, and more.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "surveys_data_retention", + "name": "Data retention", + "description": "Keep a historical record of your data.", + "unit": "years", + "limit": 7, + "note": null + } + ], + "tiers": [ + { + "flat_amount_usd": "0", + "unit_amount_usd": "0", + "up_to": 250, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.2", + "up_to": 500, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.1", + "up_to": 1000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.035", + "up_to": 10000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.015", + "up_to": 20000, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + }, + { + "flat_amount_usd": "0", + "unit_amount_usd": "0.01", + "up_to": null, + "current_amount_usd": "0.00", + "current_usage": 0, + "projected_usage": null, + "projected_amount_usd": null + } + ], + "current_plan": false, + "included_if": null + } + ], + "type": "surveys", + "free_allocation": 250, + "tiers": null, + "tiered": true, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 250, + "has_exceeded_limit": false, + "percentage_usage": 0.0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": "survey response", + "addons": [], + "contact_support": false, + "inclusion_only": false + }, + { + "name": "Integrations + CDP", + "description": "Connect PostHog to your favorite tools.", + "price_description": null, + "usage_key": null, + "image_url": "https://posthog.com/images/product/product-icons/integrations.svg", + "icon_key": "IconBolt", + "docs_url": "https://posthog.com/docs/apps", + "subscribed": null, + "plans": [ + { + "plan_key": "free-20230117", + "product_key": "integrations", + "name": "Integrations + CDP", + "description": "Connect PostHog to your favorite tools.", + "image_url": "https://posthog.com/images/product/product-icons/integrations.svg", + "docs_url": "https://posthog.com/docs/apps", + "note": null, + "unit": null, + "free_allocation": null, + "features": [ + { + "key": "zapier", + "name": "Zapier", + "description": "Zapier lets you connect PostHog with thousands of the most popular apps, so you can automate your work and have more time for what matters most—no code required.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "slack_integration", + "name": "Slack", + "description": "Get notified about new actions in Slack.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "microsoft_teams_integration", + "name": "Microsoft Teams", + "description": "Get notified about new actions in Microsoft Teams.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "discord_integration", + "name": "Discord", + "description": "Get notified about new actions in Discord.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "apps", + "name": "CDP + Apps library", + "description": "Connect your data with 50+ apps including BigQuery, Redshift, and more.", + "unit": null, + "limit": null, + "note": null + } + ], + "tiers": null, + "current_plan": true, + "included_if": "no_active_subscription" + }, + { + "plan_key": "paid-20230117", + "product_key": "integrations", + "name": "Integrations + CDP", + "description": "Connect PostHog to your favorite tools.", + "image_url": "https://posthog.com/images/product/product-icons/integrations.svg", + "docs_url": "https://posthog.com/docs/apps", + "note": null, + "unit": null, + "free_allocation": null, + "features": [ + { + "key": "zapier", + "name": "Zapier", + "description": "Zapier lets you connect PostHog with thousands of the most popular apps, so you can automate your work and have more time for what matters most—no code required.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "slack_integration", + "name": "Slack", + "description": "Get notified about new actions in Slack.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "microsoft_teams_integration", + "name": "Microsoft Teams", + "description": "Get notified about new actions in Microsoft Teams.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "discord_integration", + "name": "Discord", + "description": "Get notified about new actions in Discord.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "apps", + "name": "CDP + Apps library", + "description": "Connect your data with 50+ apps including BigQuery, Redshift, and more.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "app_metrics", + "name": "App metrics", + "description": "Get metrics on your apps to see their usage, reliability, and more.", + "unit": null, + "limit": null, + "note": null + } + ], + "tiers": null, + "current_plan": false, + "included_if": "has_subscription" + } + ], + "type": "integrations", + "free_allocation": 0, + "tiers": null, + "tiered": false, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 0, + "has_exceeded_limit": false, + "percentage_usage": 0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": null, + "addons": [], + "contact_support": false, + "inclusion_only": true + }, + { + "name": "Platform and support", + "description": "SSO, permission management, and support.", + "price_description": null, + "usage_key": null, + "image_url": "https://posthog.com/images/product/product-icons/platform.svg", + "icon_key": "IconStack", + "docs_url": "https://posthog.com/docs", + "subscribed": null, + "plans": [ + { + "plan_key": "free-20230117", + "product_key": "platform_and_support", + "name": "Platform and support", + "description": "SSO, permission management, and support.", + "image_url": "https://posthog.com/images/product/product-icons/platform.svg", + "docs_url": "https://posthog.com/docs", + "note": null, + "unit": null, + "free_allocation": null, + "features": [ + { + "key": "tracked_users", + "name": "Tracked users", + "description": "Track users across devices and sessions.", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "team_members", + "name": "Team members", + "description": "PostHog doesn't charge per seat add your entire team!", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "organizations_projects", + "name": "Projects", + "description": "Create silos of data within PostHog. All data belongs to a single project and all queries are project-specific.", + "unit": "project", + "limit": 1, + "note": null + }, + { + "key": "api_access", + "name": "API access", + "description": "Access your data via our developer-friendly API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "social_sso", + "name": "SSO via Google, Github, or Gitlab", + "description": "Log in to PostHog with your Google, Github, or Gitlab account.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "community_support", + "name": "Community support", + "description": "Get help from other users and PostHog team members in our Community forums.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "terms_and_conditions", + "name": "Terms and conditions", + "description": "Terms and conditions", + "unit": null, + "limit": null, + "note": "Standard" + } + ], + "tiers": null, + "current_plan": true, + "included_if": "no_active_subscription" + }, + { + "plan_key": "paid-20230926", + "product_key": "platform_and_support", + "name": "Platform and support", + "description": "SSO, permission management, and support.", + "image_url": "https://posthog.com/images/product/product-icons/platform.svg", + "docs_url": "https://posthog.com/docs", + "note": null, + "unit": null, + "free_allocation": null, + "features": [ + { + "key": "tracked_users", + "name": "Tracked users", + "description": "Track users across devices and sessions.", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "team_members", + "name": "Team members", + "description": "PostHog doesn't charge per seat add your entire team!", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "organizations_projects", + "name": "Projects", + "description": "Create silos of data within PostHog. All data belongs to a single project and all queries are project-specific.", + "unit": null, + "limit": null, + "note": "Unlimited" + }, + { + "key": "api_access", + "name": "API access", + "description": "Access your data via our developer-friendly API.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "social_sso", + "name": "SSO via Google, Github, or Gitlab", + "description": "Log in to PostHog with your Google, Github, or Gitlab account.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "project_based_permissioning", + "name": "Project permissions", + "description": "Restrict access to data within the organization to only those who need it.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "white_labelling", + "name": "White labeling", + "description": "Use your own branding in your PostHog organization.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "community_support", + "name": "Community support", + "description": "Get help from other users and PostHog team members in our Community forums.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "dedicated_support", + "name": "Slack (dedicated channel)", + "description": "Get help firectly from our support team in a dedicated Slack channel shared between you and the PostHog team.", + "unit": null, + "limit": null, + "note": "$2k/month spend or above" + }, + { + "key": "email_support", + "name": "Direct access to engineers", + "description": "Get help directly from our product engineers via email. No wading through multiple support people before you get help.", + "unit": null, + "limit": null, + "note": null + }, + { + "key": "terms_and_conditions", + "name": "Terms and conditions", + "description": "Terms and conditions", + "unit": null, + "limit": null, + "note": "Standard" + }, + { + "key": "security_assessment", + "name": "Security assessment", + "description": "Security assessment", + "unit": null, + "limit": null, + "note": null + } + ], + "tiers": null, + "current_plan": false, + "included_if": "has_subscription" + } + ], + "type": "platform_and_support", + "free_allocation": 0, + "tiers": null, + "tiered": false, + "unit_amount_usd": null, + "current_amount_usd_before_addons": null, + "current_amount_usd": null, + "current_usage": 0, + "usage_limit": 0, + "has_exceeded_limit": false, + "percentage_usage": 0, + "projected_usage": 0, + "projected_amount_usd": null, + "unit": null, + "addons": [], + "contact_support": true, + "inclusion_only": true + } + ], + "custom_limits_usd": {}, + "usage_summary": { + "events": { + "usage": 0, + "limit": 1000000 + }, + "recordings": { + "usage": 0, + "limit": 15000 + }, + "feature_flag_requests": { + "usage": 0, + "limit": 1000000 + }, + "survey_responses": { + "usage": 0, + "limit": 250 + } + }, + "free_trial_until": null, + "discount_percent": null, + "discount_amount_usd": null, + "amount_off_expires_at": null, + "never_drop_data": null, + "stripe_portal_url": "https://billing.stripe.com/p/session/test_YWNjdF8xSElNRERFdUlhdFJYU2R6LF9QN0ltZVQ3RmpLbTZacXgzYWo3Q0FFbFpITHZydlpK0100iKmkfAZi" +} diff --git a/frontend/src/scenes/billing/PlanComparison.tsx b/frontend/src/scenes/billing/PlanComparison.tsx index 3b341f534f9ecb..6c54369d984cae 100644 --- a/frontend/src/scenes/billing/PlanComparison.tsx +++ b/frontend/src/scenes/billing/PlanComparison.tsx @@ -63,7 +63,7 @@ const getProductTiers = ( {tiers ? ( tiers?.map((tier, i) => (
@@ -79,7 +79,7 @@ const getProductTiers = ( )) ) : product?.free_allocation ? (
@@ -111,7 +111,7 @@ export const PlanComparison = ({ const upgradeButtons = plans?.map((plan) => { return ( - + - {!feature ? ( - <> - - - ) : feature.limit ? ( - <> - - {feature.limit && - `${convertLargeNumberToWords(feature.limit, null)} ${feature.unit && feature.unit}${ - timeDenominator ? `/${timeDenominator}` : '' - }`} - {feature.note} - - ) : ( - <> - - {feature.note} - - )} -
- ) -} - -const getPlanBasePrice = (plan: BillingV2PlanType): number | string => { - const basePlan = plan.products.find((product) => product.type === 'enterprise' || product.type === 'base') - if (basePlan?.unit_amount_usd) { - return `$${parseInt(basePlan.unit_amount_usd)}/mo` - } - if (plan.is_free) { - return 'Free forever' - } - return '$0/mo' -} - -const convertLargeNumberToWords = ( - // The number to convert - num: number | null, - // The previous tier's number - previousNum: number | null, - // Whether we will be showing multiple tiers (to denote the first tier with 'first') - multipleTiers: boolean = false, - // The product type (to denote the unit) - productType: BillingProductV2Type['type'] | null = null -): string => { - if (num === null && previousNum) { - return `${convertLargeNumberToWords(previousNum, null)} +` - } - if (num === null) { - return '' - } - - let denominator = 1 - - if (num >= 1000000) { - denominator = 1000000 - } else if (num >= 1000) { - denominator = 1000 - } - - return `${previousNum ? `${(previousNum / denominator).toFixed(0)}-` : multipleTiers ? 'First ' : ''}${( - num / denominator - ).toFixed(0)}${denominator === 1000000 ? ' million' : denominator === 1000 ? 'k' : ''}${ - !previousNum && multipleTiers ? ` ${productType}/mo` : '' - }` -} - -const getProductTiers = (plan: BillingV2PlanType, productType: BillingProductV2Type['type']): JSX.Element => { - const product = plan.products.find((planProduct) => planProduct.type === productType) - const tiers = product?.tiers - return ( - <> - {tiers ? ( - tiers?.map((tier, i) => ( -
- - {convertLargeNumberToWords(tier.up_to, tiers[i - 1]?.up_to, true, productType)} - - - {i === 0 && parseFloat(tier.unit_amount_usd) === 0 - ? // if the base product has a price, then the first tier is included, otherwise it's free - plan.products.filter((p) => p.type === 'base')?.[0]?.unit_amount_usd - ? 'Included' - : 'Free' - : `$${parseFloat(tier.unit_amount_usd).toFixed(6)}`} - -
- )) - ) : product?.free_allocation ? ( -
- - Up to {convertLargeNumberToWords(product?.free_allocation, null)} {product?.type}/mo - - Free -
- ) : null} - - ) -} - -export function PlanTable({ redirectPath }: { redirectPath: string }): JSX.Element { - const { billing } = useValues(billingLogic) - const { reportBillingUpgradeClicked } = useActions(eventUsageLogic) - - const plans = billing?.available_plans?.filter((plan) => plan.name !== 'Enterprise') - - const excludedFeatures: string[] = [AvailableFeature.DASHBOARD_COLLABORATION] - - const upgradeButtons = plans?.map((plan) => ( - - { - if (!plan.is_free) { - reportBillingUpgradeClicked(plan.name) - } - }} - > - {!billing?.has_active_subscription && plan.is_free ? 'Current plan' : 'Upgrade'} - - - )) - - return !plans?.length ? ( - - ) : ( -
- - - - - ))} - - - - - - - - - {plans?.map((plan) => ( - - ))} - - {plans - ? plans[plans.length - 1].products - .filter((product) => product.type !== 'base') - .map((product, i) => ( - - - {plans?.map((plan) => ( - - ))} - - )) - : null} - - - - - - - {plans?.length > 0 - ? plans[plans.length - 1].products.map((product) => - product.feature_groups?.map((feature_group) => ( - <> - - - {(product.type === 'events' || product.type === 'recordings') && - plans?.map((plan) => ( - - ))} - - {feature_group.features.map((feature: BillingV2FeatureType, j: number) => { - return excludedFeatures.includes(feature.key) ? ( - <> - ) : ( - - - {plans?.map((plan) => ( - - ))} - - ) - })} - - )) - ) - : null} - - - -
- {plans?.map((plan) => ( - -

{plan.name}

-

{plan.description}

-
- Pricing -
Monthly base price - {getPlanBasePrice(plan)} -
- {product.name} -

- Priced per {product.type === 'events' ? 'event' : 'recording'} -

-
- {getProductTiers(plan, product.type)} -
- {upgradeButtons} -
- Features -
{feature_group.name} - p.type === product.type) - ?.free_allocation, - }} - timeDenominator="mo" - className={'text-base'} - /> -
- {feature.name} - - p.type === product.type) - ?.feature_groups?.find( - (fg) => fg.name === feature_group.name - ) - ?.features?.find((f) => f.key === feature.key)} - className={'text-base'} - /> -
- {upgradeButtons} -
-
- ) -} diff --git a/frontend/src/scenes/billing/billingLogic.ts b/frontend/src/scenes/billing/billingLogic.ts index 63c5c5222d9e83..ec549af6fe2641 100644 --- a/frontend/src/scenes/billing/billingLogic.ts +++ b/frontend/src/scenes/billing/billingLogic.ts @@ -200,7 +200,7 @@ export const billingLogic = kea([ } const productOverLimit = billing.products?.find((x: BillingProductV2Type) => { - return x.percentage_usage > 1 + return x.percentage_usage > 1 && x.usage_key }) if (productOverLimit) { @@ -223,7 +223,9 @@ export const billingLogic = kea([ title: 'You will soon hit your usage limit', message: `You have currently used ${parseFloat( (productApproachingLimit.percentage_usage * 100).toFixed(2) - )}% of your ${productApproachingLimit.usage_key.toLowerCase()} allocation.`, + )}% of your ${ + productApproachingLimit.usage_key && productApproachingLimit.usage_key.toLowerCase() + } allocation.`, } } diff --git a/frontend/src/scenes/billing/billingProductLogic.ts b/frontend/src/scenes/billing/billingProductLogic.ts index 5d78ef5ac7e81e..56e279ac2a66b6 100644 --- a/frontend/src/scenes/billing/billingProductLogic.ts +++ b/frontend/src/scenes/billing/billingProductLogic.ts @@ -104,7 +104,10 @@ export const billingProductLogic = kea([ customLimitUsd: [ (s, p) => [s.billing, p.product], (billing, product) => { - return billing?.custom_limits_usd?.[product.type] || billing?.custom_limits_usd?.[product.usage_key] + return ( + billing?.custom_limits_usd?.[product.type] || + (product.usage_key ? billing?.custom_limits_usd?.[product.usage_key] : '') + ) }, ], currentAndUpgradePlans: [ diff --git a/frontend/src/scenes/onboarding/Onboarding.stories.tsx b/frontend/src/scenes/onboarding/Onboarding.stories.tsx new file mode 100644 index 00000000000000..971a3651ebc472 --- /dev/null +++ b/frontend/src/scenes/onboarding/Onboarding.stories.tsx @@ -0,0 +1,93 @@ +import { Meta } from '@storybook/react' +import { useActions, useMountedLogic } from 'kea' +import { router } from 'kea-router' +import { useEffect } from 'react' +import { App } from 'scenes/App' +import { urls } from 'scenes/urls' + +import { mswDecorator, useStorybookMocks } from '~/mocks/browser' +import billingUnsubscribedJson from '~/mocks/fixtures/_billing_unsubscribed.json' +import billingJson from '~/mocks/fixtures/_billing_v2.json' +import preflightJson from '~/mocks/fixtures/_preflight.json' +import { BillingProductV2Type, ProductKey } from '~/types' + +import { onboardingLogic, OnboardingStepKey } from './onboardingLogic' + +const meta: Meta = { + title: 'Scenes-Other/Onboarding', + parameters: { + layout: 'fullscreen', + viewMode: 'story', + mockDate: '2023-05-25', + }, + decorators: [ + mswDecorator({ + get: { + '/_preflight': { + ...preflightJson, + cloud: true, + realm: 'cloud', + }, + }, + }), + ], +} +export default meta +export const _OnboardingSDKs = (): JSX.Element => { + useStorybookMocks({ + get: { + '/api/billing-v2/': { + ...billingJson, + }, + }, + }) + useMountedLogic(onboardingLogic) + const { setProduct } = useActions(onboardingLogic) + + useEffect(() => { + const product: BillingProductV2Type = billingJson.products[1] as BillingProductV2Type + setProduct(product) + router.actions.push(urls.onboarding(ProductKey.SESSION_REPLAY) + '?step=sdks') + }, []) + return +} + +export const _OnboardingBilling = (): JSX.Element => { + useStorybookMocks({ + get: { + '/api/billing-v2/': { + ...billingUnsubscribedJson, + }, + }, + }) + useMountedLogic(onboardingLogic) + const { setProduct, setStepKey } = useActions(onboardingLogic) + + useEffect(() => { + const product: BillingProductV2Type = billingUnsubscribedJson.products[1] as BillingProductV2Type + setProduct(product) + router.actions.push(urls.onboarding(ProductKey.SESSION_REPLAY)) + setStepKey(OnboardingStepKey.BILLING) + }, []) + return +} + +export const _OnboardingOtherProducts = (): JSX.Element => { + useStorybookMocks({ + get: { + '/api/billing-v2/': { + ...billingJson, + }, + }, + }) + useMountedLogic(onboardingLogic) + const { setProduct, setStepKey } = useActions(onboardingLogic) + + useEffect(() => { + const product: BillingProductV2Type = billingJson.products[1] as BillingProductV2Type + setProduct(product) + router.actions.push(urls.onboarding(ProductKey.SESSION_REPLAY)) + setStepKey(OnboardingStepKey.OTHER_PRODUCTS) + }, []) + return +} diff --git a/frontend/src/scenes/onboarding/sdks/SDKs.tsx b/frontend/src/scenes/onboarding/sdks/SDKs.tsx index 3c51ba77b0a720..0627a11bac8ead 100644 --- a/frontend/src/scenes/onboarding/sdks/SDKs.tsx +++ b/frontend/src/scenes/onboarding/sdks/SDKs.tsx @@ -73,7 +73,14 @@ export function SDKs({ onClick={selectedSDK?.key !== sdk.key ? () => setSelectedSDK(sdk) : undefined} fullWidth icon={ - typeof sdk.image === 'string' ? : sdk.image + typeof sdk.image === 'string' ? ( + + ) : // storybook handles require() differently and returns an object, from which we can use the url in .default + typeof sdk.image === 'object' && 'default' in sdk.image ? ( + + ) : ( + sdk.image + ) } > {sdk.name} diff --git a/frontend/src/scenes/products/Products.stories.tsx b/frontend/src/scenes/products/Products.stories.tsx new file mode 100644 index 00000000000000..cea22b96b3f972 --- /dev/null +++ b/frontend/src/scenes/products/Products.stories.tsx @@ -0,0 +1,44 @@ +import { Meta } from '@storybook/react' +import { router } from 'kea-router' +import { useEffect } from 'react' +import { App } from 'scenes/App' +import { urls } from 'scenes/urls' + +import { mswDecorator, useStorybookMocks } from '~/mocks/browser' +import billingJson from '~/mocks/fixtures/_billing_v2.json' +import preflightJson from '~/mocks/fixtures/_preflight.json' + +const meta: Meta = { + title: 'Scenes-Other/Products', + parameters: { + layout: 'fullscreen', + viewMode: 'story', + mockDate: '2023-05-25', + }, + decorators: [ + mswDecorator({ + get: { + '/_preflight': { + ...preflightJson, + cloud: true, + realm: 'cloud', + }, + }, + }), + ], +} +export default meta +export const _Products = (): JSX.Element => { + useStorybookMocks({ + get: { + '/api/billing-v2/': { + ...billingJson, + }, + }, + }) + + useEffect(() => { + router.actions.push(urls.products()) + }, []) + return +} diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 71c748ba01325a..309fb338084dd2 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -92,15 +92,6 @@ export enum AvailableFeature { SURVEYS_MULTIPLE_QUESTIONS = 'surveys_multiple_questions', } -export type AvailableProductFeature = { - key: AvailableFeature - name: string - description?: string | null - limit?: number | null - note?: string | null - unit?: string | null -} - export enum ProductKey { COHORTS = 'cohorts', ACTIONS = 'actions', @@ -234,7 +225,7 @@ export interface OrganizationType extends OrganizationBasicType { plugins_access_level: PluginsAccessLevel teams: TeamBasicType[] | null available_features: AvailableFeature[] - available_product_features: AvailableProductFeature[] + available_product_features: BillingV2FeatureType[] is_member_join_email_enabled: boolean customer_id: string | null enforce_2fa: boolean | null @@ -1203,14 +1194,13 @@ export interface CurrentBillCycleType { current_period_end: number } -export interface BillingV2FeatureType { - key: string +export type BillingV2FeatureType = { + key: AvailableFeature name: string - description?: string - unit?: string - limit?: number - note?: string - group?: AvailableFeature + description?: string | null + limit?: number | null + note?: string | null + unit?: string | null } export interface BillingV2TierType { @@ -1225,36 +1215,30 @@ export interface BillingV2TierType { export interface BillingProductV2Type { type: string - usage_key: string + usage_key: string | null name: string description: string price_description?: string | null icon_key?: string | null image_url?: string | null docs_url: string | null - free_allocation?: number - subscribed: boolean + free_allocation?: number | null + subscribed: boolean | null tiers?: BillingV2TierType[] | null tiered: boolean current_usage?: number - projected_amount_usd?: string + projected_amount_usd?: string | null projected_usage?: number percentage_usage: number current_amount_usd_before_addons: string | null current_amount_usd: string | null usage_limit: number | null has_exceeded_limit: boolean - unit: string + unit: string | null unit_amount_usd: string | null plans: BillingV2PlanType[] contact_support: boolean inclusion_only: any - feature_groups: { - // deprecated, remove after removing the billing plans table - group: string - name: string - features: BillingV2FeatureType[] - }[] addons: BillingProductV2AddonType[] // addons-only: if this addon is included with the base product and not subscribed individually. for backwards compatibility. @@ -1283,7 +1267,7 @@ export interface BillingProductV2AddonType { projected_amount_usd: string | null plans: BillingV2PlanType[] usage_key: string - free_allocation?: number + free_allocation?: number | null percentage_usage?: number } export interface BillingV2Type { @@ -1314,16 +1298,14 @@ export interface BillingV2Type { } export interface BillingV2PlanType { - free_allocation?: number + free_allocation?: number | null features: BillingV2FeatureType[] - key: string name: string description: string is_free?: boolean - products: BillingProductV2Type[] plan_key?: string current_plan?: any - tiers?: BillingV2TierType[] + tiers?: BillingV2TierType[] | null included_if?: 'no_active_subscription' | 'has_subscription' | null initial_billing_limit?: number } @@ -3433,7 +3415,13 @@ export type SDK = { key: string recommended?: boolean tags: string[] - image: string | JSX.Element + image: + | string + | JSX.Element + // storybook handles require() differently, so we need to support both + | { + default: string + } docsLink: string }