Three drop-in gating components for the self-serve signup flow. - FeatureGate reads useFeature(flag) and renders children when enabled, else a fallback (default UpgradePrompt). UX-only — security boundary remains require_feature on the backend. - UpgradePrompt resolves a feature key to display name + required plan via an inline catalog and links to /account/billing/select-plan. - EmailVerificationGate gates protected content behind a 6-day grace period; renders a minimal EmailVerificationWall (resend + sign out) on Day 7+ unverified. Wall design will be refined in Task 37. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
import type { ReactNode } from 'react'
|
|
import { useFeature } from '@/hooks/useFeature'
|
|
import { UpgradePrompt } from './UpgradePrompt'
|
|
|
|
interface FeatureGateProps {
|
|
/** Feature flag key (e.g. `psa_integration`). Must match a backend `feature_flags.flag_key`. */
|
|
feature: string
|
|
/**
|
|
* Rendered when the feature is enabled for the current account.
|
|
*/
|
|
children: ReactNode
|
|
/**
|
|
* Rendered when the feature is disabled. Defaults to `<UpgradePrompt feature={feature} />`.
|
|
* Pass `null` to render nothing.
|
|
*/
|
|
fallback?: ReactNode
|
|
}
|
|
|
|
/**
|
|
* Conditionally renders `children` based on whether `feature` is enabled
|
|
* for the current account.
|
|
*
|
|
* This is a UX affordance — the security boundary is the backend
|
|
* `require_feature` dependency. Never trust this gate for authorization.
|
|
*/
|
|
export function FeatureGate({ feature, children, fallback }: FeatureGateProps) {
|
|
const enabled = useFeature(feature)
|
|
|
|
if (enabled) {
|
|
return <>{children}</>
|
|
}
|
|
|
|
// Use explicit fallback when provided, otherwise render the standard prompt.
|
|
// `null` is a valid fallback (renders nothing).
|
|
if (fallback !== undefined) {
|
|
return <>{fallback}</>
|
|
}
|
|
|
|
return <UpgradePrompt feature={feature} />
|
|
}
|
|
|
|
export default FeatureGate
|