Better messaging for accounts that are too young (#31212)

Right now you find this out the first time you try and submit a
completion.

These changes communicate much earlier to the user what the issue is
with their account and what they can do about it.

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
Ben Brandt 2025-05-23 11:32:03 +02:00 committed by GitHub
parent 9f7987c532
commit 508ccde363
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 207 additions and 77 deletions

View file

@ -4,7 +4,6 @@ use std::sync::Arc;
use std::time::Duration;
use db::kvp::{Dismissable, KEY_VALUE_STORE};
use markdown::Markdown;
use serde::{Deserialize, Serialize};
use anyhow::{Result, anyhow};
@ -157,7 +156,7 @@ pub fn init(cx: &mut App) {
window.refresh();
})
.register_action(|_workspace, _: &ResetTrialUpsell, _window, cx| {
TrialUpsell::set_dismissed(false, cx);
Upsell::set_dismissed(false, cx);
})
.register_action(|_workspace, _: &ResetTrialEndUpsell, _window, cx| {
TrialEndUpsell::set_dismissed(false, cx);
@ -370,8 +369,7 @@ pub struct AgentPanel {
height: Option<Pixels>,
zoomed: bool,
pending_serialization: Option<Task<Result<()>>>,
hide_trial_upsell: bool,
_trial_markdown: Entity<Markdown>,
hide_upsell: bool,
}
impl AgentPanel {
@ -676,15 +674,6 @@ impl AgentPanel {
},
);
let trial_markdown = cx.new(|cx| {
Markdown::new(
include_str!("trial_markdown.md").into(),
Some(language_registry.clone()),
None,
cx,
)
});
Self {
active_view,
workspace,
@ -721,8 +710,7 @@ impl AgentPanel {
height: None,
zoomed: false,
pending_serialization: None,
hide_trial_upsell: false,
_trial_markdown: trial_markdown,
hide_upsell: false,
}
}
@ -1946,7 +1934,7 @@ impl AgentPanel {
return false;
}
if self.hide_trial_upsell || TrialUpsell::dismissed() {
if self.hide_upsell || Upsell::dismissed() {
return false;
}
@ -1976,7 +1964,7 @@ impl AgentPanel {
true
}
fn render_trial_upsell(
fn render_upsell(
&self,
_window: &mut Window,
cx: &mut Context<Self>,
@ -1985,6 +1973,14 @@ impl AgentPanel {
return None;
}
if self.user_store.read(cx).current_user_account_too_young() {
Some(self.render_young_account_upsell(cx).into_any_element())
} else {
Some(self.render_trial_upsell(cx).into_any_element())
}
}
fn render_young_account_upsell(&self, cx: &mut Context<Self>) -> impl IntoElement {
let checkbox = CheckboxWithLabel::new(
"dont-show-again",
Label::new("Don't show again").color(Color::Muted),
@ -1992,7 +1988,70 @@ impl AgentPanel {
move |toggle_state, _window, cx| {
let toggle_state_bool = toggle_state.selected();
TrialUpsell::set_dismissed(toggle_state_bool, cx);
Upsell::set_dismissed(toggle_state_bool, cx);
},
);
let contents = div()
.size_full()
.gap_2()
.flex()
.flex_col()
.child(Headline::new("Build better with Zed Pro").size(HeadlineSize::Small))
.child(
Label::new("Your GitHub account was created less than 30 days ago, so we can't offer you a free trial.")
.size(LabelSize::Small),
)
.child(
Label::new(
"Use your own API keys, upgrade to Zed Pro or send an email to billing-support@zed.dev.",
)
.color(Color::Muted),
)
.child(
h_flex()
.w_full()
.px_neg_1()
.justify_between()
.items_center()
.child(h_flex().items_center().gap_1().child(checkbox))
.child(
h_flex()
.gap_2()
.child(
Button::new("dismiss-button", "Not Now")
.style(ButtonStyle::Transparent)
.color(Color::Muted)
.on_click({
let agent_panel = cx.entity();
move |_, _, cx| {
agent_panel.update(cx, |this, cx| {
this.hide_upsell = true;
cx.notify();
});
}
}),
)
.child(
Button::new("cta-button", "Upgrade to Zed Pro")
.style(ButtonStyle::Transparent)
.on_click(|_, _, cx| cx.open_url(&zed_urls::account_url(cx))),
),
),
);
self.render_upsell_container(cx, contents)
}
fn render_trial_upsell(&self, cx: &mut Context<Self>) -> impl IntoElement {
let checkbox = CheckboxWithLabel::new(
"dont-show-again",
Label::new("Don't show again").color(Color::Muted),
ToggleState::Unselected,
move |toggle_state, _window, cx| {
let toggle_state_bool = toggle_state.selected();
Upsell::set_dismissed(toggle_state_bool, cx);
},
);
@ -2030,7 +2089,7 @@ impl AgentPanel {
let agent_panel = cx.entity();
move |_, _, cx| {
agent_panel.update(cx, |this, cx| {
this.hide_trial_upsell = true;
this.hide_upsell = true;
cx.notify();
});
}
@ -2044,7 +2103,7 @@ impl AgentPanel {
),
);
Some(self.render_upsell_container(cx, contents))
self.render_upsell_container(cx, contents)
}
fn render_trial_end_upsell(
@ -2910,7 +2969,7 @@ impl Render for AgentPanel {
.on_action(cx.listener(Self::reset_font_size))
.on_action(cx.listener(Self::toggle_zoom))
.child(self.render_toolbar(window, cx))
.children(self.render_trial_upsell(window, cx))
.children(self.render_upsell(window, cx))
.children(self.render_trial_end_upsell(window, cx))
.map(|parent| match &self.active_view {
ActiveView::Thread { .. } => parent
@ -3099,9 +3158,9 @@ impl AgentPanelDelegate for ConcreteAssistantPanelDelegate {
}
}
struct TrialUpsell;
struct Upsell;
impl Dismissable for TrialUpsell {
impl Dismissable for Upsell {
const KEY: &'static str = "dismissed-trial-upsell";
}

View file

@ -1,3 +0,0 @@
# Build better with Zed Pro
Try [Zed Pro](https://zed.dev/pricing) for free for 14 days - no credit card required. Only $20/month afterward. Cancel anytime.