From fbeee1f832c0cd1b658584931138406c53d05c99 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 9 May 2025 18:46:10 -0400 Subject: [PATCH] zeta: Update onboarding modal with subscription info (#30439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR updates the edit prediction onboarding modal with steps about subscribing to a plan. When the user is not subscribed to a plan, we display a link to the account page to sign up for one: Screenshot 2025-05-09 at 6 04 05 PM If the user is already subscribed to a plan we indicate which plan they are on and how many edit predictions they get with it: Screenshot 2025-05-09 at 6 03 16 PM Screenshot 2025-05-09 at 5 46 18 PM Release Notes: - N/A --- Cargo.lock | 1 + .../src/inline_completion_button.rs | 10 +++- crates/zeta/Cargo.toml | 1 + crates/zeta/src/onboarding_modal.rs | 49 ++++++++++++++++++- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60db87032f..10e949c359 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18952,6 +18952,7 @@ dependencies = [ "paths", "postage", "project", + "proto", "regex", "release_channel", "reqwest_client", diff --git a/crates/inline_completion_button/src/inline_completion_button.rs b/crates/inline_completion_button/src/inline_completion_button.rs index 1231063b89..296b169950 100644 --- a/crates/inline_completion_button/src/inline_completion_button.rs +++ b/crates/inline_completion_button/src/inline_completion_button.rs @@ -237,11 +237,17 @@ impl Render for InlineCompletionButton { let current_user_terms_accepted = self.user_store.read(cx).current_user_has_accepted_terms(); + let has_subscription = self.user_store.read(cx).current_plan().is_some() + && self.user_store.read(cx).subscription_period().is_some(); - if !current_user_terms_accepted.unwrap_or(false) { + if !has_subscription || !current_user_terms_accepted.unwrap_or(false) { let signed_in = current_user_terms_accepted.is_some(); let tooltip_meta = if signed_in { - "Read Terms of Service" + if has_subscription { + "Read Terms of Service" + } else { + "Choose a Plan" + } } else { "Sign in to use" }; diff --git a/crates/zeta/Cargo.toml b/crates/zeta/Cargo.toml index 0e3af9353e..8d3da636df 100644 --- a/crates/zeta/Cargo.toml +++ b/crates/zeta/Cargo.toml @@ -39,6 +39,7 @@ migrator.workspace = true paths.workspace = true postage.workspace = true project.workspace = true +proto.workspace = true regex.workspace = true release_channel.workspace = true serde.workspace = true diff --git a/crates/zeta/src/onboarding_modal.rs b/crates/zeta/src/onboarding_modal.rs index 321cfd0e90..80159cd075 100644 --- a/crates/zeta/src/onboarding_modal.rs +++ b/crates/zeta/src/onboarding_modal.rs @@ -2,7 +2,7 @@ use std::{sync::Arc, time::Duration}; use crate::{ZED_PREDICT_DATA_COLLECTION_CHOICE, onboarding_event}; use anyhow::Context as _; -use client::{Client, UserStore}; +use client::{Client, UserStore, zed_urls}; use db::kvp::KEY_VALUE_STORE; use fs::Fs; use gpui::{ @@ -246,6 +246,12 @@ impl Render for ZedPredictModal { let window_height = window.viewport_size().height; let max_height = window_height - px(200.); + let has_subscription_period = self.user_store.read(cx).subscription_period().is_some(); + let plan = self.user_store.read(cx).current_plan().filter(|_| { + // Since the user might be on the legacy free plan we filter based on whether we have a subscription period. + has_subscription_period + }); + let base = v_flex() .id("edit-prediction-onboarding") .key_context("ZedPredictModal") @@ -377,6 +383,45 @@ impl Render for ZedPredictModal { }; base.child(Label::new(copy).color(Color::Muted)) + .child(h_flex().map(|parent| { + if let Some(plan) = plan { + parent.child( + Checkbox::new("plan", ToggleState::Selected) + .fill() + .disabled(true) + .label(format!( + "You get {} edit predictions through your {}.", + if plan == proto::Plan::Free { + "2,000" + } else { + "unlimited" + }, + match plan { + proto::Plan::Free => "Zed Free plan", + proto::Plan::ZedPro => "Zed Pro plan", + proto::Plan::ZedProTrial => "Zed Pro trial", + } + )), + ) + } else { + parent + .child( + Checkbox::new("plan-required", ToggleState::Unselected) + .fill() + .disabled(true) + .label("To get started with edit prediction"), + ) + .child( + Button::new("subscribe", "choose a plan") + .icon(IconName::ArrowUpRight) + .icon_size(IconSize::Indicator) + .icon_color(Color::Muted) + .on_click(|_event, _window, cx| { + cx.open_url(&zed_urls::account_url(cx)); + }), + ) + } + })) .child( h_flex() .child( @@ -447,7 +492,7 @@ impl Render for ZedPredictModal { .w_full() .child( Button::new("accept-tos", "Enable Edit Prediction") - .disabled(!self.terms_of_service) + .disabled(plan.is_none() || !self.terms_of_service) .style(ButtonStyle::Tinted(TintColor::Accent)) .full_width() .on_click(cx.listener(Self::accept_and_enable)),