forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParticipantList.tsx
More file actions
88 lines (79 loc) · 4.43 KB
/
Copy pathParticipantList.tsx
File metadata and controls
88 lines (79 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { CheckCircle2 } from 'lucide-react';
import type { Participant } from '../../types';
import { useTranslation } from 'react-i18next';
import { formatCurrency } from '../../utils/format';
interface ParticipantListProps {
participants: Participant[];
currency: string;
}
export const ParticipantList = ({ participants, currency }: ParticipantListProps) => {
const { t } = useTranslation();
const getStatusLabel = (status: Participant['status']) => {
if (status === 'paid') {
return t('common.paid');
}
if (status === 'partial') {
return 'Partially paid';
}
return t('common.pending');
};
const getStatusClasses = (status: Participant['status']) => {
if (status === 'paid') {
return 'text-green-600';
}
if (status === 'partial') {
return 'text-blue-600';
}
return 'text-orange-500';
};
return (
<div className="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden mb-24 md:mb-6">
<div className="p-4 border-b border-gray-50 bg-gray-50/50 flex justify-between items-center">
<h3 className="font-semibold text-gray-700">{t('split.participants')}</h3>
<span className="text-xs font-medium text-gray-400">{participants.length} {t('split.participants', { count: participants.length }).toLowerCase()}</span>
</div>
<div className="divide-y divide-gray-50">
{participants.map((person) => (
<div key={person.id} className="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div className="flex items-center gap-3">
<div className="relative">
<div className={`w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 ${person.isCurrentUser ? 'bg-purple-100 text-purple-600 border-purple-200' : 'bg-gray-100 text-gray-600 border-gray-200'
}`}>
{person.avatar ? (
<img src={person.avatar} alt={person.name === 'You' ? t('common.you') : person.name} className="w-full h-full rounded-full object-cover" />
) : (
(person.name === 'You' ? t('common.you') : person.name).charAt(0).toUpperCase()
)}
</div>
{person.status === 'paid' && (
<div className="absolute -bottom-1 -right-1 bg-white rounded-full p-0.5">
<CheckCircle2 size={14} className="text-green-500 fill-current" />
</div>
)}
</div>
<div className="flex flex-col">
<span className="font-medium text-gray-900 flex items-center gap-2">
{person.name === 'You' ? t('common.you') : person.name}
{person.isCurrentUser && <span className="text-[10px] uppercase font-bold bg-purple-100 text-purple-600 px-1.5 py-0.5 rounded tracking-wide">{t('common.you')}</span>}
</span>
<span className={`text-xs flex items-center gap-1 font-medium ${getStatusClasses(person.status)}`}>
{getStatusLabel(person.status)}
</span>
</div>
</div>
<div className="text-right">
<p className={`font-bold ${person.status === 'paid' ? 'text-gray-400 line-through' : 'text-gray-900'}`}>
{formatCurrency(person.amountDue ?? person.amountOwed, currency)}
</p>
{person.status === 'partial' && person.amountPaid ? (
<p className="mt-1 text-xs text-gray-500">
Paid {formatCurrency(person.amountPaid, currency)}
</p>
) : null}
</div>
</div>
))}
</div>
</div>
);
};