134 lines
3.3 KiB
TypeScript
134 lines
3.3 KiB
TypeScript
import Feather from "@expo/vector-icons/Feather";
|
|
import { router } from "expo-router";
|
|
import React from "react";
|
|
import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
|
|
export type PersonLite = {
|
|
id?: number;
|
|
personId?: number;
|
|
name?: string;
|
|
birthDate?: string | null;
|
|
imageUrl?: string | null;
|
|
};
|
|
|
|
const calcAge = (birthDate?: string | null): number | null => {
|
|
if (!birthDate) return null;
|
|
const d = new Date(birthDate);
|
|
if (isNaN(d.getTime())) return null;
|
|
const today = new Date();
|
|
let age = today.getFullYear() - d.getFullYear();
|
|
const m = today.getMonth() - d.getMonth();
|
|
if (m < 0 || (m === 0 && today.getDate() < d.getDate())) age--;
|
|
return age < 0 || age > 130 ? null : age;
|
|
};
|
|
|
|
type Props = {
|
|
person: any;
|
|
isFirst?: boolean;
|
|
isLast?: boolean;
|
|
};
|
|
|
|
export default function PersonRow({ person, isFirst, isLast }: Props) {
|
|
const age = calcAge(person.birthDate);
|
|
const id = person.personId ?? person.id;
|
|
const imageUrl = person.imageUrl ?? person.imageUri ?? null;
|
|
const isPravatar = imageUrl?.includes("pravatar");
|
|
|
|
const goToPerson = React.useCallback(
|
|
(id: number) => {
|
|
router.push({
|
|
pathname: "/participant",
|
|
params: {
|
|
participantId: String(id),
|
|
name: person.name,
|
|
imageUri: imageUrl || "",
|
|
},
|
|
});
|
|
},
|
|
[person.name, imageUrl],
|
|
);
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
onPress={() => goToPerson(Number(id))}
|
|
style={[
|
|
styles.personRow,
|
|
isFirst && styles.firstRow,
|
|
isLast && styles.lastRow,
|
|
]}
|
|
activeOpacity={0.6}
|
|
>
|
|
<View style={styles.avatarCircle}>
|
|
{imageUrl && !isPravatar ? (
|
|
<Image
|
|
source={{ uri: imageUrl }}
|
|
style={styles.avatarImage}
|
|
resizeMode="cover"
|
|
/>
|
|
) : (
|
|
<Feather name="user" size={20} color="rgba(255,255,255,0.7)" />
|
|
)}
|
|
</View>
|
|
<View style={styles.content}>
|
|
<View style={{ flex: 1 }}>
|
|
<Text style={styles.personName}>{person.name || "Unbekannt"}</Text>
|
|
{age != null && <Text style={styles.personMeta}>{age} Jahre</Text>}
|
|
</View>
|
|
<Feather name="chevron-right" size={16} color="rgba(255,255,255,0.3)" />
|
|
</View>
|
|
</TouchableOpacity>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
personRow: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
backgroundColor: "rgba(255,255,255,0.06)",
|
|
paddingLeft: 16,
|
|
minHeight: 56,
|
|
},
|
|
firstRow: {
|
|
borderTopLeftRadius: 10,
|
|
borderTopRightRadius: 10,
|
|
},
|
|
lastRow: {
|
|
borderBottomLeftRadius: 10,
|
|
borderBottomRightRadius: 10,
|
|
},
|
|
avatarCircle: {
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: 18,
|
|
backgroundColor: "rgba(255,255,255,0.1)",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
marginRight: 12,
|
|
overflow: "hidden",
|
|
},
|
|
avatarImage: {
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: 18,
|
|
},
|
|
content: {
|
|
flex: 1,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
paddingRight: 16,
|
|
paddingVertical: 12,
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
borderBottomColor: "rgba(255,255,255,0.08)",
|
|
},
|
|
personName: {
|
|
color: "white",
|
|
fontSize: 17,
|
|
fontWeight: "400",
|
|
},
|
|
personMeta: {
|
|
color: "rgba(255,255,255,0.5)",
|
|
fontSize: 14,
|
|
marginTop: 1,
|
|
},
|
|
});
|