Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/workspaces/BlogBanners.tsx
2500 views
1
/**
2
* Copyright (c) 2024 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import React, { useEffect, useState } from "react";
8
import { trackEvent } from "../Analytics";
9
import { useCurrentUser } from "../user-context";
10
import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";
11
import { useToast } from "../components/toasts/Toasts";
12
import onaWordmark from "../images/ona-wordmark.svg";
13
14
const onaBanner = {
15
type: "Introducing",
16
title: "ONA",
17
subtitle: "Parallel SWE agents in the cloud, sandboxed for high-autonomy.",
18
ctaText: "Get early access",
19
learnMoreText: "Learn more",
20
link: "https://ona.com/stories/gitpod-classic-payg-sunset",
21
};
22
23
export const OnaBanner: React.FC = () => {
24
const [onaClicked, setOnaClicked] = useState(false);
25
const [isDismissed, setIsDismissed] = useState(false);
26
const user = useCurrentUser();
27
const { toast } = useToast();
28
29
useEffect(() => {
30
const storedOnaData = localStorage.getItem("workspaces-ona-banner-data");
31
32
// Check Ona banner state
33
if (storedOnaData) {
34
const { clicked, dismissed } = JSON.parse(storedOnaData);
35
setOnaClicked(clicked || false);
36
setIsDismissed(dismissed || false);
37
}
38
39
// Clean up old blog banner data
40
localStorage.removeItem("blog-banner-data");
41
}, []);
42
43
const handleOnaBannerClick = () => {
44
if (!onaClicked) {
45
// Track "Get early access" click
46
const userEmail = user ? getPrimaryEmail(user) || "" : "";
47
trackEvent("waitlist_joined", { email: userEmail, feature: "Ona" });
48
49
setOnaClicked(true);
50
localStorage.setItem(
51
"workspaces-ona-banner-data",
52
JSON.stringify({ clicked: true, dismissed: isDismissed }),
53
);
54
55
// Also set the global ona-banner-data clicked state (preserve existing dismissed state)
56
const existingOnaData = localStorage.getItem("ona-banner-data");
57
const existingDismissed = existingOnaData ? JSON.parse(existingOnaData).dismissed || false : false;
58
localStorage.setItem("ona-banner-data", JSON.stringify({ clicked: true, dismissed: existingDismissed }));
59
60
// Show success toast
61
toast(
62
<div>
63
<div className="font-medium">You're on the waitlist</div>
64
<div className="text-sm opacity-80">We'll reach out to you soon.</div>
65
</div>,
66
);
67
} else {
68
// "Learn more" click - open link
69
window.open(onaBanner.link, "_blank", "noopener,noreferrer");
70
}
71
};
72
73
const handleDismiss = () => {
74
setIsDismissed(true);
75
localStorage.setItem("workspaces-ona-banner-data", JSON.stringify({ clicked: onaClicked, dismissed: true }));
76
};
77
78
// Don't render if dismissed
79
if (isDismissed) {
80
return null;
81
}
82
83
return (
84
<div className="flex flex-col gap-4">
85
<div
86
className="relative rounded-lg overflow-hidden flex flex-col gap-4 text-white max-w-[320px] p-6"
87
style={{
88
background:
89
"linear-gradient(340deg, #1F1329 0%, #333A75 20%, #556CA8 40%, #90A898 60%, #E2B15C 80%, #BEA462 100%)",
90
}}
91
>
92
{/* Close button */}
93
<button
94
onClick={handleDismiss}
95
className="absolute top-4 right-4 text-white/70 hover:text-white w-6 h-6 flex items-center justify-center rounded-full hover:bg-white/10 transition-colors"
96
aria-label="Dismiss banner"
97
>
98
99
</button>
100
101
{/* Content */}
102
<div className="flex flex-col gap-4">
103
<div className="flex items-center gap-2 text-lg font-normal">
104
{onaBanner.type}
105
<img src={onaWordmark} alt="ONA" className="w-16" draggable="false" />
106
</div>
107
<div className="text-base font-normal opacity-90">{onaBanner.subtitle}</div>
108
</div>
109
110
{/* CTA Button */}
111
<button
112
onClick={handleOnaBannerClick}
113
className="bg-white/20 backdrop-blur-sm text-white font-medium py-1 px-6 rounded-full hover:bg-white/30 transition-colors border border-white/20 max-w-[180px]"
114
>
115
{onaClicked ? onaBanner.learnMoreText : onaBanner.ctaText}
116
</button>
117
</div>
118
</div>
119
);
120
};
121
122
// Export with old name for backward compatibility
123
export const BlogBanners = OnaBanner;
124
125