209 lines
5.5 KiB
TypeScript
209 lines
5.5 KiB
TypeScript
// src/components/JoinedGroupCard.tsx
|
|
|
|
import React, { FC } from 'react';
|
|
import { View, Text, StyleSheet } from 'react-native';
|
|
|
|
// Update the type to match the full data structure
|
|
interface JoinedGroup {
|
|
id: string;
|
|
groupName: string;
|
|
description: string;
|
|
visibility: 'PUBLIC' | 'PRIVATE';
|
|
createdByUserId: number;
|
|
createdByName: string; // Renamed from createdBy for clarity
|
|
startDate: [number, number, number] | null;
|
|
endDate: [number, number, number] | null;
|
|
minParticipants: number;
|
|
maxParticipants: number;
|
|
currentParticipants: number;
|
|
contributionAmount: number;
|
|
cycleType: 'MONTHLY' | 'WEEKLY' | 'QUARTERLY' | 'CUSTOM';
|
|
status: 'ACTIVE' | 'PENDING' | 'COMPLETED';
|
|
}
|
|
|
|
interface JoinedGroupCardProps {
|
|
item: JoinedGroup | any;
|
|
}
|
|
|
|
// Helper function to format dates
|
|
const formatDate = (dateArray: [number, number, number] | null): string => {
|
|
if (!dateArray) return 'N/A';
|
|
const date = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
|
|
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
};
|
|
|
|
// Helper to determine status color
|
|
const getStatusStyle = (status: JoinedGroup['status']) => {
|
|
switch (status) {
|
|
case 'ACTIVE':
|
|
return {
|
|
backgroundColor: '#D1FAE5', // Green tint
|
|
textColor: '#065F46', // Dark Green
|
|
};
|
|
case 'PENDING':
|
|
return {
|
|
backgroundColor: '#FEF3C7', // Yellow tint
|
|
textColor: '#92400E', // Dark Yellow/Brown
|
|
};
|
|
case 'COMPLETED':
|
|
return {
|
|
backgroundColor: '#E5E7EB', // Gray tint
|
|
textColor: '#4B5563', // Dark Gray
|
|
};
|
|
default:
|
|
return {
|
|
backgroundColor: '#E5E7EB',
|
|
textColor: '#4B5563',
|
|
};
|
|
}
|
|
};
|
|
|
|
export const JoinedGroupCard: FC<JoinedGroupCardProps> = ({ item }) => {
|
|
const progress = (item.currentParticipants / item.maxParticipants) * 100;
|
|
const statusStyle = getStatusStyle(item.status);
|
|
|
|
return (
|
|
<View style={styles.card}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<Text style={styles.groupName}>{item.groupName}</Text>
|
|
<View style={[styles.statusBadge, { backgroundColor: statusStyle.backgroundColor }]}>
|
|
<Text style={[styles.statusText, { color: statusStyle.textColor }]}>{item.status}</Text>
|
|
</View>
|
|
</View>
|
|
<Text style={styles.createdBy}>Created by {item.createdByName}</Text>
|
|
|
|
{/* Financial Info */}
|
|
<View style={styles.infoRow}>
|
|
<View style={styles.infoItem}>
|
|
<Text style={styles.infoLabel}>Contribution</Text>
|
|
<Text style={styles.infoValue}>₹{item.contributionAmount.toLocaleString('en-IN')}</Text>
|
|
</View>
|
|
<View style={styles.infoItem}>
|
|
<Text style={styles.infoLabel}>Cycle</Text>
|
|
<Text style={styles.infoValue}>{item.cycleType}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Participants Progress */}
|
|
<View style={styles.progressContainer}>
|
|
<View style={styles.progressLabels}>
|
|
<Text style={styles.participantText}>Participants</Text>
|
|
<Text style={styles.participantCount}>{item.currentParticipants} / {item.maxParticipants}</Text>
|
|
</View>
|
|
<View style={styles.progressBarBackground}>
|
|
<View style={[styles.progressBarFill, { width: `${progress}%` }]} />
|
|
</View>
|
|
</View>
|
|
|
|
{/* Dates */}
|
|
<View style={styles.footer}>
|
|
<Text style={styles.dateText}>
|
|
{formatDate(item.startDate)} - {formatDate(item.endDate)}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
card: {
|
|
backgroundColor: '#FFFFFF',
|
|
borderRadius: 16,
|
|
padding: 20,
|
|
marginBottom: 16,
|
|
shadowColor: '#374151',
|
|
shadowOpacity: 0.08,
|
|
shadowRadius: 10,
|
|
shadowOffset: { width: 0, height: 4 },
|
|
elevation: 3,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'flex-start',
|
|
marginBottom: 4,
|
|
},
|
|
groupName: {
|
|
fontSize: 20,
|
|
fontWeight: 'bold',
|
|
color: '#1F2937',
|
|
flexShrink: 1,
|
|
},
|
|
createdBy: {
|
|
fontSize: 14,
|
|
color: '#6B7280',
|
|
marginBottom: 16,
|
|
},
|
|
statusBadge: {
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 5,
|
|
borderRadius: 12,
|
|
},
|
|
statusText: {
|
|
fontSize: 12,
|
|
fontWeight: '600',
|
|
textTransform: 'uppercase',
|
|
},
|
|
infoRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
paddingVertical: 16,
|
|
borderTopWidth: 1,
|
|
borderBottomWidth: 1,
|
|
borderColor: '#F3F4F6',
|
|
marginBottom: 16,
|
|
},
|
|
infoItem: {
|
|
alignItems: 'flex-start',
|
|
},
|
|
infoLabel: {
|
|
fontSize: 14,
|
|
color: '#6B7280',
|
|
marginBottom: 4,
|
|
},
|
|
infoValue: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
color: '#111827',
|
|
textTransform: 'capitalize',
|
|
},
|
|
progressContainer: {
|
|
marginBottom: 16,
|
|
},
|
|
progressLabels: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginBottom: 8,
|
|
},
|
|
participantText: {
|
|
fontSize: 14,
|
|
color: '#6B7280',
|
|
},
|
|
participantCount: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#111827',
|
|
},
|
|
progressBarBackground: {
|
|
height: 8,
|
|
backgroundColor: '#E5E7EB',
|
|
borderRadius: 4,
|
|
overflow: 'hidden',
|
|
},
|
|
progressBarFill: {
|
|
height: '100%',
|
|
backgroundColor: '#4F46E5',
|
|
borderRadius: 4,
|
|
},
|
|
footer: {
|
|
alignItems: 'center',
|
|
marginTop: 8,
|
|
},
|
|
dateText: {
|
|
fontSize: 14,
|
|
color: '#4B5563',
|
|
fontWeight: '500',
|
|
},
|
|
});
|