179 lines
5.7 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import {
Text,
View,
FlatList,
ScrollView,
TouchableOpacity,
ActivityIndicator,
Alert,
} from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import Icon from 'react-native-vector-icons/Ionicons';
import { getStyles } from './leads.styles';
import { useTheme } from '@theme';
import { useAppDispatch, useAppSelector, RootState } from '@store';
import { getLeads, getLeadCountList, updateLeadStatus } from './thunk';
import { LeadItem } from '@interfaces';
import { LeadItemCard, SearchInput, Loader, StatCard } from '@components';
import { LeadsStackParamList } from '../../navigation/leadsStack';
import { route } from '@utils';
type LeadsScreenNavigationProp = NativeStackNavigationProp<
LeadsStackParamList,
'leadsList'
>;
export const LeadsScreen = () => {
const dispatch = useAppDispatch();
const navigation = useNavigation<LeadsScreenNavigationProp>();
const { theme: colors } = useTheme();
const styles = getStyles(colors);
const [searchTerm, setSearchTerm] = useState('');
const [selectedStatusId, setSelectedStatusId] = useState<string | null>(null);
const { items, loading, error, counts, countsLoading } = useAppSelector(
(state: RootState) => state.leads,
);
const { items: statusItems } = useAppSelector(
(state: RootState) => state.statusList,
);
const user_data = useAppSelector((state: RootState) => state.auth.user_data);
useEffect(() => {
if (user_data?.staffid) {
dispatch(getLeads({ leadId: null, staffid: user_data.staffid }));
dispatch(getLeadCountList(user_data.staffid));
}
}, [dispatch, user_data]);
const filteredLeads = items.filter(lead => {
const matchesSearch = searchTerm
? lead.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
lead.company.toLowerCase().includes(searchTerm.toLowerCase()) ||
lead.email.toLowerCase().includes(searchTerm.toLowerCase())
: true;
const matchesStatus =
!selectedStatusId || selectedStatusId === '0'
? true
: lead.status === selectedStatusId;
return matchesSearch && matchesStatus;
});
const handleStatusPress = (id: string) => {
setSelectedStatusId(prev => (prev === id ? null : id));
};
const handleLeadPress = (lead: LeadItem) => {
navigation.navigate(route.leadDetails, { lead });
};
const handleStatusChange = (lead: LeadItem, newStatusId: string) => {
const matchedStatus = statusItems.find(s => s.id === newStatusId);
const newStatusName = matchedStatus ? matchedStatus.name : newStatusId;
const newColor = matchedStatus ? matchedStatus.color : colors.icon;
dispatch(
updateLeadStatus({
lead,
newStatusId,
newStatusName,
newColor,
}),
)
.unwrap()
.then(res => {
Alert.alert('Success', res.message || 'Status updated successfully');
if (user_data?.staffid) {
dispatch(getLeadCountList(user_data.staffid));
}
})
.catch(err => {
Alert.alert('Error', err || 'Failed to update status');
});
};
const renderLead = ({ item }: { item: LeadItem }) => (
<LeadItemCard
item={item}
onPress={() => handleLeadPress(item)}
onStatusChange={newStatusId => handleStatusChange(item, newStatusId)}
/>
);
return (
<View style={styles.container}>
{/* Search + Filter Header (Fixed at top) */}
<View style={styles.header}>
<SearchInput
value={searchTerm}
onChangeText={setSearchTerm}
placeholder="Search leads, companies, emails..."
style={styles.searchInput}
/>
{/* <TouchableOpacity style={styles.filterButton}>
<Icon name="filter-outline" size={20} color={colors.text} />
</TouchableOpacity> */}
</View>
{/* Status count cards */}
{countsLoading ? (
<View style={styles.countsLoading}>
<ActivityIndicator size="small" color={colors.icon} />
</View>
) : counts.length > 0 ? (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flexGrow: 0 }}
contentContainerStyle={styles.countsScroll}
>
{counts.map(item => (
<StatCard
key={item.id}
label={item.name}
count={item.count}
color={item.color || colors.icon}
isSelected={selectedStatusId === item.id}
onPress={() => handleStatusPress(item.id)}
/>
))}
</ScrollView>
) : null}
{/* Lead list */}
{loading ? (
<Loader message="Loading leads..." />
) : error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
</View>
) : (
<FlatList
data={filteredLeads}
keyExtractor={item => item.id}
style={{ flex: 1 }}
contentContainerStyle={styles.listContent}
renderItem={renderLead}
ListEmptyComponent={() => (
<View style={styles.emptyContainer}>
<View style={styles.emptyIconWrap}>
<Icon name="people-outline" size={32} color={colors.icon} />
</View>
<Text style={styles.emptyTitle}>No Leads Found</Text>
<Text style={styles.emptyText}>
{searchTerm
? `No leads match "${searchTerm}". Try a different search.`
: 'You have no leads yet. New leads will appear here.'}
</Text>
</View>
)}
/>
)}
</View>
);
};