import { useEffect, useState } from 'react'; import type { ReactNode } from 'react'; import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'; import { mobileKillSwitchClient } from '@/lib/runtime'; import { Colors, Fonts, Spacing } from '@/constants/theme'; type AvailabilityStatus = 'loading' | 'available' | 'maintenance' | 'product_disabled'; export function ProductAvailabilityGate({ children }: { children: ReactNode }) { const [status, setStatus] = useState('loading'); const [message, setMessage] = useState(); useEffect(() => { let active = true; async function loadAvailability() { try { const result = await mobileKillSwitchClient.check(); if (!active) { return; } if (result.disabled) { setStatus('product_disabled'); setMessage(result.message ?? 'Trading access is temporarily disabled.'); return; } setStatus('available'); } catch (error) { console.warn('[ProductAvailabilityGate] Failed to evaluate kill switch.', error); if (active) { setStatus('available'); } } } void loadAvailability(); return () => { active = false; }; }, []); if (status === 'loading') { return ( Loading trading workspace... ); } if (status !== 'available') { return ( CONTROL PLANE {status === 'maintenance' ? 'Trading under maintenance' : 'Trading temporarily unavailable'} {message ? {message} : null} ); } return <>{children}; } const styles = StyleSheet.create({ centered: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: Colors.background.primary, padding: Spacing.screenPadding, gap: 12, }, eyebrow: { fontFamily: Fonts.inter.black, fontSize: 11, letterSpacing: 2.5, color: Colors.accent.green, }, title: { fontFamily: Fonts.inter.black, fontSize: 24, color: Colors.text.primary, textAlign: 'center', }, body: { fontFamily: Fonts.inter.medium, fontSize: 14, lineHeight: 22, color: Colors.text.secondary, textAlign: 'center', maxWidth: 320, }, });