Centralized_Rreporting_System/src/modules/crm/components/CrmDataCards.tsx
2025-09-15 19:59:08 +05:30

549 lines
19 KiB
TypeScript

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { useTheme } from '@/shared/styles/useTheme';
import type { CrmLead, CrmTask, CrmContact, CrmDeal, CrmSalesOrder, CrmPurchaseOrder, CrmInvoice } from '../types/CrmTypes';
interface BaseCardProps {
onPress: () => void;
}
interface LeadCardProps extends BaseCardProps {
lead: CrmLead;
}
interface TaskCardProps extends BaseCardProps {
task: CrmTask;
}
interface ContactCardProps extends BaseCardProps {
contact: CrmContact;
}
interface DealCardProps extends BaseCardProps {
deal: CrmDeal;
}
interface SalesOrderCardProps extends BaseCardProps {
salesOrder: CrmSalesOrder;
}
interface PurchaseOrderCardProps extends BaseCardProps {
purchaseOrder: CrmPurchaseOrder;
}
interface InvoiceCardProps extends BaseCardProps {
invoice: CrmInvoice;
}
const getStatusColor = (status: string, colors: any) => {
// return '#3AA0FF';
switch (status.toLowerCase()) {
case 'new':
case 'not started':
case 'attempted to contact':
return '#3AA0FF';
case 'contacted':
case 'in progress':
case 'qualification':
return '#F59E0B';
case 'qualified':
case 'proposal':
return '#10B981';
case 'completed':
case 'closed won':
return '#22C55E';
case 'unqualified':
case 'cancelled':
case 'lost lead':
return '#EF4444';
default:
return colors.textLight;
}
};
const getPriorityColor = (priority: string) => {
return '#EF4444';
switch (priority.toLowerCase()) {
case 'high':
return '#EF4444';
case 'medium':
return '#F59E0B';
case 'low':
return '#10B981';
default:
return '#6B7280';
}
};
export const LeadCard: React.FC<LeadCardProps> = ({ lead, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{lead.Full_Name}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(lead.Lead_Status, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{lead.Lead_Status}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
{lead.Company}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="email-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]} numberOfLines={1}>
{lead.Email}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="phone-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
{lead.Phone}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="source-branch" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Source: {lead.Lead_Source}
</Text>
</View>
{lead.Annual_Revenue && (
<View style={styles.infoRow}>
<Icon name="currency-usd" size={16} color={colors.primary} />
<Text style={[styles.infoText, { color: colors.primary, fontFamily: fonts.bold }]}>
${lead.Annual_Revenue.toLocaleString()}
</Text>
</View>
)}
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Created: {new Date(lead.Created_Time)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={2}>
{task.Subject}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(task.Status, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{task.Status}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
{task.Priority}
</Text>
</View>
<View style={styles.cardContent}>
<Text style={[styles.descriptionText, { color: colors.text, fontFamily: fonts.regular }]} numberOfLines={2}>
{task.Description}
</Text>
<View style={styles.infoRow}>
<Icon name="flag-outline" size={16} color={getPriorityColor(task.Priority)} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Priority: {task.Priority}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="account-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Assigned: {task.Owner.name}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Due: {new Date(task.Due_Date)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const ContactCard: React.FC<ContactCardProps> = ({ contact, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{contact.Full_Name}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor('Active', colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
Active
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
{contact.Title} at {contact.Account_Name?.name || 'N/A'}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="email-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]} numberOfLines={1}>
{contact.Email}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="phone-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
{contact.Phone}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="source-branch" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Source: {contact.Lead_Source}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Last contact: {new Date(contact.Last_Activity_Time)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const DealCard: React.FC<DealCardProps> = ({ deal, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{deal.Deal_Name}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(deal.Stage, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{deal.Stage}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
{deal.Account_Name?.name || 'N/A'}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="currency-usd" size={16} color={colors.primary} />
<Text style={[styles.infoText, { color: colors.primary, fontFamily: fonts.bold }]}>
${deal.Amount?.toLocaleString()}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="trending-up" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Probability: {deal.Probability}%
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="account-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Contact: {deal.Contact_Name?.name || 'N/A'}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Close date: {new Date(deal.Closing_Date)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const SalesOrderCard: React.FC<SalesOrderCardProps> = ({ salesOrder, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{salesOrder.Subject}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(salesOrder.Status, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{salesOrder.Status}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
SO: {salesOrder.SO_Number}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="currency-usd" size={16} color={colors.primary} />
<Text style={[styles.infoText, { color: colors.primary, fontFamily: fonts.bold }]}>
{salesOrder.$currency_symbol}{salesOrder.Grand_Total?.toLocaleString()}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="account-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Account: {salesOrder.Account_Name?.name || 'N/A'}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="map-marker-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
{salesOrder.Billing_City}, {salesOrder.Billing_Country}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="truck-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Carrier: {salesOrder.Carrier}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Created: {new Date(salesOrder.Created_Time)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const PurchaseOrderCard: React.FC<PurchaseOrderCardProps> = ({ purchaseOrder, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{purchaseOrder.Subject}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(purchaseOrder.Status, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{purchaseOrder.Status}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
PO: {purchaseOrder.PO_Number || 'N/A'}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="currency-usd" size={16} color={colors.primary} />
<Text style={[styles.infoText, { color: colors.primary, fontFamily: fonts.bold }]}>
{purchaseOrder.$currency_symbol}{purchaseOrder.Grand_Total?.toLocaleString()}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="store-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Vendor: {purchaseOrder.Vendor_Name?.name || 'N/A'}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="map-marker-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
{purchaseOrder.Billing_City}, {purchaseOrder.Billing_Country}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="truck-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Carrier: {purchaseOrder.Carrier}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
PO Date: {new Date(purchaseOrder.PO_Date)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
export const InvoiceCard: React.FC<InvoiceCardProps> = ({ invoice, onPress }) => {
const { colors, fonts, shadows } = useTheme();
return (
<TouchableOpacity
style={[styles.card, { backgroundColor: colors.surface, borderColor: colors.border, ...shadows.medium }]}
onPress={onPress}
activeOpacity={0.8}
>
<View style={styles.cardHeader}>
<View style={styles.cardTitleRow}>
<Text style={[styles.cardTitle, { color: colors.text, fontFamily: fonts.bold }]} numberOfLines={1}>
{invoice.Subject}
</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(invoice.Status, colors) }]}>
<Text style={[styles.statusText, { color: colors.surface, fontFamily: fonts.medium }]}>
{invoice.Status}
</Text>
</View>
</View>
<Text style={[styles.cardSubtitle, { color: colors.textLight, fontFamily: fonts.regular }]} numberOfLines={1}>
Invoice: {invoice.Invoice_Number}
</Text>
</View>
<View style={styles.cardContent}>
<View style={styles.infoRow}>
<Icon name="currency-usd" size={16} color={colors.primary} />
<Text style={[styles.infoText, { color: colors.primary, fontFamily: fonts.bold }]}>
{invoice.$currency_symbol}{invoice.Grand_Total?.toLocaleString()}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="account-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Account: {invoice.Account_Name?.name || 'N/A'}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="map-marker-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
{invoice.Billing_City}, {invoice.Billing_Country}
</Text>
</View>
<View style={styles.infoRow}>
<Icon name="calendar-outline" size={16} color={colors.textLight} />
<Text style={[styles.infoText, { color: colors.text, fontFamily: fonts.regular }]}>
Due: {new Date(invoice.Due_Date)?.toLocaleDateString()}
</Text>
</View>
</View>
<View style={styles.cardFooter}>
<Text style={[styles.dateText, { color: colors.textLight, fontFamily: fonts.regular }]}>
Invoice Date: {new Date(invoice.Invoice_Date)?.toLocaleDateString()}
</Text>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
card: {
borderRadius: 12,
borderWidth: 1,
marginBottom: 16,
overflow: 'hidden',
},
cardHeader: {
padding: 16,
paddingBottom: 12,
},
cardTitleRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 4,
},
cardTitle: {
fontSize: 16,
flex: 1,
marginRight: 8,
},
cardSubtitle: {
fontSize: 14,
},
statusBadge: {
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 12,
},
statusText: {
fontSize: 12,
},
cardContent: {
paddingHorizontal: 16,
paddingBottom: 12,
},
infoRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 6,
},
infoText: {
marginLeft: 8,
fontSize: 14,
flex: 1,
},
descriptionText: {
fontSize: 14,
marginBottom: 8,
lineHeight: 20,
},
cardFooter: {
paddingHorizontal: 16,
paddingVertical: 12,
backgroundColor: '#F8F9FA',
},
dateText: {
fontSize: 12,
},
});