Files
Kordant/packages/mobile/src/components/Button.tsx
Michael Freno a071aa736e 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>
2026-05-17 10:12:46 -04:00

66 lines
1.5 KiB
TypeScript

import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { COLORS, BORDER_RADIUS, FONT_SIZES } from '@/constants/theme';
interface ButtonProps {
title: string;
onPress: () => void;
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
disabled?: boolean;
loading?: boolean;
fullWidth?: boolean;
}
export function Button({
title,
onPress,
variant = 'primary',
disabled = false,
loading = false,
fullWidth = false,
}: ButtonProps) {
const variantColors = {
primary: { bg: COLORS.primary, text: '#fff' },
secondary: { bg: COLORS.secondary, text: '#fff' },
danger: { bg: COLORS.danger, text: '#fff' },
ghost: { bg: 'transparent', text: COLORS.primary },
};
const colors = variantColors[variant];
return (
<TouchableOpacity
style={[
styles.button,
{ backgroundColor: colors.bg, opacity: disabled || loading ? 0.5 : 1 },
fullWidth && styles.fullWidth,
]}
onPress={onPress}
disabled={disabled || loading}
activeOpacity={0.7}
>
<Text style={[styles.text, { color: colors.text }]}>
{loading ? '...' : title}
</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
button: {
borderRadius: BORDER_RADIUS.md,
paddingVertical: 12,
paddingHorizontal: 24,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 4,
},
fullWidth: {
width: '100%',
},
text: {
fontSize: FONT_SIZES.md,
fontWeight: '600',
},
});