98 lines
2.5 KiB
TypeScript
98 lines
2.5 KiB
TypeScript
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<AvailabilityStatus>('loading');
|
|
const [message, setMessage] = useState<string | undefined>();
|
|
|
|
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 (
|
|
<View style={styles.centered}>
|
|
<ActivityIndicator size="large" color={Colors.accent.green} />
|
|
<Text style={styles.title}>Loading trading workspace...</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
if (status !== 'available') {
|
|
return (
|
|
<View style={styles.centered}>
|
|
<Text style={styles.eyebrow}>CONTROL PLANE</Text>
|
|
<Text style={styles.title}>
|
|
{status === 'maintenance' ? 'Trading under maintenance' : 'Trading temporarily unavailable'}
|
|
</Text>
|
|
{message ? <Text style={styles.body}>{message}</Text> : null}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
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,
|
|
},
|
|
});
|