mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
feat(misc): Add GitHub star toast (#409)
* github star toast * changelog
This commit is contained in:
parent
50dc59886a
commit
45416a41d1
4 changed files with 90 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
84
packages/web/src/app/[domain]/components/githubStarToast.tsx
Normal file
84
packages/web/src/app/[domain]/components/githubStarToast.tsx
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
@ -134,6 +135,7 @@ export default async function Layout({
|
|||
<SyntaxGuideProvider>
|
||||
{children}
|
||||
<SyntaxReferenceGuide />
|
||||
<GitHubStarToast />
|
||||
</SyntaxGuideProvider>
|
||||
)
|
||||
}
|
||||
|
|
@ -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;
|
||||
Loading…
Reference in a new issue