feat: scaffold ShieldAI React Native mobile app MVP (FRE-4572)

Build complete Expo/React Native mobile app with:
- Auth flow: email/password login, registration, biometric auth
- Dashboard: exposure summary, spam stats, voice protection status
- DarkWatch: watch list management, exposure feed, alert toggles
- SpamShield: call/text history, whitelist/blacklist management
- VoicePrint: family member enrollment, voice analysis
- Settings: tier management, notification preferences, security
- Push notification integration via FCM/APNs
- Offline-first state management with Zustand + AsyncStorage
- Integration with @shieldai/mobile-api-client for API services
- React Navigation with auth-aware routing (stack + bottom tabs)
- Dark theme with consistent design system (colors, spacing, typography)
- Network status monitoring and offline request queuing

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-05-17 10:12:46 -04:00
parent 7fb8b83810
commit a071aa736e
50 changed files with 3026 additions and 13 deletions

View File

@@ -0,0 +1,119 @@
import React from 'react';
import { Text, ViewStyle, StyleSheet } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { DashboardScreen } from '@/screens/dashboard';
import { DarkWatchScreen } from '@/screens/darkwatch';
import { SpamShieldScreen } from '@/screens/spamshield';
import { VoicePrintScreen } from '@/screens/voiceprint';
import { SettingsScreen } from '@/screens/settings';
import { COLORS, FONT_SIZES } from '@/constants/theme';
type MainTabParamList = {
Dashboard: undefined;
DarkWatch: undefined;
SpamShield: undefined;
VoicePrint: undefined;
Settings: undefined;
};
const Tab = createBottomTabNavigator<MainTabParamList>();
const iconMap: Record<string, string> = {
Dashboard: '\u{1F6E1}\u{FE0F}',
DarkWatch: '\u{1F441}\u{FE0F}',
SpamShield: '\u{1F6AB}',
VoicePrint: '\u{1F399}\u{FE0F}',
Settings: '\u{2699}\u{FE0F}',
};
function TabIcon({ routeName, color }: { routeName: string; color: string }) {
return (
<Text style={[styles.icon, { color }]}>{iconMap[routeName] || '\u{2022}'}</Text>
);
}
const styles = StyleSheet.create({
icon: {
fontSize: 22,
},
});
export function MainTabNavigator() {
return (
<Tab.Navigator
screenOptions={{
headerStyle: {
backgroundColor: COLORS.background,
},
headerTintColor: COLORS.text,
headerTitleStyle: {
fontSize: FONT_SIZES.lg,
fontWeight: '600',
},
tabBarStyle: {
backgroundColor: COLORS.backgroundLight,
borderTopColor: COLORS.border,
borderTopWidth: 1,
height: 60,
paddingBottom: 8,
paddingTop: 8,
} as ViewStyle,
tabBarActiveTintColor: COLORS.primary,
tabBarInactiveTintColor: COLORS.textMuted,
tabBarLabelStyle: {
fontSize: FONT_SIZES.xs,
},
tabBarIconStyle: {
marginTop: 4,
},
tabBarShowLabel: true,
}}
>
<Tab.Screen
name="Dashboard"
component={DashboardScreen}
options={{
headerTitle: 'Dashboard',
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => <TabIcon routeName="Dashboard" color={color} />,
}}
/>
<Tab.Screen
name="DarkWatch"
component={DarkWatchScreen}
options={{
headerTitle: 'DarkWatch',
tabBarLabel: 'DarkWatch',
tabBarIcon: ({ color }) => <TabIcon routeName="DarkWatch" color={color} />,
}}
/>
<Tab.Screen
name="SpamShield"
component={SpamShieldScreen}
options={{
headerTitle: 'SpamShield',
tabBarLabel: 'SpamShield',
tabBarIcon: ({ color }) => <TabIcon routeName="SpamShield" color={color} />,
}}
/>
<Tab.Screen
name="VoicePrint"
component={VoicePrintScreen}
options={{
headerTitle: 'VoicePrint',
tabBarLabel: 'VoicePrint',
tabBarIcon: ({ color }) => <TabIcon routeName="VoicePrint" color={color} />,
}}
/>
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
headerTitle: 'Settings',
tabBarLabel: 'Settings',
tabBarIcon: ({ color }) => <TabIcon routeName="Settings" color={color} />,
}}
/>
</Tab.Navigator>
);
}