Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add search context to ask sourcebot context selector. [#397](https://github.com/sourcebot-dev/sourcebot/pull/397)
- Add ability to include/exclude connection in search context. [#399](https://github.com/sourcebot-dev/sourcebot/pull/399)
- Search context refactor to search scope and demo card UI changes. [#405](https://github.com/sourcebot-dev/sourcebot/pull/405)
- Add GitHub star toast. [#409](https://github.com/sourcebot-dev/sourcebot/pull/409)

### Fixed
- Fixed multiple writes race condition on config file watcher. [#398](https://github.com/sourcebot-dev/sourcebot/pull/398)
Expand Down
84 changes: 84 additions & 0 deletions packages/web/src/app/[domain]/components/githubStarToast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use client';

import { useToast } from "@/components/hooks/use-toast";
import { ToastAction } from "@/components/ui/toast";
import { useEffect } from "react";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import { captureEvent } from "@/hooks/useCaptureEvent";

const POPUP_SHOWN_COOKIE = "github_popup_shown";
const POPUP_START_TIME_COOKIE = "github_popup_start_time";
const POPUP_DELAY_S = 60;
const SOURCEBOT_GITHUB_URL = "https://github.com/sourcebot-dev/sourcebot";

function getCookie(name: string): string | null {
if (typeof document === "undefined") return null;

const cookies = document.cookie.split(';').map(cookie => cookie.trim());
const targetCookie = cookies.find(cookie => cookie.startsWith(`${name}=`));

if (!targetCookie) return null;

return targetCookie.substring(`${name}=`.length);
}

function setCookie(name: string, value: string, days: number = 365) {
if (typeof document === "undefined") return;

try {
const expires = new Date();
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${value}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;
} catch (error) {
console.warn('Failed to set GitHub popup cookie:', error);
}
}

export const GitHubStarToast = () => {
const { toast } = useToast();

useEffect(() => {
const hasShownPopup = getCookie(POPUP_SHOWN_COOKIE);
const startTime = getCookie(POPUP_START_TIME_COOKIE);

if (hasShownPopup) {
return;
}

const currentTime = Date.now();
if (!startTime) {
setCookie(POPUP_START_TIME_COOKIE, currentTime.toString());
return;
}

const elapsed = currentTime - parseInt(startTime, 10);
if (elapsed >= (POPUP_DELAY_S * 1000)) {
toast({
title: "Star us on GitHub ❤️",
description: "If you've found Sourcebot useful, please consider starring us on GitHub. Your support means a lot!",
duration: 15 * 1000,
action: (
<div className="flex flex-col gap-1">
<ToastAction
altText="GitHub Button"
onClick={() => {
captureEvent('wa_github_star_toast_clicked', {});
window.open(SOURCEBOT_GITHUB_URL, "_blank");
}}
>
<div className="flex items-center gap-2">
<GitHubLogoIcon className="w-4 h-4" />
Sourcebot
</div>
</ToastAction>
</div>
)
});

captureEvent('wa_github_star_toast_displayed', {});
setCookie(POPUP_SHOWN_COOKIE, "true");
}
}, [toast]);

return null;
}
2 changes: 2 additions & 0 deletions packages/web/src/app/[domain]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { GcpIapAuth } from "./components/gcpIapAuth";
import { getAnonymousAccessStatus, getMemberApprovalRequired } from "@/actions";
import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard";
import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch";
import { GitHubStarToast } from "./components/githubStarToast";

interface LayoutProps {
children: React.ReactNode,
Expand Down Expand Up @@ -134,6 +135,7 @@ export default async function Layout({
<SyntaxGuideProvider>
{children}
<SyntaxReferenceGuide />
<GitHubStarToast />
</SyntaxGuideProvider>
)
}
3 changes: 3 additions & 0 deletions packages/web/src/lib/posthogEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,5 +293,8 @@ export type PosthogEventMap = {
exampleTitle: string,
exampleUrl: string,
},
//////////////////////////////////////////////////////////////////
wa_github_star_toast_displayed: {},
wa_github_star_toast_clicked: {},
}
export type PosthogEvent = keyof PosthogEventMap;