Files
task-team/mobile/app/(tabs)/settings.tsx
Admin db81100b5b React Native Expo app — full mobile client
- Expo SDK 54, expo-router, NativeWind
- 7 screens: login, tasks, calendar, goals, chat, settings, tabs
- API client (api.hasdo.info), SecureStore auth, AuthContext
- Tab navigation: Ukoly, Kalendar, Cile, Chat, Nastaveni
- Pull-to-refresh, FAB, group colors, priority dots
- Calendar grid with task dots
- AI chat with keyboard avoiding
- Web export verified (780 modules, 1.5MB bundle)
- Bundle ID: info.hasdo.taskteam

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:09:35 +00:00

221 lines
6.1 KiB
TypeScript

import { useState } from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
Switch,
Alert,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useAuthContext } from '../../lib/AuthContext';
import Constants from 'expo-constants';
export default function SettingsScreen() {
const { user, logout } = useAuthContext();
const [darkMode, setDarkMode] = useState(false);
const [notifications, setNotifications] = useState(true);
const [language, setLanguage] = useState<'cs' | 'en'>('cs');
const handleLogout = () => {
Alert.alert(
'Odhlaseni',
'Opravdu se chcete odhlasit?',
[
{ text: 'Zrusit', style: 'cancel' },
{
text: 'Odhlasit',
style: 'destructive',
onPress: logout,
},
],
);
};
const renderSection = (title: string, children: React.ReactNode) => (
<View style={styles.section}>
<Text style={styles.sectionTitle}>{title}</Text>
<View style={styles.sectionContent}>{children}</View>
</View>
);
const renderRow = (
icon: string,
label: string,
right?: React.ReactNode,
onPress?: () => void,
) => (
<TouchableOpacity
style={styles.row}
onPress={onPress}
disabled={!onPress && !right}
activeOpacity={onPress ? 0.7 : 1}
>
<View style={styles.rowLeft}>
<Ionicons name={icon as any} size={20} color="#64748B" />
<Text style={styles.rowLabel}>{label}</Text>
</View>
{right || (onPress && <Ionicons name="chevron-forward" size={18} color="#CBD5E1" />)}
</TouchableOpacity>
);
return (
<ScrollView style={styles.container}>
{/* User card */}
<View style={styles.userCard}>
<View style={styles.userAvatar}>
<Text style={styles.userAvatarText}>
{(user?.name || 'U')[0].toUpperCase()}
</Text>
</View>
<View style={styles.userInfo}>
<Text style={styles.userName}>{user?.name || 'Uzivatel'}</Text>
<Text style={styles.userEmail}>{user?.email || ''}</Text>
</View>
</View>
{renderSection('Predvolby', (
<>
{renderRow(
'moon-outline',
'Tmavy rezim',
<Switch
value={darkMode}
onValueChange={setDarkMode}
trackColor={{ false: '#E2E8F0', true: '#3B82F6' }}
/>,
)}
{renderRow(
'notifications-outline',
'Oznameni',
<Switch
value={notifications}
onValueChange={setNotifications}
trackColor={{ false: '#E2E8F0', true: '#3B82F6' }}
/>,
)}
{renderRow(
'language-outline',
'Jazyk',
<TouchableOpacity
style={styles.langToggle}
onPress={() => setLanguage(language === 'cs' ? 'en' : 'cs')}
>
<Text style={styles.langText}>
{language === 'cs' ? 'Cestina' : 'English'}
</Text>
</TouchableOpacity>,
)}
</>
))}
{renderSection('Ucet', (
<>
{renderRow('person-outline', 'Upravit profil', undefined, () =>
Alert.alert('Info', 'Bude k dispozici brzy'),
)}
{renderRow('lock-closed-outline', 'Zmenit heslo', undefined, () =>
Alert.alert('Info', 'Bude k dispozici brzy'),
)}
</>
))}
{renderSection('Informace', (
<>
{renderRow('information-circle-outline', 'Verze', (
<Text style={styles.versionText}>
{Constants.expoConfig?.version || '1.0.0'}
</Text>
))}
{renderRow('document-text-outline', 'Podminky pouziti', undefined, () =>
Alert.alert('Info', 'Bude k dispozici brzy'),
)}
</>
))}
{/* Logout */}
<TouchableOpacity style={styles.logoutBtn} onPress={handleLogout}>
<Ionicons name="log-out-outline" size={20} color="#EF4444" />
<Text style={styles.logoutText}>Odhlasit se</Text>
</TouchableOpacity>
<View style={{ height: 40 }} />
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#F8FAFC' },
userCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#fff',
padding: 20,
margin: 12,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 3,
elevation: 2,
},
userAvatar: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: '#3B82F6',
alignItems: 'center',
justifyContent: 'center',
},
userAvatarText: { color: '#fff', fontSize: 22, fontWeight: '700' },
userInfo: { marginLeft: 16, flex: 1 },
userName: { fontSize: 18, fontWeight: '600', color: '#1E293B' },
userEmail: { fontSize: 14, color: '#64748B', marginTop: 2 },
section: { marginTop: 12, marginHorizontal: 12 },
sectionTitle: {
fontSize: 13,
fontWeight: '600',
color: '#64748B',
textTransform: 'uppercase',
marginBottom: 6,
marginLeft: 4,
},
sectionContent: {
backgroundColor: '#fff',
borderRadius: 12,
overflow: 'hidden',
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 14,
borderBottomWidth: 1,
borderBottomColor: '#F1F5F9',
},
rowLeft: { flexDirection: 'row', alignItems: 'center', gap: 12 },
rowLabel: { fontSize: 15, color: '#1E293B' },
langToggle: {
backgroundColor: '#F1F5F9',
paddingHorizontal: 12,
paddingVertical: 4,
borderRadius: 8,
},
langText: { fontSize: 13, color: '#3B82F6', fontWeight: '600' },
versionText: { fontSize: 14, color: '#94A3B8' },
logoutBtn: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
marginTop: 24,
marginHorizontal: 12,
paddingVertical: 14,
backgroundColor: '#FEF2F2',
borderRadius: 12,
},
logoutText: { color: '#EF4444', fontSize: 16, fontWeight: '600' },
});