218 lines
6.2 KiB
TypeScript
218 lines
6.2 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
FlatList,
|
|
RefreshControl,
|
|
} from 'react-native';
|
|
import LucideIcon from '../../components/common/LucideIcon';
|
|
import { responsiveFontSize } from 'react-native-responsive-dimensions';
|
|
import AppView from '../../components/AppView';
|
|
import { useTheme } from '../../hooks/ui/useTheme';
|
|
import { useFetch } from '../../hooks/core/useFetch';
|
|
import { BASE_URL } from '../../utils/ApiUrls';
|
|
import FontsFamily from '../../constents/FontsFamily';
|
|
import SkeletonLoader from '../../components/common/SkeletonLoader';
|
|
|
|
interface Member {
|
|
id: string;
|
|
userId: number;
|
|
firstName: string;
|
|
lastName: string | null;
|
|
mobile: string;
|
|
gender: string;
|
|
email: string;
|
|
username: string;
|
|
address: string;
|
|
role: 'USER' | 'ORGANIZER';
|
|
}
|
|
|
|
const MemberScreen = ({ route }: any) => {
|
|
const theme = useTheme();
|
|
const { groupId } = route?.params || {};
|
|
|
|
const { data: membersRes, isLoading, refetch } = useFetch<any>(
|
|
`${BASE_URL}fund/group/all/member?groupId=${groupId}`,
|
|
{ enabled: !!groupId }
|
|
);
|
|
|
|
const members: Member[] = membersRes?.data || [];
|
|
|
|
const renderItem = ({ item }: { item: Member }) => {
|
|
const fullName = `${item.firstName} ${item.lastName || ''}`.trim();
|
|
const initial = item.firstName ? item.firstName.charAt(0).toUpperCase() : '?';
|
|
const isOrganizer = item.role === 'ORGANIZER';
|
|
|
|
return (
|
|
<View style={[styles.card, { backgroundColor: theme.colors.surface, borderColor: theme.colors.border }]}>
|
|
<View style={[styles.avatarPlaceholder, { backgroundColor: theme.colors.background }]}>
|
|
<Text style={[styles.avatarText, { color: theme.colors.textPrimary }]}>{initial}</Text>
|
|
</View>
|
|
<View style={styles.infoContainer}>
|
|
<View style={styles.nameRow}>
|
|
<Text style={[styles.name, { color: theme.colors.textPrimary }]}>{fullName}</Text>
|
|
{isOrganizer && (
|
|
<View style={[styles.badge, { backgroundColor: theme.colors.primary }]}>
|
|
<Text style={[styles.badgeText, { color: theme.colors.onPrimary }]}>Organizer</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
<Text style={[styles.username, { color: theme.colors.textSecondary }]}>@{item.username}</Text>
|
|
<View style={styles.contactInfo}>
|
|
<LucideIcon name="call-outline" size={12} color={theme.colors.textMuted} />
|
|
<Text style={[styles.contactText, { color: theme.colors.textMuted }]}>{item.mobile}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const renderSkeletons = () => (
|
|
<View style={styles.skeletonList}>
|
|
{[1, 2, 3, 4, 5].map(i => (
|
|
<SkeletonLoader key={i} width="100%" height={80} style={{ marginBottom: 12, borderRadius: 12 }} />
|
|
))}
|
|
</View>
|
|
);
|
|
|
|
return (
|
|
<AppView paddingHorizontal={0}>
|
|
<View style={styles.header}>
|
|
<Text style={[styles.headerTitle, { color: theme.colors.textPrimary }]}>Group Members</Text>
|
|
<Text style={[styles.headerSubtitle, { color: theme.colors.textSecondary }]}>
|
|
{members.length} member{members.length !== 1 ? 's' : ''} in this circle
|
|
</Text>
|
|
</View>
|
|
|
|
{isLoading ? (
|
|
renderSkeletons()
|
|
) : (
|
|
<FlatList
|
|
data={members}
|
|
renderItem={renderItem}
|
|
keyExtractor={item => item.id}
|
|
contentContainerStyle={styles.listContainer}
|
|
showsVerticalScrollIndicator={false}
|
|
refreshControl={
|
|
<RefreshControl refreshing={isLoading} onRefresh={refetch} colors={[theme.colors.primary]} />
|
|
}
|
|
ListEmptyComponent={
|
|
<View style={styles.emptyContainer}>
|
|
<LucideIcon name="people-outline" size={64} color={theme.colors.textMuted} />
|
|
<Text style={[styles.emptyTitle, { color: theme.colors.textPrimary }]}>No Members Yet</Text>
|
|
<Text style={[styles.emptySubtitle, { color: theme.colors.textSecondary }]}>
|
|
Invite people to join your group to get started.
|
|
</Text>
|
|
</View>
|
|
}
|
|
/>
|
|
)}
|
|
</AppView>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
header: {
|
|
paddingHorizontal: 14,
|
|
paddingVertical: 10,
|
|
},
|
|
headerTitle: {
|
|
fontSize: responsiveFontSize(2.8),
|
|
fontFamily: FontsFamily.nunitoBold,
|
|
},
|
|
headerSubtitle: {
|
|
fontSize: responsiveFontSize(1.6),
|
|
fontFamily: FontsFamily.nunitoRegular,
|
|
marginTop: 4,
|
|
},
|
|
listContainer: {
|
|
paddingHorizontal: 14,
|
|
paddingBottom: 86,
|
|
},
|
|
skeletonList: {
|
|
paddingHorizontal: 14,
|
|
},
|
|
card: {
|
|
flexDirection: 'row',
|
|
padding: 16,
|
|
borderRadius: 16,
|
|
marginBottom: 12,
|
|
alignItems: 'center',
|
|
borderWidth: 1,
|
|
elevation: 2,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.05,
|
|
shadowRadius: 8,
|
|
},
|
|
avatarPlaceholder: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 24,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginRight: 16,
|
|
},
|
|
avatarText: {
|
|
fontSize: responsiveFontSize(2),
|
|
fontFamily: FontsFamily.nunitoBold,
|
|
},
|
|
infoContainer: {
|
|
flex: 1,
|
|
},
|
|
nameRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
name: {
|
|
fontSize: responsiveFontSize(1.8),
|
|
fontFamily: FontsFamily.nunitoBold,
|
|
},
|
|
badge: {
|
|
paddingHorizontal: 8,
|
|
paddingVertical: 2,
|
|
borderRadius: 4,
|
|
},
|
|
badgeText: {
|
|
fontSize: responsiveFontSize(1),
|
|
fontFamily: FontsFamily.nunitoBold,
|
|
textTransform: 'uppercase',
|
|
},
|
|
username: {
|
|
fontSize: responsiveFontSize(1.4),
|
|
fontFamily: FontsFamily.nunitoRegular,
|
|
marginTop: 2,
|
|
},
|
|
contactInfo: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginTop: 6,
|
|
gap: 4,
|
|
},
|
|
contactText: {
|
|
fontSize: responsiveFontSize(1.3),
|
|
fontFamily: FontsFamily.nunitoMedium,
|
|
},
|
|
emptyContainer: {
|
|
alignItems: 'center',
|
|
marginTop: 80,
|
|
paddingHorizontal: 40,
|
|
},
|
|
emptyTitle: {
|
|
fontSize: responsiveFontSize(2.2),
|
|
fontFamily: FontsFamily.nunitoBold,
|
|
marginTop: 20,
|
|
},
|
|
emptySubtitle: {
|
|
fontSize: responsiveFontSize(1.6),
|
|
fontFamily: FontsFamily.nunitoRegular,
|
|
textAlign: 'center',
|
|
marginTop: 8,
|
|
lineHeight: 22,
|
|
},
|
|
});
|
|
|
|
export default MemberScreen;
|