Path: blob/main/components/dashboard/src/start/OnaBanner.tsx
2500 views
/**1* Copyright (c) 2024 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import React, { useEffect, useState } from "react";7import { trackEvent } from "../Analytics";8import { useCurrentUser } from "../user-context";9import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";10import { useToast } from "../components/toasts/Toasts";11import onaWordmark from "../images/ona-wordmark.svg";1213const onaBanner = {14type: "Introducing",15title: "ONA",16subtitle: "Parallel SWE agents in the cloud, sandboxed for high-autonomy.",17ctaText: "Get early access",18learnMoreText: "Learn more",19link: "https://ona.com/stories/gitpod-classic-payg-sunset",20};2122interface OnaBannerProps {23compact?: boolean;24}2526export const OnaBanner: React.FC<OnaBannerProps> = ({ compact = false }) => {27const [onaClicked, setOnaClicked] = useState(false);28const [isDismissed, setIsDismissed] = useState(false);29const user = useCurrentUser();30const { toast } = useToast();3132useEffect(() => {33const storedOnaData = localStorage.getItem("ona-banner-data");3435if (storedOnaData) {36const { clicked, dismissed } = JSON.parse(storedOnaData);37setOnaClicked(clicked || false);38setIsDismissed(dismissed || false);39}40}, []);4142const handleOnaBannerClick = () => {43// Track "Get early access" click44const userEmail = user ? getPrimaryEmail(user) || "" : "";45trackEvent("waitlist_joined", { email: userEmail, feature: "Ona" });4647setOnaClicked(true);48localStorage.setItem("ona-banner-data", JSON.stringify({ clicked: true, dismissed: isDismissed }));4950// Show success toast51toast(52<div>53<div className="font-medium">You're on the waitlist</div>54<div className="text-sm opacity-80">We'll reach out to you soon.</div>55</div>,56);57};5859const handleDismiss = () => {60setIsDismissed(true);61localStorage.setItem("ona-banner-data", JSON.stringify({ clicked: onaClicked, dismissed: true }));62};6364// Don't render if dismissed65if (isDismissed) {66return null;67}6869if (compact) {70return (71<div72className="relative rounded-lg hidden lg:flex flex-col gap-3 text-white max-w-80 p-4 shadow-lg"73style={{74background:75"linear-gradient(340deg, #1F1329 0%, #333A75 20%, #556CA8 40%, #90A898 60%, #E2B15C 80%, #BEA462 100%)",76}}77>78{/* Close button */}79<button80onClick={handleDismiss}81className="absolute top-3 right-3 text-white/70 hover:text-white w-6 h-6 flex items-center justify-center rounded-full hover:bg-white/10 transition-colors"82aria-label="Dismiss banner"83>84✕85</button>8687{/* Compact layout */}88<div className="flex items-center gap-2 text-sm font-normal">89{onaBanner.type}90<img src={onaWordmark} alt="ONA" className="w-12" draggable="false" />91</div>9293<p className="text-white text-base font-semibold leading-tight text-left">94Parallel SWE agents in the cloud, sandboxed for high-autonomy.95</p>9697<a98href={onaBanner.link}99target="_blank"100rel="noopener noreferrer"101className="bg-white/20 backdrop-blur-sm text-white font-medium py-1 px-3 rounded-full hover:bg-white/30 transition-colors border border-white/20 inline-flex items-center gap-2 text-sm w-fit"102>103{onaBanner.learnMoreText}104<span className="font-bold">→</span>105</a>106</div>107);108}109110return (111<div112className="relative rounded-lg flex flex-col lg:flex-row gap-6 text-white max-w-5xl mx-auto p-4 lg:p-4 mt-6 mb-2"113style={{114background:115"linear-gradient(340deg, #1F1329 0%, #333A75 20%, #556CA8 40%, #90A898 60%, #E2B15C 80%, #BEA462 100%)",116}}117>118{/* Close button */}119<button120onClick={handleDismiss}121className="absolute top-2 right-2 text-white/70 hover:text-white w-6 h-6 flex items-center justify-center rounded-full hover:bg-white/10 transition-colors z-10"122aria-label="Dismiss banner"123>124✕125</button>126127{/* Left section - ONA branding and image */}128<div className="flex-1 max-w-full lg:max-w-[330px] order-1">129<div className="relative bg-white/10 backdrop-blur-sm rounded-lg h-full flex items-center justify-center px-4 lg:px-6 py-4 lg:py-6">130{/* ONA Logo prominently displayed */}131<div className="flex justify-center">132<img src={onaWordmark} alt="ONA" className="w-28 lg:w-36" draggable="false" />133</div>134</div>135</div>136137{/* Right section - Text content and CTA */}138<div className="flex-1 max-w-[500px] lg:max-w-[550px] order-2 text-left">139<div className="max-lg:mt-2 max-w-sm space-y-3 lg:space-y-4">140{/* Main title */}141<h2 className="text-white text-lg sm:text-lg font-bold">142The privacy-first software engineering agent143</h2>144145{/* CTA Button */}146<div className="mt-2 mb-4">147{!onaClicked ? (148<button149onClick={handleOnaBannerClick}150className="inline-flex items-center justify-center gap-2 bg-[#fdfdfd] text-[#12100C] px-3 py-1.5 rounded-[8px] text-xs transition-all duration-200 shadow-sm hover:shadow-md focus:shadow-md hover:bg-[#F5F4F3] font-medium"151>152<span>{onaBanner.ctaText}</span>153<span className="font-bold">→</span>154</button>155) : (156<a157href={onaBanner.link}158target="_blank"159rel="noopener noreferrer"160className="inline-flex items-center justify-center gap-2 bg-[#fdfdfd] text-[#12100C] px-3 py-1.5 rounded-[8px] text-xs transition-all duration-200 shadow-sm hover:shadow-md focus:shadow-md hover:bg-[#F5F4F3] font-medium"161>162<span>{onaBanner.learnMoreText}</span>163<span className="font-bold">→</span>164</a>165)}166</div>167</div>168</div>169</div>170);171};172173174