239 lines
6.1 KiB
TypeScript
239 lines
6.1 KiB
TypeScript
import {
|
|
View, Text, ScrollView, TouchableOpacity, Linking, ActivityIndicator, StyleSheet,
|
|
} from 'react-native'
|
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
|
import { useLocalSearchParams, useRouter } from 'expo-router'
|
|
import { Ionicons } from '@expo/vector-icons'
|
|
import { useMemberDetail } from '@/hooks/useMembers'
|
|
import { Avatar } from '@/components/ui/Avatar'
|
|
|
|
export default function MemberDetailScreen() {
|
|
const { id } = useLocalSearchParams<{ id: string }>()
|
|
const router = useRouter()
|
|
const { data: member, isLoading } = useMemberDetail(id)
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<SafeAreaView style={styles.loadingContainer}>
|
|
<ActivityIndicator size="large" color="#003B7E" />
|
|
</SafeAreaView>
|
|
)
|
|
}
|
|
if (!member) return null
|
|
|
|
const fields = [
|
|
member.sparte ? ['SPARTE', member.sparte] : null,
|
|
member.ort ? ['ORT', member.ort] : null,
|
|
member.seit ? ['MITGLIED SEIT', String(member.seit)] : null,
|
|
].filter(Boolean) as [string, string][]
|
|
|
|
return (
|
|
<SafeAreaView style={styles.safeArea} edges={['top']}>
|
|
{/* Nav */}
|
|
<View style={styles.navBar}>
|
|
<TouchableOpacity onPress={() => router.back()} style={styles.backBtn} activeOpacity={0.7}>
|
|
<Ionicons name="chevron-back" size={20} color="#003B7E" />
|
|
<Text style={styles.backText}>Zurück</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={styles.divider} />
|
|
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
{/* Hero */}
|
|
<View style={styles.hero}>
|
|
<Avatar name={member.name} imageUrl={member.avatarUrl ?? undefined} size={80} shadow />
|
|
<Text style={styles.heroName}>{member.name}</Text>
|
|
<Text style={styles.heroCompany}>{member.betrieb}</Text>
|
|
{member.istAusbildungsbetrieb && (
|
|
<View style={styles.ausbildungPill}>
|
|
<Ionicons name="school" size={12} color="#15803D" />
|
|
<Text style={styles.ausbildungText}>Ausbildungsbetrieb</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
|
|
<View style={styles.divider} />
|
|
|
|
{/* Details */}
|
|
<View style={styles.card}>
|
|
{fields.map(([label, value], idx) => (
|
|
<View
|
|
key={label}
|
|
style={[styles.fieldRow, idx < fields.length - 1 && styles.fieldRowBorder]}
|
|
>
|
|
<Text style={styles.fieldLabel}>{label}</Text>
|
|
<Text style={styles.fieldValue}>{value}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
|
|
{/* Actions */}
|
|
<View style={styles.actions}>
|
|
{member.telefon && (
|
|
<TouchableOpacity
|
|
onPress={() => Linking.openURL(`tel:${member.telefon}`)}
|
|
style={styles.btnPrimary}
|
|
activeOpacity={0.82}
|
|
>
|
|
<Ionicons name="call" size={18} color="#FFFFFF" />
|
|
<Text style={styles.btnPrimaryText}>Anrufen</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
<TouchableOpacity
|
|
onPress={() => Linking.openURL(`mailto:${member.email}`)}
|
|
style={styles.btnSecondary}
|
|
activeOpacity={0.8}
|
|
>
|
|
<Ionicons name="mail-outline" size={18} color="#0F172A" />
|
|
<Text style={styles.btnSecondaryText}>E-Mail senden</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
safeArea: {
|
|
flex: 1,
|
|
backgroundColor: '#F8FAFC',
|
|
},
|
|
loadingContainer: {
|
|
flex: 1,
|
|
backgroundColor: '#FFFFFF',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
navBar: {
|
|
backgroundColor: '#FFFFFF',
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
},
|
|
backBtn: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 2,
|
|
},
|
|
backText: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#003B7E',
|
|
},
|
|
divider: {
|
|
height: 1,
|
|
backgroundColor: '#E2E8F0',
|
|
},
|
|
hero: {
|
|
backgroundColor: '#FFFFFF',
|
|
alignItems: 'center',
|
|
paddingVertical: 32,
|
|
paddingHorizontal: 24,
|
|
},
|
|
heroName: {
|
|
fontSize: 21,
|
|
fontWeight: '800',
|
|
color: '#0F172A',
|
|
letterSpacing: -0.4,
|
|
marginTop: 14,
|
|
textAlign: 'center',
|
|
},
|
|
heroCompany: {
|
|
fontSize: 14,
|
|
color: '#475569',
|
|
marginTop: 3,
|
|
textAlign: 'center',
|
|
},
|
|
ausbildungPill: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 5,
|
|
backgroundColor: '#F0FDF4',
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 6,
|
|
borderRadius: 99,
|
|
marginTop: 10,
|
|
},
|
|
ausbildungText: {
|
|
fontSize: 12,
|
|
color: '#15803D',
|
|
fontWeight: '600',
|
|
},
|
|
card: {
|
|
backgroundColor: '#FFFFFF',
|
|
marginHorizontal: 16,
|
|
marginTop: 16,
|
|
borderRadius: 16,
|
|
overflow: 'hidden',
|
|
shadowColor: '#1C1917',
|
|
shadowOffset: { width: 0, height: 1 },
|
|
shadowOpacity: 0.05,
|
|
shadowRadius: 8,
|
|
elevation: 1,
|
|
},
|
|
fieldRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 13,
|
|
},
|
|
fieldRowBorder: {
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: '#F9F9F9',
|
|
},
|
|
fieldLabel: {
|
|
fontSize: 10,
|
|
fontWeight: '700',
|
|
color: '#64748B',
|
|
letterSpacing: 0.8,
|
|
width: 110,
|
|
},
|
|
fieldValue: {
|
|
flex: 1,
|
|
fontSize: 14,
|
|
fontWeight: '500',
|
|
color: '#0F172A',
|
|
},
|
|
actions: {
|
|
marginHorizontal: 16,
|
|
marginTop: 16,
|
|
marginBottom: 32,
|
|
gap: 10,
|
|
},
|
|
btnPrimary: {
|
|
backgroundColor: '#003B7E',
|
|
borderRadius: 14,
|
|
paddingVertical: 15,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 8,
|
|
shadowColor: '#003B7E',
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.24,
|
|
shadowRadius: 10,
|
|
elevation: 5,
|
|
},
|
|
btnPrimaryText: {
|
|
color: '#FFFFFF',
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
letterSpacing: 0.2,
|
|
},
|
|
btnSecondary: {
|
|
backgroundColor: '#FFFFFF',
|
|
borderRadius: 14,
|
|
paddingVertical: 15,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 8,
|
|
borderWidth: 1,
|
|
borderColor: '#E2E8F0',
|
|
},
|
|
btnSecondaryText: {
|
|
color: '#0F172A',
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
},
|
|
})
|