143 lines
5.6 KiB
TypeScript
143 lines
5.6 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, Text, TouchableOpacity } from 'react-native';
|
|
import Icon from 'react-native-vector-icons/Ionicons';
|
|
import { useTheme } from '@theme';
|
|
import { getStyles } from './leadItemCard.styles';
|
|
import { LeadItemCardProps } from './leadItemCard.props';
|
|
import { getInitials, handleEmailPress, handlePhonePress, formatDate } from '@utils';
|
|
import { useAppSelector, RootState } from '@store';
|
|
|
|
export const LeadItemCard: React.FC<LeadItemCardProps> = ({ item, onPress, onStatusChange }) => {
|
|
const { theme: colors } = useTheme();
|
|
const styles = getStyles(colors);
|
|
|
|
const { items: statusList } = useAppSelector((state: RootState) => state.statusList);
|
|
|
|
const [selectedStatusId, setSelectedStatusId] = useState(item.status);
|
|
const [menuVisible, setMenuVisible] = useState(false);
|
|
|
|
const currentStatus = statusList.find(s => s.id === selectedStatusId) || {
|
|
name: item.status_name || item.status,
|
|
color: item.color || colors.icon,
|
|
};
|
|
|
|
const displayName = item.name || 'No Name';
|
|
const initials = getInitials(displayName);
|
|
const accent = currentStatus.color?.startsWith('#') ? currentStatus.color : colors.icon;
|
|
|
|
const handleSelectStatus = (statusId: string) => {
|
|
setSelectedStatusId(statusId);
|
|
setMenuVisible(false);
|
|
if (onStatusChange) {
|
|
onStatusChange(statusId);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View style={[styles.customerCard, menuVisible && { zIndex: 100, elevation: 10 }]}>
|
|
<View style={styles.cardHeader}>
|
|
<TouchableOpacity
|
|
activeOpacity={onPress ? 0.7 : 1}
|
|
onPress={onPress}
|
|
disabled={!onPress}
|
|
style={styles.cardHeaderLeft}>
|
|
<View style={[styles.avatarCircle, { backgroundColor: accent }]}>
|
|
<Text style={styles.avatarInitial}>{initials}</Text>
|
|
</View>
|
|
<View style={styles.cardInfo}>
|
|
<Text style={styles.customerName} numberOfLines={1}>
|
|
{displayName}
|
|
</Text>
|
|
{item.company ? (
|
|
<Text style={styles.contactPerson} numberOfLines={1}>
|
|
{item.company}
|
|
</Text>
|
|
) : null}
|
|
<Text style={styles.location} numberOfLines={1}>
|
|
<Icon name="call-outline" size={11} color={colors.textMuted} />
|
|
{' '}{item.phonenumber || 'N/A'}{' • '}
|
|
<Icon name="mail-outline" size={11} color={colors.textMuted} />
|
|
{' '}{item.email || 'N/A'}
|
|
</Text>
|
|
{item.source_name || item.source || item.dateadded ? (
|
|
<Text style={styles.location} numberOfLines={1}>
|
|
{item.source_name || item.source ? (
|
|
<>
|
|
<Icon name="radio-outline" size={11} color={colors.textMuted} />
|
|
{' '}{item.source_name || item.source}
|
|
</>
|
|
) : null}
|
|
{item.dateadded ? ` • ${formatDate(item.dateadded)}` : ''}
|
|
</Text>
|
|
) : null}
|
|
</View>
|
|
</TouchableOpacity>
|
|
|
|
<View style={styles.cardHeaderRight}>
|
|
<View style={{ position: 'relative' }}>
|
|
<TouchableOpacity
|
|
activeOpacity={0.7}
|
|
onPress={() => setMenuVisible(!menuVisible)}
|
|
style={[
|
|
styles.statusDropdownButton,
|
|
{
|
|
backgroundColor: `${accent}12`,
|
|
borderColor: `${accent}40`,
|
|
},
|
|
]}>
|
|
<Text style={[styles.statusDropdownText, { color: accent }]}>
|
|
{currentStatus.name}
|
|
</Text>
|
|
<Icon name={menuVisible ? 'chevron-up' : 'chevron-down'} size={10} color={accent} />
|
|
</TouchableOpacity>
|
|
|
|
{menuVisible && (
|
|
<View style={styles.menuOverlay}>
|
|
{statusList.map(statusItem => {
|
|
const isActive = statusItem.id === selectedStatusId;
|
|
const statusColor = statusItem.color?.startsWith('#') ? statusItem.color : colors.icon;
|
|
return (
|
|
<TouchableOpacity
|
|
key={statusItem.id}
|
|
style={[styles.menuItem, isActive && styles.menuItemActive]}
|
|
onPress={() => handleSelectStatus(statusItem.id)}>
|
|
<View style={[styles.menuItemDot, { backgroundColor: statusColor }]} />
|
|
<Text
|
|
style={[
|
|
styles.menuItemText,
|
|
isActive && styles.menuItemTextActive,
|
|
]}
|
|
numberOfLines={1}>
|
|
{statusItem.name}
|
|
</Text>
|
|
{isActive && (
|
|
<Icon name="checkmark" size={12} color={colors.text} />
|
|
)}
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
)}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.cardFooter}>
|
|
<TouchableOpacity
|
|
style={[styles.actionButton, styles.callButton, { backgroundColor: `${accent}10` }]}
|
|
onPress={() => handlePhonePress(item.phonenumber)}>
|
|
<Icon name="call" size={15} color={accent} />
|
|
<Text style={[styles.callButtonText, { color: accent }]}>Call</Text>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={[styles.actionButton, styles.emailButton]}
|
|
onPress={() => handleEmailPress(item.email)}>
|
|
<Icon name="mail" size={15} color={colors.textSecondary} />
|
|
<Text style={styles.emailButtonText}>Email</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|