Files
fusion/packages/dashboard/app/hooks/useGitHubStarPrompt.ts
gsxdsm 962b97ce84 FN-5967: add first-task GitHub star prompt
Show a one-time GitHub star prompt after a task first reaches done.

- detect task status transitions into done and trigger the prompt only in project view
- add a dismissible GitHub star prompt component plus localStorage-backed persistence hook
- cover the new prompt behavior with component, hook, and transition helper tests
- document the prompt behavior and styling guidance in the dashboard guide

Files changed:
 docs/dashboard-guide.md                            |  3 +
 packages/dashboard/app/App.tsx                     | 21 +++++-
 .../dashboard/app/components/GitHubStarPrompt.css  | 76 ++++++++++++++++++++++
 .../dashboard/app/components/GitHubStarPrompt.tsx  | 53 +++++++++++++++
 .../app/components/__tests__/App.test.tsx          | 12 +++-
 .../components/__tests__/GitHubStarPrompt.test.tsx | 40 ++++++++++++
 .../hooks/__tests__/useGitHubStarPrompt.test.ts    | 64 ++++++++++++++++++
 .../dashboard/app/hooks/useGitHubStarPrompt.ts     | 46 +++++++++++++
 8 files changed, 313 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-5967

Fusion-Task-Lineage: 5fffdf4d-61d8-4ac8-bcf4-8b453b639b28
2026-06-03 22:35:28 -07:00

47 lines
1.2 KiB
TypeScript

import { useSyncExternalStore } from "react";
const STORAGE_KEY = "fusion:github-star-prompt-shown";
const EVENT_NAME = "fusion:github-star-prompt-changed";
function read(): boolean {
if (typeof window === "undefined") return false;
try {
return window.localStorage.getItem(STORAGE_KEY) === "1";
} catch {
return false;
}
}
function subscribe(onChange: () => void): () => void {
if (typeof window === "undefined") return () => {};
const handleStorage = (event: StorageEvent) => {
if (event.key === STORAGE_KEY) {
onChange();
}
};
const handleCustom = () => onChange();
window.addEventListener("storage", handleStorage);
window.addEventListener(EVENT_NAME, handleCustom);
return () => {
window.removeEventListener("storage", handleStorage);
window.removeEventListener(EVENT_NAME, handleCustom);
};
}
export function markGitHubStarPromptShown(): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(STORAGE_KEY, "1");
window.dispatchEvent(new Event(EVENT_NAME));
} catch {
// ignore
}
}
export function useGitHubStarPromptShown(): boolean {
return useSyncExternalStore(subscribe, read, () => false);
}