1use std::sync::Arc;
2
3use ai_onboarding::{AgentPanelOnboardingCard, PlanDefinitions};
4use client::zed_urls;
5use gpui::{AnyElement, App, IntoElement, RenderOnce, Window};
6use ui::{Divider, Tooltip, prelude::*};
7
8#[derive(IntoElement, RegisterComponent)]
9pub struct EndTrialUpsell {
10 dismiss_upsell: Arc<dyn Fn(&mut Window, &mut App)>,
11}
12
13impl EndTrialUpsell {
14 pub fn new(dismiss_upsell: Arc<dyn Fn(&mut Window, &mut App)>) -> Self {
15 Self { dismiss_upsell }
16 }
17}
18
19impl RenderOnce for EndTrialUpsell {
20 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
21 let plan_definitions = PlanDefinitions;
22
23 let pro_section = v_flex()
24 .gap_1()
25 .child(
26 h_flex()
27 .gap_2()
28 .child(
29 Label::new("Pro")
30 .size(LabelSize::Small)
31 .color(Color::Accent)
32 .buffer_font(cx),
33 )
34 .child(Divider::horizontal()),
35 )
36 .child(plan_definitions.pro_plan(false))
37 .child(
38 Button::new("cta-button", "Upgrade to Zed Pro")
39 .full_width()
40 .style(ButtonStyle::Tinted(ui::TintColor::Accent))
41 .on_click(move |_, _window, cx| {
42 telemetry::event!("Upgrade To Pro Clicked", state = "end-of-trial");
43 cx.open_url(&zed_urls::upgrade_to_zed_pro_url(cx))
44 }),
45 );
46
47 let free_section = v_flex()
48 .mt_1p5()
49 .gap_1()
50 .child(
51 h_flex()
52 .gap_2()
53 .child(
54 Label::new("Free")
55 .size(LabelSize::Small)
56 .color(Color::Muted)
57 .buffer_font(cx),
58 )
59 .child(
60 Label::new("(Current Plan)")
61 .size(LabelSize::Small)
62 .color(Color::Custom(cx.theme().colors().text_muted.opacity(0.6)))
63 .buffer_font(cx),
64 )
65 .child(Divider::horizontal()),
66 )
67 .child(plan_definitions.free_plan());
68
69 AgentPanelOnboardingCard::new()
70 .child(Headline::new("Your Zed Pro Trial has expired"))
71 .child(
72 Label::new("You've been automatically reset to the Free plan.")
73 .color(Color::Muted)
74 .mb_2(),
75 )
76 .child(pro_section)
77 .child(free_section)
78 .child(
79 h_flex().absolute().top_4().right_4().child(
80 IconButton::new("dismiss_onboarding", IconName::Close)
81 .icon_size(IconSize::Small)
82 .tooltip(Tooltip::text("Dismiss"))
83 .on_click({
84 let callback = self.dismiss_upsell.clone();
85 move |_, window, cx| {
86 telemetry::event!("Banner Dismissed", source = "AI Onboarding");
87 callback(window, cx)
88 }
89 }),
90 ),
91 )
92 }
93}
94
95impl Component for EndTrialUpsell {
96 fn scope() -> ComponentScope {
97 ComponentScope::Onboarding
98 }
99
100 fn name() -> &'static str {
101 "End of Trial Upsell Banner"
102 }
103
104 fn sort_name() -> &'static str {
105 "End of Trial Upsell Banner"
106 }
107
108 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
109 Some(
110 v_flex()
111 .child(EndTrialUpsell {
112 dismiss_upsell: Arc::new(|_, _| {}),
113 })
114 .into_any_element(),
115 )
116 }
117}