feat(onboarding): add beta notice banner (#729) (#736)

Shows a dismissible amber banner at the top of the onboarding flow
on first launch. Dismissal is persisted to localStorage so it only
shows once per installation.

Co-authored-by: Jwalin Shah <jshah1331@gmail.com>
This commit is contained in:
Jwalin Shah
2026-04-21 14:00:32 -07:00
committed by GitHub
co-authored by Jwalin Shah
parent 8f927369d1
commit 0dfcb7d71d
2 changed files with 66 additions and 1 deletions
+5 -1
View File
@@ -4,6 +4,7 @@ import { useCoreState } from '../../providers/CoreStateProvider';
import { referralApi } from '../../services/api/referralApi';
import { userApi } from '../../services/api/userApi';
import { getDefaultEnabledTools } from '../../utils/toolDefinitions';
import BetaBanner from './components/BetaBanner';
import ContextGatheringStep from './steps/ContextGatheringStep';
import ReferralApplyStep from './steps/ReferralApplyStep';
import SkillsStep from './steps/SkillsStep';
@@ -208,7 +209,10 @@ const Onboarding = ({ onComplete, onDefer }: OnboardingProps) => {
</button>
</div>
)}
<div className="relative z-10 max-w-lg w-full mx-4">{renderStep()}</div>
<div className="relative z-10 max-w-lg w-full mx-4">
<BetaBanner />
{renderStep()}
</div>
</div>
);
};
@@ -0,0 +1,61 @@
import { useState } from 'react';
const DISMISSED_KEY = 'openhuman_beta_banner_dismissed';
const BetaBanner = () => {
const [visible, setVisible] = useState(() => {
try {
return localStorage.getItem(DISMISSED_KEY) !== 'true';
} catch {
return true;
}
});
if (!visible) return null;
const handleDismiss = () => {
try {
localStorage.setItem(DISMISSED_KEY, 'true');
} catch {
// localStorage unavailable — dismiss for this session only
}
setVisible(false);
};
return (
<div className="mb-4 flex items-start gap-3 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3">
{/* Beta pill */}
<span className="mt-0.5 flex-shrink-0 rounded-md bg-amber-400 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-white">
Beta
</span>
{/* Message */}
<p className="flex-1 text-xs leading-relaxed text-stone-700">
OpenHuman is in beta &mdash; you may hit rough edges. Your feedback helps us ship faster.
</p>
{/* Dismiss */}
<button
type="button"
aria-label="Dismiss beta notice"
onClick={handleDismiss}
className="mt-0.5 flex-shrink-0 text-stone-400 hover:text-stone-600 transition-colors">
<svg
className="h-3.5 w-3.5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
);
};
export default BetaBanner;