import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, SafeAreaView, Animated, Modal, } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import { Ionicons, Feather, MaterialCommunityIcons, FontAwesome5 } from '@expo/vector-icons'; import { colors, typography, spacing, borderRadius, shadows } from '../theme/colors'; import { SystemStatus, KillSwitchLog } from '../types'; import VaultScreen from './VaultScreen'; // Status configuration with nautical theme const statusConfig: Record = { normal: { color: colors.sentinel.statusNormal, label: 'ALL CLEAR', icon: 'checkmark-circle', description: 'The lighthouse burns bright. All systems nominal.', gradientColors: ['#6BBF8A', '#4A9F6A'], }, warning: { color: colors.sentinel.statusWarning, label: 'STORM WARNING', icon: 'warning', description: 'Anomaly detected. Captain\'s attention required.', gradientColors: ['#E5B873', '#C99953'], }, releasing: { color: colors.sentinel.statusCritical, label: 'RELEASE ACTIVE', icon: 'alert-circle', description: 'Legacy release protocol initiated.', gradientColors: ['#E57373', '#C55353'], }, }; // Mock data const initialLogs: KillSwitchLog[] = [ { id: '1', action: 'HEARTBEAT_CONFIRMED', timestamp: new Date('2024-01-18T09:30:00'), }, { id: '2', action: 'SUBSCRIPTION_VERIFIED', timestamp: new Date('2024-01-17T00:00:00'), }, { id: '3', action: 'JOURNAL_ACTIVITY', timestamp: new Date('2024-01-16T15:42:00'), }, { id: '4', action: 'HEARTBEAT_CONFIRMED', timestamp: new Date('2024-01-15T11:20:00'), }, ]; export default function SentinelScreen() { const [status, setStatus] = useState('normal'); const [lastSubscriptionCheck] = useState(new Date('2024-01-18T00:00:00')); const [lastFlowActivity] = useState(new Date('2024-01-18T10:30:00')); const [logs, setLogs] = useState(initialLogs); const [pulseAnim] = useState(new Animated.Value(1)); const [glowAnim] = useState(new Animated.Value(0.5)); const [rotateAnim] = useState(new Animated.Value(0)); const [showVault, setShowVault] = useState(false); useEffect(() => { // Pulse animation Animated.loop( Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1.06, duration: 1200, useNativeDriver: true, }), Animated.timing(pulseAnim, { toValue: 1, duration: 1200, useNativeDriver: true, }), ]) ).start(); // Glow animation Animated.loop( Animated.sequence([ Animated.timing(glowAnim, { toValue: 1, duration: 1500, useNativeDriver: true, }), Animated.timing(glowAnim, { toValue: 0.5, duration: 1500, useNativeDriver: true, }), ]) ).start(); // Slow rotate for ship wheel Animated.loop( Animated.timing(rotateAnim, { toValue: 1, duration: 30000, useNativeDriver: true, }) ).start(); }, []); const openVault = () => { setShowVault(true); }; const handleHeartbeat = () => { // Animate pulse Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1.15, duration: 150, useNativeDriver: true, }), Animated.timing(pulseAnim, { toValue: 1, duration: 150, useNativeDriver: true, }), ]).start(); // Add new log const newLog: KillSwitchLog = { id: Date.now().toString(), action: 'HEARTBEAT_CONFIRMED', timestamp: new Date(), }; setLogs([newLog, ...logs]); // Reset status if warning if (status === 'warning') { setStatus('normal'); } }; const formatDateTime = (date: Date) => { return date.toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }); }; const formatTimeAgo = (date: Date) => { const now = new Date(); const diff = now.getTime() - date.getTime(); const hours = Math.floor(diff / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); if (hours > 24) { const days = Math.floor(hours / 24); return `${days} days ago`; } if (hours > 0) { return `${hours}h ${minutes}m ago`; } return `${minutes}m ago`; }; const currentStatus = statusConfig[status]; const spin = rotateAnim.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'], }); return ( {/* Header */} LIGHTHOUSE The Watchful Guardian {/* Status Display */} {currentStatus.label} {currentStatus.description} {/* Ship Wheel Watermark */} {/* Metrics Grid */} SUBSCRIPTION {formatTimeAgo(lastSubscriptionCheck)} {formatDateTime(lastSubscriptionCheck)} LAST JOURNAL {formatTimeAgo(lastFlowActivity)} {formatDateTime(lastFlowActivity)} {/* Shadow Vault Access */} Shadow Vault Access sealed assets from the Lighthouse. Open {/* Heartbeat Button */} SIGNAL THE WATCH Confirm your presence, Captain {/* Watch Log */} WATCH LOG {logs.map((log) => ( {log.action} {formatDateTime(log.timestamp)} ))} {/* Vault Modal */} setShowVault(false)} > {showVault ? : null} setShowVault(false)} activeOpacity={0.85} > ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradient: { flex: 1, }, safeArea: { flex: 1, }, scrollView: { flex: 1, }, scrollContent: { padding: spacing.lg, paddingBottom: 120, }, header: { marginBottom: spacing.xl, }, headerTitleRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.xs, }, title: { fontSize: typography.fontSize.xl, fontWeight: '700', color: colors.sentinel.text, letterSpacing: typography.letterSpacing.widest, fontFamily: typography.fontFamily.serif, }, subtitle: { fontSize: typography.fontSize.sm, color: colors.sentinel.textSecondary, marginLeft: spacing.xl + spacing.sm, fontStyle: 'italic', }, statusContainer: { alignItems: 'center', paddingVertical: spacing.xl, marginBottom: spacing.lg, position: 'relative', }, statusCircleOuter: { position: 'absolute', width: 170, height: 170, borderRadius: 85, }, statusCircle: { width: 140, height: 140, borderRadius: 70, justifyContent: 'center', alignItems: 'center', marginBottom: spacing.md, ...shadows.glow, }, statusLabel: { fontSize: typography.fontSize.xl, fontWeight: '700', letterSpacing: typography.letterSpacing.widest, marginBottom: spacing.sm, }, statusDescription: { fontSize: typography.fontSize.base, color: colors.sentinel.textSecondary, textAlign: 'center', maxWidth: 280, fontStyle: 'italic', }, wheelWatermark: { position: 'absolute', top: 200, right: -60, opacity: 0.5, }, metricsGrid: { flexDirection: 'row', gap: spacing.md, marginBottom: spacing.lg, }, metricCard: { flex: 1, backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.xl, padding: spacing.base, borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, metricIconContainer: { width: 40, height: 40, borderRadius: 20, backgroundColor: `${colors.sentinel.primary}15`, justifyContent: 'center', alignItems: 'center', marginBottom: spacing.sm, }, metricLabel: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, letterSpacing: typography.letterSpacing.wide, marginBottom: spacing.xs, fontWeight: '600', }, metricValue: { fontSize: typography.fontSize.md, color: colors.sentinel.text, fontWeight: '700', marginBottom: spacing.xs, }, metricTime: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, fontFamily: typography.fontFamily.mono, }, heartbeatButton: { borderRadius: borderRadius.xl, overflow: 'hidden', marginBottom: spacing.xl, ...shadows.medium, }, heartbeatGradient: { padding: spacing.lg, }, heartbeatContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: spacing.md, }, heartbeatText: { fontSize: typography.fontSize.lg, fontWeight: '700', color: '#fff', letterSpacing: typography.letterSpacing.wider, }, heartbeatSubtext: { fontSize: typography.fontSize.sm, color: 'rgba(255, 255, 255, 0.8)', marginTop: 2, fontStyle: 'italic', }, logsSection: { backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.xl, padding: spacing.base, borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, logsSectionHeader: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.md, paddingBottom: spacing.sm, borderBottomWidth: 1, borderBottomColor: colors.sentinel.cardBorder, }, logsSectionTitle: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, letterSpacing: typography.letterSpacing.widest, fontWeight: '700', }, logItem: { flexDirection: 'row', alignItems: 'flex-start', paddingVertical: spacing.sm, }, logDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: colors.sentinel.primary, marginTop: 6, marginRight: spacing.md, }, logContent: { flex: 1, }, logAction: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, fontFamily: typography.fontFamily.mono, fontWeight: '500', marginBottom: 2, }, logTime: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, fontFamily: typography.fontFamily.mono, }, // Shadow Vault Access Card vaultAccessCard: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.xl, padding: spacing.base, marginBottom: spacing.lg, borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, vaultAccessIcon: { width: 44, height: 44, borderRadius: 22, backgroundColor: `${colors.nautical.teal}20`, alignItems: 'center', justifyContent: 'center', marginRight: spacing.md, }, vaultAccessContent: { flex: 1, }, vaultAccessTitle: { fontSize: typography.fontSize.base, fontWeight: '600', color: colors.sentinel.text, marginBottom: 2, }, vaultAccessText: { fontSize: typography.fontSize.sm, color: colors.sentinel.textSecondary, }, vaultAccessButton: { backgroundColor: colors.nautical.teal, paddingHorizontal: spacing.md, paddingVertical: spacing.sm, borderRadius: borderRadius.full, }, vaultAccessButtonText: { color: colors.nautical.cream, fontWeight: '700', fontSize: typography.fontSize.sm, }, // Vault Modal vaultModalContainer: { flex: 1, backgroundColor: colors.vault.background, }, vaultCloseButton: { position: 'absolute', top: spacing.xl + spacing.lg, right: spacing.lg, width: 36, height: 36, borderRadius: 18, backgroundColor: 'rgba(26, 58, 74, 0.65)', alignItems: 'center', justifyContent: 'center', }, });