@sudobility/building_blocks 0.0.49 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,8 +30,8 @@ export interface SubscriptionContextValue {
30
30
  currentSubscription: CurrentSubscription | null;
31
31
  isLoading: boolean;
32
32
  error: string | null;
33
- /** Purchase a subscription product. subscriptionUserId identifies which user/entity the subscription is for. */
34
- purchase: (productId: string, subscriptionUserId?: string) => Promise<boolean>;
33
+ /** Purchase a subscription product. subscriptionUserId identifies which user/entity the subscription is for. email pre-fills the checkout form. */
34
+ purchase: (productId: string, subscriptionUserId?: string, email?: string) => Promise<boolean>;
35
35
  /** Restore purchases. subscriptionUserId identifies which user/entity to restore for. */
36
36
  restore: (subscriptionUserId?: string) => Promise<boolean>;
37
37
  clearError: () => void;
@@ -109,6 +109,8 @@ export interface AppSubscriptionsPageProps {
109
109
  rateLimitsConfig?: RateLimitsConfigData | null;
110
110
  /** User ID used for subscription (the selected entity's ID when logged in) */
111
111
  subscriptionUserId?: string;
112
+ /** User email to pre-fill in the checkout form */
113
+ userEmail?: string;
112
114
  /** All localized labels */
113
115
  labels: SubscriptionPageLabels;
114
116
  /** Formatter functions for dynamic strings */
@@ -132,4 +134,4 @@ export interface AppSubscriptionsPageProps {
132
134
  * Page for managing app subscriptions.
133
135
  * Uses the same entitlement mapping and features display as AppPricingPage.
134
136
  */
135
- export declare function AppSubscriptionsPage({ subscription, rateLimitsConfig, subscriptionUserId, labels, formatters, entitlementMap, entitlementLevels: _entitlementLevels, onPurchaseSuccess, onRestoreSuccess, onError, onWarning, onTrack, }: AppSubscriptionsPageProps): import("react/jsx-runtime").JSX.Element;
137
+ export declare function AppSubscriptionsPage({ subscription, rateLimitsConfig, subscriptionUserId, userEmail, labels, formatters, entitlementMap, entitlementLevels: _entitlementLevels, onPurchaseSuccess, onRestoreSuccess, onError, onWarning, onTrack, }: AppSubscriptionsPageProps): import("react/jsx-runtime").JSX.Element;
package/dist/index.js CHANGED
@@ -1262,6 +1262,7 @@ function AppSubscriptionsPage({
1262
1262
  subscription,
1263
1263
  rateLimitsConfig,
1264
1264
  subscriptionUserId,
1265
+ userEmail,
1265
1266
  labels,
1266
1267
  formatters,
1267
1268
  entitlementMap,
@@ -1321,7 +1322,11 @@ function AppSubscriptionsPage({
1321
1322
  clearError();
1322
1323
  track("purchase_initiated", { plan_identifier: selectedPlan });
1323
1324
  try {
1324
- const result = await purchase(selectedPlan, subscriptionUserId);
1325
+ const result = await purchase(
1326
+ selectedPlan,
1327
+ subscriptionUserId,
1328
+ userEmail
1329
+ );
1325
1330
  if (result) {
1326
1331
  track("purchase_completed", { plan_identifier: selectedPlan });
1327
1332
  onPurchaseSuccess == null ? void 0 : onPurchaseSuccess();
@@ -1348,6 +1353,7 @@ function AppSubscriptionsPage({
1348
1353
  track,
1349
1354
  purchase,
1350
1355
  subscriptionUserId,
1356
+ userEmail,
1351
1357
  onPurchaseSuccess,
1352
1358
  labels.errorTitle,
1353
1359
  labels.purchaseError,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/constants/languages.ts","../src/components/topbar/language-selector.tsx","../src/components/topbar/app-topbar.tsx","../src/components/topbar/app-topbar-with-firebase-auth.tsx","../src/components/topbar/app-topbar-with-wallet.tsx","../src/components/breadcrumbs/app-breadcrumbs.tsx","../src/components/footer/app-footer.tsx","../src/components/footer/app-footer-for-home-page.tsx","../src/components/layout/app-page-layout.tsx","../src/components/settings/appearance-settings.tsx","../src/components/settings/global-settings-page.tsx","../src/components/subscription/AppSubscriptionsPage.tsx","../src/components/subscription/AppPricingPage.tsx","../src/components/pages/app-sitemap-page.tsx","../src/components/pages/app-text-page.tsx","../src/components/pages/login-page.tsx"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names with Tailwind CSS classes.\n * Combines clsx for conditional classes and tailwind-merge for deduplication.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","export interface LanguageConfig {\n code: string;\n name: string;\n flag: string;\n}\n\n/**\n * Default set of 16 supported languages with their flags.\n * Apps can override this list by passing their own languages prop.\n */\nexport const DEFAULT_LANGUAGES: LanguageConfig[] = [\n { code: 'en', name: 'English', flag: '🇺🇸' },\n { code: 'ar', name: 'العربية', flag: '🇸🇦' },\n { code: 'de', name: 'Deutsch', flag: '🇩🇪' },\n { code: 'es', name: 'Español', flag: '🇪🇸' },\n { code: 'fr', name: 'Français', flag: '🇫🇷' },\n { code: 'it', name: 'Italiano', flag: '🇮🇹' },\n { code: 'ja', name: '日本語', flag: '🇯🇵' },\n { code: 'ko', name: '한국어', flag: '🇰🇷' },\n { code: 'pt', name: 'Português', flag: '🇵🇹' },\n { code: 'ru', name: 'Русский', flag: '🇷🇺' },\n { code: 'sv', name: 'Svenska', flag: '🇸🇪' },\n { code: 'th', name: 'ไทย', flag: '🇹🇭' },\n { code: 'uk', name: 'Українська', flag: '🇺🇦' },\n { code: 'vi', name: 'Tiếng Việt', flag: '🇻🇳' },\n { code: 'zh', name: '简体中文', flag: '🇨🇳' },\n { code: 'zh-hant', name: '繁體中文', flag: '🇹🇼' },\n];\n\n/**\n * Languages that use right-to-left text direction.\n */\nexport const RTL_LANGUAGES = ['ar'];\n\n/**\n * Check if a language code is RTL.\n */\nexport function isRTL(languageCode: string): boolean {\n return RTL_LANGUAGES.includes(languageCode);\n}\n","import React, {\n useState,\n useCallback,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport { ChevronDownIcon } from '@heroicons/react/24/outline';\nimport { cn } from '../../utils';\nimport {\n DEFAULT_LANGUAGES,\n type LanguageConfig,\n} from '../../constants/languages';\n\nexport interface LanguageSelectorProps {\n /** Available languages (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n /** Current language code */\n currentLanguage?: string;\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n /** Variant: 'compact' for topbar, 'full' for settings */\n variant?: 'compact' | 'full';\n /** Custom className */\n className?: string;\n /** Label text for full variant */\n label?: string;\n /** Helper text for full variant */\n helperText?: string;\n}\n\n/**\n * LanguageSelector component with dropdown for switching languages.\n * Uses default 16 languages if none provided.\n */\nexport const LanguageSelector: React.FC<LanguageSelectorProps> = ({\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n variant = 'compact',\n className,\n label = 'Language',\n helperText = 'Select your preferred language',\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Sort languages alphabetically by name\n const sortedLanguages = useMemo(\n () => [...languages].sort((a, b) => a.name.localeCompare(b.name)),\n [languages]\n );\n\n const currentLang = useMemo(\n () => languages.find(lang => lang.code === currentLanguage) || languages[0],\n [languages, currentLanguage]\n );\n\n const handleLanguageChange = useCallback(\n (langCode: string) => {\n if (langCode !== currentLanguage) {\n onLanguageChange?.(langCode);\n }\n setIsOpen(false);\n },\n [currentLanguage, onLanguageChange]\n );\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Close dropdown on escape\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n if (variant === 'compact') {\n return (\n <div ref={dropdownRef} className={cn('relative', className)}>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center gap-2 px-3 py-2 h-10 rounded-lg',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-label='Select language'\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='hidden sm:block text-sm font-medium text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute right-0 mt-2 w-48 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Full variant for settings pages\n return (\n <div ref={dropdownRef} className={cn('space-y-2', className)}>\n <label className='text-sm font-medium text-gray-700 dark:text-gray-300 flex items-center gap-2'>\n <span>{label}</span>\n </label>\n\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center justify-between w-full px-3 py-2 text-left',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-300 dark:border-gray-600',\n 'rounded-md',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div className='flex items-center gap-2'>\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute left-0 right-0 mt-1 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-md shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {helperText && (\n <p className='text-xs text-gray-500 dark:text-gray-400'>{helperText}</p>\n )}\n </div>\n );\n};\n\nexport default LanguageSelector;\n","import React, { useMemo, type ComponentType, type ReactNode } from 'react';\nimport {\n Topbar,\n TopbarProvider,\n TopbarLeft,\n TopbarCenter,\n TopbarRight,\n TopbarLogo,\n TopbarNavigation,\n TopbarActions,\n TopbarMobileContent,\n Logo,\n type TopbarNavItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport {\n LanguageSelector,\n type LanguageSelectorProps,\n} from './language-selector';\nimport type {\n MenuItemConfig,\n LogoConfig,\n LanguageConfig,\n LinkComponentProps,\n} from '../../types';\nimport { DEFAULT_LANGUAGES } from '../../constants/languages';\n\nexport interface AppTopBarProps {\n /** Logo configuration */\n logo: LogoConfig;\n\n /** Navigation menu items */\n menuItems: MenuItemConfig[];\n\n /** Available languages for selector (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n\n /** Current language code */\n currentLanguage?: string;\n\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n\n /** Hide language selector */\n hideLanguageSelector?: boolean;\n\n /** Language selector props override */\n languageSelectorProps?: Partial<LanguageSelectorProps>;\n\n /** Breakpoint to collapse navigation to hamburger menu */\n collapseBelow?: 'sm' | 'md' | 'lg' | 'xl';\n\n /** Render prop for account/auth section (right side of topbar) */\n renderAccountSection?: () => ReactNode;\n\n /** Render prop for center section (e.g., search bar) - shown on desktop */\n renderCenterSection?: () => ReactNode;\n\n /** Render prop for mobile-specific content (e.g., mobile search) - shown below main topbar on mobile */\n renderMobileContent?: () => ReactNode;\n\n /** Custom Link component for navigation (for react-router-dom, Next.js, etc.) */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Optional sticky positioning */\n sticky?: boolean;\n\n /** Optional variant */\n variant?: 'default' | 'app';\n\n /** Mobile menu label for accessibility */\n mobileMenuLabel?: string;\n\n /** Custom className for topbar */\n className?: string;\n\n /** z-index level */\n zIndex?: 'default' | 'highest' | 'high';\n\n /** Aria label for navigation */\n ariaLabel?: string;\n}\n\n/**\n * Default Link component that renders a plain anchor tag.\n * Apps should provide their own LinkComponent for router integration.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * AppTopBar - Base topbar component for Sudobility apps.\n *\n * Features:\n * - Logo with app name on the left\n * - Navigation menu items with icons\n * - Language selector\n * - Render prop for center section (e.g., search bar)\n * - Render prop for account/auth section\n * - Render prop for mobile-specific content\n * - Responsive with hamburger menu on mobile\n * - Dark mode support\n */\nexport const AppTopBar: React.FC<AppTopBarProps> = ({\n logo,\n menuItems,\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n hideLanguageSelector = false,\n languageSelectorProps,\n collapseBelow = 'lg',\n renderAccountSection,\n renderCenterSection,\n renderMobileContent,\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n variant = 'default',\n mobileMenuLabel = 'Menu',\n className,\n zIndex = 'highest',\n ariaLabel = 'Main navigation',\n}) => {\n // Filter menu items that should be shown\n const visibleMenuItems = useMemo(\n () => menuItems.filter(item => item.show !== false),\n [menuItems]\n );\n\n // Convert MenuItemConfig to TopbarNavItem\n const navItems: TopbarNavItem[] = useMemo(\n () =>\n visibleMenuItems.map(item => ({\n id: item.id,\n label: item.label,\n icon: item.icon,\n href: item.href,\n className: item.className,\n })),\n [visibleMenuItems]\n );\n\n // Wrapper to adapt LinkComponent to TopbarNavigation expected interface\n const LinkWrapper: ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n }> = useMemo(\n () =>\n ({ href, className, children }) => (\n <LinkComponent href={href} className={className}>\n {children}\n </LinkComponent>\n ),\n [LinkComponent]\n );\n\n const handleLogoClick = () => {\n logo.onClick?.();\n };\n\n return (\n <TopbarProvider variant={variant} sticky={sticky}>\n <Topbar\n variant={variant}\n sticky={sticky}\n zIndex={zIndex}\n aria-label={ariaLabel}\n className={cn(className)}\n >\n <TopbarLeft>\n <TopbarNavigation\n items={navItems}\n collapseBelow={collapseBelow}\n LinkComponent={LinkWrapper}\n mobileMenuLabel={mobileMenuLabel}\n >\n <TopbarLogo onClick={handleLogoClick} size='md'>\n <Logo\n size='md'\n logoSrc={logo.src}\n logoText={logo.appName}\n logoAlt={logo.alt || logo.appName}\n showText={true}\n />\n </TopbarLogo>\n </TopbarNavigation>\n </TopbarLeft>\n\n {renderCenterSection && (\n <TopbarCenter>{renderCenterSection()}</TopbarCenter>\n )}\n\n <TopbarRight>\n <TopbarActions gap='md'>\n {!hideLanguageSelector && (\n <LanguageSelector\n languages={languages}\n currentLanguage={currentLanguage}\n onLanguageChange={onLanguageChange}\n variant='compact'\n {...languageSelectorProps}\n />\n )}\n {renderAccountSection?.()}\n </TopbarActions>\n </TopbarRight>\n\n {renderMobileContent && (\n <TopbarMobileContent>{renderMobileContent()}</TopbarMobileContent>\n )}\n </Topbar>\n </TopbarProvider>\n );\n};\n\nexport default AppTopBar;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Auth menu item for the authenticated user dropdown.\n * This matches the AuthMenuItem interface from @sudobility/auth-components.\n */\nexport interface AuthMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon element (typically a small SVG) */\n icon?: ReactNode;\n /** Click handler */\n onClick?: () => void;\n /** Show divider after this item */\n dividerAfter?: boolean;\n}\n\n/**\n * Props for the AuthAction component from @sudobility/auth-components.\n */\nexport interface AuthActionProps {\n /** Avatar size in pixels */\n avatarSize?: number;\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n /** Login button click handler */\n onLoginClick?: () => void;\n /** Menu items for authenticated user dropdown */\n menuItems?: AuthMenuItem[];\n /** Custom login button text */\n loginButtonText?: string;\n /** Custom className for login button */\n loginButtonClassName?: string;\n}\n\nexport interface AppTopBarWithFirebaseAuthProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * AuthAction component from @sudobility/auth-components.\n * This is passed as a prop to avoid hard dependency on auth-components.\n */\n AuthActionComponent: ComponentType<AuthActionProps>;\n\n /** Additional menu items for authenticated users */\n authenticatedMenuItems?: AuthMenuItem[];\n\n /** Login button click handler */\n onLoginClick?: () => void;\n\n /** Avatar size in pixels */\n avatarSize?: number;\n\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n\n /** Custom login button text */\n loginButtonText?: string;\n\n /** Custom login button className */\n loginButtonClassName?: string;\n}\n\n/**\n * AppTopBarWithFirebaseAuth - TopBar with Firebase authentication integration.\n *\n * This component wraps AppTopBar and provides the AuthAction component\n * from @sudobility/auth-components for the account section.\n *\n * Note: The AuthAction component must be passed as a prop to avoid\n * hard dependency on @sudobility/auth-components.\n *\n * @example\n * ```tsx\n * import { AuthAction } from '@sudobility/auth-components';\n *\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * authenticatedMenuItems={[\n * { id: 'dashboard', label: 'Dashboard', onClick: () => navigate('/dashboard') },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithFirebaseAuth: React.FC<\n AppTopBarWithFirebaseAuthProps\n> = ({\n AuthActionComponent,\n authenticatedMenuItems = [],\n onLoginClick,\n avatarSize = 32,\n dropdownAlign = 'right',\n loginButtonText,\n loginButtonClassName,\n ...topBarProps\n}) => {\n const renderAccountSection = () => (\n <AuthActionComponent\n avatarSize={avatarSize}\n dropdownAlign={dropdownAlign}\n onLoginClick={onLoginClick}\n menuItems={authenticatedMenuItems}\n loginButtonText={loginButtonText}\n loginButtonClassName={cn(\n GRADIENT_CLASSES.headerButton,\n loginButtonClassName\n )}\n />\n );\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithFirebaseAuth;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Wallet menu item for the connected wallet dropdown.\n */\nexport interface WalletMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon component */\n icon?: ComponentType<{ className?: string }>;\n /** Click handler */\n onClick: () => void;\n /** Whether this is a separator */\n separator?: boolean;\n}\n\n/**\n * Auth status enum matching @sudobility/types.\n */\nexport enum AuthStatus {\n DISCONNECTED = 'disconnected',\n CONNECTED = 'connected',\n VERIFIED = 'verified',\n}\n\n/**\n * Chain type enum matching @sudobility/types.\n */\nexport enum ChainType {\n EVM = 'evm',\n SOLANA = 'solana',\n}\n\n/**\n * Props for the WalletDropdownMenu component from @sudobility/web3-components.\n */\nexport interface WalletDropdownMenuProps {\n walletAddress: string;\n authStatus: AuthStatus | string;\n chainType: ChainType | string | 'unknown';\n menuItems: WalletMenuItem[];\n avatar?: string;\n displayName?: string;\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\nexport interface AppTopBarWithWalletProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * WalletDropdownMenu component from @sudobility/web3-components.\n * This is passed as a prop to avoid hard dependency on web3-components.\n */\n WalletDropdownMenuComponent?: ComponentType<WalletDropdownMenuProps>;\n\n /** Whether wallet is connected */\n isConnected: boolean;\n\n /** Connected wallet address */\n walletAddress?: string;\n\n /** Authentication status */\n authStatus?: AuthStatus | string;\n\n /** Chain type (EVM, Solana, etc.) */\n chainType?: ChainType | string | 'unknown';\n\n /** Connect button click handler */\n onConnect: () => void;\n\n /** Disconnect handler */\n onDisconnect: () => Promise<void>;\n\n /** Custom menu items for wallet dropdown */\n walletMenuItems?: WalletMenuItem[];\n\n /** Connect button content (default: \"Connect Wallet\") */\n connectButtonContent?: ReactNode;\n\n /** Connect button className (supports gradient classes from @sudobility/design) */\n connectButtonClassName?: string;\n\n /** Use gradient styling for connect button */\n useGradientButton?: boolean;\n\n /** Optional user avatar */\n avatar?: string;\n\n /** Optional display name */\n displayName?: string;\n\n /** Custom status labels */\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\n/**\n * Default connect button when WalletDropdownMenuComponent is not provided\n * or when wallet is not connected.\n */\nconst DefaultConnectButton: React.FC<{\n onClick: () => void;\n content?: ReactNode;\n className?: string;\n useGradient?: boolean;\n}> = ({ onClick, content = 'Connect Wallet', className, useGradient }) => (\n <button\n onClick={onClick}\n className={cn(\n useGradient\n ? GRADIENT_CLASSES.headerButton\n : 'px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors',\n className\n )}\n >\n {content}\n </button>\n);\n\n/**\n * Simple fallback wallet display when WalletDropdownMenuComponent is not provided.\n */\nconst FallbackWalletDisplay: React.FC<{\n walletAddress: string;\n onDisconnect: () => Promise<void>;\n}> = ({ walletAddress, onDisconnect }) => {\n const truncatedAddress = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n\n return (\n <div className='flex items-center gap-2'>\n <span className='text-sm font-medium text-gray-700 dark:text-gray-300'>\n {truncatedAddress}\n </span>\n <button\n onClick={() => onDisconnect()}\n className='text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'\n >\n Disconnect\n </button>\n </div>\n );\n};\n\n/**\n * AppTopBarWithWallet - TopBar with wallet connection integration.\n *\n * This component wraps AppTopBar and provides wallet connection UI\n * for the account section. Uses WalletDropdownMenu from @sudobility/web3-components\n * when provided.\n *\n * @example\n * ```tsx\n * import { WalletDropdownMenu } from '@sudobility/web3-components';\n *\n * <AppTopBarWithWallet\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * WalletDropdownMenuComponent={WalletDropdownMenu}\n * isConnected={isConnected}\n * walletAddress={walletAddress}\n * authStatus={authStatus}\n * chainType={chainType}\n * onConnect={() => navigate('/connect')}\n * onDisconnect={handleDisconnect}\n * walletMenuItems={[\n * { id: 'copy', label: 'Copy Address', icon: ClipboardIcon, onClick: handleCopy },\n * { id: 'disconnect', label: 'Disconnect', icon: LogoutIcon, onClick: handleDisconnect },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithWallet: React.FC<AppTopBarWithWalletProps> = ({\n WalletDropdownMenuComponent,\n isConnected,\n walletAddress,\n authStatus = AuthStatus.DISCONNECTED,\n chainType = 'unknown',\n onConnect,\n onDisconnect,\n walletMenuItems = [],\n connectButtonContent,\n connectButtonClassName,\n useGradientButton = true,\n avatar,\n displayName,\n statusLabels,\n ...topBarProps\n}) => {\n const renderAccountSection = () => {\n // Not connected - show connect button\n if (!isConnected || !walletAddress) {\n return (\n <DefaultConnectButton\n onClick={onConnect}\n content={connectButtonContent}\n className={connectButtonClassName}\n useGradient={useGradientButton}\n />\n );\n }\n\n // Connected with WalletDropdownMenu component\n if (WalletDropdownMenuComponent) {\n return (\n <WalletDropdownMenuComponent\n walletAddress={walletAddress}\n authStatus={authStatus}\n chainType={chainType}\n menuItems={walletMenuItems}\n avatar={avatar}\n displayName={displayName}\n statusLabels={statusLabels}\n />\n );\n }\n\n // Connected without WalletDropdownMenu - fallback display\n return (\n <FallbackWalletDisplay\n walletAddress={walletAddress}\n onDisconnect={onDisconnect}\n />\n );\n };\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithWallet;\n","import React, { useState, type ComponentType } from 'react';\nimport { CalendarDaysIcon } from '@heroicons/react/24/outline';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport type {\n BreadcrumbItem,\n ShareConfig,\n TalkToFounderConfig,\n LinkComponentProps,\n} from '../../types';\n\nconst breadcrumbContainerVariants = cva('border-b', {\n variants: {\n variant: {\n default: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700',\n transparent: 'bg-transparent border-transparent',\n subtle:\n 'bg-gray-50 dark:bg-gray-900/50 border-gray-200 dark:border-gray-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\nexport interface AppBreadcrumbsProps extends VariantProps<\n typeof breadcrumbContainerVariants\n> {\n /** Breadcrumb items */\n items: BreadcrumbItem[];\n\n /** Share configuration (shows social share buttons on right) */\n shareConfig?: ShareConfig;\n\n /** Talk to founder button configuration */\n talkToFounder?: TalkToFounderConfig;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Custom className for the container */\n className?: string;\n\n /** Custom className for the inner content */\n contentClassName?: string;\n}\n\n// Social media share URL generators\nconst createShareUrl = {\n twitter: (url: string, text: string, hashtags: string[]) => {\n const hashtagStr =\n hashtags.length > 0 ? `&hashtags=${hashtags.join(',')}` : '';\n return `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}${hashtagStr}`;\n },\n facebook: (url: string) => {\n return `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`;\n },\n linkedin: (url: string) => {\n return `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`;\n },\n reddit: (url: string, title: string) => {\n return `https://reddit.com/submit?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`;\n },\n telegram: (url: string, text: string) => {\n return `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`;\n },\n email: (url: string, title: string, description: string) => {\n return `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(description + '\\n\\n' + url)}`;\n },\n};\n\n/**\n * Share dropdown component\n */\nconst ShareDropdown: React.FC<{ shareConfig: ShareConfig }> = ({\n shareConfig,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shareUrl, setShareUrl] = useState<string>('');\n const [isPreparingShare, setIsPreparingShare] = useState(false);\n const [showCopiedFeedback, setShowCopiedFeedback] = useState(false);\n\n React.useEffect(() => {\n const onBeforeShare = shareConfig.onBeforeShare;\n if (onBeforeShare && !shareUrl) {\n const prepareUrl = async () => {\n setIsPreparingShare(true);\n try {\n const baseUrl =\n typeof window !== 'undefined' ? window.location.href : '';\n const modifiedUrl = await onBeforeShare(baseUrl);\n setShareUrl(modifiedUrl);\n } catch {\n const baseUrl =\n typeof window !== 'undefined' ? window.location.href : '';\n setShareUrl(baseUrl);\n } finally {\n setIsPreparingShare(false);\n }\n };\n prepareUrl();\n }\n }, [shareConfig, shareUrl]);\n\n const url =\n shareUrl || (typeof window !== 'undefined' ? window.location.href : '');\n\n const copyToClipboard = async () => {\n try {\n await navigator.clipboard.writeText(url);\n setShowCopiedFeedback(true);\n setTimeout(() => {\n setShowCopiedFeedback(false);\n setIsOpen(false);\n }, 1500);\n } catch {\n // Copy failed\n }\n };\n\n const handleSocialShare = (platformUrl: string) => {\n window.open(\n platformUrl,\n '_blank',\n 'noopener,noreferrer,width=600,height=400'\n );\n setIsOpen(false);\n };\n\n const sharePlatforms = [\n {\n name: 'Twitter',\n url: createShareUrl.twitter(url, shareConfig.title, shareConfig.hashtags),\n color: 'text-blue-400',\n },\n {\n name: 'Facebook',\n url: createShareUrl.facebook(url),\n color: 'text-blue-600',\n },\n {\n name: 'LinkedIn',\n url: createShareUrl.linkedin(url),\n color: 'text-blue-700',\n },\n {\n name: 'Reddit',\n url: createShareUrl.reddit(url, shareConfig.title),\n color: 'text-orange-600',\n },\n {\n name: 'Telegram',\n url: createShareUrl.telegram(url, shareConfig.title),\n color: 'text-blue-500',\n },\n {\n name: 'Email',\n url: createShareUrl.email(\n url,\n shareConfig.title,\n shareConfig.description\n ),\n color: 'text-gray-600',\n },\n ];\n\n return (\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n disabled={isPreparingShare}\n className='flex items-center justify-center w-8 h-8 bg-blue-50 hover:bg-blue-100 dark:bg-blue-900/30 dark:hover:bg-blue-900/50 text-blue-600 dark:text-blue-400 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\n title='Share this page'\n >\n {isPreparingShare ? (\n <div className='w-4 h-4 border-2 border-blue-600 border-t-transparent rounded-full animate-spin' />\n ) : (\n <svg\n className='w-4 h-4'\n fill='none'\n stroke='currentColor'\n viewBox='0 0 24 24'\n >\n <path\n strokeLinecap='round'\n strokeLinejoin='round'\n strokeWidth={2}\n d='M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.367 2.684 3 3 0 00-5.367-2.684z'\n />\n </svg>\n )}\n </button>\n\n {isOpen && (\n <>\n <div\n className='fixed inset-0 z-[999998]'\n onClick={() => setIsOpen(false)}\n />\n <div className='absolute right-0 top-10 z-[999999] w-40 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 py-1'>\n {sharePlatforms.map(platform => (\n <button\n key={platform.name}\n onClick={() => handleSocialShare(platform.url)}\n className='w-full flex items-center px-3 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors'\n >\n <span className={`text-sm ${platform.color}`}>\n {platform.name}\n </span>\n </button>\n ))}\n <div className='border-t border-gray-200 dark:border-gray-700 my-1' />\n <button\n onClick={copyToClipboard}\n className='w-full flex items-center px-3 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors'\n >\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {showCopiedFeedback ? 'Copied!' : 'Copy Link'}\n </span>\n </button>\n </div>\n </>\n )}\n </div>\n );\n};\n\n/**\n * Talk to Founder button - matches share button style\n */\nconst TalkToFounderButton: React.FC<{ config: TalkToFounderConfig }> = ({\n config,\n}) => {\n const IconComponent = config.icon || CalendarDaysIcon;\n const buttonText = config.buttonText || 'Talk to Founder';\n\n return (\n <a\n href={config.meetingUrl}\n target='_blank'\n rel='noopener noreferrer'\n className={cn(\n 'inline-flex items-center gap-1.5 px-2.5 h-8',\n 'text-sm font-medium',\n 'text-blue-600 dark:text-blue-400',\n 'hover:text-blue-700 dark:hover:text-blue-300',\n 'bg-blue-50 dark:bg-blue-900/30',\n 'hover:bg-blue-100 dark:hover:bg-blue-900/50',\n 'rounded-lg',\n 'transition-colors'\n )}\n >\n <IconComponent className='h-4 w-4' />\n <span>{buttonText}</span>\n </a>\n );\n};\n\n/**\n * AppBreadcrumbs - Self-contained breadcrumb navigation with share and \"Talk to Founder\" button.\n */\nexport const AppBreadcrumbs: React.FC<AppBreadcrumbsProps> = ({\n items,\n shareConfig,\n talkToFounder,\n variant = 'default',\n className,\n contentClassName,\n}) => {\n // Don't render if no items\n if (!items || items.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(breadcrumbContainerVariants({ variant }), className)}>\n <div className={cn('max-w-7xl mx-auto px-4 py-2', contentClassName)}>\n <div className='flex items-center justify-between'>\n {/* Breadcrumb trail */}\n <nav aria-label='Breadcrumb'>\n <ol className='flex items-center text-sm space-x-2'>\n {items.map((item, index) => (\n <React.Fragment key={index}>\n <li>\n {item.current || !item.href ? (\n <span className='text-gray-700 dark:text-gray-300'>\n {item.label}\n </span>\n ) : (\n <a\n href={item.href}\n className='text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 transition-colors'\n >\n {item.label}\n </a>\n )}\n </li>\n {index < items.length - 1 && (\n <li>\n <span className='text-gray-400 dark:text-gray-500'>\n /\n </span>\n </li>\n )}\n </React.Fragment>\n ))}\n </ol>\n </nav>\n\n {/* Right side: Talk to Founder + Share */}\n <div className='flex items-center gap-2'>\n {talkToFounder && <TalkToFounderButton config={talkToFounder} />}\n {shareConfig && <ShareDropdown shareConfig={shareConfig} />}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default AppBreadcrumbs;\n","import React, { useCallback, type ComponentType } from 'react';\nimport {\n Footer as FooterContainer,\n FooterCompact,\n FooterCompactLeft,\n FooterCompactRight,\n FooterVersion,\n FooterCopyright,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkItem,\n AnalyticsTrackingParams,\n} from '../../types';\n\n/**\n * Props for the SystemStatusIndicator component from @sudobility/devops-components.\n */\nexport interface SystemStatusIndicatorProps {\n statusPageUrl: string;\n apiEndpoint?: string;\n refreshInterval?: number;\n size?: 'sm' | 'md' | 'lg';\n version?: string;\n isNetworkOnline?: boolean;\n}\n\nexport interface AppFooterProps {\n /** App version string */\n version?: string;\n\n /** Copyright year or range (e.g., \"2025\" or \"2025-2026\") */\n copyrightYear?: string;\n\n /** Company name */\n companyName: string;\n\n /** Company URL (optional - creates a link if provided) */\n companyUrl?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Status indicator config (optional) */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** Right-side links (e.g., Privacy, Terms) */\n links?: FooterLinkItem[];\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Sticky positioning (sticks to bottom of viewport) */\n sticky?: boolean;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * AppFooter - Compact footer for app pages.\n *\n * Features:\n * - Version display\n * - Copyright with company name\n * - System status indicator (optional)\n * - Right-side links (Privacy, Terms, etc.)\n * - Sticky positioning option\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * companyUrl=\"/\"\n * rightsText=\"All rights reserved\"\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * apiEndpoint: 'https://status.example.com/api/v1/status',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * links={[\n * { label: 'Privacy', href: '/privacy' },\n * { label: 'Terms', href: '/terms' },\n * ]}\n * sticky\n * />\n * ```\n */\nexport const AppFooter: React.FC<AppFooterProps> = ({\n version,\n copyrightYear,\n companyName,\n companyUrl,\n rightsText = 'All rights reserved',\n statusIndicator,\n StatusIndicatorComponent,\n links = [],\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n isNetworkOnline = true,\n className,\n onTrack,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'link_click',\n componentName: 'AppFooter',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Create a tracked link click handler\n const createTrackedLinkHandler = useCallback(\n (\n linkLabel: string,\n linkHref: string,\n originalOnClick?: (e: React.MouseEvent) => void\n ) =>\n (e: React.MouseEvent) => {\n track('footer_link_clicked', {\n link_label: linkLabel,\n link_href: linkHref,\n });\n originalOnClick?.(e);\n },\n [track]\n );\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer\n variant='compact'\n sticky={sticky}\n className={cn(className)}\n >\n <FooterCompact>\n <FooterCompactLeft>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterCompactLeft>\n <FooterCompactRight>\n {links.map((link, index) => (\n <React.Fragment key={link.href || index}>\n {link.onClick ? (\n <button\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n link.onClick\n )}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n onClick={createTrackedLinkHandler(link.label, link.href)}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </LinkComponent>\n )}\n </React.Fragment>\n ))}\n </FooterCompactRight>\n </FooterCompact>\n </FooterContainer>\n );\n};\n\nexport default AppFooter;\n","import React, { useCallback, type ComponentType } from 'react';\nimport {\n Logo,\n Footer as FooterContainer,\n FooterGrid,\n FooterBrand,\n FooterLinkSection,\n FooterLink,\n FooterBottom,\n FooterVersion,\n FooterCopyright,\n FooterSocialLinks,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkSection as FooterLinkSectionConfig,\n SocialLinksConfig,\n AnalyticsTrackingParams,\n} from '../../types';\nimport type { SystemStatusIndicatorProps } from './app-footer';\n\nexport interface AppFooterForHomePageProps {\n /** App logo configuration */\n logo: {\n /** Logo image src (optional - if not provided, uses Logo component) */\n src?: string;\n /** App name */\n appName: string;\n };\n\n /** Footer link sections (columns of links) */\n linkSections: FooterLinkSectionConfig[];\n\n /** Social media links */\n socialLinks?: SocialLinksConfig;\n\n /** System status indicator configuration */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** App version string */\n version?: string;\n\n /** Copyright year or range */\n copyrightYear?: string;\n\n /** Company name for copyright */\n companyName: string;\n\n /** Company link URL (optional) */\n companyUrl?: string;\n\n /** Footer description text (below logo) */\n description?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Number of columns for link grid (default: auto based on section count) */\n gridColumns?: 2 | 3 | 4 | 5;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * Get grid columns class based on section count.\n */\nfunction getGridColumnsClass(sectionCount: number, explicit?: number): string {\n const cols = explicit || Math.min(sectionCount, 4);\n switch (cols) {\n case 2:\n return 'md:grid-cols-2';\n case 3:\n return 'md:grid-cols-3';\n case 4:\n return 'md:grid-cols-4';\n case 5:\n return 'md:grid-cols-5';\n default:\n return 'md:grid-cols-4';\n }\n}\n\n/**\n * AppFooterForHomePage - Full footer for home/landing pages.\n *\n * Features:\n * - Multiple link sections in a grid\n * - Logo and brand description\n * - Social media links\n * - System status indicator (optional)\n * - Version and copyright\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooterForHomePage\n * logo={{ appName: 'My App' }}\n * linkSections={[\n * {\n * title: 'Product',\n * links: [\n * { label: 'Features', href: '/features' },\n * { label: 'Pricing', href: '/pricing' },\n * ],\n * },\n * {\n * title: 'Company',\n * links: [\n * { label: 'About', href: '/about' },\n * { label: 'Contact', href: '/contact' },\n * ],\n * },\n * ]}\n * socialLinks={{\n * twitterUrl: 'https://twitter.com/myapp',\n * discordUrl: 'https://discord.gg/myapp',\n * }}\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * description=\"Building the future of web3 communication\"\n * />\n * ```\n */\nexport const AppFooterForHomePage: React.FC<AppFooterForHomePageProps> = ({\n logo,\n linkSections,\n socialLinks,\n statusIndicator,\n StatusIndicatorComponent,\n version,\n copyrightYear,\n companyName,\n companyUrl,\n description,\n rightsText = 'All rights reserved',\n LinkComponent = DefaultLinkComponent,\n isNetworkOnline = true,\n className,\n gridColumns,\n onTrack,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n const gridClass = getGridColumnsClass(linkSections.length, gridColumns);\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'link_click',\n componentName: 'AppFooterForHomePage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Create a tracked link click handler\n const createTrackedLinkHandler = useCallback(\n (\n linkLabel: string,\n linkHref: string,\n sectionTitle: string,\n originalOnClick?: (e: React.MouseEvent) => void\n ) =>\n (e: React.MouseEvent) => {\n track('footer_link_clicked', {\n link_label: linkLabel,\n link_href: linkHref,\n section_title: sectionTitle,\n });\n originalOnClick?.(e);\n },\n [track]\n );\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer variant='full' className={cn(className)}>\n <FooterGrid className={gridClass}>\n {linkSections.map((section, sectionIndex) => (\n <FooterLinkSection\n key={section.title || sectionIndex}\n title={section.title}\n >\n {section.links.map((link, linkIndex) => (\n <FooterLink key={link.href || linkIndex}>\n {link.onClick ? (\n <button\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n section.title,\n link.onClick\n )}\n className='text-left'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n section.title\n )}\n >\n {link.label}\n </LinkComponent>\n )}\n </FooterLink>\n ))}\n </FooterLinkSection>\n ))}\n </FooterGrid>\n\n <FooterBottom>\n <FooterBrand\n description={description}\n className='flex flex-col items-center'\n >\n <LinkComponent\n href='/'\n className='text-white hover:opacity-80 transition-opacity'\n >\n {logo.src ? (\n <img\n src={logo.src}\n alt={logo.appName}\n className='h-8 object-contain'\n />\n ) : (\n <Logo size='md' showText={true} logoText={logo.appName} />\n )}\n </LinkComponent>\n </FooterBrand>\n <div className='space-y-2'>\n {version && <FooterVersion version={version} className='block' />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n className='block'\n />\n </div>\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterBottom>\n\n {socialLinks && (\n <div className='flex justify-center mt-4'>\n <FooterSocialLinks\n twitterUrl={socialLinks.twitterUrl}\n discordUrl={socialLinks.discordUrl}\n linkedinUrl={socialLinks.linkedinUrl}\n githubUrl={socialLinks.githubUrl}\n redditUrl={socialLinks.redditUrl}\n farcasterUrl={socialLinks.farcasterUrl}\n telegramUrl={socialLinks.telegramUrl}\n />\n </div>\n )}\n </FooterContainer>\n );\n};\n\nexport default AppFooterForHomePage;\n","import React, { type ReactNode } from 'react';\nimport { LayoutProvider } from '@sudobility/components';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport {\n AppBreadcrumbs,\n type AppBreadcrumbsProps,\n} from '../breadcrumbs/app-breadcrumbs';\nimport type { MaxWidth, ContentPadding, BackgroundVariant } from '../../types';\n\nconst layoutVariants = cva('min-h-screen flex flex-col', {\n variants: {\n background: {\n default: 'bg-gray-50 dark:bg-gray-900',\n white: 'bg-white dark:bg-gray-900',\n gradient:\n 'bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-900 dark:to-gray-800',\n },\n },\n defaultVariants: {\n background: 'default',\n },\n});\n\nconst maxWidthClasses: Record<MaxWidth, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '4xl': 'max-w-4xl',\n '7xl': 'max-w-7xl',\n full: 'max-w-full',\n};\n\nconst paddingClasses: Record<ContentPadding, string> = {\n none: '',\n sm: 'px-4 sm:px-6 py-6',\n md: 'px-4 py-8',\n lg: 'px-4 py-12',\n};\n\nexport interface AppPageLayoutProps extends VariantProps<\n typeof layoutVariants\n> {\n /** Page content */\n children: ReactNode;\n\n /** TopBar slot - pass an AppTopBar variant or custom component */\n topBar: ReactNode;\n\n /** Breadcrumbs configuration (optional) */\n breadcrumbs?: AppBreadcrumbsProps;\n\n /** Footer slot - pass an AppFooter variant or custom component */\n footer?: ReactNode;\n\n /** Max width for content area (default: '7xl') */\n maxWidth?: MaxWidth;\n\n /** Content padding (default: 'md') */\n contentPadding?: ContentPadding;\n\n /** Background variant */\n background?: BackgroundVariant;\n\n /** Layout mode for LayoutProvider */\n layoutMode?: 'standard';\n\n /** Custom className for the layout container */\n className?: string;\n\n /** Custom className for the content area */\n contentClassName?: string;\n\n /** Custom className for the main element */\n mainClassName?: string;\n}\n\n/**\n * AppPageLayout - Layout wrapper combining TopBar, Breadcrumbs, Content, and Footer.\n *\n * Features:\n * - Flexible slots for TopBar and Footer\n * - Optional breadcrumbs with share and \"Talk to Founder\"\n * - Configurable content max-width and padding\n * - Background variants\n * - Dark mode support\n * - Sticky footer behavior\n *\n * @example\n * ```tsx\n * <AppPageLayout\n * topBar={\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={menuItems}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * />\n * }\n * breadcrumbs={{\n * items: breadcrumbItems,\n * shareConfig: { title: 'Page', description: 'Description', hashtags: [] },\n * }}\n * footer={\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"My Company\"\n * links={[{ label: 'Privacy', href: '/privacy' }]}\n * />\n * }\n * maxWidth=\"7xl\"\n * background=\"default\"\n * >\n * <h1>Page Content</h1>\n * </AppPageLayout>\n * ```\n */\nexport const AppPageLayout: React.FC<AppPageLayoutProps> = ({\n children,\n topBar,\n breadcrumbs,\n footer,\n maxWidth = '7xl',\n contentPadding = 'md',\n background = 'default',\n layoutMode = 'standard',\n className,\n contentClassName,\n mainClassName,\n}) => {\n return (\n <LayoutProvider mode={layoutMode}>\n <div className={cn(layoutVariants({ background }), className)}>\n {/* Header Section */}\n <header>{topBar}</header>\n\n {/* Breadcrumb Section */}\n {breadcrumbs && breadcrumbs.items && breadcrumbs.items.length > 0 && (\n <AppBreadcrumbs {...breadcrumbs} />\n )}\n\n {/* Main Content */}\n <main className={cn('flex-1 overflow-auto', mainClassName)}>\n <div\n className={cn(\n 'mx-auto',\n maxWidthClasses[maxWidth],\n paddingClasses[contentPadding],\n contentClassName\n )}\n >\n {children}\n </div>\n </main>\n\n {/* Footer */}\n {footer && <footer>{footer}</footer>}\n </div>\n </LayoutProvider>\n );\n};\n\nexport default AppPageLayout;\n","import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Label,\n} from '@sudobility/components';\nimport { textVariants } from '@sudobility/design';\n\n/**\n * Theme options for appearance settings.\n */\nexport enum Theme {\n LIGHT = 'light',\n DARK = 'dark',\n SYSTEM = 'system',\n}\n\n/**\n * Font size options for appearance settings.\n */\nexport enum FontSize {\n SMALL = 'small',\n MEDIUM = 'medium',\n LARGE = 'large',\n}\n\n/**\n * Translation keys used by AppearanceSettings.\n * Provide a translation function to customize labels.\n */\nexport interface AppearanceSettingsTranslations {\n heading: string;\n description: string;\n themeLabel: string;\n themeSelectPlaceholder: string;\n themeLight: string;\n themeDark: string;\n themeSystem: string;\n themeDescription: string;\n fontSizeLabel: string;\n fontSizeSelectPlaceholder: string;\n fontSizeSmall: string;\n fontSizeMedium: string;\n fontSizeLarge: string;\n fontSizeDescription: string;\n infoHeading: string;\n infoDescription: string;\n}\n\nconst defaultTranslations: AppearanceSettingsTranslations = {\n heading: 'Appearance',\n description: 'Customize the look and feel of the application.',\n themeLabel: 'Theme',\n themeSelectPlaceholder: 'Select theme',\n themeLight: 'Light',\n themeDark: 'Dark',\n themeSystem: 'System',\n themeDescription: 'Choose your preferred color theme.',\n fontSizeLabel: 'Font Size',\n fontSizeSelectPlaceholder: 'Select font size',\n fontSizeSmall: 'Small',\n fontSizeMedium: 'Medium',\n fontSizeLarge: 'Large',\n fontSizeDescription: 'Adjust the text size for better readability.',\n infoHeading: 'About Settings',\n infoDescription:\n 'Your appearance preferences are saved locally and will be applied automatically on your next visit.',\n};\n\nexport interface AppearanceSettingsProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Optional translation function.\n * If provided, will be called with a key from AppearanceSettingsTranslations.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the information box at the bottom */\n showInfoBox?: boolean;\n}\n\n/**\n * AppearanceSettings - A reusable component for theme and font size settings.\n *\n * This component can be used across different apps to provide consistent\n * appearance customization options.\n *\n * @example\n * ```tsx\n * // Basic usage with useTheme hook\n * const { theme, fontSize, setTheme, setFontSize } = useTheme();\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With i18n translation\n * const { t } = useTranslation('settings');\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * t={(key, fallback) => t(`appearance.${key}`, fallback)}\n * />\n * ```\n */\nexport const AppearanceSettings: React.FC<AppearanceSettingsProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n t,\n className,\n showInfoBox = true,\n}) => {\n // Helper to get translated string with fallback\n const getText = (key: keyof AppearanceSettingsTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n };\n\n return (\n <div className={className}>\n <div className='space-y-6'>\n <div>\n <h2 className={`${textVariants.heading.h4()} mb-2`}>\n {getText('heading')}\n </h2>\n <p\n className={`${textVariants.body.sm()} text-gray-600 dark:text-gray-400`}\n >\n {getText('description')}\n </p>\n </div>\n\n <div className='space-y-6'>\n {/* Theme Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='theme-select'\n className={textVariants.label.default()}\n >\n {getText('themeLabel')}\n </Label>\n <Select\n value={theme}\n onValueChange={(value: string) => onThemeChange(value as Theme)}\n >\n <SelectTrigger id='theme-select'>\n <SelectValue placeholder={getText('themeSelectPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={Theme.LIGHT}>\n {getText('themeLight')}\n </SelectItem>\n <SelectItem value={Theme.DARK}>\n {getText('themeDark')}\n </SelectItem>\n <SelectItem value={Theme.SYSTEM}>\n {getText('themeSystem')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('themeDescription')}\n </p>\n </div>\n\n {/* Font Size Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='font-size-select'\n className={textVariants.label.default()}\n >\n {getText('fontSizeLabel')}\n </Label>\n <Select\n value={fontSize}\n onValueChange={(value: string) =>\n onFontSizeChange(value as FontSize)\n }\n >\n <SelectTrigger id='font-size-select'>\n <SelectValue\n placeholder={getText('fontSizeSelectPlaceholder')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={FontSize.SMALL}>\n {getText('fontSizeSmall')}\n </SelectItem>\n <SelectItem value={FontSize.MEDIUM}>\n {getText('fontSizeMedium')}\n </SelectItem>\n <SelectItem value={FontSize.LARGE}>\n {getText('fontSizeLarge')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('fontSizeDescription')}\n </p>\n </div>\n </div>\n\n {/* Information Box */}\n {showInfoBox && (\n <div className='bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800'>\n <h4 className='text-sm font-medium text-blue-900 dark:text-blue-100 mb-2'>\n {getText('infoHeading')}\n </h4>\n <p className='text-sm text-blue-700 dark:text-blue-300'>\n {getText('infoDescription')}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default AppearanceSettings;\n","/**\n * @fileoverview Global Settings Page\n * @description Reusable settings page with sidebar navigation.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, {\n useState,\n useMemo,\n useCallback,\n type ReactNode,\n type ComponentType,\n} from 'react';\nimport { PaintBrushIcon } from '@heroicons/react/24/outline';\nimport {\n Section,\n MasterDetailLayout,\n MasterListItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport { AppearanceSettings } from './appearance-settings';\nimport { Theme, FontSize } from './appearance-settings';\nimport type { AnalyticsTrackingParams } from '../../types';\n\n/**\n * Configuration for a settings section in the navigation.\n */\nexport interface SettingsSectionConfig {\n /** Unique identifier for the section */\n id: string;\n /** Icon component to display */\n icon: ComponentType<{ className?: string }>;\n /** Display label */\n label: string;\n /** Short description shown below label */\n description: string;\n /** The content to render when this section is selected */\n content: ReactNode;\n}\n\n/**\n * Translation keys used by GlobalSettingsPage.\n */\nexport interface GlobalSettingsPageTranslations {\n title: string;\n backButton: string;\n appearanceLabel: string;\n appearanceDescription: string;\n}\n\nconst defaultTranslations: GlobalSettingsPageTranslations = {\n title: 'Settings',\n backButton: 'Back',\n appearanceLabel: 'Appearance',\n appearanceDescription: 'Theme and font size settings',\n};\n\nexport interface GlobalSettingsPageProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Additional settings sections to display after Appearance.\n * Each section needs an id, icon, label, description, and content.\n */\n additionalSections?: SettingsSectionConfig[];\n\n /**\n * Optional translation function.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /**\n * Translation function for AppearanceSettings.\n * If provided, will be passed to AppearanceSettings component.\n */\n appearanceT?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the info box in appearance settings */\n showAppearanceInfoBox?: boolean;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * GlobalSettingsPage - A reusable settings page with master-detail layout.\n *\n * Features:\n * - Appearance settings built-in as the first section\n * - Extensible via additionalSections prop\n * - Responsive master-detail layout\n * - Mobile-friendly with back navigation\n *\n * @example\n * ```tsx\n * // Basic usage\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With additional sections\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * additionalSections={[\n * {\n * id: 'notifications',\n * icon: BellIcon,\n * label: 'Notifications',\n * description: 'Manage notification preferences',\n * content: <NotificationSettings />,\n * },\n * ]}\n * />\n * ```\n */\nexport const GlobalSettingsPage: React.FC<GlobalSettingsPageProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n additionalSections = [],\n t,\n appearanceT,\n className,\n showAppearanceInfoBox = true,\n onTrack,\n}) => {\n const [selectedSection, setSelectedSection] = useState('appearance');\n const [mobileView, setMobileView] = useState<'navigation' | 'content'>(\n 'navigation'\n );\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'settings_change',\n componentName: 'GlobalSettingsPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Wrapped handlers with tracking\n const handleThemeChange = useCallback(\n (newTheme: Theme) => {\n track('theme_changed', { theme: newTheme });\n onThemeChange(newTheme);\n },\n [track, onThemeChange]\n );\n\n const handleFontSizeChange = useCallback(\n (newFontSize: FontSize) => {\n track('font_size_changed', { font_size: newFontSize });\n onFontSizeChange(newFontSize);\n },\n [track, onFontSizeChange]\n );\n\n // Helper to get translated string with fallback\n const getText = useCallback(\n (key: keyof GlobalSettingsPageTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n },\n [t]\n );\n\n // Build all sections with appearance first\n const allSections: SettingsSectionConfig[] = useMemo(\n () => [\n {\n id: 'appearance',\n icon: PaintBrushIcon,\n label: getText('appearanceLabel'),\n description: getText('appearanceDescription'),\n content: (\n <AppearanceSettings\n theme={theme}\n fontSize={fontSize}\n onThemeChange={handleThemeChange}\n onFontSizeChange={handleFontSizeChange}\n t={appearanceT}\n showInfoBox={showAppearanceInfoBox}\n />\n ),\n },\n ...additionalSections,\n ],\n [\n additionalSections,\n getText,\n theme,\n fontSize,\n handleThemeChange,\n handleFontSizeChange,\n appearanceT,\n showAppearanceInfoBox,\n ]\n );\n\n const currentSection =\n allSections.find(s => s.id === selectedSection) || allSections[0];\n\n const handleSectionSelect = (sectionId: string) => {\n track('section_selected', { section_id: sectionId });\n setSelectedSection(sectionId);\n setMobileView('content');\n };\n\n const handleBackToNavigation = () => {\n track('back_to_navigation');\n setMobileView('navigation');\n };\n\n // Navigation list using MasterListItem\n const navigationList = (\n <div>\n {allSections.map(section => (\n <MasterListItem\n key={section.id}\n isSelected={selectedSection === section.id}\n onClick={() => handleSectionSelect(section.id)}\n icon={section.icon}\n label={section.label}\n description={section.description}\n />\n ))}\n </div>\n );\n\n return (\n <Section spacing='lg' maxWidth='6xl' className={cn(className)}>\n <MasterDetailLayout\n masterTitle={getText('title')}\n backButtonText={getText('backButton')}\n masterContent={navigationList}\n detailContent={currentSection.content}\n detailTitle={currentSection.label}\n mobileView={mobileView}\n onBackToNavigation={handleBackToNavigation}\n masterWidth={280}\n stickyMaster={true}\n enableAnimations={true}\n />\n </Section>\n );\n};\n\nexport default GlobalSettingsPage;\n","/**\n * @fileoverview App Subscriptions Page\n * @description Page for managing app subscriptions and viewing rate limits.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n SubscriptionLayout,\n SubscriptionTile,\n SegmentedControl,\n} from '@sudobility/subscription-components';\nimport { Section } from '@sudobility/components';\nimport type { RateLimitsConfigData } from '@sudobility/types';\nimport type { AnalyticsTrackingParams } from '../../types';\n\ntype BillingPeriod = 'monthly' | 'yearly';\n\n/** Product from subscription provider */\nexport interface SubscriptionProduct {\n identifier: string;\n title: string;\n price: string;\n priceString: string;\n period?: string;\n freeTrialPeriod?: string;\n introPrice?: string;\n}\n\n/** Current subscription state */\nexport interface CurrentSubscription {\n isActive: boolean;\n productIdentifier?: string;\n expirationDate?: Date;\n willRenew?: boolean;\n}\n\n/** Subscription context value passed from consumer */\nexport interface SubscriptionContextValue {\n products: SubscriptionProduct[];\n currentSubscription: CurrentSubscription | null;\n isLoading: boolean;\n error: string | null;\n /** Purchase a subscription product. subscriptionUserId identifies which user/entity the subscription is for. */\n purchase: (\n productId: string,\n subscriptionUserId?: string\n ) => Promise<boolean>;\n /** Restore purchases. subscriptionUserId identifies which user/entity to restore for. */\n restore: (subscriptionUserId?: string) => Promise<boolean>;\n clearError: () => void;\n}\n\n/** All localized labels for the subscription page */\nexport interface SubscriptionPageLabels {\n title: string;\n errorTitle: string;\n purchaseError: string;\n restoreError: string;\n restoreNoPurchases: string;\n\n // Periods\n periodYear: string;\n periodMonth: string;\n periodWeek: string;\n\n // Billing period toggle\n billingMonthly: string;\n billingYearly: string;\n\n // Rate limits\n unlimited: string;\n unlimitedRequests: string;\n\n // Current status\n currentStatusLabel: string;\n statusActive: string;\n statusInactive: string;\n statusInactiveMessage: string;\n labelPlan: string;\n labelPremium: string;\n labelExpires: string;\n labelWillRenew: string;\n labelMonthlyUsage: string;\n labelDailyUsage: string;\n yes: string;\n no: string;\n\n // Buttons\n buttonSubscribe: string;\n buttonPurchasing: string;\n buttonRestore: string;\n buttonRestoring: string;\n\n // Empty states\n noProducts: string;\n noProductsForPeriod: string;\n\n // Free tier\n freeTierTitle: string;\n freeTierPrice: string;\n freeTierFeatures: string[];\n\n // Badges\n currentPlanBadge: string;\n}\n\n/** Formatter functions for dynamic strings */\nexport interface SubscriptionPageFormatters {\n /** Format rate limit: \"1,000 requests/hour\" */\n formatHourlyLimit: (limit: string) => string;\n /** Format rate limit: \"10,000 requests/day\" */\n formatDailyLimit: (limit: string) => string;\n /** Format rate limit: \"100,000 requests/month\" */\n formatMonthlyLimit: (limit: string) => string;\n /** Format trial period: \"7 days free trial\" */\n formatTrialDays: (count: number) => string;\n /** Format trial period: \"2 weeks free trial\" */\n formatTrialWeeks: (count: number) => string;\n /** Format trial period: \"1 month free trial\" */\n formatTrialMonths: (count: number) => string;\n /** Format savings badge: \"Save 20%\" */\n formatSavePercent: (percent: number) => string;\n /** Format intro price note */\n formatIntroNote: (price: string) => string;\n /** Get features for a product by its identifier (required - same as pricing page) */\n getProductFeatures: (productId: string) => string[];\n}\n\n/** Package ID to entitlement mapping (same as PricingPage) */\nexport interface EntitlementMap {\n [packageId: string]: string;\n}\n\n/** Entitlement to level mapping for comparing plan tiers (same as PricingPage) */\nexport interface EntitlementLevels {\n [entitlement: string]: number;\n}\n\nexport interface AppSubscriptionsPageProps {\n /** Subscription context value */\n subscription: SubscriptionContextValue;\n /** Rate limit configuration (for displaying current usage, not for features) */\n rateLimitsConfig?: RateLimitsConfigData | null;\n /** User ID used for subscription (the selected entity's ID when logged in) */\n subscriptionUserId?: string;\n /** All localized labels */\n labels: SubscriptionPageLabels;\n /** Formatter functions for dynamic strings */\n formatters: SubscriptionPageFormatters;\n /** Package ID to entitlement mapping (same as PricingPage) */\n entitlementMap: EntitlementMap;\n /** Entitlement to level mapping for comparing tiers (same as PricingPage) */\n entitlementLevels: EntitlementLevels;\n /** Called when purchase succeeds */\n onPurchaseSuccess?: () => void;\n /** Called when restore succeeds */\n onRestoreSuccess?: () => void;\n /** Called on error */\n onError?: (title: string, message: string) => void;\n /** Called on warning */\n onWarning?: (title: string, message: string) => void;\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Page for managing app subscriptions.\n * Uses the same entitlement mapping and features display as AppPricingPage.\n */\nexport function AppSubscriptionsPage({\n subscription,\n rateLimitsConfig,\n subscriptionUserId,\n labels,\n formatters,\n entitlementMap,\n entitlementLevels: _entitlementLevels,\n onPurchaseSuccess,\n onRestoreSuccess,\n onError,\n onWarning,\n onTrack,\n}: AppSubscriptionsPageProps) {\n const {\n products,\n currentSubscription,\n isLoading,\n error,\n purchase,\n restore,\n clearError,\n } = subscription;\n\n const [billingPeriod, setBillingPeriod] = useState<BillingPeriod>('monthly');\n const [selectedPlan, setSelectedPlan] = useState<string | null>(null);\n const [isPurchasing, setIsPurchasing] = useState(false);\n const [isRestoring, setIsRestoring] = useState(false);\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'subscription_action',\n componentName: 'AppSubscriptionsPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Show error via callback\n useEffect(() => {\n if (error) {\n onError?.(labels.errorTitle, error);\n clearError();\n }\n }, [error, clearError, labels.errorTitle, onError]);\n\n // Filter products by billing period and sort by price\n const filteredProducts = products\n .filter(product => {\n if (!product.period) return false;\n const isYearly =\n product.period.includes('Y') || product.period.includes('year');\n return billingPeriod === 'yearly' ? isYearly : !isYearly;\n })\n .sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n\n const handlePeriodChange = useCallback(\n (period: BillingPeriod) => {\n setBillingPeriod(period);\n setSelectedPlan(null);\n track('billing_period_changed', { billing_period: period });\n },\n [track]\n );\n\n const handlePurchase = useCallback(async () => {\n if (!selectedPlan) return;\n\n setIsPurchasing(true);\n clearError();\n track('purchase_initiated', { plan_identifier: selectedPlan });\n\n try {\n const result = await purchase(selectedPlan, subscriptionUserId);\n if (result) {\n track('purchase_completed', { plan_identifier: selectedPlan });\n onPurchaseSuccess?.();\n setSelectedPlan(null);\n } else {\n track('purchase_failed', {\n plan_identifier: selectedPlan,\n reason: 'purchase_returned_false',\n });\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : labels.purchaseError;\n track('purchase_failed', {\n plan_identifier: selectedPlan,\n reason: errorMessage,\n });\n onError?.(labels.errorTitle, errorMessage);\n } finally {\n setIsPurchasing(false);\n }\n }, [\n selectedPlan,\n clearError,\n track,\n purchase,\n subscriptionUserId,\n onPurchaseSuccess,\n labels.errorTitle,\n labels.purchaseError,\n onError,\n ]);\n\n const handlePlanSelect = useCallback(\n (planIdentifier: string | null) => {\n setSelectedPlan(planIdentifier);\n track('plan_selected', {\n plan_identifier: planIdentifier ?? 'free',\n is_free_tier: planIdentifier === null,\n });\n },\n [track]\n );\n\n const handleRestore = useCallback(async () => {\n setIsRestoring(true);\n clearError();\n track('restore_initiated');\n\n try {\n const result = await restore(subscriptionUserId);\n if (result) {\n track('restore_completed');\n onRestoreSuccess?.();\n } else {\n track('restore_failed', { reason: 'no_purchases_found' });\n onWarning?.(labels.errorTitle, labels.restoreNoPurchases);\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : labels.restoreError;\n track('restore_failed', { reason: errorMessage });\n onError?.(labels.errorTitle, errorMessage);\n } finally {\n setIsRestoring(false);\n }\n }, [\n clearError,\n track,\n restore,\n subscriptionUserId,\n onRestoreSuccess,\n labels.errorTitle,\n labels.restoreNoPurchases,\n labels.restoreError,\n onWarning,\n onError,\n ]);\n\n const formatExpirationDate = useCallback((date?: Date) => {\n if (!date) return '';\n return new Intl.DateTimeFormat(undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n }).format(date);\n }, []);\n\n const getPeriodLabel = useCallback(\n (period?: string) => {\n if (!period) return '';\n if (period.includes('Y') || period.includes('year'))\n return labels.periodYear;\n if (period.includes('M') || period.includes('month'))\n return labels.periodMonth;\n if (period.includes('W') || period.includes('week'))\n return labels.periodWeek;\n return '';\n },\n [labels]\n );\n\n const getTrialLabel = useCallback(\n (trialPeriod?: string) => {\n if (!trialPeriod) return undefined;\n const num = parseInt(trialPeriod.replace(/\\D/g, '') || '1', 10);\n if (trialPeriod.includes('W')) {\n return formatters.formatTrialWeeks(num);\n }\n if (trialPeriod.includes('M')) {\n return formatters.formatTrialMonths(num);\n }\n return formatters.formatTrialDays(num);\n },\n [formatters]\n );\n\n const formatRateLimit = useCallback(\n (limit: number | null): string => {\n if (limit === null) return labels.unlimited;\n return limit.toLocaleString();\n },\n [labels.unlimited]\n );\n\n // Use formatters.getProductFeatures directly (same as AppPricingPage)\n const getProductFeatures = useCallback(\n (packageId: string): string[] => {\n return formatters.getProductFeatures(packageId);\n },\n [formatters]\n );\n\n // Free tier features come from labels (same as AppPricingPage)\n const getFreeTierFeatures = useCallback((): string[] => {\n return labels.freeTierFeatures;\n }, [labels.freeTierFeatures]);\n\n const getYearlySavingsPercent = useCallback(\n (yearlyPackageId: string): number | undefined => {\n const yearlyEntitlement = entitlementMap[yearlyPackageId];\n if (!yearlyEntitlement) return undefined;\n\n const yearlyProduct = products.find(\n p => p.identifier === yearlyPackageId\n );\n if (!yearlyProduct) return undefined;\n\n const monthlyPackageId = Object.entries(entitlementMap).find(\n ([pkgId, ent]) => ent === yearlyEntitlement && pkgId.includes('monthly')\n )?.[0];\n if (!monthlyPackageId) return undefined;\n\n const monthlyProduct = products.find(\n p => p.identifier === monthlyPackageId\n );\n if (!monthlyProduct) return undefined;\n\n const yearlyPrice = parseFloat(yearlyProduct.price);\n const monthlyPrice = parseFloat(monthlyProduct.price);\n\n if (monthlyPrice <= 0 || yearlyPrice <= 0) return undefined;\n\n const annualizedMonthly = monthlyPrice * 12;\n const savings =\n ((annualizedMonthly - yearlyPrice) / annualizedMonthly) * 100;\n\n return Math.round(savings);\n },\n [products, entitlementMap]\n );\n\n const billingPeriodOptions = [\n { value: 'monthly' as const, label: labels.billingMonthly },\n { value: 'yearly' as const, label: labels.billingYearly },\n ];\n\n return (\n <Section spacing='lg' maxWidth='4xl'>\n <SubscriptionLayout\n title={labels.title}\n error={error}\n currentStatusLabel={labels.currentStatusLabel}\n currentStatus={{\n isActive: currentSubscription?.isActive ?? false,\n activeContent: currentSubscription?.isActive\n ? {\n title: labels.statusActive,\n fields: [\n {\n label: labels.labelPlan,\n value:\n currentSubscription.productIdentifier ||\n labels.labelPremium,\n },\n {\n label: labels.labelExpires,\n value: formatExpirationDate(\n currentSubscription.expirationDate\n ),\n },\n {\n label: labels.labelWillRenew,\n value: currentSubscription.willRenew\n ? labels.yes\n : labels.no,\n },\n ...(rateLimitsConfig\n ? [\n {\n label: labels.labelMonthlyUsage,\n value: `${rateLimitsConfig.currentUsage.monthly.toLocaleString()} / ${formatRateLimit(rateLimitsConfig.currentLimits.monthly)}`,\n },\n {\n label: labels.labelDailyUsage,\n value: `${rateLimitsConfig.currentUsage.daily.toLocaleString()} / ${formatRateLimit(rateLimitsConfig.currentLimits.daily)}`,\n },\n ]\n : []),\n ],\n }\n : undefined,\n inactiveContent: !currentSubscription?.isActive\n ? {\n title: labels.statusInactive,\n message: labels.statusInactiveMessage,\n }\n : undefined,\n }}\n aboveProducts={\n !isLoading && products.length > 0 ? (\n <div className='flex justify-center mb-6'>\n <SegmentedControl\n options={billingPeriodOptions}\n value={billingPeriod}\n onChange={handlePeriodChange}\n />\n </div>\n ) : null\n }\n primaryAction={{\n label: isPurchasing\n ? labels.buttonPurchasing\n : labels.buttonSubscribe,\n onClick: handlePurchase,\n disabled: !selectedPlan || isPurchasing || isRestoring,\n loading: isPurchasing,\n }}\n secondaryAction={{\n label: isRestoring ? labels.buttonRestoring : labels.buttonRestore,\n onClick: handleRestore,\n disabled: isPurchasing || isRestoring,\n loading: isRestoring,\n }}\n >\n {isLoading ? (\n <div className='flex items-center justify-center py-12'>\n <div className='animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600' />\n </div>\n ) : products.length === 0 ? (\n <div className='text-center py-12 text-theme-text-secondary'>\n {labels.noProducts}\n </div>\n ) : filteredProducts.length === 0 ? (\n <div className='text-center py-12 text-theme-text-secondary'>\n {labels.noProductsForPeriod}\n </div>\n ) : (\n <>\n {/* Free tier tile */}\n <SubscriptionTile\n key='free'\n id='free'\n title={labels.freeTierTitle}\n price={labels.freeTierPrice}\n periodLabel={labels.periodMonth}\n features={getFreeTierFeatures()}\n isSelected={\n !currentSubscription?.isActive && selectedPlan === null\n }\n onSelect={() => handlePlanSelect(null)}\n topBadge={\n !currentSubscription?.isActive\n ? {\n text: labels.currentPlanBadge,\n color: 'green',\n }\n : undefined\n }\n disabled={isPurchasing || isRestoring}\n hideSelectionIndicator\n />\n {/* Paid plans */}\n {filteredProducts.map(product => (\n <SubscriptionTile\n key={product.identifier}\n id={product.identifier}\n title={product.title}\n price={product.priceString}\n periodLabel={getPeriodLabel(product.period)}\n features={getProductFeatures(product.identifier)}\n isSelected={selectedPlan === product.identifier}\n onSelect={() => handlePlanSelect(product.identifier)}\n isBestValue={product.identifier.includes('pro')}\n discountBadge={\n product.period?.includes('Y')\n ? (() => {\n const savings = getYearlySavingsPercent(\n product.identifier\n );\n return savings && savings > 0\n ? {\n text: formatters.formatSavePercent(savings),\n isBestValue: true,\n }\n : undefined;\n })()\n : undefined\n }\n introPriceNote={\n product.freeTrialPeriod\n ? getTrialLabel(product.freeTrialPeriod)\n : product.introPrice\n ? formatters.formatIntroNote(product.introPrice)\n : undefined\n }\n disabled={isPurchasing || isRestoring}\n />\n ))}\n </>\n )}\n </SubscriptionLayout>\n </Section>\n );\n}\n","/**\n * @fileoverview App Pricing Page\n * @description Public pricing page for displaying subscription options.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport { useState, useCallback } from 'react';\nimport {\n SubscriptionTile,\n SegmentedControl,\n} from '@sudobility/subscription-components';\nimport { Section } from '@sudobility/components';\nimport type { AnalyticsTrackingParams } from '../../types';\n\ntype BillingPeriod = 'monthly' | 'yearly';\n\n/** Product from subscription provider */\nexport interface PricingProduct {\n identifier: string;\n title: string;\n price: string;\n priceString: string;\n period?: string;\n}\n\n/** FAQ item */\nexport interface FAQItem {\n question: string;\n answer: string;\n}\n\n/** All localized labels for the pricing page */\nexport interface PricingPageLabels {\n // Header\n title: string;\n subtitle: string;\n\n // Periods\n periodYear: string;\n periodMonth: string;\n periodWeek: string;\n\n // Billing period toggle\n billingMonthly: string;\n billingYearly: string;\n\n // Free tier\n freeTierTitle: string;\n freeTierPrice: string;\n freeTierFeatures: string[];\n\n // Badges\n currentPlanBadge: string;\n mostPopularBadge: string;\n\n // CTA buttons\n ctaLogIn: string;\n ctaTryFree: string;\n ctaUpgrade: string;\n\n // FAQ\n faqTitle: string;\n}\n\n/** Formatter functions for dynamic strings */\nexport interface PricingPageFormatters {\n /** Format savings badge: \"Save 20%\" */\n formatSavePercent: (percent: number) => string;\n /** Get features for a product by its identifier */\n getProductFeatures: (productId: string) => string[];\n}\n\n/** Package ID to entitlement mapping */\nexport interface EntitlementMap {\n [packageId: string]: string;\n}\n\n/** Entitlement to level mapping for comparing plan tiers */\nexport interface EntitlementLevels {\n [entitlement: string]: number;\n}\n\nexport interface AppPricingPageProps {\n /** Available subscription products */\n products: PricingProduct[];\n /** Whether user is authenticated */\n isAuthenticated: boolean;\n /** Whether user has an active subscription */\n hasActiveSubscription: boolean;\n /** Current subscription product identifier (if any) */\n currentProductIdentifier?: string;\n /** User ID used for subscription (the selected entity's ID when logged in) */\n subscriptionUserId?: string;\n /** All localized labels */\n labels: PricingPageLabels;\n /** Formatter functions */\n formatters: PricingPageFormatters;\n /** Package ID to entitlement mapping for calculating savings */\n entitlementMap: EntitlementMap;\n /** Entitlement to level mapping for comparing tiers (higher = better) */\n entitlementLevels: EntitlementLevels;\n /** Called when user clicks on a plan */\n onPlanClick: (planIdentifier: string) => void;\n /** Called when user clicks on free plan */\n onFreePlanClick: () => void;\n /** Optional FAQ items */\n faqItems?: FAQItem[];\n /** Optional className for the container */\n className?: string;\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Public pricing page for displaying subscription options.\n * - Non-authenticated: Free tile shows \"Try it for Free\", paid tiles show \"Log in to Continue\"\n * - Authenticated on free: Free tile shows \"Current Plan\" badge (no CTA), paid tiles show \"Upgrade\"\n * - Authenticated with subscription: Current plan shows badge (no CTA), higher tiers show \"Upgrade\"\n */\nexport function AppPricingPage({\n products,\n isAuthenticated,\n hasActiveSubscription,\n currentProductIdentifier,\n labels,\n formatters,\n entitlementMap,\n entitlementLevels,\n onPlanClick,\n onFreePlanClick,\n faqItems,\n className,\n onTrack,\n}: AppPricingPageProps) {\n const [billingPeriod, setBillingPeriod] = useState<BillingPeriod>('monthly');\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'subscription_action',\n componentName: 'AppPricingPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Handle billing period change with tracking\n const handleBillingPeriodChange = useCallback(\n (value: string) => {\n const newPeriod = value as BillingPeriod;\n setBillingPeriod(newPeriod);\n track('billing_period_changed', { billing_period: newPeriod });\n },\n [track]\n );\n\n // Handle free plan click with tracking\n const handleFreePlanClick = useCallback(() => {\n track('free_plan_clicked', { plan: 'free' });\n onFreePlanClick();\n }, [track, onFreePlanClick]);\n\n // Handle paid plan click with tracking\n const handlePlanClick = useCallback(\n (planIdentifier: string, actionType: 'login' | 'upgrade') => {\n track('plan_clicked', {\n plan_identifier: planIdentifier,\n action_type: actionType,\n });\n onPlanClick(planIdentifier);\n },\n [track, onPlanClick]\n );\n\n // Get entitlement level for a product (0 for free/none)\n const getProductLevel = useCallback(\n (productId: string): number => {\n const entitlement = entitlementMap[productId];\n if (!entitlement) return 0;\n return entitlementLevels[entitlement] ?? 0;\n },\n [entitlementMap, entitlementLevels]\n );\n\n // Get current user's subscription level\n const currentLevel = currentProductIdentifier\n ? getProductLevel(currentProductIdentifier)\n : 0;\n\n // Filter products by billing period and sort by price\n const filteredProducts = products\n .filter(product => {\n if (!product.period) return false;\n const isYearly =\n product.period.includes('Y') || product.period.includes('year');\n return billingPeriod === 'yearly' ? isYearly : !isYearly;\n })\n .sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n\n const getPeriodLabel = useCallback(\n (period?: string) => {\n if (!period) return '';\n if (period.includes('Y') || period.includes('year'))\n return labels.periodYear;\n if (period.includes('M') || period.includes('month'))\n return labels.periodMonth;\n if (period.includes('W') || period.includes('week'))\n return labels.periodWeek;\n return '';\n },\n [labels]\n );\n\n const getYearlySavingsPercent = useCallback(\n (yearlyPackageId: string): number | undefined => {\n const yearlyEntitlement = entitlementMap[yearlyPackageId];\n if (!yearlyEntitlement) return undefined;\n\n const yearlyProduct = products.find(\n p => p.identifier === yearlyPackageId\n );\n if (!yearlyProduct) return undefined;\n\n const monthlyPackageId = Object.entries(entitlementMap).find(\n ([pkgId, ent]) => ent === yearlyEntitlement && pkgId.includes('monthly')\n )?.[0];\n if (!monthlyPackageId) return undefined;\n\n const monthlyProduct = products.find(\n p => p.identifier === monthlyPackageId\n );\n if (!monthlyProduct) return undefined;\n\n const yearlyPrice = parseFloat(yearlyProduct.price);\n const monthlyPrice = parseFloat(monthlyProduct.price);\n\n if (monthlyPrice <= 0 || yearlyPrice <= 0) return undefined;\n\n const annualizedMonthly = monthlyPrice * 12;\n const savings =\n ((annualizedMonthly - yearlyPrice) / annualizedMonthly) * 100;\n\n return Math.round(savings);\n },\n [products, entitlementMap]\n );\n\n const billingPeriodOptions = [\n { value: 'monthly' as const, label: labels.billingMonthly },\n { value: 'yearly' as const, label: labels.billingYearly },\n ];\n\n // Determine if a product is the current plan (same entitlement level)\n const isCurrentPlan = useCallback(\n (productId: string): boolean => {\n if (!isAuthenticated) return false;\n if (!hasActiveSubscription) return false;\n // Compare entitlement levels (handles monthly/yearly variants of same tier)\n return getProductLevel(productId) === currentLevel && currentLevel > 0;\n },\n [isAuthenticated, hasActiveSubscription, getProductLevel, currentLevel]\n );\n\n // Determine if a product is an upgrade from current plan\n const isUpgrade = useCallback(\n (productId: string): boolean => {\n const productLevel = getProductLevel(productId);\n return productLevel > currentLevel;\n },\n [getProductLevel, currentLevel]\n );\n\n return (\n <div className={className}>\n {/* Header */}\n <Section spacing='2xl' maxWidth='4xl'>\n <div className='text-center'>\n <h1 className='text-4xl sm:text-5xl font-bold text-theme-text-primary mb-4'>\n {labels.title}\n </h1>\n <p className='text-lg text-theme-text-secondary'>{labels.subtitle}</p>\n </div>\n </Section>\n\n {/* Pricing Cards */}\n <Section spacing='3xl' maxWidth='6xl'>\n {/* Billing Period Selector */}\n <div className='flex justify-center mb-8'>\n <SegmentedControl\n options={billingPeriodOptions}\n value={billingPeriod}\n onChange={handleBillingPeriodChange}\n />\n </div>\n\n {/* Subscription Tiles Grid */}\n <div\n style={{\n display: 'grid',\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 280px), 1fr))',\n gridAutoRows: '1fr',\n gap: '1.5rem',\n overflow: 'visible',\n }}\n >\n {/* Free Tier */}\n <SubscriptionTile\n id='free'\n title={labels.freeTierTitle}\n price={labels.freeTierPrice}\n periodLabel={labels.periodMonth}\n features={labels.freeTierFeatures}\n isSelected={false}\n onSelect={() => {}}\n topBadge={\n isAuthenticated && !hasActiveSubscription\n ? {\n text: labels.currentPlanBadge,\n color: 'green',\n }\n : undefined\n }\n ctaButton={\n // Not logged in: show \"Try it for Free\"\n // Logged in on free plan: no CTA (current plan)\n // Logged in with subscription: no CTA (can't downgrade here)\n !isAuthenticated\n ? {\n label: labels.ctaTryFree,\n onClick: handleFreePlanClick,\n }\n : undefined\n }\n hideSelectionIndicator={isAuthenticated}\n />\n\n {/* Paid Plans */}\n {filteredProducts.map(product => {\n const isCurrent = isCurrentPlan(product.identifier);\n const canUpgrade = isUpgrade(product.identifier);\n\n // Determine CTA button\n let ctaButton: { label: string; onClick: () => void } | undefined;\n if (!isAuthenticated) {\n // Not logged in: show \"Log in to Continue\"\n ctaButton = {\n label: labels.ctaLogIn,\n onClick: () => handlePlanClick(product.identifier, 'login'),\n };\n } else if (isCurrent) {\n // Current plan: no CTA\n ctaButton = undefined;\n } else if (canUpgrade) {\n // Higher tier: show \"Upgrade\"\n ctaButton = {\n label: labels.ctaUpgrade,\n onClick: () => handlePlanClick(product.identifier, 'upgrade'),\n };\n }\n // Lower tier than current: no CTA (implicit downgrade not shown)\n\n // Determine top badge\n let topBadge:\n | {\n text: string;\n color: 'purple' | 'green' | 'blue' | 'yellow' | 'red';\n }\n | undefined;\n if (isCurrent) {\n topBadge = {\n text: labels.currentPlanBadge,\n color: 'green',\n };\n } else if (product.identifier.includes('pro')) {\n topBadge = {\n text: labels.mostPopularBadge,\n color: 'yellow',\n };\n }\n\n return (\n <SubscriptionTile\n key={product.identifier}\n id={product.identifier}\n title={product.title}\n price={product.priceString}\n periodLabel={getPeriodLabel(product.period)}\n features={formatters.getProductFeatures(product.identifier)}\n isSelected={false}\n onSelect={() => {}}\n isBestValue={product.identifier.includes('pro')}\n topBadge={topBadge}\n discountBadge={\n product.period?.includes('Y')\n ? (() => {\n const savings = getYearlySavingsPercent(\n product.identifier\n );\n return savings && savings > 0\n ? {\n text: formatters.formatSavePercent(savings),\n isBestValue: true,\n }\n : undefined;\n })()\n : undefined\n }\n ctaButton={ctaButton}\n hideSelectionIndicator={!ctaButton}\n />\n );\n })}\n </div>\n </Section>\n\n {/* FAQ Section */}\n {faqItems && faqItems.length > 0 && (\n <Section spacing='3xl' background='surface' maxWidth='3xl'>\n <h2 className='text-3xl font-bold text-theme-text-primary text-center mb-12'>\n {labels.faqTitle}\n </h2>\n\n <div className='space-y-6'>\n {faqItems.map((item, index) => (\n <div\n key={index}\n className='bg-theme-bg-primary p-6 rounded-xl border border-theme-border'\n >\n <h3 className='text-lg font-semibold text-theme-text-primary mb-2'>\n {item.question}\n </h3>\n <p className='text-theme-text-secondary'>{item.answer}</p>\n </div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n","/**\n * @fileoverview App Sitemap Page\n * @description Reusable sitemap page component with categorized links.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, { type ComponentType, type ReactNode } from 'react';\nimport {\n ChevronRightIcon,\n HomeIcon,\n DocumentTextIcon,\n EnvelopeIcon,\n CogIcon,\n LanguageIcon,\n} from '@heroicons/react/24/outline';\nimport { Section } from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type { LinkComponentProps } from '../../types';\n\n/**\n * Configuration for a single sitemap link\n */\nexport interface SitemapLink {\n /** URL path */\n path: string;\n /** Display label */\n label: string;\n /** Optional description */\n description?: string;\n}\n\n/**\n * Configuration for a sitemap section\n */\nexport interface SitemapSection {\n /** Section title */\n title: string;\n /** Section icon type (optional) */\n icon?: 'home' | 'document' | 'envelope' | 'cog' | 'language';\n /** Links in this section */\n links: SitemapLink[];\n}\n\n/**\n * Configuration for a language option\n */\nexport interface LanguageOption {\n /** Language code (e.g., 'en', 'es') */\n code: string;\n /** Display name */\n name: string;\n /** Flag emoji */\n flag: string;\n}\n\n/**\n * Configuration for quick action buttons\n */\nexport interface QuickLink {\n /** URL path */\n path: string;\n /** Display label */\n label: string;\n /** Button variant */\n variant: 'primary' | 'secondary' | 'outline';\n /** Optional icon */\n icon?: 'envelope' | 'document';\n}\n\n/**\n * Text content for the sitemap page\n */\nexport interface SitemapPageText {\n /** Page title */\n title: string;\n /** Page subtitle */\n subtitle: string;\n /** Languages section title */\n languagesSectionTitle: string;\n /** Languages section description */\n languagesDescription: string;\n /** Quick links section title */\n quickLinksTitle: string;\n}\n\n/**\n * Props for AppSitemapPage component\n */\nexport interface AppSitemapPageProps {\n /** All text content (must be provided by consumer) */\n text: SitemapPageText;\n /** Sitemap sections */\n sections: SitemapSection[];\n /** Available languages */\n languages: LanguageOption[];\n /** Quick action links */\n quickLinks?: QuickLink[];\n /** Custom Link component for navigation */\n LinkComponent: ComponentType<LinkComponentProps & { language?: string }>;\n /** Optional wrapper component for the page layout */\n PageWrapper?: ComponentType<{ children: ReactNode }>;\n /** Optional className for the container */\n className?: string;\n}\n\n/**\n * Get icon component based on icon type\n */\nconst getIcon = (icon?: string) => {\n switch (icon) {\n case 'home':\n return <HomeIcon className='w-5 h-5 mr-2' />;\n case 'document':\n return <DocumentTextIcon className='w-5 h-5 mr-2' />;\n case 'envelope':\n return <EnvelopeIcon className='w-5 h-5 mr-2' />;\n case 'cog':\n return <CogIcon className='w-5 h-5 mr-2' />;\n case 'language':\n return <LanguageIcon className='w-5 h-5 mr-2' />;\n default:\n return null;\n }\n};\n\n/**\n * AppSitemapPage - A reusable sitemap page component\n *\n * Displays a comprehensive sitemap with:\n * - Language selector\n * - Organized sections with links\n * - Quick action buttons\n *\n * All text content must be provided by the consumer app.\n *\n * @example\n * ```tsx\n * <AppSitemapPage\n * text={{\n * title: \"Sitemap\",\n * subtitle: \"Explore all pages\",\n * languagesSectionTitle: \"Languages\",\n * languagesDescription: \"Available in multiple languages\",\n * quickLinksTitle: \"Quick Links\"\n * }}\n * sections={[\n * { title: \"Main\", icon: \"home\", links: [{ path: \"/\", label: \"Home\" }] }\n * ]}\n * languages={[{ code: \"en\", name: \"English\", flag: \"🇺🇸\" }]}\n * LinkComponent={LocalizedLink}\n * />\n * ```\n */\nexport const AppSitemapPage: React.FC<AppSitemapPageProps> = ({\n text,\n sections,\n languages,\n quickLinks = [],\n LinkComponent,\n PageWrapper,\n className,\n}) => {\n const content = (\n <Section spacing='3xl' maxWidth='6xl' className={cn(className)}>\n {/* Header */}\n <div className='text-center mb-12'>\n <h1 className='text-4xl font-bold text-gray-900 dark:text-white mb-4'>\n {text.title}\n </h1>\n <p className='text-xl text-gray-600 dark:text-gray-300'>\n {text.subtitle}\n </p>\n </div>\n\n {/* Language Section */}\n {languages.length > 0 && (\n <div className='mb-12 p-6 bg-blue-50 dark:bg-blue-900/20 rounded-lg'>\n <h2 className='text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center'>\n <LanguageIcon className='w-6 h-6 mr-2' />\n {text.languagesSectionTitle}\n </h2>\n <p className='text-gray-600 dark:text-gray-300 mb-6'>\n {text.languagesDescription}\n </p>\n <div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4'>\n {languages.map(lang => (\n <LinkComponent\n key={lang.code}\n href='/'\n language={lang.code}\n className='flex items-center space-x-2 p-3 bg-white dark:bg-gray-800 rounded-lg hover:shadow-md transition-shadow'\n >\n <span className='text-2xl'>{lang.flag}</span>\n <div className='font-medium text-gray-900 dark:text-white'>\n {lang.name}\n </div>\n </LinkComponent>\n ))}\n </div>\n </div>\n )}\n\n {/* Sitemap Grid */}\n <div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8'>\n {sections.map((section, index) => (\n <div\n key={index}\n className='bg-white dark:bg-gray-800 rounded-lg shadow-sm p-6'\n >\n <h2 className='text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center'>\n {getIcon(section.icon)}\n {section.title}\n </h2>\n <ul className='space-y-2'>\n {section.links.map((link, linkIndex) => (\n <li key={linkIndex}>\n <LinkComponent\n href={link.path}\n className='group flex items-start text-sm hover:text-blue-600 dark:hover:text-blue-400 transition-colors'\n >\n <ChevronRightIcon className='w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400' />\n <div>\n <span className='font-medium text-gray-700 dark:text-gray-300 group-hover:text-blue-600 dark:group-hover:text-blue-400'>\n {link.label}\n </span>\n {link.description && (\n <span className='block text-xs text-gray-500 dark:text-gray-400 mt-0.5'>\n {link.description}\n </span>\n )}\n </div>\n </LinkComponent>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n\n {/* Quick Links Section */}\n {quickLinks.length > 0 && (\n <div className='mt-12 p-6 bg-gray-50 dark:bg-gray-900 rounded-lg'>\n <h3 className='text-lg font-semibold text-gray-900 dark:text-white mb-4'>\n {text.quickLinksTitle}\n </h3>\n <div className='flex flex-wrap gap-3'>\n {quickLinks.map((link, index) => {\n const baseClasses =\n 'inline-flex items-center px-4 py-2 rounded-lg transition-colors';\n const variantClasses =\n link.variant === 'primary'\n ? 'bg-blue-600 text-white hover:bg-blue-700'\n : link.variant === 'secondary'\n ? 'bg-gray-600 text-white hover:bg-gray-700'\n : 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800';\n\n return (\n <LinkComponent\n key={index}\n href={link.path}\n className={`${baseClasses} ${variantClasses}`}\n >\n {link.icon === 'envelope' && (\n <EnvelopeIcon className='w-5 h-5 mr-2' />\n )}\n {link.icon === 'document' && (\n <DocumentTextIcon className='w-5 h-5 mr-2' />\n )}\n {link.label}\n </LinkComponent>\n );\n })}\n </div>\n </div>\n )}\n </Section>\n );\n\n if (PageWrapper) {\n return <PageWrapper>{content}</PageWrapper>;\n }\n\n return content;\n};\n\nexport default AppSitemapPage;\n","/**\n * @fileoverview App Text Page\n * @description Reusable page component for text-heavy content like Privacy Policy, Terms, etc.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, { type ReactNode, type ComponentType } from 'react';\nimport { Section } from '@sudobility/components';\nimport { cn } from '../../utils';\n\n/**\n * Configuration for a text section with paragraph content\n */\nexport interface TextSectionWithContent {\n /** Section title */\n title: string;\n /** Paragraph content */\n content: string;\n /** Whether content contains HTML that should be rendered */\n isHtml?: boolean;\n}\n\n/**\n * Configuration for a text section with a list\n */\nexport interface TextSectionWithList {\n /** Section title */\n title: string;\n /** Optional description before the list */\n description?: string;\n /** List items */\n items: string[];\n /** Optional additional content after the list */\n additionalContent?: string;\n}\n\n/**\n * Configuration for a text section with subsections (e.g., \"Information You Provide\" and \"Information Collected Automatically\")\n */\nexport interface TextSectionWithSubsections {\n /** Section title */\n title: string;\n /** Subsections, each with a title and list items */\n subsections: Array<{\n title: string;\n items: string[];\n }>;\n}\n\n/**\n * Union type for all section types\n */\nexport type TextSection =\n | TextSectionWithContent\n | TextSectionWithList\n | TextSectionWithSubsections;\n\n/**\n * Contact information configuration\n */\nexport interface TextPageContactInfo {\n /** Email label (e.g., \"Email:\") */\n emailLabel: string;\n /** Email address */\n email: string;\n /** Website label (e.g., \"Website:\") */\n websiteLabel: string;\n /** Website URL */\n websiteUrl: string;\n /** Data Protection Officer label (optional, for privacy pages) */\n dpoLabel?: string;\n /** DPO email (optional, for privacy pages) */\n dpoEmail?: string;\n}\n\n/**\n * GDPR notice configuration (optional, for privacy pages)\n */\nexport interface GdprNotice {\n /** GDPR section title */\n title: string;\n /** GDPR section content */\n content: string;\n}\n\n/**\n * Contact section configuration\n */\nexport interface TextPageContact {\n /** Section title */\n title: string;\n /** Section description */\n description: string;\n /** Whether description contains HTML */\n isHtml?: boolean;\n /** Contact details */\n info: TextPageContactInfo;\n /** Optional GDPR notice (for privacy pages) */\n gdprNotice?: GdprNotice;\n}\n\n/**\n * All text content for the text page\n */\nexport interface TextPageContent {\n /** Page title */\n title: string;\n /** Last updated text (use {{date}} as placeholder for the date) */\n lastUpdated?: string;\n /** All sections in order */\n sections: TextSection[];\n /** Contact information (optional) */\n contact?: TextPageContact;\n}\n\n/**\n * Props for AppTextPage component\n */\nexport interface AppTextPageProps {\n /** All text content (must be provided by consumer) */\n text: TextPageContent;\n /** Current date for \"last updated\" display */\n lastUpdatedDate?: string;\n /** Optional wrapper component for the page layout */\n PageWrapper?: ComponentType<{ children: ReactNode }>;\n /** Optional className for the container */\n className?: string;\n}\n\n/**\n * Type guard to check if section has items (is a list section)\n */\nfunction isSectionWithList(\n section: TextSection\n): section is TextSectionWithList {\n return 'items' in section && Array.isArray(section.items);\n}\n\n/**\n * Type guard to check if section has subsections\n */\nfunction isSectionWithSubsections(\n section: TextSection\n): section is TextSectionWithSubsections {\n return 'subsections' in section && Array.isArray(section.subsections);\n}\n\n/**\n * Heading component for h2 sections\n */\nconst SectionHeading: React.FC<{ children: ReactNode }> = ({ children }) => (\n <h2 className='text-2xl font-bold text-gray-900 dark:text-gray-100 mt-8 mb-4'>\n {children}\n </h2>\n);\n\n/**\n * Heading component for h3 subsections\n */\nconst SubsectionHeading: React.FC<{ children: ReactNode }> = ({ children }) => (\n <h3 className='text-xl font-semibold text-gray-900 dark:text-gray-100 mt-6 mb-3'>\n {children}\n </h3>\n);\n\n/**\n * Paragraph component\n */\nconst Paragraph: React.FC<{ children: ReactNode; className?: string }> = ({\n children,\n className = '',\n}) => (\n <p className={`text-gray-600 dark:text-gray-300 mb-6 ${className}`}>\n {children}\n </p>\n);\n\n/**\n * List component - renders items with HTML support\n */\nconst List: React.FC<{ items: string[] }> = ({ items }) => (\n <ul className='list-disc list-inside text-gray-600 dark:text-gray-300 mb-6 space-y-1'>\n {items.map((item, index) => (\n <li key={index} dangerouslySetInnerHTML={{ __html: item }} />\n ))}\n </ul>\n);\n\n/**\n * AppTextPage - A reusable text page component for legal/informational pages\n *\n * Displays a text-heavy page with:\n * - Flexible section structure (content, list, or subsections)\n * - Optional contact information\n * - Optional GDPR notice\n *\n * Use this for Privacy Policy, Terms of Service, Cookie Policy, etc.\n *\n * @example\n * ```tsx\n * <AppTextPage\n * text={{\n * title: \"Privacy Policy\",\n * lastUpdated: \"Last updated: {{date}}\",\n * sections: [\n * { title: \"Introduction\", content: \"We respect your privacy...\" },\n * { title: \"Data We Collect\", items: [\"Email\", \"Usage data\"] },\n * {\n * title: \"Information We Collect\",\n * subsections: [\n * { title: \"You Provide\", items: [\"Email\", \"Name\"] },\n * { title: \"Automatic\", items: [\"IP\", \"Browser\"] }\n * ]\n * }\n * ],\n * contact: {\n * title: \"Contact\",\n * description: \"Questions?\",\n * info: { emailLabel: \"Email:\", email: \"support@example.com\", ... }\n * }\n * }}\n * lastUpdatedDate=\"January 1, 2025\"\n * />\n * ```\n */\nexport const AppTextPage: React.FC<AppTextPageProps> = ({\n text,\n lastUpdatedDate = new Date().toLocaleDateString(),\n PageWrapper,\n className,\n}) => {\n const content = (\n <Section spacing='3xl' maxWidth='4xl' className={cn(className)}>\n <h1 className='text-4xl font-bold text-gray-900 dark:text-gray-100 mb-8'>\n {text.title}\n </h1>\n\n <div className='prose prose-lg dark:prose-invert max-w-none'>\n {text.lastUpdated && (\n <Paragraph className='mb-6'>\n {text.lastUpdated.replace('{{date}}', lastUpdatedDate)}\n </Paragraph>\n )}\n\n {/* Render all sections */}\n {text.sections.map((section, index) => (\n <React.Fragment key={index}>\n <SectionHeading>{section.title}</SectionHeading>\n\n {isSectionWithSubsections(section) ? (\n // Section with subsections (h3 + lists)\n <>\n {section.subsections.map((subsection, subIndex) => (\n <React.Fragment key={subIndex}>\n <SubsectionHeading>{subsection.title}</SubsectionHeading>\n <List items={subsection.items} />\n </React.Fragment>\n ))}\n </>\n ) : isSectionWithList(section) ? (\n // Section with list\n <>\n {section.description && (\n <Paragraph className='mb-4'>{section.description}</Paragraph>\n )}\n <List items={section.items} />\n {section.additionalContent && (\n <Paragraph>{section.additionalContent}</Paragraph>\n )}\n </>\n ) : section.isHtml ? (\n // Section with HTML content\n <Paragraph>\n <span dangerouslySetInnerHTML={{ __html: section.content }} />\n </Paragraph>\n ) : (\n // Section with plain text content\n <Paragraph>{section.content}</Paragraph>\n )}\n </React.Fragment>\n ))}\n\n {/* Contact Section */}\n {text.contact && (\n <>\n <SectionHeading>{text.contact.title}</SectionHeading>\n {text.contact.isHtml ? (\n <Paragraph>\n <span\n dangerouslySetInnerHTML={{ __html: text.contact.description }}\n />\n </Paragraph>\n ) : (\n <Paragraph>{text.contact.description}</Paragraph>\n )}\n <div className='bg-gray-50 dark:bg-gray-800 p-4 rounded-lg'>\n <p className='text-gray-700 dark:text-gray-300'>\n {text.contact.info.emailLabel}{' '}\n <a\n href={`mailto:${text.contact.info.email}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.email}\n </a>\n <br />\n {text.contact.info.websiteLabel}{' '}\n <a\n href={text.contact.info.websiteUrl}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.websiteUrl}\n </a>\n {text.contact.info.dpoLabel && text.contact.info.dpoEmail && (\n <>\n <br />\n {text.contact.info.dpoLabel}{' '}\n <a\n href={`mailto:${text.contact.info.dpoEmail}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.dpoEmail}\n </a>\n </>\n )}\n </p>\n </div>\n\n {/* GDPR Notice */}\n {text.contact.gdprNotice && (\n <div className='mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg'>\n <h3 className='text-lg font-semibold text-blue-900 dark:text-blue-200 mb-2'>\n {text.contact.gdprNotice.title}\n </h3>\n <p className='text-blue-800 dark:text-blue-300'>\n {text.contact.gdprNotice.content}{' '}\n {text.contact.info.dpoEmail && (\n <a\n href={`mailto:${text.contact.info.dpoEmail}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.dpoEmail}\n </a>\n )}\n </p>\n </div>\n )}\n </>\n )}\n </div>\n </Section>\n );\n\n if (PageWrapper) {\n return <PageWrapper>{content}</PageWrapper>;\n }\n\n return content;\n};\n\nexport default AppTextPage;\n","import React, { useState, useEffect, useRef, type ReactNode } from 'react';\nimport {\n signInWithEmailAndPassword,\n createUserWithEmailAndPassword,\n GoogleAuthProvider,\n signInWithPopup,\n type Auth,\n} from 'firebase/auth';\n\n/**\n * Google logo SVG component\n */\nfunction GoogleIcon({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox='0 0 24 24' aria-hidden='true'>\n <path\n d='M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z'\n fill='#4285F4'\n />\n <path\n d='M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z'\n fill='#34A853'\n />\n <path\n d='M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z'\n fill='#FBBC05'\n />\n <path\n d='M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z'\n fill='#EA4335'\n />\n </svg>\n );\n}\n\n/**\n * Auth error info passed to onAuthError callback\n */\nexport interface AuthErrorInfo {\n /** Firebase error code (e.g., 'auth/popup-closed-by-user') */\n code: string;\n /** Error message */\n message: string;\n /** Whether this is a user-initiated action (like closing popup) vs actual error */\n isUserAction: boolean;\n}\n\n/**\n * Props for the LoginPage component\n */\nexport interface LoginPageProps {\n /** Application name displayed as the main title */\n appName: string;\n /** Optional logo element to display above the title */\n logo?: ReactNode;\n /** Firebase Auth instance */\n auth: Auth;\n /** Callback fired on successful authentication */\n onSuccess: () => void;\n /** Callback fired on auth errors - if provided, errors won't be shown inline */\n onAuthError?: (error: AuthErrorInfo) => void;\n /** Whether to show Google sign-in option (default: true) */\n showGoogleSignIn?: boolean;\n /** Whether to show sign-up option (default: true) */\n showSignUp?: boolean;\n /** Custom className for the container */\n className?: string;\n /** Custom primary color class (default: 'primary') */\n primaryColorClass?: string;\n}\n\n/**\n * Text content for the LoginPage\n */\nexport interface LoginPageText {\n signIn: string;\n signUp: string;\n createAccount: string;\n signInToAccount: string;\n emailLabel: string;\n emailPlaceholder: string;\n passwordLabel: string;\n passwordPlaceholder: string;\n orContinueWith: string;\n signInWithGoogle: string;\n alreadyHaveAccount: string;\n dontHaveAccount: string;\n}\n\nconst defaultText: LoginPageText = {\n signIn: 'Sign in',\n signUp: 'Sign up',\n createAccount: 'Create your account',\n signInToAccount: 'Sign in to your account',\n emailLabel: 'Email address',\n emailPlaceholder: '',\n passwordLabel: 'Password',\n passwordPlaceholder: '',\n orContinueWith: 'Or continue with',\n signInWithGoogle: 'Sign in with Google',\n alreadyHaveAccount: 'Already have an account?',\n dontHaveAccount: \"Don't have an account?\",\n};\n\n/**\n * A reusable login page component with email/password and Google sign-in support.\n *\n * @example\n * ```tsx\n * import { LoginPage } from '@sudobility/building_blocks';\n * import { getFirebaseAuth } from '@sudobility/auth_lib';\n *\n * function MyLoginPage() {\n * const navigate = useNavigate();\n * const auth = getFirebaseAuth();\n *\n * return (\n * <LoginPage\n * appName=\"My App\"\n * auth={auth}\n * onSuccess={() => navigate('/')}\n * />\n * );\n * }\n * ```\n */\n// Error codes that represent user actions rather than actual errors\nconst USER_ACTION_ERROR_CODES = [\n 'auth/popup-closed-by-user',\n 'auth/cancelled-popup-request',\n 'auth/user-cancelled',\n];\n\nexport function LoginPage({\n appName,\n logo,\n auth,\n onSuccess,\n onAuthError,\n showGoogleSignIn = true,\n showSignUp = true,\n className = '',\n primaryColorClass = 'primary',\n}: LoginPageProps) {\n const [isSignUp, setIsSignUp] = useState(false);\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [isGoogleSignInPending, setIsGoogleSignInPending] = useState(false);\n const googleSignInStartTime = useRef<number | null>(null);\n\n // Reset Google sign-in state when window regains focus\n // This handles the case where browser opens a new tab instead of popup\n useEffect(() => {\n const handleFocus = () => {\n if (isGoogleSignInPending && googleSignInStartTime.current) {\n // If more than 2 seconds have passed since sign-in started,\n // and we're back in focus, the user likely closed the tab/popup\n const elapsed = Date.now() - googleSignInStartTime.current;\n if (elapsed > 2000) {\n setIsLoading(false);\n setIsGoogleSignInPending(false);\n googleSignInStartTime.current = null;\n }\n }\n };\n\n window.addEventListener('focus', handleFocus);\n return () => window.removeEventListener('focus', handleFocus);\n }, [isGoogleSignInPending]);\n\n const handleAuthError = (err: unknown) => {\n const firebaseError = err as { code?: string; message?: string };\n const code = firebaseError.code || 'unknown';\n const message = firebaseError.message || 'Authentication failed';\n const isUserAction = USER_ACTION_ERROR_CODES.includes(code);\n\n if (onAuthError) {\n onAuthError({ code, message, isUserAction });\n } else if (!isUserAction) {\n // Only show inline error for actual errors, not user actions\n setError(message);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsLoading(true);\n\n try {\n if (!auth) throw new Error('Firebase not configured');\n if (isSignUp && showSignUp) {\n await createUserWithEmailAndPassword(auth, email, password);\n } else {\n await signInWithEmailAndPassword(auth, email, password);\n }\n onSuccess();\n } catch (err) {\n handleAuthError(err);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleGoogleSignIn = async () => {\n setError(null);\n setIsLoading(true);\n setIsGoogleSignInPending(true);\n googleSignInStartTime.current = Date.now();\n\n try {\n if (!auth) throw new Error('Firebase not configured');\n const provider = new GoogleAuthProvider();\n await signInWithPopup(auth, provider);\n onSuccess();\n } catch (err) {\n handleAuthError(err);\n } finally {\n setIsLoading(false);\n setIsGoogleSignInPending(false);\n googleSignInStartTime.current = null;\n }\n };\n\n const text = defaultText;\n\n return (\n <div\n className={`min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8 ${className}`}\n >\n <div className='max-w-md w-full space-y-8'>\n <div>\n {logo && <div className='flex justify-center mb-4'>{logo}</div>}\n <h1\n className={`text-center text-3xl font-bold text-${primaryColorClass}-600`}\n >\n {appName}\n </h1>\n <h2 className='mt-6 text-center text-2xl font-semibold text-gray-900'>\n {isSignUp && showSignUp ? text.createAccount : text.signInToAccount}\n </h2>\n </div>\n\n <form className='mt-8 space-y-6' onSubmit={handleSubmit}>\n {error && (\n <div className='bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-md text-sm'>\n {error}\n </div>\n )}\n\n <div className='space-y-4'>\n <div>\n <label\n htmlFor='email'\n className='block text-sm font-medium text-gray-700'\n >\n {text.emailLabel}\n </label>\n <input\n id='email'\n name='email'\n type='email'\n autoComplete='email'\n required\n value={email}\n onChange={e => setEmail(e.target.value)}\n placeholder={text.emailPlaceholder}\n className={`mt-1 appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-${primaryColorClass}-500 focus:border-${primaryColorClass}-500 sm:text-sm`}\n />\n </div>\n\n <div>\n <label\n htmlFor='password'\n className='block text-sm font-medium text-gray-700'\n >\n {text.passwordLabel}\n </label>\n <input\n id='password'\n name='password'\n type='password'\n autoComplete={isSignUp ? 'new-password' : 'current-password'}\n required\n value={password}\n onChange={e => setPassword(e.target.value)}\n placeholder={text.passwordPlaceholder}\n className={`mt-1 appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-${primaryColorClass}-500 focus:border-${primaryColorClass}-500 sm:text-sm`}\n />\n </div>\n </div>\n\n <div>\n <button\n type='submit'\n disabled={isLoading}\n className={`w-full inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 bg-${primaryColorClass}-600 text-white hover:bg-${primaryColorClass}-700 focus:ring-${primaryColorClass}-500 disabled:bg-${primaryColorClass}-300 px-4 py-2 text-sm`}\n >\n {isLoading && (\n <svg\n className='animate-spin -ml-1 mr-2 h-4 w-4'\n xmlns='http://www.w3.org/2000/svg'\n fill='none'\n viewBox='0 0 24 24'\n >\n <circle\n className='opacity-25'\n cx='12'\n cy='12'\n r='10'\n stroke='currentColor'\n strokeWidth='4'\n />\n <path\n className='opacity-75'\n fill='currentColor'\n d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'\n />\n </svg>\n )}\n {isSignUp && showSignUp ? text.signUp : text.signIn}\n </button>\n </div>\n\n {showGoogleSignIn && (\n <>\n <div className='relative'>\n <div className='absolute inset-0 flex items-center'>\n <div className='w-full border-t border-gray-300' />\n </div>\n <div className='relative flex justify-center text-sm'>\n <span className='px-2 bg-gray-50 text-gray-500'>\n {text.orContinueWith}\n </span>\n </div>\n </div>\n\n <div>\n <button\n type='button'\n onClick={handleGoogleSignIn}\n disabled={isLoading}\n className={`w-full inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 bg-white text-gray-700 border border-gray-300 hover:bg-gray-50 focus:ring-${primaryColorClass}-500 disabled:bg-gray-100 px-4 py-2 text-sm`}\n >\n {isLoading ? (\n <svg\n className='animate-spin -ml-1 mr-2 h-5 w-5'\n xmlns='http://www.w3.org/2000/svg'\n fill='none'\n viewBox='0 0 24 24'\n >\n <circle\n className='opacity-25'\n cx='12'\n cy='12'\n r='10'\n stroke='currentColor'\n strokeWidth='4'\n />\n <path\n className='opacity-75'\n fill='currentColor'\n d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'\n />\n </svg>\n ) : (\n <GoogleIcon className='h-5 w-5 mr-2' />\n )}\n {text.signInWithGoogle}\n </button>\n </div>\n </>\n )}\n </form>\n\n {showSignUp && (\n <p className='text-center text-sm text-gray-600'>\n {isSignUp ? text.alreadyHaveAccount : text.dontHaveAccount}{' '}\n <button\n type='button'\n onClick={() => setIsSignUp(!isSignUp)}\n className={`font-medium text-${primaryColorClass}-600 hover:text-${primaryColorClass}-500`}\n >\n {isSignUp ? text.signIn : text.signUp}\n </button>\n </p>\n )}\n </div>\n </div>\n );\n}\n"],"names":["DefaultLinkComponent","className","AuthStatus","ChainType","getCopyrightYear","FooterContainer","Theme","FontSize","defaultTranslations"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/index.ts","../src/constants/languages.ts","../src/components/topbar/language-selector.tsx","../src/components/topbar/app-topbar.tsx","../src/components/topbar/app-topbar-with-firebase-auth.tsx","../src/components/topbar/app-topbar-with-wallet.tsx","../src/components/breadcrumbs/app-breadcrumbs.tsx","../src/components/footer/app-footer.tsx","../src/components/footer/app-footer-for-home-page.tsx","../src/components/layout/app-page-layout.tsx","../src/components/settings/appearance-settings.tsx","../src/components/settings/global-settings-page.tsx","../src/components/subscription/AppSubscriptionsPage.tsx","../src/components/subscription/AppPricingPage.tsx","../src/components/pages/app-sitemap-page.tsx","../src/components/pages/app-text-page.tsx","../src/components/pages/login-page.tsx"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names with Tailwind CSS classes.\n * Combines clsx for conditional classes and tailwind-merge for deduplication.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","export interface LanguageConfig {\n code: string;\n name: string;\n flag: string;\n}\n\n/**\n * Default set of 16 supported languages with their flags.\n * Apps can override this list by passing their own languages prop.\n */\nexport const DEFAULT_LANGUAGES: LanguageConfig[] = [\n { code: 'en', name: 'English', flag: '🇺🇸' },\n { code: 'ar', name: 'العربية', flag: '🇸🇦' },\n { code: 'de', name: 'Deutsch', flag: '🇩🇪' },\n { code: 'es', name: 'Español', flag: '🇪🇸' },\n { code: 'fr', name: 'Français', flag: '🇫🇷' },\n { code: 'it', name: 'Italiano', flag: '🇮🇹' },\n { code: 'ja', name: '日本語', flag: '🇯🇵' },\n { code: 'ko', name: '한국어', flag: '🇰🇷' },\n { code: 'pt', name: 'Português', flag: '🇵🇹' },\n { code: 'ru', name: 'Русский', flag: '🇷🇺' },\n { code: 'sv', name: 'Svenska', flag: '🇸🇪' },\n { code: 'th', name: 'ไทย', flag: '🇹🇭' },\n { code: 'uk', name: 'Українська', flag: '🇺🇦' },\n { code: 'vi', name: 'Tiếng Việt', flag: '🇻🇳' },\n { code: 'zh', name: '简体中文', flag: '🇨🇳' },\n { code: 'zh-hant', name: '繁體中文', flag: '🇹🇼' },\n];\n\n/**\n * Languages that use right-to-left text direction.\n */\nexport const RTL_LANGUAGES = ['ar'];\n\n/**\n * Check if a language code is RTL.\n */\nexport function isRTL(languageCode: string): boolean {\n return RTL_LANGUAGES.includes(languageCode);\n}\n","import React, {\n useState,\n useCallback,\n useMemo,\n useRef,\n useEffect,\n} from 'react';\nimport { ChevronDownIcon } from '@heroicons/react/24/outline';\nimport { cn } from '../../utils';\nimport {\n DEFAULT_LANGUAGES,\n type LanguageConfig,\n} from '../../constants/languages';\n\nexport interface LanguageSelectorProps {\n /** Available languages (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n /** Current language code */\n currentLanguage?: string;\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n /** Variant: 'compact' for topbar, 'full' for settings */\n variant?: 'compact' | 'full';\n /** Custom className */\n className?: string;\n /** Label text for full variant */\n label?: string;\n /** Helper text for full variant */\n helperText?: string;\n}\n\n/**\n * LanguageSelector component with dropdown for switching languages.\n * Uses default 16 languages if none provided.\n */\nexport const LanguageSelector: React.FC<LanguageSelectorProps> = ({\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n variant = 'compact',\n className,\n label = 'Language',\n helperText = 'Select your preferred language',\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Sort languages alphabetically by name\n const sortedLanguages = useMemo(\n () => [...languages].sort((a, b) => a.name.localeCompare(b.name)),\n [languages]\n );\n\n const currentLang = useMemo(\n () => languages.find(lang => lang.code === currentLanguage) || languages[0],\n [languages, currentLanguage]\n );\n\n const handleLanguageChange = useCallback(\n (langCode: string) => {\n if (langCode !== currentLanguage) {\n onLanguageChange?.(langCode);\n }\n setIsOpen(false);\n },\n [currentLanguage, onLanguageChange]\n );\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n // Close dropdown on escape\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n if (variant === 'compact') {\n return (\n <div ref={dropdownRef} className={cn('relative', className)}>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center gap-2 px-3 py-2 h-10 rounded-lg',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-label='Select language'\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='hidden sm:block text-sm font-medium text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute right-0 mt-2 w-48 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // Full variant for settings pages\n return (\n <div ref={dropdownRef} className={cn('space-y-2', className)}>\n <label className='text-sm font-medium text-gray-700 dark:text-gray-300 flex items-center gap-2'>\n <span>{label}</span>\n </label>\n\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n 'flex items-center justify-between w-full px-3 py-2 text-left',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-300 dark:border-gray-600',\n 'rounded-md',\n 'hover:bg-gray-50 dark:hover:bg-gray-700',\n 'transition-colors'\n )}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div className='flex items-center gap-2'>\n <span className='text-lg leading-none'>{currentLang?.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {currentLang?.name}\n </span>\n </div>\n <ChevronDownIcon\n className={cn(\n 'h-4 w-4 text-gray-500 dark:text-gray-400 transition-transform',\n isOpen && 'rotate-180'\n )}\n />\n </button>\n\n {isOpen && (\n <div\n className={cn(\n 'absolute left-0 right-0 mt-1 py-1 z-50',\n 'bg-white dark:bg-gray-800',\n 'border border-gray-200 dark:border-gray-700',\n 'rounded-md shadow-lg'\n )}\n role='listbox'\n aria-label='Languages'\n >\n {sortedLanguages.map(lang => (\n <button\n key={lang.code}\n onClick={() => handleLanguageChange(lang.code)}\n className={cn(\n 'w-full flex items-center gap-3 px-3 py-2 text-left',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n 'transition-colors',\n lang.code === currentLanguage &&\n 'bg-gray-100 dark:bg-gray-700 font-medium'\n )}\n role='option'\n aria-selected={lang.code === currentLanguage}\n >\n <span className='text-lg leading-none'>{lang.flag}</span>\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {lang.name}\n </span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {helperText && (\n <p className='text-xs text-gray-500 dark:text-gray-400'>{helperText}</p>\n )}\n </div>\n );\n};\n\nexport default LanguageSelector;\n","import React, { useMemo, type ComponentType, type ReactNode } from 'react';\nimport {\n Topbar,\n TopbarProvider,\n TopbarLeft,\n TopbarCenter,\n TopbarRight,\n TopbarLogo,\n TopbarNavigation,\n TopbarActions,\n TopbarMobileContent,\n Logo,\n type TopbarNavItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport {\n LanguageSelector,\n type LanguageSelectorProps,\n} from './language-selector';\nimport type {\n MenuItemConfig,\n LogoConfig,\n LanguageConfig,\n LinkComponentProps,\n} from '../../types';\nimport { DEFAULT_LANGUAGES } from '../../constants/languages';\n\nexport interface AppTopBarProps {\n /** Logo configuration */\n logo: LogoConfig;\n\n /** Navigation menu items */\n menuItems: MenuItemConfig[];\n\n /** Available languages for selector (defaults to 16 built-in languages) */\n languages?: LanguageConfig[];\n\n /** Current language code */\n currentLanguage?: string;\n\n /** Language change handler */\n onLanguageChange?: (languageCode: string) => void;\n\n /** Hide language selector */\n hideLanguageSelector?: boolean;\n\n /** Language selector props override */\n languageSelectorProps?: Partial<LanguageSelectorProps>;\n\n /** Breakpoint to collapse navigation to hamburger menu */\n collapseBelow?: 'sm' | 'md' | 'lg' | 'xl';\n\n /** Render prop for account/auth section (right side of topbar) */\n renderAccountSection?: () => ReactNode;\n\n /** Render prop for center section (e.g., search bar) - shown on desktop */\n renderCenterSection?: () => ReactNode;\n\n /** Render prop for mobile-specific content (e.g., mobile search) - shown below main topbar on mobile */\n renderMobileContent?: () => ReactNode;\n\n /** Custom Link component for navigation (for react-router-dom, Next.js, etc.) */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Optional sticky positioning */\n sticky?: boolean;\n\n /** Optional variant */\n variant?: 'default' | 'app';\n\n /** Mobile menu label for accessibility */\n mobileMenuLabel?: string;\n\n /** Custom className for topbar */\n className?: string;\n\n /** z-index level */\n zIndex?: 'default' | 'highest' | 'high';\n\n /** Aria label for navigation */\n ariaLabel?: string;\n}\n\n/**\n * Default Link component that renders a plain anchor tag.\n * Apps should provide their own LinkComponent for router integration.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * AppTopBar - Base topbar component for Sudobility apps.\n *\n * Features:\n * - Logo with app name on the left\n * - Navigation menu items with icons\n * - Language selector\n * - Render prop for center section (e.g., search bar)\n * - Render prop for account/auth section\n * - Render prop for mobile-specific content\n * - Responsive with hamburger menu on mobile\n * - Dark mode support\n */\nexport const AppTopBar: React.FC<AppTopBarProps> = ({\n logo,\n menuItems,\n languages = DEFAULT_LANGUAGES,\n currentLanguage = 'en',\n onLanguageChange,\n hideLanguageSelector = false,\n languageSelectorProps,\n collapseBelow = 'lg',\n renderAccountSection,\n renderCenterSection,\n renderMobileContent,\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n variant = 'default',\n mobileMenuLabel = 'Menu',\n className,\n zIndex = 'highest',\n ariaLabel = 'Main navigation',\n}) => {\n // Filter menu items that should be shown\n const visibleMenuItems = useMemo(\n () => menuItems.filter(item => item.show !== false),\n [menuItems]\n );\n\n // Convert MenuItemConfig to TopbarNavItem\n const navItems: TopbarNavItem[] = useMemo(\n () =>\n visibleMenuItems.map(item => ({\n id: item.id,\n label: item.label,\n icon: item.icon,\n href: item.href,\n className: item.className,\n })),\n [visibleMenuItems]\n );\n\n // Wrapper to adapt LinkComponent to TopbarNavigation expected interface\n const LinkWrapper: ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n }> = useMemo(\n () =>\n ({ href, className, children }) => (\n <LinkComponent href={href} className={className}>\n {children}\n </LinkComponent>\n ),\n [LinkComponent]\n );\n\n const handleLogoClick = () => {\n logo.onClick?.();\n };\n\n return (\n <TopbarProvider variant={variant} sticky={sticky}>\n <Topbar\n variant={variant}\n sticky={sticky}\n zIndex={zIndex}\n aria-label={ariaLabel}\n className={cn(className)}\n >\n <TopbarLeft>\n <TopbarNavigation\n items={navItems}\n collapseBelow={collapseBelow}\n LinkComponent={LinkWrapper}\n mobileMenuLabel={mobileMenuLabel}\n >\n <TopbarLogo onClick={handleLogoClick} size='md'>\n <Logo\n size='md'\n logoSrc={logo.src}\n logoText={logo.appName}\n logoAlt={logo.alt || logo.appName}\n showText={true}\n />\n </TopbarLogo>\n </TopbarNavigation>\n </TopbarLeft>\n\n {renderCenterSection && (\n <TopbarCenter>{renderCenterSection()}</TopbarCenter>\n )}\n\n <TopbarRight>\n <TopbarActions gap='md'>\n {!hideLanguageSelector && (\n <LanguageSelector\n languages={languages}\n currentLanguage={currentLanguage}\n onLanguageChange={onLanguageChange}\n variant='compact'\n {...languageSelectorProps}\n />\n )}\n {renderAccountSection?.()}\n </TopbarActions>\n </TopbarRight>\n\n {renderMobileContent && (\n <TopbarMobileContent>{renderMobileContent()}</TopbarMobileContent>\n )}\n </Topbar>\n </TopbarProvider>\n );\n};\n\nexport default AppTopBar;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Auth menu item for the authenticated user dropdown.\n * This matches the AuthMenuItem interface from @sudobility/auth-components.\n */\nexport interface AuthMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon element (typically a small SVG) */\n icon?: ReactNode;\n /** Click handler */\n onClick?: () => void;\n /** Show divider after this item */\n dividerAfter?: boolean;\n}\n\n/**\n * Props for the AuthAction component from @sudobility/auth-components.\n */\nexport interface AuthActionProps {\n /** Avatar size in pixels */\n avatarSize?: number;\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n /** Login button click handler */\n onLoginClick?: () => void;\n /** Menu items for authenticated user dropdown */\n menuItems?: AuthMenuItem[];\n /** Custom login button text */\n loginButtonText?: string;\n /** Custom className for login button */\n loginButtonClassName?: string;\n}\n\nexport interface AppTopBarWithFirebaseAuthProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * AuthAction component from @sudobility/auth-components.\n * This is passed as a prop to avoid hard dependency on auth-components.\n */\n AuthActionComponent: ComponentType<AuthActionProps>;\n\n /** Additional menu items for authenticated users */\n authenticatedMenuItems?: AuthMenuItem[];\n\n /** Login button click handler */\n onLoginClick?: () => void;\n\n /** Avatar size in pixels */\n avatarSize?: number;\n\n /** Dropdown alignment */\n dropdownAlign?: 'left' | 'right';\n\n /** Custom login button text */\n loginButtonText?: string;\n\n /** Custom login button className */\n loginButtonClassName?: string;\n}\n\n/**\n * AppTopBarWithFirebaseAuth - TopBar with Firebase authentication integration.\n *\n * This component wraps AppTopBar and provides the AuthAction component\n * from @sudobility/auth-components for the account section.\n *\n * Note: The AuthAction component must be passed as a prop to avoid\n * hard dependency on @sudobility/auth-components.\n *\n * @example\n * ```tsx\n * import { AuthAction } from '@sudobility/auth-components';\n *\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * authenticatedMenuItems={[\n * { id: 'dashboard', label: 'Dashboard', onClick: () => navigate('/dashboard') },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithFirebaseAuth: React.FC<\n AppTopBarWithFirebaseAuthProps\n> = ({\n AuthActionComponent,\n authenticatedMenuItems = [],\n onLoginClick,\n avatarSize = 32,\n dropdownAlign = 'right',\n loginButtonText,\n loginButtonClassName,\n ...topBarProps\n}) => {\n const renderAccountSection = () => (\n <AuthActionComponent\n avatarSize={avatarSize}\n dropdownAlign={dropdownAlign}\n onLoginClick={onLoginClick}\n menuItems={authenticatedMenuItems}\n loginButtonText={loginButtonText}\n loginButtonClassName={cn(\n GRADIENT_CLASSES.headerButton,\n loginButtonClassName\n )}\n />\n );\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithFirebaseAuth;\n","import React, { type ReactNode, type ComponentType } from 'react';\nimport { AppTopBar, type AppTopBarProps } from './app-topbar';\nimport { cn } from '../../utils';\nimport { GRADIENT_CLASSES } from '@sudobility/design';\n\n/**\n * Wallet menu item for the connected wallet dropdown.\n */\nexport interface WalletMenuItem {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Icon component */\n icon?: ComponentType<{ className?: string }>;\n /** Click handler */\n onClick: () => void;\n /** Whether this is a separator */\n separator?: boolean;\n}\n\n/**\n * Auth status enum matching @sudobility/types.\n */\nexport enum AuthStatus {\n DISCONNECTED = 'disconnected',\n CONNECTED = 'connected',\n VERIFIED = 'verified',\n}\n\n/**\n * Chain type enum matching @sudobility/types.\n */\nexport enum ChainType {\n EVM = 'evm',\n SOLANA = 'solana',\n}\n\n/**\n * Props for the WalletDropdownMenu component from @sudobility/web3-components.\n */\nexport interface WalletDropdownMenuProps {\n walletAddress: string;\n authStatus: AuthStatus | string;\n chainType: ChainType | string | 'unknown';\n menuItems: WalletMenuItem[];\n avatar?: string;\n displayName?: string;\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\nexport interface AppTopBarWithWalletProps extends Omit<\n AppTopBarProps,\n 'renderAccountSection'\n> {\n /**\n * WalletDropdownMenu component from @sudobility/web3-components.\n * This is passed as a prop to avoid hard dependency on web3-components.\n */\n WalletDropdownMenuComponent?: ComponentType<WalletDropdownMenuProps>;\n\n /** Whether wallet is connected */\n isConnected: boolean;\n\n /** Connected wallet address */\n walletAddress?: string;\n\n /** Authentication status */\n authStatus?: AuthStatus | string;\n\n /** Chain type (EVM, Solana, etc.) */\n chainType?: ChainType | string | 'unknown';\n\n /** Connect button click handler */\n onConnect: () => void;\n\n /** Disconnect handler */\n onDisconnect: () => Promise<void>;\n\n /** Custom menu items for wallet dropdown */\n walletMenuItems?: WalletMenuItem[];\n\n /** Connect button content (default: \"Connect Wallet\") */\n connectButtonContent?: ReactNode;\n\n /** Connect button className (supports gradient classes from @sudobility/design) */\n connectButtonClassName?: string;\n\n /** Use gradient styling for connect button */\n useGradientButton?: boolean;\n\n /** Optional user avatar */\n avatar?: string;\n\n /** Optional display name */\n displayName?: string;\n\n /** Custom status labels */\n statusLabels?: {\n verified?: string;\n connected?: string;\n disconnected?: string;\n };\n}\n\n/**\n * Default connect button when WalletDropdownMenuComponent is not provided\n * or when wallet is not connected.\n */\nconst DefaultConnectButton: React.FC<{\n onClick: () => void;\n content?: ReactNode;\n className?: string;\n useGradient?: boolean;\n}> = ({ onClick, content = 'Connect Wallet', className, useGradient }) => (\n <button\n onClick={onClick}\n className={cn(\n useGradient\n ? GRADIENT_CLASSES.headerButton\n : 'px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors',\n className\n )}\n >\n {content}\n </button>\n);\n\n/**\n * Simple fallback wallet display when WalletDropdownMenuComponent is not provided.\n */\nconst FallbackWalletDisplay: React.FC<{\n walletAddress: string;\n onDisconnect: () => Promise<void>;\n}> = ({ walletAddress, onDisconnect }) => {\n const truncatedAddress = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n\n return (\n <div className='flex items-center gap-2'>\n <span className='text-sm font-medium text-gray-700 dark:text-gray-300'>\n {truncatedAddress}\n </span>\n <button\n onClick={() => onDisconnect()}\n className='text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'\n >\n Disconnect\n </button>\n </div>\n );\n};\n\n/**\n * AppTopBarWithWallet - TopBar with wallet connection integration.\n *\n * This component wraps AppTopBar and provides wallet connection UI\n * for the account section. Uses WalletDropdownMenu from @sudobility/web3-components\n * when provided.\n *\n * @example\n * ```tsx\n * import { WalletDropdownMenu } from '@sudobility/web3-components';\n *\n * <AppTopBarWithWallet\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={[...]}\n * WalletDropdownMenuComponent={WalletDropdownMenu}\n * isConnected={isConnected}\n * walletAddress={walletAddress}\n * authStatus={authStatus}\n * chainType={chainType}\n * onConnect={() => navigate('/connect')}\n * onDisconnect={handleDisconnect}\n * walletMenuItems={[\n * { id: 'copy', label: 'Copy Address', icon: ClipboardIcon, onClick: handleCopy },\n * { id: 'disconnect', label: 'Disconnect', icon: LogoutIcon, onClick: handleDisconnect },\n * ]}\n * />\n * ```\n */\nexport const AppTopBarWithWallet: React.FC<AppTopBarWithWalletProps> = ({\n WalletDropdownMenuComponent,\n isConnected,\n walletAddress,\n authStatus = AuthStatus.DISCONNECTED,\n chainType = 'unknown',\n onConnect,\n onDisconnect,\n walletMenuItems = [],\n connectButtonContent,\n connectButtonClassName,\n useGradientButton = true,\n avatar,\n displayName,\n statusLabels,\n ...topBarProps\n}) => {\n const renderAccountSection = () => {\n // Not connected - show connect button\n if (!isConnected || !walletAddress) {\n return (\n <DefaultConnectButton\n onClick={onConnect}\n content={connectButtonContent}\n className={connectButtonClassName}\n useGradient={useGradientButton}\n />\n );\n }\n\n // Connected with WalletDropdownMenu component\n if (WalletDropdownMenuComponent) {\n return (\n <WalletDropdownMenuComponent\n walletAddress={walletAddress}\n authStatus={authStatus}\n chainType={chainType}\n menuItems={walletMenuItems}\n avatar={avatar}\n displayName={displayName}\n statusLabels={statusLabels}\n />\n );\n }\n\n // Connected without WalletDropdownMenu - fallback display\n return (\n <FallbackWalletDisplay\n walletAddress={walletAddress}\n onDisconnect={onDisconnect}\n />\n );\n };\n\n return (\n <AppTopBar {...topBarProps} renderAccountSection={renderAccountSection} />\n );\n};\n\nexport default AppTopBarWithWallet;\n","import React, { useState, type ComponentType } from 'react';\nimport { CalendarDaysIcon } from '@heroicons/react/24/outline';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport type {\n BreadcrumbItem,\n ShareConfig,\n TalkToFounderConfig,\n LinkComponentProps,\n} from '../../types';\n\nconst breadcrumbContainerVariants = cva('border-b', {\n variants: {\n variant: {\n default: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700',\n transparent: 'bg-transparent border-transparent',\n subtle:\n 'bg-gray-50 dark:bg-gray-900/50 border-gray-200 dark:border-gray-700',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n});\n\nexport interface AppBreadcrumbsProps extends VariantProps<\n typeof breadcrumbContainerVariants\n> {\n /** Breadcrumb items */\n items: BreadcrumbItem[];\n\n /** Share configuration (shows social share buttons on right) */\n shareConfig?: ShareConfig;\n\n /** Talk to founder button configuration */\n talkToFounder?: TalkToFounderConfig;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Custom className for the container */\n className?: string;\n\n /** Custom className for the inner content */\n contentClassName?: string;\n}\n\n// Social media share URL generators\nconst createShareUrl = {\n twitter: (url: string, text: string, hashtags: string[]) => {\n const hashtagStr =\n hashtags.length > 0 ? `&hashtags=${hashtags.join(',')}` : '';\n return `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}${hashtagStr}`;\n },\n facebook: (url: string) => {\n return `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`;\n },\n linkedin: (url: string) => {\n return `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`;\n },\n reddit: (url: string, title: string) => {\n return `https://reddit.com/submit?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`;\n },\n telegram: (url: string, text: string) => {\n return `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`;\n },\n email: (url: string, title: string, description: string) => {\n return `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(description + '\\n\\n' + url)}`;\n },\n};\n\n/**\n * Share dropdown component\n */\nconst ShareDropdown: React.FC<{ shareConfig: ShareConfig }> = ({\n shareConfig,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shareUrl, setShareUrl] = useState<string>('');\n const [isPreparingShare, setIsPreparingShare] = useState(false);\n const [showCopiedFeedback, setShowCopiedFeedback] = useState(false);\n\n React.useEffect(() => {\n const onBeforeShare = shareConfig.onBeforeShare;\n if (onBeforeShare && !shareUrl) {\n const prepareUrl = async () => {\n setIsPreparingShare(true);\n try {\n const baseUrl =\n typeof window !== 'undefined' ? window.location.href : '';\n const modifiedUrl = await onBeforeShare(baseUrl);\n setShareUrl(modifiedUrl);\n } catch {\n const baseUrl =\n typeof window !== 'undefined' ? window.location.href : '';\n setShareUrl(baseUrl);\n } finally {\n setIsPreparingShare(false);\n }\n };\n prepareUrl();\n }\n }, [shareConfig, shareUrl]);\n\n const url =\n shareUrl || (typeof window !== 'undefined' ? window.location.href : '');\n\n const copyToClipboard = async () => {\n try {\n await navigator.clipboard.writeText(url);\n setShowCopiedFeedback(true);\n setTimeout(() => {\n setShowCopiedFeedback(false);\n setIsOpen(false);\n }, 1500);\n } catch {\n // Copy failed\n }\n };\n\n const handleSocialShare = (platformUrl: string) => {\n window.open(\n platformUrl,\n '_blank',\n 'noopener,noreferrer,width=600,height=400'\n );\n setIsOpen(false);\n };\n\n const sharePlatforms = [\n {\n name: 'Twitter',\n url: createShareUrl.twitter(url, shareConfig.title, shareConfig.hashtags),\n color: 'text-blue-400',\n },\n {\n name: 'Facebook',\n url: createShareUrl.facebook(url),\n color: 'text-blue-600',\n },\n {\n name: 'LinkedIn',\n url: createShareUrl.linkedin(url),\n color: 'text-blue-700',\n },\n {\n name: 'Reddit',\n url: createShareUrl.reddit(url, shareConfig.title),\n color: 'text-orange-600',\n },\n {\n name: 'Telegram',\n url: createShareUrl.telegram(url, shareConfig.title),\n color: 'text-blue-500',\n },\n {\n name: 'Email',\n url: createShareUrl.email(\n url,\n shareConfig.title,\n shareConfig.description\n ),\n color: 'text-gray-600',\n },\n ];\n\n return (\n <div className='relative'>\n <button\n onClick={() => setIsOpen(!isOpen)}\n disabled={isPreparingShare}\n className='flex items-center justify-center w-8 h-8 bg-blue-50 hover:bg-blue-100 dark:bg-blue-900/30 dark:hover:bg-blue-900/50 text-blue-600 dark:text-blue-400 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\n title='Share this page'\n >\n {isPreparingShare ? (\n <div className='w-4 h-4 border-2 border-blue-600 border-t-transparent rounded-full animate-spin' />\n ) : (\n <svg\n className='w-4 h-4'\n fill='none'\n stroke='currentColor'\n viewBox='0 0 24 24'\n >\n <path\n strokeLinecap='round'\n strokeLinejoin='round'\n strokeWidth={2}\n d='M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.367 2.684 3 3 0 00-5.367-2.684z'\n />\n </svg>\n )}\n </button>\n\n {isOpen && (\n <>\n <div\n className='fixed inset-0 z-[999998]'\n onClick={() => setIsOpen(false)}\n />\n <div className='absolute right-0 top-10 z-[999999] w-40 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 py-1'>\n {sharePlatforms.map(platform => (\n <button\n key={platform.name}\n onClick={() => handleSocialShare(platform.url)}\n className='w-full flex items-center px-3 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors'\n >\n <span className={`text-sm ${platform.color}`}>\n {platform.name}\n </span>\n </button>\n ))}\n <div className='border-t border-gray-200 dark:border-gray-700 my-1' />\n <button\n onClick={copyToClipboard}\n className='w-full flex items-center px-3 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer transition-colors'\n >\n <span className='text-sm text-gray-700 dark:text-gray-300'>\n {showCopiedFeedback ? 'Copied!' : 'Copy Link'}\n </span>\n </button>\n </div>\n </>\n )}\n </div>\n );\n};\n\n/**\n * Talk to Founder button - matches share button style\n */\nconst TalkToFounderButton: React.FC<{ config: TalkToFounderConfig }> = ({\n config,\n}) => {\n const IconComponent = config.icon || CalendarDaysIcon;\n const buttonText = config.buttonText || 'Talk to Founder';\n\n return (\n <a\n href={config.meetingUrl}\n target='_blank'\n rel='noopener noreferrer'\n className={cn(\n 'inline-flex items-center gap-1.5 px-2.5 h-8',\n 'text-sm font-medium',\n 'text-blue-600 dark:text-blue-400',\n 'hover:text-blue-700 dark:hover:text-blue-300',\n 'bg-blue-50 dark:bg-blue-900/30',\n 'hover:bg-blue-100 dark:hover:bg-blue-900/50',\n 'rounded-lg',\n 'transition-colors'\n )}\n >\n <IconComponent className='h-4 w-4' />\n <span>{buttonText}</span>\n </a>\n );\n};\n\n/**\n * AppBreadcrumbs - Self-contained breadcrumb navigation with share and \"Talk to Founder\" button.\n */\nexport const AppBreadcrumbs: React.FC<AppBreadcrumbsProps> = ({\n items,\n shareConfig,\n talkToFounder,\n variant = 'default',\n className,\n contentClassName,\n}) => {\n // Don't render if no items\n if (!items || items.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(breadcrumbContainerVariants({ variant }), className)}>\n <div className={cn('max-w-7xl mx-auto px-4 py-2', contentClassName)}>\n <div className='flex items-center justify-between'>\n {/* Breadcrumb trail */}\n <nav aria-label='Breadcrumb'>\n <ol className='flex items-center text-sm space-x-2'>\n {items.map((item, index) => (\n <React.Fragment key={index}>\n <li>\n {item.current || !item.href ? (\n <span className='text-gray-700 dark:text-gray-300'>\n {item.label}\n </span>\n ) : (\n <a\n href={item.href}\n className='text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 transition-colors'\n >\n {item.label}\n </a>\n )}\n </li>\n {index < items.length - 1 && (\n <li>\n <span className='text-gray-400 dark:text-gray-500'>\n /\n </span>\n </li>\n )}\n </React.Fragment>\n ))}\n </ol>\n </nav>\n\n {/* Right side: Talk to Founder + Share */}\n <div className='flex items-center gap-2'>\n {talkToFounder && <TalkToFounderButton config={talkToFounder} />}\n {shareConfig && <ShareDropdown shareConfig={shareConfig} />}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default AppBreadcrumbs;\n","import React, { useCallback, type ComponentType } from 'react';\nimport {\n Footer as FooterContainer,\n FooterCompact,\n FooterCompactLeft,\n FooterCompactRight,\n FooterVersion,\n FooterCopyright,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkItem,\n AnalyticsTrackingParams,\n} from '../../types';\n\n/**\n * Props for the SystemStatusIndicator component from @sudobility/devops-components.\n */\nexport interface SystemStatusIndicatorProps {\n statusPageUrl: string;\n apiEndpoint?: string;\n refreshInterval?: number;\n size?: 'sm' | 'md' | 'lg';\n version?: string;\n isNetworkOnline?: boolean;\n}\n\nexport interface AppFooterProps {\n /** App version string */\n version?: string;\n\n /** Copyright year or range (e.g., \"2025\" or \"2025-2026\") */\n copyrightYear?: string;\n\n /** Company name */\n companyName: string;\n\n /** Company URL (optional - creates a link if provided) */\n companyUrl?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Status indicator config (optional) */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** Right-side links (e.g., Privacy, Terms) */\n links?: FooterLinkItem[];\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Sticky positioning (sticks to bottom of viewport) */\n sticky?: boolean;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * AppFooter - Compact footer for app pages.\n *\n * Features:\n * - Version display\n * - Copyright with company name\n * - System status indicator (optional)\n * - Right-side links (Privacy, Terms, etc.)\n * - Sticky positioning option\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * companyUrl=\"/\"\n * rightsText=\"All rights reserved\"\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * apiEndpoint: 'https://status.example.com/api/v1/status',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * links={[\n * { label: 'Privacy', href: '/privacy' },\n * { label: 'Terms', href: '/terms' },\n * ]}\n * sticky\n * />\n * ```\n */\nexport const AppFooter: React.FC<AppFooterProps> = ({\n version,\n copyrightYear,\n companyName,\n companyUrl,\n rightsText = 'All rights reserved',\n statusIndicator,\n StatusIndicatorComponent,\n links = [],\n LinkComponent = DefaultLinkComponent,\n sticky = true,\n isNetworkOnline = true,\n className,\n onTrack,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'link_click',\n componentName: 'AppFooter',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Create a tracked link click handler\n const createTrackedLinkHandler = useCallback(\n (\n linkLabel: string,\n linkHref: string,\n originalOnClick?: (e: React.MouseEvent) => void\n ) =>\n (e: React.MouseEvent) => {\n track('footer_link_clicked', {\n link_label: linkLabel,\n link_href: linkHref,\n });\n originalOnClick?.(e);\n },\n [track]\n );\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer\n variant='compact'\n sticky={sticky}\n className={cn(className)}\n >\n <FooterCompact>\n <FooterCompactLeft>\n {version && <FooterVersion version={version} />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n />\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterCompactLeft>\n <FooterCompactRight>\n {links.map((link, index) => (\n <React.Fragment key={link.href || index}>\n {link.onClick ? (\n <button\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n link.onClick\n )}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n onClick={createTrackedLinkHandler(link.label, link.href)}\n className='text-gray-400 hover:text-white transition-colors'\n >\n {link.label}\n </LinkComponent>\n )}\n </React.Fragment>\n ))}\n </FooterCompactRight>\n </FooterCompact>\n </FooterContainer>\n );\n};\n\nexport default AppFooter;\n","import React, { useCallback, type ComponentType } from 'react';\nimport {\n Logo,\n Footer as FooterContainer,\n FooterGrid,\n FooterBrand,\n FooterLinkSection,\n FooterLink,\n FooterBottom,\n FooterVersion,\n FooterCopyright,\n FooterSocialLinks,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type {\n StatusIndicatorConfig,\n LinkComponentProps,\n FooterLinkSection as FooterLinkSectionConfig,\n SocialLinksConfig,\n AnalyticsTrackingParams,\n} from '../../types';\nimport type { SystemStatusIndicatorProps } from './app-footer';\n\nexport interface AppFooterForHomePageProps {\n /** App logo configuration */\n logo: {\n /** Logo image src (optional - if not provided, uses Logo component) */\n src?: string;\n /** App name */\n appName: string;\n };\n\n /** Footer link sections (columns of links) */\n linkSections: FooterLinkSectionConfig[];\n\n /** Social media links */\n socialLinks?: SocialLinksConfig;\n\n /** System status indicator configuration */\n statusIndicator?: StatusIndicatorConfig;\n\n /**\n * SystemStatusIndicator component from @sudobility/devops-components.\n * Pass this to enable status indicator functionality.\n */\n StatusIndicatorComponent?: ComponentType<SystemStatusIndicatorProps>;\n\n /** App version string */\n version?: string;\n\n /** Copyright year or range */\n copyrightYear?: string;\n\n /** Company name for copyright */\n companyName: string;\n\n /** Company link URL (optional) */\n companyUrl?: string;\n\n /** Footer description text (below logo) */\n description?: string;\n\n /** Rights text (e.g., \"All rights reserved\") */\n rightsText?: string;\n\n /** Custom Link component */\n LinkComponent?: ComponentType<LinkComponentProps>;\n\n /** Network online status (for status indicator) */\n isNetworkOnline?: boolean;\n\n /** Custom className */\n className?: string;\n\n /** Number of columns for link grid (default: auto based on section count) */\n gridColumns?: 2 | 3 | 4 | 5;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Default link component that renders a plain anchor.\n */\nconst DefaultLinkComponent: ComponentType<LinkComponentProps> = ({\n href,\n className,\n children,\n onClick,\n}) => (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n);\n\n/**\n * Helper to get copyright year or range.\n */\nfunction getCopyrightYear(startYear = 2025): string {\n const currentYear = new Date().getFullYear();\n if (currentYear === startYear) {\n return String(startYear);\n } else if (currentYear > startYear) {\n return `${startYear}-${currentYear}`;\n }\n return String(startYear);\n}\n\n/**\n * Get grid columns class based on section count.\n */\nfunction getGridColumnsClass(sectionCount: number, explicit?: number): string {\n const cols = explicit || Math.min(sectionCount, 4);\n switch (cols) {\n case 2:\n return 'md:grid-cols-2';\n case 3:\n return 'md:grid-cols-3';\n case 4:\n return 'md:grid-cols-4';\n case 5:\n return 'md:grid-cols-5';\n default:\n return 'md:grid-cols-4';\n }\n}\n\n/**\n * AppFooterForHomePage - Full footer for home/landing pages.\n *\n * Features:\n * - Multiple link sections in a grid\n * - Logo and brand description\n * - Social media links\n * - System status indicator (optional)\n * - Version and copyright\n * - Dark mode support\n *\n * @example\n * ```tsx\n * import { SystemStatusIndicator } from '@sudobility/devops-components';\n *\n * <AppFooterForHomePage\n * logo={{ appName: 'My App' }}\n * linkSections={[\n * {\n * title: 'Product',\n * links: [\n * { label: 'Features', href: '/features' },\n * { label: 'Pricing', href: '/pricing' },\n * ],\n * },\n * {\n * title: 'Company',\n * links: [\n * { label: 'About', href: '/about' },\n * { label: 'Contact', href: '/contact' },\n * ],\n * },\n * ]}\n * socialLinks={{\n * twitterUrl: 'https://twitter.com/myapp',\n * discordUrl: 'https://discord.gg/myapp',\n * }}\n * statusIndicator={{\n * statusPageUrl: 'https://status.example.com',\n * }}\n * StatusIndicatorComponent={SystemStatusIndicator}\n * version=\"1.0.0\"\n * companyName=\"Sudobility Inc.\"\n * description=\"Building the future of web3 communication\"\n * />\n * ```\n */\nexport const AppFooterForHomePage: React.FC<AppFooterForHomePageProps> = ({\n logo,\n linkSections,\n socialLinks,\n statusIndicator,\n StatusIndicatorComponent,\n version,\n copyrightYear,\n companyName,\n companyUrl,\n description,\n rightsText = 'All rights reserved',\n LinkComponent = DefaultLinkComponent,\n isNetworkOnline = true,\n className,\n gridColumns,\n onTrack,\n}) => {\n const year = copyrightYear || getCopyrightYear();\n const gridClass = getGridColumnsClass(linkSections.length, gridColumns);\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'link_click',\n componentName: 'AppFooterForHomePage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Create a tracked link click handler\n const createTrackedLinkHandler = useCallback(\n (\n linkLabel: string,\n linkHref: string,\n sectionTitle: string,\n originalOnClick?: (e: React.MouseEvent) => void\n ) =>\n (e: React.MouseEvent) => {\n track('footer_link_clicked', {\n link_label: linkLabel,\n link_href: linkHref,\n section_title: sectionTitle,\n });\n originalOnClick?.(e);\n },\n [track]\n );\n\n const companyLink = companyUrl ? (\n <LinkComponent\n href={companyUrl}\n className='text-blue-400 hover:text-blue-300 transition-colors'\n >\n {companyName}\n </LinkComponent>\n ) : undefined;\n\n return (\n <FooterContainer variant='full' className={cn(className)}>\n <FooterGrid className={gridClass}>\n {linkSections.map((section, sectionIndex) => (\n <FooterLinkSection\n key={section.title || sectionIndex}\n title={section.title}\n >\n {section.links.map((link, linkIndex) => (\n <FooterLink key={link.href || linkIndex}>\n {link.onClick ? (\n <button\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n section.title,\n link.onClick\n )}\n className='text-left'\n >\n {link.label}\n </button>\n ) : (\n <LinkComponent\n href={link.href}\n onClick={createTrackedLinkHandler(\n link.label,\n link.href,\n section.title\n )}\n >\n {link.label}\n </LinkComponent>\n )}\n </FooterLink>\n ))}\n </FooterLinkSection>\n ))}\n </FooterGrid>\n\n <FooterBottom>\n <FooterBrand\n description={description}\n className='flex flex-col items-center'\n >\n <LinkComponent\n href='/'\n className='text-white hover:opacity-80 transition-opacity'\n >\n {logo.src ? (\n <img\n src={logo.src}\n alt={logo.appName}\n className='h-8 object-contain'\n />\n ) : (\n <Logo size='md' showText={true} logoText={logo.appName} />\n )}\n </LinkComponent>\n </FooterBrand>\n <div className='space-y-2'>\n {version && <FooterVersion version={version} className='block' />}\n <FooterCopyright\n year={year}\n companyName={companyName}\n rightsText={rightsText}\n companyLink={companyLink}\n className='block'\n />\n </div>\n {statusIndicator && StatusIndicatorComponent && (\n <StatusIndicatorComponent\n statusPageUrl={statusIndicator.statusPageUrl}\n apiEndpoint={statusIndicator.apiEndpoint}\n refreshInterval={statusIndicator.refreshInterval || 60000}\n size='sm'\n version={version}\n isNetworkOnline={isNetworkOnline}\n />\n )}\n </FooterBottom>\n\n {socialLinks && (\n <div className='flex justify-center mt-4'>\n <FooterSocialLinks\n twitterUrl={socialLinks.twitterUrl}\n discordUrl={socialLinks.discordUrl}\n linkedinUrl={socialLinks.linkedinUrl}\n githubUrl={socialLinks.githubUrl}\n redditUrl={socialLinks.redditUrl}\n farcasterUrl={socialLinks.farcasterUrl}\n telegramUrl={socialLinks.telegramUrl}\n />\n </div>\n )}\n </FooterContainer>\n );\n};\n\nexport default AppFooterForHomePage;\n","import React, { type ReactNode } from 'react';\nimport { LayoutProvider } from '@sudobility/components';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils';\nimport {\n AppBreadcrumbs,\n type AppBreadcrumbsProps,\n} from '../breadcrumbs/app-breadcrumbs';\nimport type { MaxWidth, ContentPadding, BackgroundVariant } from '../../types';\n\nconst layoutVariants = cva('min-h-screen flex flex-col', {\n variants: {\n background: {\n default: 'bg-gray-50 dark:bg-gray-900',\n white: 'bg-white dark:bg-gray-900',\n gradient:\n 'bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-900 dark:to-gray-800',\n },\n },\n defaultVariants: {\n background: 'default',\n },\n});\n\nconst maxWidthClasses: Record<MaxWidth, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '4xl': 'max-w-4xl',\n '7xl': 'max-w-7xl',\n full: 'max-w-full',\n};\n\nconst paddingClasses: Record<ContentPadding, string> = {\n none: '',\n sm: 'px-4 sm:px-6 py-6',\n md: 'px-4 py-8',\n lg: 'px-4 py-12',\n};\n\nexport interface AppPageLayoutProps extends VariantProps<\n typeof layoutVariants\n> {\n /** Page content */\n children: ReactNode;\n\n /** TopBar slot - pass an AppTopBar variant or custom component */\n topBar: ReactNode;\n\n /** Breadcrumbs configuration (optional) */\n breadcrumbs?: AppBreadcrumbsProps;\n\n /** Footer slot - pass an AppFooter variant or custom component */\n footer?: ReactNode;\n\n /** Max width for content area (default: '7xl') */\n maxWidth?: MaxWidth;\n\n /** Content padding (default: 'md') */\n contentPadding?: ContentPadding;\n\n /** Background variant */\n background?: BackgroundVariant;\n\n /** Layout mode for LayoutProvider */\n layoutMode?: 'standard';\n\n /** Custom className for the layout container */\n className?: string;\n\n /** Custom className for the content area */\n contentClassName?: string;\n\n /** Custom className for the main element */\n mainClassName?: string;\n}\n\n/**\n * AppPageLayout - Layout wrapper combining TopBar, Breadcrumbs, Content, and Footer.\n *\n * Features:\n * - Flexible slots for TopBar and Footer\n * - Optional breadcrumbs with share and \"Talk to Founder\"\n * - Configurable content max-width and padding\n * - Background variants\n * - Dark mode support\n * - Sticky footer behavior\n *\n * @example\n * ```tsx\n * <AppPageLayout\n * topBar={\n * <AppTopBarWithFirebaseAuth\n * logo={{ src: '/logo.png', appName: 'My App' }}\n * menuItems={menuItems}\n * AuthActionComponent={AuthAction}\n * onLoginClick={() => navigate('/login')}\n * />\n * }\n * breadcrumbs={{\n * items: breadcrumbItems,\n * shareConfig: { title: 'Page', description: 'Description', hashtags: [] },\n * }}\n * footer={\n * <AppFooter\n * version=\"1.0.0\"\n * companyName=\"My Company\"\n * links={[{ label: 'Privacy', href: '/privacy' }]}\n * />\n * }\n * maxWidth=\"7xl\"\n * background=\"default\"\n * >\n * <h1>Page Content</h1>\n * </AppPageLayout>\n * ```\n */\nexport const AppPageLayout: React.FC<AppPageLayoutProps> = ({\n children,\n topBar,\n breadcrumbs,\n footer,\n maxWidth = '7xl',\n contentPadding = 'md',\n background = 'default',\n layoutMode = 'standard',\n className,\n contentClassName,\n mainClassName,\n}) => {\n return (\n <LayoutProvider mode={layoutMode}>\n <div className={cn(layoutVariants({ background }), className)}>\n {/* Header Section */}\n <header>{topBar}</header>\n\n {/* Breadcrumb Section */}\n {breadcrumbs && breadcrumbs.items && breadcrumbs.items.length > 0 && (\n <AppBreadcrumbs {...breadcrumbs} />\n )}\n\n {/* Main Content */}\n <main className={cn('flex-1 overflow-auto', mainClassName)}>\n <div\n className={cn(\n 'mx-auto',\n maxWidthClasses[maxWidth],\n paddingClasses[contentPadding],\n contentClassName\n )}\n >\n {children}\n </div>\n </main>\n\n {/* Footer */}\n {footer && <footer>{footer}</footer>}\n </div>\n </LayoutProvider>\n );\n};\n\nexport default AppPageLayout;\n","import React from 'react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Label,\n} from '@sudobility/components';\nimport { textVariants } from '@sudobility/design';\n\n/**\n * Theme options for appearance settings.\n */\nexport enum Theme {\n LIGHT = 'light',\n DARK = 'dark',\n SYSTEM = 'system',\n}\n\n/**\n * Font size options for appearance settings.\n */\nexport enum FontSize {\n SMALL = 'small',\n MEDIUM = 'medium',\n LARGE = 'large',\n}\n\n/**\n * Translation keys used by AppearanceSettings.\n * Provide a translation function to customize labels.\n */\nexport interface AppearanceSettingsTranslations {\n heading: string;\n description: string;\n themeLabel: string;\n themeSelectPlaceholder: string;\n themeLight: string;\n themeDark: string;\n themeSystem: string;\n themeDescription: string;\n fontSizeLabel: string;\n fontSizeSelectPlaceholder: string;\n fontSizeSmall: string;\n fontSizeMedium: string;\n fontSizeLarge: string;\n fontSizeDescription: string;\n infoHeading: string;\n infoDescription: string;\n}\n\nconst defaultTranslations: AppearanceSettingsTranslations = {\n heading: 'Appearance',\n description: 'Customize the look and feel of the application.',\n themeLabel: 'Theme',\n themeSelectPlaceholder: 'Select theme',\n themeLight: 'Light',\n themeDark: 'Dark',\n themeSystem: 'System',\n themeDescription: 'Choose your preferred color theme.',\n fontSizeLabel: 'Font Size',\n fontSizeSelectPlaceholder: 'Select font size',\n fontSizeSmall: 'Small',\n fontSizeMedium: 'Medium',\n fontSizeLarge: 'Large',\n fontSizeDescription: 'Adjust the text size for better readability.',\n infoHeading: 'About Settings',\n infoDescription:\n 'Your appearance preferences are saved locally and will be applied automatically on your next visit.',\n};\n\nexport interface AppearanceSettingsProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Optional translation function.\n * If provided, will be called with a key from AppearanceSettingsTranslations.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the information box at the bottom */\n showInfoBox?: boolean;\n}\n\n/**\n * AppearanceSettings - A reusable component for theme and font size settings.\n *\n * This component can be used across different apps to provide consistent\n * appearance customization options.\n *\n * @example\n * ```tsx\n * // Basic usage with useTheme hook\n * const { theme, fontSize, setTheme, setFontSize } = useTheme();\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With i18n translation\n * const { t } = useTranslation('settings');\n *\n * <AppearanceSettings\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * t={(key, fallback) => t(`appearance.${key}`, fallback)}\n * />\n * ```\n */\nexport const AppearanceSettings: React.FC<AppearanceSettingsProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n t,\n className,\n showInfoBox = true,\n}) => {\n // Helper to get translated string with fallback\n const getText = (key: keyof AppearanceSettingsTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n };\n\n return (\n <div className={className}>\n <div className='space-y-6'>\n <div>\n <h2 className={`${textVariants.heading.h4()} mb-2`}>\n {getText('heading')}\n </h2>\n <p\n className={`${textVariants.body.sm()} text-gray-600 dark:text-gray-400`}\n >\n {getText('description')}\n </p>\n </div>\n\n <div className='space-y-6'>\n {/* Theme Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='theme-select'\n className={textVariants.label.default()}\n >\n {getText('themeLabel')}\n </Label>\n <Select\n value={theme}\n onValueChange={(value: string) => onThemeChange(value as Theme)}\n >\n <SelectTrigger id='theme-select'>\n <SelectValue placeholder={getText('themeSelectPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={Theme.LIGHT}>\n {getText('themeLight')}\n </SelectItem>\n <SelectItem value={Theme.DARK}>\n {getText('themeDark')}\n </SelectItem>\n <SelectItem value={Theme.SYSTEM}>\n {getText('themeSystem')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('themeDescription')}\n </p>\n </div>\n\n {/* Font Size Setting */}\n <div className='space-y-2'>\n <Label\n htmlFor='font-size-select'\n className={textVariants.label.default()}\n >\n {getText('fontSizeLabel')}\n </Label>\n <Select\n value={fontSize}\n onValueChange={(value: string) =>\n onFontSizeChange(value as FontSize)\n }\n >\n <SelectTrigger id='font-size-select'>\n <SelectValue\n placeholder={getText('fontSizeSelectPlaceholder')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={FontSize.SMALL}>\n {getText('fontSizeSmall')}\n </SelectItem>\n <SelectItem value={FontSize.MEDIUM}>\n {getText('fontSizeMedium')}\n </SelectItem>\n <SelectItem value={FontSize.LARGE}>\n {getText('fontSizeLarge')}\n </SelectItem>\n </SelectContent>\n </Select>\n <p\n className={`${textVariants.body.xs()} text-gray-500 dark:text-gray-400`}\n >\n {getText('fontSizeDescription')}\n </p>\n </div>\n </div>\n\n {/* Information Box */}\n {showInfoBox && (\n <div className='bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800'>\n <h4 className='text-sm font-medium text-blue-900 dark:text-blue-100 mb-2'>\n {getText('infoHeading')}\n </h4>\n <p className='text-sm text-blue-700 dark:text-blue-300'>\n {getText('infoDescription')}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default AppearanceSettings;\n","/**\n * @fileoverview Global Settings Page\n * @description Reusable settings page with sidebar navigation.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, {\n useState,\n useMemo,\n useCallback,\n type ReactNode,\n type ComponentType,\n} from 'react';\nimport { PaintBrushIcon } from '@heroicons/react/24/outline';\nimport {\n Section,\n MasterDetailLayout,\n MasterListItem,\n} from '@sudobility/components';\nimport { cn } from '../../utils';\nimport { AppearanceSettings } from './appearance-settings';\nimport { Theme, FontSize } from './appearance-settings';\nimport type { AnalyticsTrackingParams } from '../../types';\n\n/**\n * Configuration for a settings section in the navigation.\n */\nexport interface SettingsSectionConfig {\n /** Unique identifier for the section */\n id: string;\n /** Icon component to display */\n icon: ComponentType<{ className?: string }>;\n /** Display label */\n label: string;\n /** Short description shown below label */\n description: string;\n /** The content to render when this section is selected */\n content: ReactNode;\n}\n\n/**\n * Translation keys used by GlobalSettingsPage.\n */\nexport interface GlobalSettingsPageTranslations {\n title: string;\n backButton: string;\n appearanceLabel: string;\n appearanceDescription: string;\n}\n\nconst defaultTranslations: GlobalSettingsPageTranslations = {\n title: 'Settings',\n backButton: 'Back',\n appearanceLabel: 'Appearance',\n appearanceDescription: 'Theme and font size settings',\n};\n\nexport interface GlobalSettingsPageProps {\n /** Current theme value */\n theme: Theme | string;\n\n /** Current font size value */\n fontSize: FontSize | string;\n\n /** Callback when theme changes */\n onThemeChange: (theme: Theme) => void;\n\n /** Callback when font size changes */\n onFontSizeChange: (fontSize: FontSize) => void;\n\n /**\n * Additional settings sections to display after Appearance.\n * Each section needs an id, icon, label, description, and content.\n */\n additionalSections?: SettingsSectionConfig[];\n\n /**\n * Optional translation function.\n * Falls back to default English strings if not provided.\n */\n t?: (key: string, fallback?: string) => string;\n\n /**\n * Translation function for AppearanceSettings.\n * If provided, will be passed to AppearanceSettings component.\n */\n appearanceT?: (key: string, fallback?: string) => string;\n\n /** Optional className for the container */\n className?: string;\n\n /** Whether to show the info box in appearance settings */\n showAppearanceInfoBox?: boolean;\n\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * GlobalSettingsPage - A reusable settings page with master-detail layout.\n *\n * Features:\n * - Appearance settings built-in as the first section\n * - Extensible via additionalSections prop\n * - Responsive master-detail layout\n * - Mobile-friendly with back navigation\n *\n * @example\n * ```tsx\n * // Basic usage\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * />\n *\n * // With additional sections\n * <GlobalSettingsPage\n * theme={theme}\n * fontSize={fontSize}\n * onThemeChange={setTheme}\n * onFontSizeChange={setFontSize}\n * additionalSections={[\n * {\n * id: 'notifications',\n * icon: BellIcon,\n * label: 'Notifications',\n * description: 'Manage notification preferences',\n * content: <NotificationSettings />,\n * },\n * ]}\n * />\n * ```\n */\nexport const GlobalSettingsPage: React.FC<GlobalSettingsPageProps> = ({\n theme,\n fontSize,\n onThemeChange,\n onFontSizeChange,\n additionalSections = [],\n t,\n appearanceT,\n className,\n showAppearanceInfoBox = true,\n onTrack,\n}) => {\n const [selectedSection, setSelectedSection] = useState('appearance');\n const [mobileView, setMobileView] = useState<'navigation' | 'content'>(\n 'navigation'\n );\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'settings_change',\n componentName: 'GlobalSettingsPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Wrapped handlers with tracking\n const handleThemeChange = useCallback(\n (newTheme: Theme) => {\n track('theme_changed', { theme: newTheme });\n onThemeChange(newTheme);\n },\n [track, onThemeChange]\n );\n\n const handleFontSizeChange = useCallback(\n (newFontSize: FontSize) => {\n track('font_size_changed', { font_size: newFontSize });\n onFontSizeChange(newFontSize);\n },\n [track, onFontSizeChange]\n );\n\n // Helper to get translated string with fallback\n const getText = useCallback(\n (key: keyof GlobalSettingsPageTranslations): string => {\n const fallback = defaultTranslations[key];\n return t ? t(key, fallback) : fallback;\n },\n [t]\n );\n\n // Build all sections with appearance first\n const allSections: SettingsSectionConfig[] = useMemo(\n () => [\n {\n id: 'appearance',\n icon: PaintBrushIcon,\n label: getText('appearanceLabel'),\n description: getText('appearanceDescription'),\n content: (\n <AppearanceSettings\n theme={theme}\n fontSize={fontSize}\n onThemeChange={handleThemeChange}\n onFontSizeChange={handleFontSizeChange}\n t={appearanceT}\n showInfoBox={showAppearanceInfoBox}\n />\n ),\n },\n ...additionalSections,\n ],\n [\n additionalSections,\n getText,\n theme,\n fontSize,\n handleThemeChange,\n handleFontSizeChange,\n appearanceT,\n showAppearanceInfoBox,\n ]\n );\n\n const currentSection =\n allSections.find(s => s.id === selectedSection) || allSections[0];\n\n const handleSectionSelect = (sectionId: string) => {\n track('section_selected', { section_id: sectionId });\n setSelectedSection(sectionId);\n setMobileView('content');\n };\n\n const handleBackToNavigation = () => {\n track('back_to_navigation');\n setMobileView('navigation');\n };\n\n // Navigation list using MasterListItem\n const navigationList = (\n <div>\n {allSections.map(section => (\n <MasterListItem\n key={section.id}\n isSelected={selectedSection === section.id}\n onClick={() => handleSectionSelect(section.id)}\n icon={section.icon}\n label={section.label}\n description={section.description}\n />\n ))}\n </div>\n );\n\n return (\n <Section spacing='lg' maxWidth='6xl' className={cn(className)}>\n <MasterDetailLayout\n masterTitle={getText('title')}\n backButtonText={getText('backButton')}\n masterContent={navigationList}\n detailContent={currentSection.content}\n detailTitle={currentSection.label}\n mobileView={mobileView}\n onBackToNavigation={handleBackToNavigation}\n masterWidth={280}\n stickyMaster={true}\n enableAnimations={true}\n />\n </Section>\n );\n};\n\nexport default GlobalSettingsPage;\n","/**\n * @fileoverview App Subscriptions Page\n * @description Page for managing app subscriptions and viewing rate limits.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n SubscriptionLayout,\n SubscriptionTile,\n SegmentedControl,\n} from '@sudobility/subscription-components';\nimport { Section } from '@sudobility/components';\nimport type { RateLimitsConfigData } from '@sudobility/types';\nimport type { AnalyticsTrackingParams } from '../../types';\n\ntype BillingPeriod = 'monthly' | 'yearly';\n\n/** Product from subscription provider */\nexport interface SubscriptionProduct {\n identifier: string;\n title: string;\n price: string;\n priceString: string;\n period?: string;\n freeTrialPeriod?: string;\n introPrice?: string;\n}\n\n/** Current subscription state */\nexport interface CurrentSubscription {\n isActive: boolean;\n productIdentifier?: string;\n expirationDate?: Date;\n willRenew?: boolean;\n}\n\n/** Subscription context value passed from consumer */\nexport interface SubscriptionContextValue {\n products: SubscriptionProduct[];\n currentSubscription: CurrentSubscription | null;\n isLoading: boolean;\n error: string | null;\n /** Purchase a subscription product. subscriptionUserId identifies which user/entity the subscription is for. email pre-fills the checkout form. */\n purchase: (\n productId: string,\n subscriptionUserId?: string,\n email?: string\n ) => Promise<boolean>;\n /** Restore purchases. subscriptionUserId identifies which user/entity to restore for. */\n restore: (subscriptionUserId?: string) => Promise<boolean>;\n clearError: () => void;\n}\n\n/** All localized labels for the subscription page */\nexport interface SubscriptionPageLabels {\n title: string;\n errorTitle: string;\n purchaseError: string;\n restoreError: string;\n restoreNoPurchases: string;\n\n // Periods\n periodYear: string;\n periodMonth: string;\n periodWeek: string;\n\n // Billing period toggle\n billingMonthly: string;\n billingYearly: string;\n\n // Rate limits\n unlimited: string;\n unlimitedRequests: string;\n\n // Current status\n currentStatusLabel: string;\n statusActive: string;\n statusInactive: string;\n statusInactiveMessage: string;\n labelPlan: string;\n labelPremium: string;\n labelExpires: string;\n labelWillRenew: string;\n labelMonthlyUsage: string;\n labelDailyUsage: string;\n yes: string;\n no: string;\n\n // Buttons\n buttonSubscribe: string;\n buttonPurchasing: string;\n buttonRestore: string;\n buttonRestoring: string;\n\n // Empty states\n noProducts: string;\n noProductsForPeriod: string;\n\n // Free tier\n freeTierTitle: string;\n freeTierPrice: string;\n freeTierFeatures: string[];\n\n // Badges\n currentPlanBadge: string;\n}\n\n/** Formatter functions for dynamic strings */\nexport interface SubscriptionPageFormatters {\n /** Format rate limit: \"1,000 requests/hour\" */\n formatHourlyLimit: (limit: string) => string;\n /** Format rate limit: \"10,000 requests/day\" */\n formatDailyLimit: (limit: string) => string;\n /** Format rate limit: \"100,000 requests/month\" */\n formatMonthlyLimit: (limit: string) => string;\n /** Format trial period: \"7 days free trial\" */\n formatTrialDays: (count: number) => string;\n /** Format trial period: \"2 weeks free trial\" */\n formatTrialWeeks: (count: number) => string;\n /** Format trial period: \"1 month free trial\" */\n formatTrialMonths: (count: number) => string;\n /** Format savings badge: \"Save 20%\" */\n formatSavePercent: (percent: number) => string;\n /** Format intro price note */\n formatIntroNote: (price: string) => string;\n /** Get features for a product by its identifier (required - same as pricing page) */\n getProductFeatures: (productId: string) => string[];\n}\n\n/** Package ID to entitlement mapping (same as PricingPage) */\nexport interface EntitlementMap {\n [packageId: string]: string;\n}\n\n/** Entitlement to level mapping for comparing plan tiers (same as PricingPage) */\nexport interface EntitlementLevels {\n [entitlement: string]: number;\n}\n\nexport interface AppSubscriptionsPageProps {\n /** Subscription context value */\n subscription: SubscriptionContextValue;\n /** Rate limit configuration (for displaying current usage, not for features) */\n rateLimitsConfig?: RateLimitsConfigData | null;\n /** User ID used for subscription (the selected entity's ID when logged in) */\n subscriptionUserId?: string;\n /** User email to pre-fill in the checkout form */\n userEmail?: string;\n /** All localized labels */\n labels: SubscriptionPageLabels;\n /** Formatter functions for dynamic strings */\n formatters: SubscriptionPageFormatters;\n /** Package ID to entitlement mapping (same as PricingPage) */\n entitlementMap: EntitlementMap;\n /** Entitlement to level mapping for comparing tiers (same as PricingPage) */\n entitlementLevels: EntitlementLevels;\n /** Called when purchase succeeds */\n onPurchaseSuccess?: () => void;\n /** Called when restore succeeds */\n onRestoreSuccess?: () => void;\n /** Called on error */\n onError?: (title: string, message: string) => void;\n /** Called on warning */\n onWarning?: (title: string, message: string) => void;\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Page for managing app subscriptions.\n * Uses the same entitlement mapping and features display as AppPricingPage.\n */\nexport function AppSubscriptionsPage({\n subscription,\n rateLimitsConfig,\n subscriptionUserId,\n userEmail,\n labels,\n formatters,\n entitlementMap,\n entitlementLevels: _entitlementLevels,\n onPurchaseSuccess,\n onRestoreSuccess,\n onError,\n onWarning,\n onTrack,\n}: AppSubscriptionsPageProps) {\n const {\n products,\n currentSubscription,\n isLoading,\n error,\n purchase,\n restore,\n clearError,\n } = subscription;\n\n const [billingPeriod, setBillingPeriod] = useState<BillingPeriod>('monthly');\n const [selectedPlan, setSelectedPlan] = useState<string | null>(null);\n const [isPurchasing, setIsPurchasing] = useState(false);\n const [isRestoring, setIsRestoring] = useState(false);\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'subscription_action',\n componentName: 'AppSubscriptionsPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Show error via callback\n useEffect(() => {\n if (error) {\n onError?.(labels.errorTitle, error);\n clearError();\n }\n }, [error, clearError, labels.errorTitle, onError]);\n\n // Filter products by billing period and sort by price\n const filteredProducts = products\n .filter(product => {\n if (!product.period) return false;\n const isYearly =\n product.period.includes('Y') || product.period.includes('year');\n return billingPeriod === 'yearly' ? isYearly : !isYearly;\n })\n .sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n\n const handlePeriodChange = useCallback(\n (period: BillingPeriod) => {\n setBillingPeriod(period);\n setSelectedPlan(null);\n track('billing_period_changed', { billing_period: period });\n },\n [track]\n );\n\n const handlePurchase = useCallback(async () => {\n if (!selectedPlan) return;\n\n setIsPurchasing(true);\n clearError();\n track('purchase_initiated', { plan_identifier: selectedPlan });\n\n try {\n const result = await purchase(\n selectedPlan,\n subscriptionUserId,\n userEmail\n );\n if (result) {\n track('purchase_completed', { plan_identifier: selectedPlan });\n onPurchaseSuccess?.();\n setSelectedPlan(null);\n } else {\n track('purchase_failed', {\n plan_identifier: selectedPlan,\n reason: 'purchase_returned_false',\n });\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : labels.purchaseError;\n track('purchase_failed', {\n plan_identifier: selectedPlan,\n reason: errorMessage,\n });\n onError?.(labels.errorTitle, errorMessage);\n } finally {\n setIsPurchasing(false);\n }\n }, [\n selectedPlan,\n clearError,\n track,\n purchase,\n subscriptionUserId,\n userEmail,\n onPurchaseSuccess,\n labels.errorTitle,\n labels.purchaseError,\n onError,\n ]);\n\n const handlePlanSelect = useCallback(\n (planIdentifier: string | null) => {\n setSelectedPlan(planIdentifier);\n track('plan_selected', {\n plan_identifier: planIdentifier ?? 'free',\n is_free_tier: planIdentifier === null,\n });\n },\n [track]\n );\n\n const handleRestore = useCallback(async () => {\n setIsRestoring(true);\n clearError();\n track('restore_initiated');\n\n try {\n const result = await restore(subscriptionUserId);\n if (result) {\n track('restore_completed');\n onRestoreSuccess?.();\n } else {\n track('restore_failed', { reason: 'no_purchases_found' });\n onWarning?.(labels.errorTitle, labels.restoreNoPurchases);\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : labels.restoreError;\n track('restore_failed', { reason: errorMessage });\n onError?.(labels.errorTitle, errorMessage);\n } finally {\n setIsRestoring(false);\n }\n }, [\n clearError,\n track,\n restore,\n subscriptionUserId,\n onRestoreSuccess,\n labels.errorTitle,\n labels.restoreNoPurchases,\n labels.restoreError,\n onWarning,\n onError,\n ]);\n\n const formatExpirationDate = useCallback((date?: Date) => {\n if (!date) return '';\n return new Intl.DateTimeFormat(undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n }).format(date);\n }, []);\n\n const getPeriodLabel = useCallback(\n (period?: string) => {\n if (!period) return '';\n if (period.includes('Y') || period.includes('year'))\n return labels.periodYear;\n if (period.includes('M') || period.includes('month'))\n return labels.periodMonth;\n if (period.includes('W') || period.includes('week'))\n return labels.periodWeek;\n return '';\n },\n [labels]\n );\n\n const getTrialLabel = useCallback(\n (trialPeriod?: string) => {\n if (!trialPeriod) return undefined;\n const num = parseInt(trialPeriod.replace(/\\D/g, '') || '1', 10);\n if (trialPeriod.includes('W')) {\n return formatters.formatTrialWeeks(num);\n }\n if (trialPeriod.includes('M')) {\n return formatters.formatTrialMonths(num);\n }\n return formatters.formatTrialDays(num);\n },\n [formatters]\n );\n\n const formatRateLimit = useCallback(\n (limit: number | null): string => {\n if (limit === null) return labels.unlimited;\n return limit.toLocaleString();\n },\n [labels.unlimited]\n );\n\n // Use formatters.getProductFeatures directly (same as AppPricingPage)\n const getProductFeatures = useCallback(\n (packageId: string): string[] => {\n return formatters.getProductFeatures(packageId);\n },\n [formatters]\n );\n\n // Free tier features come from labels (same as AppPricingPage)\n const getFreeTierFeatures = useCallback((): string[] => {\n return labels.freeTierFeatures;\n }, [labels.freeTierFeatures]);\n\n const getYearlySavingsPercent = useCallback(\n (yearlyPackageId: string): number | undefined => {\n const yearlyEntitlement = entitlementMap[yearlyPackageId];\n if (!yearlyEntitlement) return undefined;\n\n const yearlyProduct = products.find(\n p => p.identifier === yearlyPackageId\n );\n if (!yearlyProduct) return undefined;\n\n const monthlyPackageId = Object.entries(entitlementMap).find(\n ([pkgId, ent]) => ent === yearlyEntitlement && pkgId.includes('monthly')\n )?.[0];\n if (!monthlyPackageId) return undefined;\n\n const monthlyProduct = products.find(\n p => p.identifier === monthlyPackageId\n );\n if (!monthlyProduct) return undefined;\n\n const yearlyPrice = parseFloat(yearlyProduct.price);\n const monthlyPrice = parseFloat(monthlyProduct.price);\n\n if (monthlyPrice <= 0 || yearlyPrice <= 0) return undefined;\n\n const annualizedMonthly = monthlyPrice * 12;\n const savings =\n ((annualizedMonthly - yearlyPrice) / annualizedMonthly) * 100;\n\n return Math.round(savings);\n },\n [products, entitlementMap]\n );\n\n const billingPeriodOptions = [\n { value: 'monthly' as const, label: labels.billingMonthly },\n { value: 'yearly' as const, label: labels.billingYearly },\n ];\n\n return (\n <Section spacing='lg' maxWidth='4xl'>\n <SubscriptionLayout\n title={labels.title}\n error={error}\n currentStatusLabel={labels.currentStatusLabel}\n currentStatus={{\n isActive: currentSubscription?.isActive ?? false,\n activeContent: currentSubscription?.isActive\n ? {\n title: labels.statusActive,\n fields: [\n {\n label: labels.labelPlan,\n value:\n currentSubscription.productIdentifier ||\n labels.labelPremium,\n },\n {\n label: labels.labelExpires,\n value: formatExpirationDate(\n currentSubscription.expirationDate\n ),\n },\n {\n label: labels.labelWillRenew,\n value: currentSubscription.willRenew\n ? labels.yes\n : labels.no,\n },\n ...(rateLimitsConfig\n ? [\n {\n label: labels.labelMonthlyUsage,\n value: `${rateLimitsConfig.currentUsage.monthly.toLocaleString()} / ${formatRateLimit(rateLimitsConfig.currentLimits.monthly)}`,\n },\n {\n label: labels.labelDailyUsage,\n value: `${rateLimitsConfig.currentUsage.daily.toLocaleString()} / ${formatRateLimit(rateLimitsConfig.currentLimits.daily)}`,\n },\n ]\n : []),\n ],\n }\n : undefined,\n inactiveContent: !currentSubscription?.isActive\n ? {\n title: labels.statusInactive,\n message: labels.statusInactiveMessage,\n }\n : undefined,\n }}\n aboveProducts={\n !isLoading && products.length > 0 ? (\n <div className='flex justify-center mb-6'>\n <SegmentedControl\n options={billingPeriodOptions}\n value={billingPeriod}\n onChange={handlePeriodChange}\n />\n </div>\n ) : null\n }\n primaryAction={{\n label: isPurchasing\n ? labels.buttonPurchasing\n : labels.buttonSubscribe,\n onClick: handlePurchase,\n disabled: !selectedPlan || isPurchasing || isRestoring,\n loading: isPurchasing,\n }}\n secondaryAction={{\n label: isRestoring ? labels.buttonRestoring : labels.buttonRestore,\n onClick: handleRestore,\n disabled: isPurchasing || isRestoring,\n loading: isRestoring,\n }}\n >\n {isLoading ? (\n <div className='flex items-center justify-center py-12'>\n <div className='animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600' />\n </div>\n ) : products.length === 0 ? (\n <div className='text-center py-12 text-theme-text-secondary'>\n {labels.noProducts}\n </div>\n ) : filteredProducts.length === 0 ? (\n <div className='text-center py-12 text-theme-text-secondary'>\n {labels.noProductsForPeriod}\n </div>\n ) : (\n <>\n {/* Free tier tile */}\n <SubscriptionTile\n key='free'\n id='free'\n title={labels.freeTierTitle}\n price={labels.freeTierPrice}\n periodLabel={labels.periodMonth}\n features={getFreeTierFeatures()}\n isSelected={\n !currentSubscription?.isActive && selectedPlan === null\n }\n onSelect={() => handlePlanSelect(null)}\n topBadge={\n !currentSubscription?.isActive\n ? {\n text: labels.currentPlanBadge,\n color: 'green',\n }\n : undefined\n }\n disabled={isPurchasing || isRestoring}\n hideSelectionIndicator\n />\n {/* Paid plans */}\n {filteredProducts.map(product => (\n <SubscriptionTile\n key={product.identifier}\n id={product.identifier}\n title={product.title}\n price={product.priceString}\n periodLabel={getPeriodLabel(product.period)}\n features={getProductFeatures(product.identifier)}\n isSelected={selectedPlan === product.identifier}\n onSelect={() => handlePlanSelect(product.identifier)}\n isBestValue={product.identifier.includes('pro')}\n discountBadge={\n product.period?.includes('Y')\n ? (() => {\n const savings = getYearlySavingsPercent(\n product.identifier\n );\n return savings && savings > 0\n ? {\n text: formatters.formatSavePercent(savings),\n isBestValue: true,\n }\n : undefined;\n })()\n : undefined\n }\n introPriceNote={\n product.freeTrialPeriod\n ? getTrialLabel(product.freeTrialPeriod)\n : product.introPrice\n ? formatters.formatIntroNote(product.introPrice)\n : undefined\n }\n disabled={isPurchasing || isRestoring}\n />\n ))}\n </>\n )}\n </SubscriptionLayout>\n </Section>\n );\n}\n","/**\n * @fileoverview App Pricing Page\n * @description Public pricing page for displaying subscription options.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport { useState, useCallback } from 'react';\nimport {\n SubscriptionTile,\n SegmentedControl,\n} from '@sudobility/subscription-components';\nimport { Section } from '@sudobility/components';\nimport type { AnalyticsTrackingParams } from '../../types';\n\ntype BillingPeriod = 'monthly' | 'yearly';\n\n/** Product from subscription provider */\nexport interface PricingProduct {\n identifier: string;\n title: string;\n price: string;\n priceString: string;\n period?: string;\n}\n\n/** FAQ item */\nexport interface FAQItem {\n question: string;\n answer: string;\n}\n\n/** All localized labels for the pricing page */\nexport interface PricingPageLabels {\n // Header\n title: string;\n subtitle: string;\n\n // Periods\n periodYear: string;\n periodMonth: string;\n periodWeek: string;\n\n // Billing period toggle\n billingMonthly: string;\n billingYearly: string;\n\n // Free tier\n freeTierTitle: string;\n freeTierPrice: string;\n freeTierFeatures: string[];\n\n // Badges\n currentPlanBadge: string;\n mostPopularBadge: string;\n\n // CTA buttons\n ctaLogIn: string;\n ctaTryFree: string;\n ctaUpgrade: string;\n\n // FAQ\n faqTitle: string;\n}\n\n/** Formatter functions for dynamic strings */\nexport interface PricingPageFormatters {\n /** Format savings badge: \"Save 20%\" */\n formatSavePercent: (percent: number) => string;\n /** Get features for a product by its identifier */\n getProductFeatures: (productId: string) => string[];\n}\n\n/** Package ID to entitlement mapping */\nexport interface EntitlementMap {\n [packageId: string]: string;\n}\n\n/** Entitlement to level mapping for comparing plan tiers */\nexport interface EntitlementLevels {\n [entitlement: string]: number;\n}\n\nexport interface AppPricingPageProps {\n /** Available subscription products */\n products: PricingProduct[];\n /** Whether user is authenticated */\n isAuthenticated: boolean;\n /** Whether user has an active subscription */\n hasActiveSubscription: boolean;\n /** Current subscription product identifier (if any) */\n currentProductIdentifier?: string;\n /** User ID used for subscription (the selected entity's ID when logged in) */\n subscriptionUserId?: string;\n /** All localized labels */\n labels: PricingPageLabels;\n /** Formatter functions */\n formatters: PricingPageFormatters;\n /** Package ID to entitlement mapping for calculating savings */\n entitlementMap: EntitlementMap;\n /** Entitlement to level mapping for comparing tiers (higher = better) */\n entitlementLevels: EntitlementLevels;\n /** Called when user clicks on a plan */\n onPlanClick: (planIdentifier: string) => void;\n /** Called when user clicks on free plan */\n onFreePlanClick: () => void;\n /** Optional FAQ items */\n faqItems?: FAQItem[];\n /** Optional className for the container */\n className?: string;\n /** Optional analytics tracking callback */\n onTrack?: (params: AnalyticsTrackingParams) => void;\n}\n\n/**\n * Public pricing page for displaying subscription options.\n * - Non-authenticated: Free tile shows \"Try it for Free\", paid tiles show \"Log in to Continue\"\n * - Authenticated on free: Free tile shows \"Current Plan\" badge (no CTA), paid tiles show \"Upgrade\"\n * - Authenticated with subscription: Current plan shows badge (no CTA), higher tiers show \"Upgrade\"\n */\nexport function AppPricingPage({\n products,\n isAuthenticated,\n hasActiveSubscription,\n currentProductIdentifier,\n labels,\n formatters,\n entitlementMap,\n entitlementLevels,\n onPlanClick,\n onFreePlanClick,\n faqItems,\n className,\n onTrack,\n}: AppPricingPageProps) {\n const [billingPeriod, setBillingPeriod] = useState<BillingPeriod>('monthly');\n\n // Helper to track analytics events\n const track = useCallback(\n (label: string, params?: Record<string, unknown>) => {\n onTrack?.({\n eventType: 'subscription_action',\n componentName: 'AppPricingPage',\n label,\n params,\n });\n },\n [onTrack]\n );\n\n // Handle billing period change with tracking\n const handleBillingPeriodChange = useCallback(\n (value: string) => {\n const newPeriod = value as BillingPeriod;\n setBillingPeriod(newPeriod);\n track('billing_period_changed', { billing_period: newPeriod });\n },\n [track]\n );\n\n // Handle free plan click with tracking\n const handleFreePlanClick = useCallback(() => {\n track('free_plan_clicked', { plan: 'free' });\n onFreePlanClick();\n }, [track, onFreePlanClick]);\n\n // Handle paid plan click with tracking\n const handlePlanClick = useCallback(\n (planIdentifier: string, actionType: 'login' | 'upgrade') => {\n track('plan_clicked', {\n plan_identifier: planIdentifier,\n action_type: actionType,\n });\n onPlanClick(planIdentifier);\n },\n [track, onPlanClick]\n );\n\n // Get entitlement level for a product (0 for free/none)\n const getProductLevel = useCallback(\n (productId: string): number => {\n const entitlement = entitlementMap[productId];\n if (!entitlement) return 0;\n return entitlementLevels[entitlement] ?? 0;\n },\n [entitlementMap, entitlementLevels]\n );\n\n // Get current user's subscription level\n const currentLevel = currentProductIdentifier\n ? getProductLevel(currentProductIdentifier)\n : 0;\n\n // Filter products by billing period and sort by price\n const filteredProducts = products\n .filter(product => {\n if (!product.period) return false;\n const isYearly =\n product.period.includes('Y') || product.period.includes('year');\n return billingPeriod === 'yearly' ? isYearly : !isYearly;\n })\n .sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n\n const getPeriodLabel = useCallback(\n (period?: string) => {\n if (!period) return '';\n if (period.includes('Y') || period.includes('year'))\n return labels.periodYear;\n if (period.includes('M') || period.includes('month'))\n return labels.periodMonth;\n if (period.includes('W') || period.includes('week'))\n return labels.periodWeek;\n return '';\n },\n [labels]\n );\n\n const getYearlySavingsPercent = useCallback(\n (yearlyPackageId: string): number | undefined => {\n const yearlyEntitlement = entitlementMap[yearlyPackageId];\n if (!yearlyEntitlement) return undefined;\n\n const yearlyProduct = products.find(\n p => p.identifier === yearlyPackageId\n );\n if (!yearlyProduct) return undefined;\n\n const monthlyPackageId = Object.entries(entitlementMap).find(\n ([pkgId, ent]) => ent === yearlyEntitlement && pkgId.includes('monthly')\n )?.[0];\n if (!monthlyPackageId) return undefined;\n\n const monthlyProduct = products.find(\n p => p.identifier === monthlyPackageId\n );\n if (!monthlyProduct) return undefined;\n\n const yearlyPrice = parseFloat(yearlyProduct.price);\n const monthlyPrice = parseFloat(monthlyProduct.price);\n\n if (monthlyPrice <= 0 || yearlyPrice <= 0) return undefined;\n\n const annualizedMonthly = monthlyPrice * 12;\n const savings =\n ((annualizedMonthly - yearlyPrice) / annualizedMonthly) * 100;\n\n return Math.round(savings);\n },\n [products, entitlementMap]\n );\n\n const billingPeriodOptions = [\n { value: 'monthly' as const, label: labels.billingMonthly },\n { value: 'yearly' as const, label: labels.billingYearly },\n ];\n\n // Determine if a product is the current plan (same entitlement level)\n const isCurrentPlan = useCallback(\n (productId: string): boolean => {\n if (!isAuthenticated) return false;\n if (!hasActiveSubscription) return false;\n // Compare entitlement levels (handles monthly/yearly variants of same tier)\n return getProductLevel(productId) === currentLevel && currentLevel > 0;\n },\n [isAuthenticated, hasActiveSubscription, getProductLevel, currentLevel]\n );\n\n // Determine if a product is an upgrade from current plan\n const isUpgrade = useCallback(\n (productId: string): boolean => {\n const productLevel = getProductLevel(productId);\n return productLevel > currentLevel;\n },\n [getProductLevel, currentLevel]\n );\n\n return (\n <div className={className}>\n {/* Header */}\n <Section spacing='2xl' maxWidth='4xl'>\n <div className='text-center'>\n <h1 className='text-4xl sm:text-5xl font-bold text-theme-text-primary mb-4'>\n {labels.title}\n </h1>\n <p className='text-lg text-theme-text-secondary'>{labels.subtitle}</p>\n </div>\n </Section>\n\n {/* Pricing Cards */}\n <Section spacing='3xl' maxWidth='6xl'>\n {/* Billing Period Selector */}\n <div className='flex justify-center mb-8'>\n <SegmentedControl\n options={billingPeriodOptions}\n value={billingPeriod}\n onChange={handleBillingPeriodChange}\n />\n </div>\n\n {/* Subscription Tiles Grid */}\n <div\n style={{\n display: 'grid',\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 280px), 1fr))',\n gridAutoRows: '1fr',\n gap: '1.5rem',\n overflow: 'visible',\n }}\n >\n {/* Free Tier */}\n <SubscriptionTile\n id='free'\n title={labels.freeTierTitle}\n price={labels.freeTierPrice}\n periodLabel={labels.periodMonth}\n features={labels.freeTierFeatures}\n isSelected={false}\n onSelect={() => {}}\n topBadge={\n isAuthenticated && !hasActiveSubscription\n ? {\n text: labels.currentPlanBadge,\n color: 'green',\n }\n : undefined\n }\n ctaButton={\n // Not logged in: show \"Try it for Free\"\n // Logged in on free plan: no CTA (current plan)\n // Logged in with subscription: no CTA (can't downgrade here)\n !isAuthenticated\n ? {\n label: labels.ctaTryFree,\n onClick: handleFreePlanClick,\n }\n : undefined\n }\n hideSelectionIndicator={isAuthenticated}\n />\n\n {/* Paid Plans */}\n {filteredProducts.map(product => {\n const isCurrent = isCurrentPlan(product.identifier);\n const canUpgrade = isUpgrade(product.identifier);\n\n // Determine CTA button\n let ctaButton: { label: string; onClick: () => void } | undefined;\n if (!isAuthenticated) {\n // Not logged in: show \"Log in to Continue\"\n ctaButton = {\n label: labels.ctaLogIn,\n onClick: () => handlePlanClick(product.identifier, 'login'),\n };\n } else if (isCurrent) {\n // Current plan: no CTA\n ctaButton = undefined;\n } else if (canUpgrade) {\n // Higher tier: show \"Upgrade\"\n ctaButton = {\n label: labels.ctaUpgrade,\n onClick: () => handlePlanClick(product.identifier, 'upgrade'),\n };\n }\n // Lower tier than current: no CTA (implicit downgrade not shown)\n\n // Determine top badge\n let topBadge:\n | {\n text: string;\n color: 'purple' | 'green' | 'blue' | 'yellow' | 'red';\n }\n | undefined;\n if (isCurrent) {\n topBadge = {\n text: labels.currentPlanBadge,\n color: 'green',\n };\n } else if (product.identifier.includes('pro')) {\n topBadge = {\n text: labels.mostPopularBadge,\n color: 'yellow',\n };\n }\n\n return (\n <SubscriptionTile\n key={product.identifier}\n id={product.identifier}\n title={product.title}\n price={product.priceString}\n periodLabel={getPeriodLabel(product.period)}\n features={formatters.getProductFeatures(product.identifier)}\n isSelected={false}\n onSelect={() => {}}\n isBestValue={product.identifier.includes('pro')}\n topBadge={topBadge}\n discountBadge={\n product.period?.includes('Y')\n ? (() => {\n const savings = getYearlySavingsPercent(\n product.identifier\n );\n return savings && savings > 0\n ? {\n text: formatters.formatSavePercent(savings),\n isBestValue: true,\n }\n : undefined;\n })()\n : undefined\n }\n ctaButton={ctaButton}\n hideSelectionIndicator={!ctaButton}\n />\n );\n })}\n </div>\n </Section>\n\n {/* FAQ Section */}\n {faqItems && faqItems.length > 0 && (\n <Section spacing='3xl' background='surface' maxWidth='3xl'>\n <h2 className='text-3xl font-bold text-theme-text-primary text-center mb-12'>\n {labels.faqTitle}\n </h2>\n\n <div className='space-y-6'>\n {faqItems.map((item, index) => (\n <div\n key={index}\n className='bg-theme-bg-primary p-6 rounded-xl border border-theme-border'\n >\n <h3 className='text-lg font-semibold text-theme-text-primary mb-2'>\n {item.question}\n </h3>\n <p className='text-theme-text-secondary'>{item.answer}</p>\n </div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n","/**\n * @fileoverview App Sitemap Page\n * @description Reusable sitemap page component with categorized links.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, { type ComponentType, type ReactNode } from 'react';\nimport {\n ChevronRightIcon,\n HomeIcon,\n DocumentTextIcon,\n EnvelopeIcon,\n CogIcon,\n LanguageIcon,\n} from '@heroicons/react/24/outline';\nimport { Section } from '@sudobility/components';\nimport { cn } from '../../utils';\nimport type { LinkComponentProps } from '../../types';\n\n/**\n * Configuration for a single sitemap link\n */\nexport interface SitemapLink {\n /** URL path */\n path: string;\n /** Display label */\n label: string;\n /** Optional description */\n description?: string;\n}\n\n/**\n * Configuration for a sitemap section\n */\nexport interface SitemapSection {\n /** Section title */\n title: string;\n /** Section icon type (optional) */\n icon?: 'home' | 'document' | 'envelope' | 'cog' | 'language';\n /** Links in this section */\n links: SitemapLink[];\n}\n\n/**\n * Configuration for a language option\n */\nexport interface LanguageOption {\n /** Language code (e.g., 'en', 'es') */\n code: string;\n /** Display name */\n name: string;\n /** Flag emoji */\n flag: string;\n}\n\n/**\n * Configuration for quick action buttons\n */\nexport interface QuickLink {\n /** URL path */\n path: string;\n /** Display label */\n label: string;\n /** Button variant */\n variant: 'primary' | 'secondary' | 'outline';\n /** Optional icon */\n icon?: 'envelope' | 'document';\n}\n\n/**\n * Text content for the sitemap page\n */\nexport interface SitemapPageText {\n /** Page title */\n title: string;\n /** Page subtitle */\n subtitle: string;\n /** Languages section title */\n languagesSectionTitle: string;\n /** Languages section description */\n languagesDescription: string;\n /** Quick links section title */\n quickLinksTitle: string;\n}\n\n/**\n * Props for AppSitemapPage component\n */\nexport interface AppSitemapPageProps {\n /** All text content (must be provided by consumer) */\n text: SitemapPageText;\n /** Sitemap sections */\n sections: SitemapSection[];\n /** Available languages */\n languages: LanguageOption[];\n /** Quick action links */\n quickLinks?: QuickLink[];\n /** Custom Link component for navigation */\n LinkComponent: ComponentType<LinkComponentProps & { language?: string }>;\n /** Optional wrapper component for the page layout */\n PageWrapper?: ComponentType<{ children: ReactNode }>;\n /** Optional className for the container */\n className?: string;\n}\n\n/**\n * Get icon component based on icon type\n */\nconst getIcon = (icon?: string) => {\n switch (icon) {\n case 'home':\n return <HomeIcon className='w-5 h-5 mr-2' />;\n case 'document':\n return <DocumentTextIcon className='w-5 h-5 mr-2' />;\n case 'envelope':\n return <EnvelopeIcon className='w-5 h-5 mr-2' />;\n case 'cog':\n return <CogIcon className='w-5 h-5 mr-2' />;\n case 'language':\n return <LanguageIcon className='w-5 h-5 mr-2' />;\n default:\n return null;\n }\n};\n\n/**\n * AppSitemapPage - A reusable sitemap page component\n *\n * Displays a comprehensive sitemap with:\n * - Language selector\n * - Organized sections with links\n * - Quick action buttons\n *\n * All text content must be provided by the consumer app.\n *\n * @example\n * ```tsx\n * <AppSitemapPage\n * text={{\n * title: \"Sitemap\",\n * subtitle: \"Explore all pages\",\n * languagesSectionTitle: \"Languages\",\n * languagesDescription: \"Available in multiple languages\",\n * quickLinksTitle: \"Quick Links\"\n * }}\n * sections={[\n * { title: \"Main\", icon: \"home\", links: [{ path: \"/\", label: \"Home\" }] }\n * ]}\n * languages={[{ code: \"en\", name: \"English\", flag: \"🇺🇸\" }]}\n * LinkComponent={LocalizedLink}\n * />\n * ```\n */\nexport const AppSitemapPage: React.FC<AppSitemapPageProps> = ({\n text,\n sections,\n languages,\n quickLinks = [],\n LinkComponent,\n PageWrapper,\n className,\n}) => {\n const content = (\n <Section spacing='3xl' maxWidth='6xl' className={cn(className)}>\n {/* Header */}\n <div className='text-center mb-12'>\n <h1 className='text-4xl font-bold text-gray-900 dark:text-white mb-4'>\n {text.title}\n </h1>\n <p className='text-xl text-gray-600 dark:text-gray-300'>\n {text.subtitle}\n </p>\n </div>\n\n {/* Language Section */}\n {languages.length > 0 && (\n <div className='mb-12 p-6 bg-blue-50 dark:bg-blue-900/20 rounded-lg'>\n <h2 className='text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center'>\n <LanguageIcon className='w-6 h-6 mr-2' />\n {text.languagesSectionTitle}\n </h2>\n <p className='text-gray-600 dark:text-gray-300 mb-6'>\n {text.languagesDescription}\n </p>\n <div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4'>\n {languages.map(lang => (\n <LinkComponent\n key={lang.code}\n href='/'\n language={lang.code}\n className='flex items-center space-x-2 p-3 bg-white dark:bg-gray-800 rounded-lg hover:shadow-md transition-shadow'\n >\n <span className='text-2xl'>{lang.flag}</span>\n <div className='font-medium text-gray-900 dark:text-white'>\n {lang.name}\n </div>\n </LinkComponent>\n ))}\n </div>\n </div>\n )}\n\n {/* Sitemap Grid */}\n <div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8'>\n {sections.map((section, index) => (\n <div\n key={index}\n className='bg-white dark:bg-gray-800 rounded-lg shadow-sm p-6'\n >\n <h2 className='text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center'>\n {getIcon(section.icon)}\n {section.title}\n </h2>\n <ul className='space-y-2'>\n {section.links.map((link, linkIndex) => (\n <li key={linkIndex}>\n <LinkComponent\n href={link.path}\n className='group flex items-start text-sm hover:text-blue-600 dark:hover:text-blue-400 transition-colors'\n >\n <ChevronRightIcon className='w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400' />\n <div>\n <span className='font-medium text-gray-700 dark:text-gray-300 group-hover:text-blue-600 dark:group-hover:text-blue-400'>\n {link.label}\n </span>\n {link.description && (\n <span className='block text-xs text-gray-500 dark:text-gray-400 mt-0.5'>\n {link.description}\n </span>\n )}\n </div>\n </LinkComponent>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n\n {/* Quick Links Section */}\n {quickLinks.length > 0 && (\n <div className='mt-12 p-6 bg-gray-50 dark:bg-gray-900 rounded-lg'>\n <h3 className='text-lg font-semibold text-gray-900 dark:text-white mb-4'>\n {text.quickLinksTitle}\n </h3>\n <div className='flex flex-wrap gap-3'>\n {quickLinks.map((link, index) => {\n const baseClasses =\n 'inline-flex items-center px-4 py-2 rounded-lg transition-colors';\n const variantClasses =\n link.variant === 'primary'\n ? 'bg-blue-600 text-white hover:bg-blue-700'\n : link.variant === 'secondary'\n ? 'bg-gray-600 text-white hover:bg-gray-700'\n : 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800';\n\n return (\n <LinkComponent\n key={index}\n href={link.path}\n className={`${baseClasses} ${variantClasses}`}\n >\n {link.icon === 'envelope' && (\n <EnvelopeIcon className='w-5 h-5 mr-2' />\n )}\n {link.icon === 'document' && (\n <DocumentTextIcon className='w-5 h-5 mr-2' />\n )}\n {link.label}\n </LinkComponent>\n );\n })}\n </div>\n </div>\n )}\n </Section>\n );\n\n if (PageWrapper) {\n return <PageWrapper>{content}</PageWrapper>;\n }\n\n return content;\n};\n\nexport default AppSitemapPage;\n","/**\n * @fileoverview App Text Page\n * @description Reusable page component for text-heavy content like Privacy Policy, Terms, etc.\n *\n * This component uses Section internally for proper page layout.\n * Do NOT wrap this component in a Section when consuming it.\n */\n\nimport React, { type ReactNode, type ComponentType } from 'react';\nimport { Section } from '@sudobility/components';\nimport { cn } from '../../utils';\n\n/**\n * Configuration for a text section with paragraph content\n */\nexport interface TextSectionWithContent {\n /** Section title */\n title: string;\n /** Paragraph content */\n content: string;\n /** Whether content contains HTML that should be rendered */\n isHtml?: boolean;\n}\n\n/**\n * Configuration for a text section with a list\n */\nexport interface TextSectionWithList {\n /** Section title */\n title: string;\n /** Optional description before the list */\n description?: string;\n /** List items */\n items: string[];\n /** Optional additional content after the list */\n additionalContent?: string;\n}\n\n/**\n * Configuration for a text section with subsections (e.g., \"Information You Provide\" and \"Information Collected Automatically\")\n */\nexport interface TextSectionWithSubsections {\n /** Section title */\n title: string;\n /** Subsections, each with a title and list items */\n subsections: Array<{\n title: string;\n items: string[];\n }>;\n}\n\n/**\n * Union type for all section types\n */\nexport type TextSection =\n | TextSectionWithContent\n | TextSectionWithList\n | TextSectionWithSubsections;\n\n/**\n * Contact information configuration\n */\nexport interface TextPageContactInfo {\n /** Email label (e.g., \"Email:\") */\n emailLabel: string;\n /** Email address */\n email: string;\n /** Website label (e.g., \"Website:\") */\n websiteLabel: string;\n /** Website URL */\n websiteUrl: string;\n /** Data Protection Officer label (optional, for privacy pages) */\n dpoLabel?: string;\n /** DPO email (optional, for privacy pages) */\n dpoEmail?: string;\n}\n\n/**\n * GDPR notice configuration (optional, for privacy pages)\n */\nexport interface GdprNotice {\n /** GDPR section title */\n title: string;\n /** GDPR section content */\n content: string;\n}\n\n/**\n * Contact section configuration\n */\nexport interface TextPageContact {\n /** Section title */\n title: string;\n /** Section description */\n description: string;\n /** Whether description contains HTML */\n isHtml?: boolean;\n /** Contact details */\n info: TextPageContactInfo;\n /** Optional GDPR notice (for privacy pages) */\n gdprNotice?: GdprNotice;\n}\n\n/**\n * All text content for the text page\n */\nexport interface TextPageContent {\n /** Page title */\n title: string;\n /** Last updated text (use {{date}} as placeholder for the date) */\n lastUpdated?: string;\n /** All sections in order */\n sections: TextSection[];\n /** Contact information (optional) */\n contact?: TextPageContact;\n}\n\n/**\n * Props for AppTextPage component\n */\nexport interface AppTextPageProps {\n /** All text content (must be provided by consumer) */\n text: TextPageContent;\n /** Current date for \"last updated\" display */\n lastUpdatedDate?: string;\n /** Optional wrapper component for the page layout */\n PageWrapper?: ComponentType<{ children: ReactNode }>;\n /** Optional className for the container */\n className?: string;\n}\n\n/**\n * Type guard to check if section has items (is a list section)\n */\nfunction isSectionWithList(\n section: TextSection\n): section is TextSectionWithList {\n return 'items' in section && Array.isArray(section.items);\n}\n\n/**\n * Type guard to check if section has subsections\n */\nfunction isSectionWithSubsections(\n section: TextSection\n): section is TextSectionWithSubsections {\n return 'subsections' in section && Array.isArray(section.subsections);\n}\n\n/**\n * Heading component for h2 sections\n */\nconst SectionHeading: React.FC<{ children: ReactNode }> = ({ children }) => (\n <h2 className='text-2xl font-bold text-gray-900 dark:text-gray-100 mt-8 mb-4'>\n {children}\n </h2>\n);\n\n/**\n * Heading component for h3 subsections\n */\nconst SubsectionHeading: React.FC<{ children: ReactNode }> = ({ children }) => (\n <h3 className='text-xl font-semibold text-gray-900 dark:text-gray-100 mt-6 mb-3'>\n {children}\n </h3>\n);\n\n/**\n * Paragraph component\n */\nconst Paragraph: React.FC<{ children: ReactNode; className?: string }> = ({\n children,\n className = '',\n}) => (\n <p className={`text-gray-600 dark:text-gray-300 mb-6 ${className}`}>\n {children}\n </p>\n);\n\n/**\n * List component - renders items with HTML support\n */\nconst List: React.FC<{ items: string[] }> = ({ items }) => (\n <ul className='list-disc list-inside text-gray-600 dark:text-gray-300 mb-6 space-y-1'>\n {items.map((item, index) => (\n <li key={index} dangerouslySetInnerHTML={{ __html: item }} />\n ))}\n </ul>\n);\n\n/**\n * AppTextPage - A reusable text page component for legal/informational pages\n *\n * Displays a text-heavy page with:\n * - Flexible section structure (content, list, or subsections)\n * - Optional contact information\n * - Optional GDPR notice\n *\n * Use this for Privacy Policy, Terms of Service, Cookie Policy, etc.\n *\n * @example\n * ```tsx\n * <AppTextPage\n * text={{\n * title: \"Privacy Policy\",\n * lastUpdated: \"Last updated: {{date}}\",\n * sections: [\n * { title: \"Introduction\", content: \"We respect your privacy...\" },\n * { title: \"Data We Collect\", items: [\"Email\", \"Usage data\"] },\n * {\n * title: \"Information We Collect\",\n * subsections: [\n * { title: \"You Provide\", items: [\"Email\", \"Name\"] },\n * { title: \"Automatic\", items: [\"IP\", \"Browser\"] }\n * ]\n * }\n * ],\n * contact: {\n * title: \"Contact\",\n * description: \"Questions?\",\n * info: { emailLabel: \"Email:\", email: \"support@example.com\", ... }\n * }\n * }}\n * lastUpdatedDate=\"January 1, 2025\"\n * />\n * ```\n */\nexport const AppTextPage: React.FC<AppTextPageProps> = ({\n text,\n lastUpdatedDate = new Date().toLocaleDateString(),\n PageWrapper,\n className,\n}) => {\n const content = (\n <Section spacing='3xl' maxWidth='4xl' className={cn(className)}>\n <h1 className='text-4xl font-bold text-gray-900 dark:text-gray-100 mb-8'>\n {text.title}\n </h1>\n\n <div className='prose prose-lg dark:prose-invert max-w-none'>\n {text.lastUpdated && (\n <Paragraph className='mb-6'>\n {text.lastUpdated.replace('{{date}}', lastUpdatedDate)}\n </Paragraph>\n )}\n\n {/* Render all sections */}\n {text.sections.map((section, index) => (\n <React.Fragment key={index}>\n <SectionHeading>{section.title}</SectionHeading>\n\n {isSectionWithSubsections(section) ? (\n // Section with subsections (h3 + lists)\n <>\n {section.subsections.map((subsection, subIndex) => (\n <React.Fragment key={subIndex}>\n <SubsectionHeading>{subsection.title}</SubsectionHeading>\n <List items={subsection.items} />\n </React.Fragment>\n ))}\n </>\n ) : isSectionWithList(section) ? (\n // Section with list\n <>\n {section.description && (\n <Paragraph className='mb-4'>{section.description}</Paragraph>\n )}\n <List items={section.items} />\n {section.additionalContent && (\n <Paragraph>{section.additionalContent}</Paragraph>\n )}\n </>\n ) : section.isHtml ? (\n // Section with HTML content\n <Paragraph>\n <span dangerouslySetInnerHTML={{ __html: section.content }} />\n </Paragraph>\n ) : (\n // Section with plain text content\n <Paragraph>{section.content}</Paragraph>\n )}\n </React.Fragment>\n ))}\n\n {/* Contact Section */}\n {text.contact && (\n <>\n <SectionHeading>{text.contact.title}</SectionHeading>\n {text.contact.isHtml ? (\n <Paragraph>\n <span\n dangerouslySetInnerHTML={{ __html: text.contact.description }}\n />\n </Paragraph>\n ) : (\n <Paragraph>{text.contact.description}</Paragraph>\n )}\n <div className='bg-gray-50 dark:bg-gray-800 p-4 rounded-lg'>\n <p className='text-gray-700 dark:text-gray-300'>\n {text.contact.info.emailLabel}{' '}\n <a\n href={`mailto:${text.contact.info.email}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.email}\n </a>\n <br />\n {text.contact.info.websiteLabel}{' '}\n <a\n href={text.contact.info.websiteUrl}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.websiteUrl}\n </a>\n {text.contact.info.dpoLabel && text.contact.info.dpoEmail && (\n <>\n <br />\n {text.contact.info.dpoLabel}{' '}\n <a\n href={`mailto:${text.contact.info.dpoEmail}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.dpoEmail}\n </a>\n </>\n )}\n </p>\n </div>\n\n {/* GDPR Notice */}\n {text.contact.gdprNotice && (\n <div className='mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg'>\n <h3 className='text-lg font-semibold text-blue-900 dark:text-blue-200 mb-2'>\n {text.contact.gdprNotice.title}\n </h3>\n <p className='text-blue-800 dark:text-blue-300'>\n {text.contact.gdprNotice.content}{' '}\n {text.contact.info.dpoEmail && (\n <a\n href={`mailto:${text.contact.info.dpoEmail}`}\n className='text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'\n >\n {text.contact.info.dpoEmail}\n </a>\n )}\n </p>\n </div>\n )}\n </>\n )}\n </div>\n </Section>\n );\n\n if (PageWrapper) {\n return <PageWrapper>{content}</PageWrapper>;\n }\n\n return content;\n};\n\nexport default AppTextPage;\n","import React, { useState, useEffect, useRef, type ReactNode } from 'react';\nimport {\n signInWithEmailAndPassword,\n createUserWithEmailAndPassword,\n GoogleAuthProvider,\n signInWithPopup,\n type Auth,\n} from 'firebase/auth';\n\n/**\n * Google logo SVG component\n */\nfunction GoogleIcon({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox='0 0 24 24' aria-hidden='true'>\n <path\n d='M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z'\n fill='#4285F4'\n />\n <path\n d='M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z'\n fill='#34A853'\n />\n <path\n d='M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z'\n fill='#FBBC05'\n />\n <path\n d='M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z'\n fill='#EA4335'\n />\n </svg>\n );\n}\n\n/**\n * Auth error info passed to onAuthError callback\n */\nexport interface AuthErrorInfo {\n /** Firebase error code (e.g., 'auth/popup-closed-by-user') */\n code: string;\n /** Error message */\n message: string;\n /** Whether this is a user-initiated action (like closing popup) vs actual error */\n isUserAction: boolean;\n}\n\n/**\n * Props for the LoginPage component\n */\nexport interface LoginPageProps {\n /** Application name displayed as the main title */\n appName: string;\n /** Optional logo element to display above the title */\n logo?: ReactNode;\n /** Firebase Auth instance */\n auth: Auth;\n /** Callback fired on successful authentication */\n onSuccess: () => void;\n /** Callback fired on auth errors - if provided, errors won't be shown inline */\n onAuthError?: (error: AuthErrorInfo) => void;\n /** Whether to show Google sign-in option (default: true) */\n showGoogleSignIn?: boolean;\n /** Whether to show sign-up option (default: true) */\n showSignUp?: boolean;\n /** Custom className for the container */\n className?: string;\n /** Custom primary color class (default: 'primary') */\n primaryColorClass?: string;\n}\n\n/**\n * Text content for the LoginPage\n */\nexport interface LoginPageText {\n signIn: string;\n signUp: string;\n createAccount: string;\n signInToAccount: string;\n emailLabel: string;\n emailPlaceholder: string;\n passwordLabel: string;\n passwordPlaceholder: string;\n orContinueWith: string;\n signInWithGoogle: string;\n alreadyHaveAccount: string;\n dontHaveAccount: string;\n}\n\nconst defaultText: LoginPageText = {\n signIn: 'Sign in',\n signUp: 'Sign up',\n createAccount: 'Create your account',\n signInToAccount: 'Sign in to your account',\n emailLabel: 'Email address',\n emailPlaceholder: '',\n passwordLabel: 'Password',\n passwordPlaceholder: '',\n orContinueWith: 'Or continue with',\n signInWithGoogle: 'Sign in with Google',\n alreadyHaveAccount: 'Already have an account?',\n dontHaveAccount: \"Don't have an account?\",\n};\n\n/**\n * A reusable login page component with email/password and Google sign-in support.\n *\n * @example\n * ```tsx\n * import { LoginPage } from '@sudobility/building_blocks';\n * import { getFirebaseAuth } from '@sudobility/auth_lib';\n *\n * function MyLoginPage() {\n * const navigate = useNavigate();\n * const auth = getFirebaseAuth();\n *\n * return (\n * <LoginPage\n * appName=\"My App\"\n * auth={auth}\n * onSuccess={() => navigate('/')}\n * />\n * );\n * }\n * ```\n */\n// Error codes that represent user actions rather than actual errors\nconst USER_ACTION_ERROR_CODES = [\n 'auth/popup-closed-by-user',\n 'auth/cancelled-popup-request',\n 'auth/user-cancelled',\n];\n\nexport function LoginPage({\n appName,\n logo,\n auth,\n onSuccess,\n onAuthError,\n showGoogleSignIn = true,\n showSignUp = true,\n className = '',\n primaryColorClass = 'primary',\n}: LoginPageProps) {\n const [isSignUp, setIsSignUp] = useState(false);\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [isGoogleSignInPending, setIsGoogleSignInPending] = useState(false);\n const googleSignInStartTime = useRef<number | null>(null);\n\n // Reset Google sign-in state when window regains focus\n // This handles the case where browser opens a new tab instead of popup\n useEffect(() => {\n const handleFocus = () => {\n if (isGoogleSignInPending && googleSignInStartTime.current) {\n // If more than 2 seconds have passed since sign-in started,\n // and we're back in focus, the user likely closed the tab/popup\n const elapsed = Date.now() - googleSignInStartTime.current;\n if (elapsed > 2000) {\n setIsLoading(false);\n setIsGoogleSignInPending(false);\n googleSignInStartTime.current = null;\n }\n }\n };\n\n window.addEventListener('focus', handleFocus);\n return () => window.removeEventListener('focus', handleFocus);\n }, [isGoogleSignInPending]);\n\n const handleAuthError = (err: unknown) => {\n const firebaseError = err as { code?: string; message?: string };\n const code = firebaseError.code || 'unknown';\n const message = firebaseError.message || 'Authentication failed';\n const isUserAction = USER_ACTION_ERROR_CODES.includes(code);\n\n if (onAuthError) {\n onAuthError({ code, message, isUserAction });\n } else if (!isUserAction) {\n // Only show inline error for actual errors, not user actions\n setError(message);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsLoading(true);\n\n try {\n if (!auth) throw new Error('Firebase not configured');\n if (isSignUp && showSignUp) {\n await createUserWithEmailAndPassword(auth, email, password);\n } else {\n await signInWithEmailAndPassword(auth, email, password);\n }\n onSuccess();\n } catch (err) {\n handleAuthError(err);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleGoogleSignIn = async () => {\n setError(null);\n setIsLoading(true);\n setIsGoogleSignInPending(true);\n googleSignInStartTime.current = Date.now();\n\n try {\n if (!auth) throw new Error('Firebase not configured');\n const provider = new GoogleAuthProvider();\n await signInWithPopup(auth, provider);\n onSuccess();\n } catch (err) {\n handleAuthError(err);\n } finally {\n setIsLoading(false);\n setIsGoogleSignInPending(false);\n googleSignInStartTime.current = null;\n }\n };\n\n const text = defaultText;\n\n return (\n <div\n className={`min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8 ${className}`}\n >\n <div className='max-w-md w-full space-y-8'>\n <div>\n {logo && <div className='flex justify-center mb-4'>{logo}</div>}\n <h1\n className={`text-center text-3xl font-bold text-${primaryColorClass}-600`}\n >\n {appName}\n </h1>\n <h2 className='mt-6 text-center text-2xl font-semibold text-gray-900'>\n {isSignUp && showSignUp ? text.createAccount : text.signInToAccount}\n </h2>\n </div>\n\n <form className='mt-8 space-y-6' onSubmit={handleSubmit}>\n {error && (\n <div className='bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-md text-sm'>\n {error}\n </div>\n )}\n\n <div className='space-y-4'>\n <div>\n <label\n htmlFor='email'\n className='block text-sm font-medium text-gray-700'\n >\n {text.emailLabel}\n </label>\n <input\n id='email'\n name='email'\n type='email'\n autoComplete='email'\n required\n value={email}\n onChange={e => setEmail(e.target.value)}\n placeholder={text.emailPlaceholder}\n className={`mt-1 appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-${primaryColorClass}-500 focus:border-${primaryColorClass}-500 sm:text-sm`}\n />\n </div>\n\n <div>\n <label\n htmlFor='password'\n className='block text-sm font-medium text-gray-700'\n >\n {text.passwordLabel}\n </label>\n <input\n id='password'\n name='password'\n type='password'\n autoComplete={isSignUp ? 'new-password' : 'current-password'}\n required\n value={password}\n onChange={e => setPassword(e.target.value)}\n placeholder={text.passwordPlaceholder}\n className={`mt-1 appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-${primaryColorClass}-500 focus:border-${primaryColorClass}-500 sm:text-sm`}\n />\n </div>\n </div>\n\n <div>\n <button\n type='submit'\n disabled={isLoading}\n className={`w-full inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 bg-${primaryColorClass}-600 text-white hover:bg-${primaryColorClass}-700 focus:ring-${primaryColorClass}-500 disabled:bg-${primaryColorClass}-300 px-4 py-2 text-sm`}\n >\n {isLoading && (\n <svg\n className='animate-spin -ml-1 mr-2 h-4 w-4'\n xmlns='http://www.w3.org/2000/svg'\n fill='none'\n viewBox='0 0 24 24'\n >\n <circle\n className='opacity-25'\n cx='12'\n cy='12'\n r='10'\n stroke='currentColor'\n strokeWidth='4'\n />\n <path\n className='opacity-75'\n fill='currentColor'\n d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'\n />\n </svg>\n )}\n {isSignUp && showSignUp ? text.signUp : text.signIn}\n </button>\n </div>\n\n {showGoogleSignIn && (\n <>\n <div className='relative'>\n <div className='absolute inset-0 flex items-center'>\n <div className='w-full border-t border-gray-300' />\n </div>\n <div className='relative flex justify-center text-sm'>\n <span className='px-2 bg-gray-50 text-gray-500'>\n {text.orContinueWith}\n </span>\n </div>\n </div>\n\n <div>\n <button\n type='button'\n onClick={handleGoogleSignIn}\n disabled={isLoading}\n className={`w-full inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 bg-white text-gray-700 border border-gray-300 hover:bg-gray-50 focus:ring-${primaryColorClass}-500 disabled:bg-gray-100 px-4 py-2 text-sm`}\n >\n {isLoading ? (\n <svg\n className='animate-spin -ml-1 mr-2 h-5 w-5'\n xmlns='http://www.w3.org/2000/svg'\n fill='none'\n viewBox='0 0 24 24'\n >\n <circle\n className='opacity-25'\n cx='12'\n cy='12'\n r='10'\n stroke='currentColor'\n strokeWidth='4'\n />\n <path\n className='opacity-75'\n fill='currentColor'\n d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'\n />\n </svg>\n ) : (\n <GoogleIcon className='h-5 w-5 mr-2' />\n )}\n {text.signInWithGoogle}\n </button>\n </div>\n </>\n )}\n </form>\n\n {showSignUp && (\n <p className='text-center text-sm text-gray-600'>\n {isSignUp ? text.alreadyHaveAccount : text.dontHaveAccount}{' '}\n <button\n type='button'\n onClick={() => setIsSignUp(!isSignUp)}\n className={`font-medium text-${primaryColorClass}-600 hover:text-${primaryColorClass}-500`}\n >\n {isSignUp ? text.signIn : text.signUp}\n </button>\n </p>\n )}\n </div>\n </div>\n );\n}\n"],"names":["DefaultLinkComponent","className","AuthStatus","ChainType","getCopyrightYear","FooterContainer","Theme","FontSize","defaultTranslations"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/building_blocks",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "Higher-level shared UI building blocks for Sudobility apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -68,7 +68,7 @@
68
68
  "devDependencies": {
69
69
  "@eslint/js": "^9.38.0",
70
70
  "@heroicons/react": "^2.2.0",
71
- "@sudobility/components": "^4.0.157",
71
+ "@sudobility/components": "^4.0.158",
72
72
  "@sudobility/design": "^1.1.18",
73
73
  "firebase": "^12.4.0",
74
74
  "@sudobility/subscription-components": "^1.0.20",