improve tab structure
This commit is contained in:
@@ -7,7 +7,7 @@ import { colors, borderRadius, typography } from '../theme/colors';
|
||||
// Screens
|
||||
import FlowScreen from '../screens/FlowScreen';
|
||||
import SentinelScreen from '../screens/SentinelScreen';
|
||||
import HeritageScreen from '../screens/HeritageScreen';
|
||||
// import HeritageScreen from '../screens/HeritageScreen'; // Heritage functionality moved to Me and Sentinel
|
||||
import MeScreen from '../screens/MeScreen';
|
||||
|
||||
const Tab = createBottomTabNavigator();
|
||||
@@ -104,6 +104,7 @@ export default function TabNavigator() {
|
||||
tabBarStyle: styles.tabBarDark,
|
||||
}}
|
||||
/>
|
||||
{/* Heritage tab commented out - functionality moved to Me (Fleet Legacy) and Sentinel (Shadow Vault)
|
||||
<Tab.Screen
|
||||
name="Heritage"
|
||||
component={HeritageScreen}
|
||||
@@ -118,6 +119,7 @@ export default function TabNavigator() {
|
||||
),
|
||||
}}
|
||||
/>
|
||||
*/}
|
||||
<Tab.Screen
|
||||
name="Me"
|
||||
component={MeScreen}
|
||||
|
||||
@@ -9,11 +9,67 @@ import {
|
||||
SafeAreaView,
|
||||
Linking,
|
||||
Alert,
|
||||
TextInput,
|
||||
} 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 { useAuth } from '../context/AuthContext';
|
||||
import { Heir, HeirStatus, PaymentStrategy } from '../types';
|
||||
import HeritageScreen from './HeritageScreen';
|
||||
|
||||
// Mock heirs data
|
||||
const initialHeirs: Heir[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Smith',
|
||||
email: 'john.smith@email.com',
|
||||
phone: '+1 415 555 0132',
|
||||
status: 'confirmed',
|
||||
releaseLevel: 3,
|
||||
releaseOrder: 1,
|
||||
paymentStrategy: 'prepaid',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Jane Doe',
|
||||
email: 'jane.doe@email.com',
|
||||
phone: '+1 212 555 0184',
|
||||
status: 'confirmed',
|
||||
releaseLevel: 2,
|
||||
releaseOrder: 2,
|
||||
paymentStrategy: 'pay_on_access',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Alice Johnson',
|
||||
email: 'alice.j@email.com',
|
||||
phone: '+1 646 555 0149',
|
||||
status: 'invited',
|
||||
releaseLevel: 1,
|
||||
releaseOrder: 3,
|
||||
paymentStrategy: 'pay_on_access',
|
||||
},
|
||||
];
|
||||
|
||||
// Release level descriptions
|
||||
const releaseLevelConfig: Record<number, { label: string; description: string; icon: string }> = {
|
||||
1: {
|
||||
label: 'Journal Summaries',
|
||||
description: 'Captain\'s log excerpts and emotional records',
|
||||
icon: 'book-open',
|
||||
},
|
||||
2: {
|
||||
label: 'Treasure Map',
|
||||
description: 'Asset inventory and metadata',
|
||||
icon: 'map',
|
||||
},
|
||||
3: {
|
||||
label: 'Full Inheritance',
|
||||
description: 'Complete encrypted treasure chest',
|
||||
icon: 'key',
|
||||
},
|
||||
};
|
||||
|
||||
// Sentinel Protocol Status
|
||||
const protocolStatus = {
|
||||
@@ -161,6 +217,19 @@ export default function MeScreen() {
|
||||
const [showSanctumModal, setShowSanctumModal] = useState(false);
|
||||
const [showCaptainFull, setShowCaptainFull] = useState(false);
|
||||
const [showTriggerModal, setShowTriggerModal] = useState(false);
|
||||
const [showHeritageModal, setShowHeritageModal] = useState(false);
|
||||
const [showThemeModal, setShowThemeModal] = useState(false);
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
|
||||
// Heritage / Fleet Legacy states
|
||||
const [heirs, setHeirs] = useState<Heir[]>(initialHeirs);
|
||||
const [showAddHeirModal, setShowAddHeirModal] = useState(false);
|
||||
const [showHeirDetailModal, setShowHeirDetailModal] = useState(false);
|
||||
const [selectedHeir, setSelectedHeir] = useState<Heir | null>(null);
|
||||
const [newHeirName, setNewHeirName] = useState('');
|
||||
const [newHeirEmail, setNewHeirEmail] = useState('');
|
||||
const [newHeirLevel, setNewHeirLevel] = useState(1);
|
||||
const [newHeirPayment, setNewHeirPayment] = useState<PaymentStrategy>('pay_on_access');
|
||||
const [tideLevel, setTideLevel] = useState<'low' | 'high' | 'red'>('low');
|
||||
const [tideChannels, setTideChannels] = useState({
|
||||
push: true,
|
||||
@@ -186,6 +255,44 @@ export default function MeScreen() {
|
||||
Linking.openURL(url).catch(() => { });
|
||||
};
|
||||
|
||||
// Heritage / Fleet Legacy functions
|
||||
const handleAddHeir = () => {
|
||||
if (!newHeirName.trim() || !newHeirEmail.trim()) return;
|
||||
|
||||
const newHeir: Heir = {
|
||||
id: Date.now().toString(),
|
||||
name: newHeirName,
|
||||
email: newHeirEmail,
|
||||
status: 'invited',
|
||||
releaseLevel: newHeirLevel,
|
||||
releaseOrder: heirs.length + 1,
|
||||
paymentStrategy: newHeirPayment,
|
||||
};
|
||||
|
||||
setHeirs([...heirs, newHeir]);
|
||||
resetAddHeirForm();
|
||||
setShowAddHeirModal(false);
|
||||
};
|
||||
|
||||
const resetAddHeirForm = () => {
|
||||
setNewHeirName('');
|
||||
setNewHeirEmail('');
|
||||
setNewHeirLevel(1);
|
||||
setNewHeirPayment('pay_on_access');
|
||||
};
|
||||
|
||||
const handleHeirPress = (heir: Heir) => {
|
||||
setSelectedHeir(heir);
|
||||
setShowHeirDetailModal(true);
|
||||
};
|
||||
|
||||
const getHeirStatusBadge = (status: HeirStatus) => {
|
||||
if (status === 'confirmed') {
|
||||
return { text: 'Aboard', color: '#6BBF8A', icon: 'checkmark-circle' };
|
||||
}
|
||||
return { text: 'Invited', color: colors.nautical.gold, icon: 'time-outline' };
|
||||
};
|
||||
|
||||
const handleAbandonIsland = () => {
|
||||
Alert.alert(
|
||||
'Sign Out',
|
||||
@@ -213,14 +320,6 @@ export default function MeScreen() {
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
>
|
||||
{/* Header with Settings */}
|
||||
<View style={styles.headerRow}>
|
||||
<View style={styles.headerSpacer} />
|
||||
<TouchableOpacity style={styles.settingsButton}>
|
||||
<Ionicons name="moon-outline" size={20} color={colors.me.primary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Profile Card */}
|
||||
<TouchableOpacity
|
||||
style={styles.profileCard}
|
||||
@@ -311,15 +410,23 @@ export default function MeScreen() {
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Abandon Island Button (Logout for now) */}
|
||||
{/* Fleet Legacy - Single Entry Point */}
|
||||
<Text style={styles.sectionTitle}>FLEET LEGACY</Text>
|
||||
<View style={styles.menuCard}>
|
||||
<TouchableOpacity
|
||||
style={styles.abandonButton}
|
||||
onPress={handleAbandonIsland}
|
||||
activeOpacity={0.8}
|
||||
style={styles.menuItem}
|
||||
onPress={() => setShowHeritageModal(true)}
|
||||
>
|
||||
<Feather name="log-out" size={18} color={colors.nautical.coral} />
|
||||
<Text style={styles.abandonButtonText}>SIGN OUT</Text>
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.teal}20` }]}>
|
||||
<MaterialCommunityIcons name="compass-outline" size={22} color={colors.nautical.teal} />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>Manage Heirs</Text>
|
||||
<Text style={styles.menuSubtitle}>{heirs.length} trustees configured</Text>
|
||||
</View>
|
||||
<Feather name="chevron-right" size={18} color={colors.me.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Settings Menu */}
|
||||
<Text style={styles.sectionTitle}>SETTINGS</Text>
|
||||
@@ -335,6 +442,9 @@ export default function MeScreen() {
|
||||
if (item.id === 'trigger') {
|
||||
setShowTriggerModal(true);
|
||||
}
|
||||
if (item.id === 'visual') {
|
||||
setShowThemeModal(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${item.color}15` }]}>
|
||||
@@ -349,44 +459,83 @@ export default function MeScreen() {
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* About Section */}
|
||||
{/* About Section - Vertical List */}
|
||||
<Text style={styles.sectionTitle}>ABOUT</Text>
|
||||
<View style={styles.aboutGrid}>
|
||||
{protocolExplainers.slice(0, 2).map((item) => (
|
||||
<View style={styles.menuCard}>
|
||||
{protocolExplainers.map((item, index) => (
|
||||
<TouchableOpacity
|
||||
key={item.id}
|
||||
style={styles.aboutCard}
|
||||
style={[
|
||||
styles.menuItem,
|
||||
index < protocolExplainers.length - 1 && styles.menuItemBorder
|
||||
]}
|
||||
onPress={() => setSelectedExplainer(item)}
|
||||
>
|
||||
<MaterialCommunityIcons name={item.icon as any} size={24} color={colors.me.primary} />
|
||||
<Text style={styles.aboutTitle}>{item.title}</Text>
|
||||
<Feather name="arrow-up-right" size={14} color={colors.me.textSecondary} />
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.me.primary}15` }]}>
|
||||
<MaterialCommunityIcons name={item.icon as any} size={20} color={colors.me.primary} />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>{item.title}</Text>
|
||||
</View>
|
||||
<Feather name="chevron-right" size={18} color={colors.me.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
<TouchableOpacity
|
||||
style={[styles.menuItem, styles.menuItemBorder]}
|
||||
onPress={() => handleOpenLink('https://github.com/sentinel')}
|
||||
>
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.navy}15` }]}>
|
||||
<Ionicons name="logo-github" size={20} color={colors.nautical.navy} />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>GitHub</Text>
|
||||
<Text style={styles.menuSubtitle}>View source code</Text>
|
||||
</View>
|
||||
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.menuItem, styles.menuItemBorder]}
|
||||
onPress={() => handleOpenLink('https://sentinel.app/privacy')}
|
||||
>
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.sage}15` }]}>
|
||||
<Ionicons name="shield-checkmark-outline" size={20} color={colors.nautical.sage} />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>Privacy Policy</Text>
|
||||
</View>
|
||||
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.menuItem}
|
||||
onPress={() => handleOpenLink('https://sentinel.app/terms')}
|
||||
>
|
||||
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.sage}15` }]}>
|
||||
<Ionicons name="document-text-outline" size={20} color={colors.nautical.sage} />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>Terms of Service</Text>
|
||||
</View>
|
||||
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Sign Out Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.abandonButton}
|
||||
onPress={handleAbandonIsland}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Feather name="log-out" size={18} color={colors.nautical.coral} />
|
||||
<Text style={styles.abandonButtonText}>SIGN OUT</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.footer}>
|
||||
<Text style={styles.footerVersion}>A E T E R N A N A U T I C A V 2 . 0</Text>
|
||||
{/* <Text style={styles.footerVersion}>A E T E R N A N A U T I C A V 2 . 0</Text> */}
|
||||
<Text style={styles.footerTagline}>
|
||||
The sea claims what is forgotten, but the Sanctuary keeps what is loved.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Footer Links */}
|
||||
<View style={styles.footerLinks}>
|
||||
<TouchableOpacity onPress={() => handleOpenLink('https://github.com/sentinel')}>
|
||||
<Text style={styles.footerLink}>GitHub</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.footerDot}>·</Text>
|
||||
<TouchableOpacity onPress={() => handleOpenLink('https://sentinel.app/privacy')}>
|
||||
<Text style={styles.footerLink}>Privacy</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.footerDot}>·</Text>
|
||||
<TouchableOpacity onPress={() => handleOpenLink('https://sentinel.app/terms')}>
|
||||
<Text style={styles.footerLink}>Terms</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
@@ -427,6 +576,114 @@ export default function MeScreen() {
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Heritage Modal - Full HeritageScreen */}
|
||||
<Modal
|
||||
visible={showHeritageModal}
|
||||
animationType="slide"
|
||||
onRequestClose={() => setShowHeritageModal(false)}
|
||||
>
|
||||
<View style={styles.heritageModalContainer}>
|
||||
<HeritageScreen />
|
||||
<TouchableOpacity
|
||||
style={styles.heritageCloseButton}
|
||||
onPress={() => setShowHeritageModal(false)}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<Ionicons name="close" size={20} color={colors.nautical.cream} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Theme Settings Modal */}
|
||||
<Modal
|
||||
visible={showThemeModal}
|
||||
animationType="fade"
|
||||
transparent
|
||||
onRequestClose={() => setShowThemeModal(false)}
|
||||
>
|
||||
<View style={styles.spiritOverlay}>
|
||||
<View style={styles.spiritModal}>
|
||||
<View style={styles.spiritHeader}>
|
||||
<View style={styles.spiritIcon}>
|
||||
<MaterialCommunityIcons name="palette-outline" size={24} color={colors.me.primary} />
|
||||
</View>
|
||||
<Text style={styles.spiritTitle}>Visual Preferences</Text>
|
||||
</View>
|
||||
<ScrollView style={styles.spiritScroll} showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.sanctumSection}>
|
||||
<Text style={styles.tideLabel}>APPEARANCE</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.sanctumToggleRow}
|
||||
onPress={() => setIsDarkMode(!isDarkMode)}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: spacing.sm }}>
|
||||
<Ionicons
|
||||
name={isDarkMode ? 'moon' : 'sunny'}
|
||||
size={18}
|
||||
color={colors.me.primary}
|
||||
/>
|
||||
<Text style={styles.sanctumText}>Dark Mode</Text>
|
||||
</View>
|
||||
<View style={[styles.sanctumToggle, isDarkMode && styles.sanctumToggleOn]}>
|
||||
<Text style={styles.sanctumToggleText}>{isDarkMode ? 'ON' : 'OFF'}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.sanctumSection}>
|
||||
<Text style={styles.tideLabel}>CARD STYLE</Text>
|
||||
<View style={styles.tideRow}>
|
||||
{['Minimal', 'Standard', 'Rich'].map((style) => (
|
||||
<TouchableOpacity
|
||||
key={style}
|
||||
style={[styles.tideButton, style === 'Standard' && styles.tideButtonActive]}
|
||||
>
|
||||
<Text style={[styles.tideButtonText, style === 'Standard' && styles.tideButtonTextActive]}>
|
||||
{style}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.sanctumSection}>
|
||||
<Text style={styles.tideLabel}>FONT SIZE</Text>
|
||||
<View style={styles.tideRow}>
|
||||
{['Small', 'Medium', 'Large'].map((size) => (
|
||||
<TouchableOpacity
|
||||
key={size}
|
||||
style={[styles.tideButton, size === 'Medium' && styles.tideButtonActive]}
|
||||
>
|
||||
<Text style={[styles.tideButtonText, size === 'Medium' && styles.tideButtonTextActive]}>
|
||||
{size}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View style={styles.tideModalButtons}>
|
||||
<TouchableOpacity
|
||||
style={styles.confirmPulseButton}
|
||||
activeOpacity={0.85}
|
||||
onPress={() => setShowThemeModal(false)}
|
||||
>
|
||||
<Ionicons name="checkmark-circle" size={18} color={colors.nautical.teal} />
|
||||
<Text style={styles.confirmPulseText}>Save</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.confirmPulseButton}
|
||||
activeOpacity={0.85}
|
||||
onPress={() => setShowThemeModal(false)}
|
||||
>
|
||||
<Ionicons name="close-circle" size={18} color={colors.nautical.teal} />
|
||||
<Text style={styles.confirmPulseText}>Close</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Spirit Keys Modal */}
|
||||
<Modal
|
||||
@@ -858,6 +1115,170 @@ export default function MeScreen() {
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Add Heir Modal */}
|
||||
<Modal
|
||||
visible={showAddHeirModal}
|
||||
animationType="slide"
|
||||
transparent
|
||||
onRequestClose={() => setShowAddHeirModal(false)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalContent}>
|
||||
<View style={styles.modalHandle} />
|
||||
<View style={styles.modalHeader}>
|
||||
<View style={styles.modalIconContainer}>
|
||||
<FontAwesome5 name="ship" size={20} color={colors.me.primary} />
|
||||
</View>
|
||||
<Text style={styles.modalTitle}>Add to Fleet</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.inputLabel}>NAME *</Text>
|
||||
<TextInput
|
||||
style={styles.heirInput}
|
||||
placeholder="Trustee name"
|
||||
placeholderTextColor={colors.me.textSecondary}
|
||||
value={newHeirName}
|
||||
onChangeText={setNewHeirName}
|
||||
/>
|
||||
|
||||
<Text style={styles.inputLabel}>EMAIL *</Text>
|
||||
<TextInput
|
||||
style={styles.heirInput}
|
||||
placeholder="For invitations and notifications"
|
||||
placeholderTextColor={colors.me.textSecondary}
|
||||
value={newHeirEmail}
|
||||
onChangeText={setNewHeirEmail}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
/>
|
||||
|
||||
<Text style={styles.inputLabel}>INHERITANCE TIER</Text>
|
||||
<View style={styles.tideRow}>
|
||||
{[1, 2, 3].map((level) => (
|
||||
<TouchableOpacity
|
||||
key={level}
|
||||
style={[styles.tideButton, newHeirLevel === level && styles.tideButtonActive]}
|
||||
onPress={() => setNewHeirLevel(level)}
|
||||
>
|
||||
<Text style={[styles.tideButtonText, newHeirLevel === level && styles.tideButtonTextActive]}>
|
||||
Tier {level}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<Text style={styles.inputLabel}>PAYMENT STRATEGY</Text>
|
||||
<View style={styles.tideRow}>
|
||||
<TouchableOpacity
|
||||
style={[styles.tideButton, newHeirPayment === 'prepaid' && styles.tideButtonActive]}
|
||||
onPress={() => setNewHeirPayment('prepaid')}
|
||||
>
|
||||
<Text style={[styles.tideButtonText, newHeirPayment === 'prepaid' && styles.tideButtonTextActive]}>
|
||||
Prepaid
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.tideButton, newHeirPayment === 'pay_on_access' && styles.tideButtonActive]}
|
||||
onPress={() => setNewHeirPayment('pay_on_access')}
|
||||
>
|
||||
<Text style={[styles.tideButtonText, newHeirPayment === 'pay_on_access' && styles.tideButtonTextActive]}>
|
||||
Pay on Access
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.tideModalButtons}>
|
||||
<TouchableOpacity
|
||||
style={styles.confirmPulseButton}
|
||||
onPress={() => {
|
||||
setShowAddHeirModal(false);
|
||||
resetAddHeirForm();
|
||||
}}
|
||||
>
|
||||
<Text style={styles.confirmPulseText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.confirmPulseButton, { backgroundColor: colors.nautical.teal }]}
|
||||
onPress={handleAddHeir}
|
||||
>
|
||||
<Feather name="send" size={16} color="#fff" />
|
||||
<Text style={[styles.confirmPulseText, { color: '#fff' }]}>Send Invitation</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Heir Detail Modal */}
|
||||
<Modal
|
||||
visible={showHeirDetailModal}
|
||||
animationType="fade"
|
||||
transparent
|
||||
onRequestClose={() => setShowHeirDetailModal(false)}
|
||||
>
|
||||
<View style={styles.spiritOverlay}>
|
||||
<View style={styles.spiritModal}>
|
||||
{selectedHeir && (
|
||||
<>
|
||||
<View style={styles.heirDetailHeader}>
|
||||
<View style={styles.heirDetailAvatar}>
|
||||
<FontAwesome5 name="ship" size={28} color={colors.me.primary} />
|
||||
</View>
|
||||
<Text style={styles.heirDetailName}>{selectedHeir.name}</Text>
|
||||
<View style={[
|
||||
styles.heirStatusBadge,
|
||||
{ backgroundColor: `${getHeirStatusBadge(selectedHeir.status).color}15` }
|
||||
]}>
|
||||
<Ionicons
|
||||
name={getHeirStatusBadge(selectedHeir.status).icon as any}
|
||||
size={12}
|
||||
color={getHeirStatusBadge(selectedHeir.status).color}
|
||||
/>
|
||||
<Text style={[styles.heirStatusText, { color: getHeirStatusBadge(selectedHeir.status).color }]}>
|
||||
{getHeirStatusBadge(selectedHeir.status).text}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.heirDetailRows}>
|
||||
<View style={styles.heirDetailRow}>
|
||||
<Feather name="mail" size={16} color={colors.me.textSecondary} />
|
||||
<Text style={styles.heirDetailLabel}>Email</Text>
|
||||
<Text style={styles.heirDetailValue}>{selectedHeir.email}</Text>
|
||||
</View>
|
||||
<View style={styles.heirDetailRow}>
|
||||
<Feather name="hash" size={16} color={colors.me.textSecondary} />
|
||||
<Text style={styles.heirDetailLabel}>Order</Text>
|
||||
<Text style={styles.heirDetailValue}>#{selectedHeir.releaseOrder}</Text>
|
||||
</View>
|
||||
<View style={styles.heirDetailRow}>
|
||||
<Feather name="layers" size={16} color={colors.me.textSecondary} />
|
||||
<Text style={styles.heirDetailLabel}>Tier</Text>
|
||||
<Text style={styles.heirDetailValue}>
|
||||
{selectedHeir.releaseLevel} · {releaseLevelConfig[selectedHeir.releaseLevel].label}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.heirDetailRow}>
|
||||
<FontAwesome5 name="coins" size={14} color={colors.me.textSecondary} />
|
||||
<Text style={styles.heirDetailLabel}>Payment</Text>
|
||||
<Text style={styles.heirDetailValue}>
|
||||
{selectedHeir.paymentStrategy === 'prepaid' ? 'Prepaid' : 'Pay on Access'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.closeButton}
|
||||
onPress={() => setShowHeirDetailModal(false)}
|
||||
>
|
||||
<Text style={styles.closeButtonText}>Close</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Trigger Logic Modal */}
|
||||
<Modal
|
||||
visible={showTriggerModal}
|
||||
@@ -1010,28 +1431,9 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
scrollContent: {
|
||||
paddingHorizontal: spacing.base,
|
||||
paddingTop: spacing.md,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
// Header
|
||||
headerRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: spacing.sm,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
headerSpacer: {
|
||||
width: 40,
|
||||
},
|
||||
settingsButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: colors.me.cardBackground,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...shadows.soft,
|
||||
},
|
||||
// Profile Card
|
||||
profileCard: {
|
||||
backgroundColor: colors.me.cardBackground,
|
||||
@@ -1760,4 +2162,175 @@ const styles = StyleSheet.create({
|
||||
color: colors.me.primary,
|
||||
fontWeight: '600',
|
||||
},
|
||||
// Fleet Legacy styles
|
||||
fleetLegalNotice: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: colors.me.cardBackground,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.base,
|
||||
marginBottom: spacing.md,
|
||||
borderLeftWidth: 4,
|
||||
borderLeftColor: colors.nautical.teal,
|
||||
...shadows.soft,
|
||||
},
|
||||
fleetLegalIcon: {
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
fleetLegalContent: {
|
||||
flex: 1,
|
||||
},
|
||||
fleetLegalTitle: {
|
||||
fontSize: typography.fontSize.base,
|
||||
fontWeight: '600',
|
||||
color: colors.me.text,
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
fleetLegalText: {
|
||||
fontSize: typography.fontSize.sm,
|
||||
color: colors.me.textSecondary,
|
||||
lineHeight: typography.fontSize.sm * 1.5,
|
||||
},
|
||||
fleetHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
padding: spacing.base,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.me.cardBorder,
|
||||
},
|
||||
fleetHeaderTitle: {
|
||||
flex: 1,
|
||||
fontSize: typography.fontSize.xs,
|
||||
fontWeight: '700',
|
||||
color: colors.me.textSecondary,
|
||||
letterSpacing: typography.letterSpacing.widest,
|
||||
},
|
||||
fleetCountBadge: {
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 4,
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
fleetCountText: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
fontWeight: '600',
|
||||
color: colors.nautical.teal,
|
||||
},
|
||||
heirAvatar: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
heirNameRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
heirStatusBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 2,
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
heirStatusText: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
fontWeight: '600',
|
||||
},
|
||||
addTrusteeButton: {
|
||||
borderRadius: borderRadius.lg,
|
||||
overflow: 'hidden',
|
||||
marginBottom: spacing.md,
|
||||
...shadows.soft,
|
||||
},
|
||||
addTrusteeGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
addTrusteeText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
fontWeight: '700',
|
||||
color: '#fff',
|
||||
},
|
||||
inputLabel: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.me.textSecondary,
|
||||
marginBottom: spacing.xs,
|
||||
marginTop: spacing.md,
|
||||
fontWeight: '600',
|
||||
letterSpacing: typography.letterSpacing.wide,
|
||||
},
|
||||
heirInput: {
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.base,
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.me.text,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.me.cardBorder,
|
||||
},
|
||||
heirDetailHeader: {
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.lg,
|
||||
paddingBottom: spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.me.cardBorder,
|
||||
},
|
||||
heirDetailAvatar: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
borderRadius: 36,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
heirDetailName: {
|
||||
fontSize: typography.fontSize.lg,
|
||||
fontWeight: '600',
|
||||
color: colors.me.text,
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
heirDetailRows: {
|
||||
gap: spacing.md,
|
||||
},
|
||||
heirDetailRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
heirDetailLabel: {
|
||||
flex: 1,
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.me.textSecondary,
|
||||
},
|
||||
heirDetailValue: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.me.text,
|
||||
fontWeight: '600',
|
||||
},
|
||||
// Heritage Modal
|
||||
heritageModalContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
heritageCloseButton: {
|
||||
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',
|
||||
zIndex: 10,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,11 +7,13 @@ import {
|
||||
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<SystemStatus, {
|
||||
@@ -76,6 +78,7 @@ export default function SentinelScreen() {
|
||||
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
|
||||
@@ -270,6 +273,26 @@ export default function SentinelScreen() {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Shadow Vault Access */}
|
||||
<View style={styles.vaultAccessCard}>
|
||||
<View style={styles.vaultAccessIcon}>
|
||||
<MaterialCommunityIcons name="treasure-chest" size={22} color={colors.nautical.teal} />
|
||||
</View>
|
||||
<View style={styles.vaultAccessContent}>
|
||||
<Text style={styles.vaultAccessTitle}>Shadow Vault</Text>
|
||||
<Text style={styles.vaultAccessText}>
|
||||
Access sealed assets from the Lighthouse.
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.vaultAccessButton}
|
||||
onPress={() => setShowVault(true)}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Text style={styles.vaultAccessButtonText}>Open</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Heartbeat Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.heartbeatButton}
|
||||
@@ -313,6 +336,24 @@ export default function SentinelScreen() {
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Vault Modal */}
|
||||
<Modal
|
||||
visible={showVault}
|
||||
animationType="slide"
|
||||
onRequestClose={() => setShowVault(false)}
|
||||
>
|
||||
<View style={styles.vaultModalContainer}>
|
||||
<VaultScreen />
|
||||
<TouchableOpacity
|
||||
style={styles.vaultCloseButton}
|
||||
onPress={() => setShowVault(false)}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<Ionicons name="close" size={20} color={colors.nautical.cream} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -513,4 +554,64 @@ const styles = StyleSheet.create({
|
||||
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',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user