import React, { useEffect, useMemo, useState } from 'react'; import { View, Text, ScrollView, StyleSheet, TouchableOpacity, RefreshControl, ActivityIndicator, Dimensions, Platform, ViewStyle, TextStyle, Modal, TextInput, KeyboardAvoidingView, Alert, } from 'react-native'; import { LinearGradient } from 'react-native-linear-gradient'; import { AlertCircle, UserCircle, User, Mail, Phone, Briefcase, Building2, Building, Tag, Network, Globe, Award, MapPin, Home, Map, Mailbox, FileText, CreditCard, Type, Calendar, Receipt, ClipboardCheck, Star, List, Factory, CheckCircle2, CheckCircle, CalendarClock, ShieldCheck, LucideIcon, Edit, X, Save, } from 'lucide-react-native'; import { useContractorProfile, useUpdateUserProfile } from '../../Services/BBPS/Hooks'; import colors from '../../Constant/Color'; const { width } = Dimensions.get('window'); // Type Definitions interface ContractorData { contractorId: number; firstName: string; middleName: string; lastName: string; fullName: string; emailId: string; mobileNo: string; company: string; contractorType: string; dialCode: string; twoFactorAuthEnabled: boolean; colorCodeHSL: string | null; isActive: string; isEnabled: boolean | null; role: string; contractorStatus: boolean; designation: string | null; contOtherId: number; contCompanyType: string | null; contOrganization: string; agentAddress: string; agentPincode: string; agentCity: string; agentState: string | null; agentWebsite: string; agentRegno: string; orgPAN: string; orgPANdob: string; orgPANname: string; gistnNo: string; comAadharNo: string; contractorClass: string; socialCategory: string; wizardStepStatus: string; registrationStatus: string; indianOrgName: string; expiryDate: string; msmeStatus: string; } interface ProfileHeaderProps { data: ContractorData; } interface QuickStatsProps { data: ContractorData; } interface InfoSectionProps { title: string; IconComponent: LucideIcon; children: React.ReactNode; delay?: number; onEdit?: () => void; showEdit?: boolean; } interface InfoRowProps { label: string; value: string | null | undefined; IconComponent: LucideIcon; valueColor?: string; } interface StatItem { Icon: LucideIcon; label: string; value: string; color: string; } interface UpdateProfilePayload { firstName: string; middleName: string; lastName: string; mobileNo: string; emailId: string; fullname: string; } // Helper function to check if value is valid const isValidValue = (value: any): boolean => { if (value === null || value === undefined) return false; if (typeof value === 'string') { const trimmed = value.trim(); return trimmed.length > 0 && trimmed.toLowerCase() !== 'n/a'; } return true; }; // Main Component const ProfileTab: React.FC = () => { const { data, refetch, isLoading, error } = useContractorProfile(); console.log("ioioi",data) const [editModalVisible, setEditModalVisible] = useState(false); if (isLoading) { return ( Loading profile... ); } if (error) { return ( {error} Retry ); } if (!data) return null; return ( <> } showsVerticalScrollIndicator={false} removeClippedSubviews={true} maxToRenderPerBatch={10} updateCellsBatchingPeriod={50} initialNumToRender={8} windowSize={10} > {/* Header with Gradient */} {/* Quick Stats */} {/* Personal Information */} setEditModalVisible(true)} > {/* Company Details */} {/* Address Information */} {/* Tax & Legal */} {/* Registration Status */} {/* Edit Modal */} setEditModalVisible(false)} data={data} onSuccess={refetch} /> ); }; // Edit Profile Modal Component interface EditProfileModalProps { visible: boolean; onClose: () => void; data: ContractorData; onSuccess: () => void; } const EditProfileModal: React.FC = ({ visible, onClose, data, onSuccess, }) => { const [formData, setFormData] = useState({ firstName: data.firstName || '', middleName: data.middleName || '', lastName: data.lastName || '', mobileNo: data.mobileNo || '', emailId: data.emailId || '', fullname: data.fullName || '', }); const [errors, setErrors] = useState>({}); const updateProfileMutation = useUpdateUserProfile(); // Reset form when modal opens useEffect(() => { if (visible) { setFormData({ firstName: data.firstName || '', middleName: data.middleName || '', lastName: data.lastName || '', mobileNo: data.mobileNo || '', emailId: data.emailId || '', fullname: data.fullName || '', }); setErrors({}); } }, [visible, data]); const validateForm = (): boolean => { const newErrors: Partial = {}; if (!formData.firstName.trim()) { newErrors.firstName = 'First name is required'; } if (!formData.lastName.trim()) { newErrors.lastName = 'Last name is required'; } if (!formData.emailId.trim()) { newErrors.emailId = 'Email is required'; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.emailId)) { newErrors.emailId = 'Invalid email format'; } if (!formData.mobileNo.trim()) { newErrors.mobileNo = 'Mobile number is required'; } else if (!/^\d{10}$/.test(formData.mobileNo.replace(/\s/g, ''))) { newErrors.mobileNo = 'Invalid mobile number'; } // Auto-generate fullname const generatedFullName = `${formData.firstName} ${formData.middleName} ${formData.lastName}`.trim(); setFormData(prev => ({ ...prev, fullname: generatedFullName })); setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSave = async () => { if (!validateForm()) { return; } try { await updateProfileMutation.mutateAsync(formData); Alert.alert('Success', 'Profile updated successfully'); onSuccess(); onClose(); } catch (error: any) { Alert.alert('Error', error?.message || 'Failed to update profile'); } }; return ( {/* Header */} Edit Personal Information {/* Form */} {/* First Name */} First Name * setFormData({ ...formData, firstName: text })} placeholder="Enter first name" placeholderTextColor={colors.grayText} /> {errors.firstName && ( {errors.firstName} )} {/* Middle Name */} Middle Name setFormData({ ...formData, middleName: text })} placeholder="Enter middle name" placeholderTextColor={colors.grayText} /> {/* Last Name */} Last Name * setFormData({ ...formData, lastName: text })} placeholder="Enter last name" placeholderTextColor={colors.grayText} /> {errors.lastName && ( {errors.lastName} )} {/* Email */} Email * setFormData({ ...formData, emailId: text })} placeholder="Enter email" placeholderTextColor={colors.grayText} keyboardType="email-address" autoCapitalize="none" /> {errors.emailId && ( {errors.emailId} )} {/* Mobile Number */} Mobile Number * setFormData({ ...formData, mobileNo: text })} placeholder="Enter mobile number" placeholderTextColor={colors.grayText} keyboardType="phone-pad" maxLength={10} /> {errors.mobileNo && ( {errors.mobileNo} )} {/* Footer Buttons */} Cancel {updateProfileMutation.isPending ? ( ) : ( <> Save )} ); }; // Profile Header Component - OPTIMIZED const ProfileHeader: React.FC = React.memo(({ data }) => { const getInitials = (name: string): string => { if (!name || typeof name !== 'string' || name.trim().length === 0) { const fallbackName = `${data.firstName || ''} ${data.lastName || ''}`.trim(); if (fallbackName) { return fallbackName .split(' ') .filter((n) => n.length > 0) .map((n) => n[0]) .join('') .toUpperCase() .substring(0, 2); } return 'NA'; } return ( name .split(' ') .filter((n) => n.length > 0) .map((n) => n[0]) .join('') .toUpperCase() .substring(0, 2) || 'NA' ); }; const getStatusColor = (): string => { if (data.isActive === 'Active') return colors.success; return colors.error; }; return ( {getInitials(data.fullName)} {data.fullName || `${data.firstName} ${data.lastName}`.trim() || 'Unknown User'} {data.role} ); }); ProfileHeader.displayName = 'ProfileHeader'; // Quick Stats Component - OPTIMIZED const QuickStats: React.FC = React.memo(({ data }) => { const stats: StatItem[] = useMemo( () => [ { Icon: CheckCircle, label: 'Status', value: data.isActive, color: colors.success, }, { Icon: ShieldCheck, label: '2FA', value: data.twoFactorAuthEnabled ? 'Enabled' : 'Disabled', color: data.twoFactorAuthEnabled ? colors.success : colors.grayText, }, { Icon: FileText, label: 'Registration', value: data.registrationStatus, color: colors.info, }, ], [data.isActive, data.twoFactorAuthEnabled, data.registrationStatus] ); return ( {stats.map((stat) => ( {stat.value} {stat.label} ))} ); }); QuickStats.displayName = 'QuickStats'; // Info Section Component - OPTIMIZED const InfoSection: React.FC = React.memo( ({ title, IconComponent, children, onEdit, showEdit = false }) => { return ( {title} {showEdit && onEdit && ( )} {children} ); } ); InfoSection.displayName = 'InfoSection'; // Info Row Component - OPTIMIZED const InfoRow: React.FC = React.memo( ({ label, value, IconComponent, valueColor }) => { // Return null if value is not valid if (!isValidValue(value)) { return null; } return ( {label} {value} ); } ); InfoRow.displayName = 'InfoRow'; // Styles interface Styles { container: ViewStyle; contentContainer: ViewStyle; centerContainer: ViewStyle; loadingText: TextStyle; errorText: TextStyle; retryButton: ViewStyle; retryButtonText: TextStyle; headerGradient: ViewStyle; avatarContainer: ViewStyle; avatar: ViewStyle; avatarText: TextStyle; statusBadge: ViewStyle; statusDot: ViewStyle; headerName: TextStyle; roleBadge: ViewStyle; roleText: TextStyle; statsContainer: ViewStyle; statCard: ViewStyle; statValue: TextStyle; statLabel: TextStyle; section: ViewStyle; sectionHeader: ViewStyle; sectionHeaderLeft: ViewStyle; sectionIconContainer: ViewStyle; sectionTitle: TextStyle; sectionContent: ViewStyle; infoRow: ViewStyle; infoRowTouchable: ViewStyle; infoRowContent: ViewStyle; infoIconContainer: ViewStyle; infoTextContainer: ViewStyle; infoLabel: TextStyle; infoValue: TextStyle; editButton: ViewStyle; modalOverlay: ViewStyle; modalContent: ViewStyle; modalHeader: ViewStyle; modalTitle: TextStyle; closeButton: ViewStyle; formContainer: ViewStyle; inputGroup: ViewStyle; inputLabel: TextStyle; input: TextStyle; inputError: TextStyle; errorText: TextStyle; modalFooter: ViewStyle; button: ViewStyle; cancelButton: ViewStyle; saveButton: ViewStyle; cancelButtonText: TextStyle; saveButtonText: TextStyle; } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.lightGray, }, contentContainer: { paddingBottom: 20, }, centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: colors.white, padding: 20, }, loadingText: { marginTop: 16, fontSize: 16, color: colors.grayText, fontWeight: '500', }, errorText: { marginTop: 16, fontSize: 16, color: colors.error, textAlign: 'center', fontWeight: '500', }, retryButton: { marginTop: 20, backgroundColor: colors.primary, paddingHorizontal: 32, paddingVertical: 12, borderRadius: 12, elevation: 2, shadowColor: colors.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, }, retryButtonText: { color: colors.white, fontSize: 16, fontWeight: '600', }, // Header Styles headerGradient: { paddingTop: Platform.OS === 'ios' ? 60 : 40, paddingBottom: 30, alignItems: 'center', borderBottomLeftRadius: 32, borderBottomRightRadius: 32, elevation: 8, shadowColor: colors.shadow, shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, }, avatarContainer: { position: 'relative', marginBottom: 16, }, avatar: { width: 100, height: 100, borderRadius: 50, backgroundColor: colors.white, justifyContent: 'center', alignItems: 'center', borderWidth: 4, borderColor: colors.white, elevation: 4, shadowColor: colors.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, }, avatarText: { fontSize: 36, fontWeight: '700', color: colors.primary, }, statusBadge: { position: 'absolute', bottom: 4, right: 4, width: 24, height: 24, borderRadius: 12, borderWidth: 3, borderColor: colors.white, justifyContent: 'center', alignItems: 'center', }, statusDot: { width: 10, height: 10, borderRadius: 5, backgroundColor: colors.white, }, headerName: { fontSize: 26, fontWeight: '700', color: colors.white, marginBottom: 8, textAlign: 'center', paddingHorizontal: 20, }, roleBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: 'rgba(255, 255, 255, 0.25)', paddingHorizontal: 16, paddingVertical: 6, borderRadius: 20, gap: 6, }, roleText: { color: colors.white, fontSize: 14, fontWeight: '600', }, // Stats Styles statsContainer: { flexDirection: 'row', marginHorizontal: 16, marginTop: -30, gap: 12, zIndex: 10, }, statCard: { flex: 1, backgroundColor: colors.white, borderRadius: 16, padding: 16, alignItems: 'center', elevation: 4, shadowColor: colors.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.15, shadowRadius: 6, }, statValue: { fontSize: 14, fontWeight: '700', color: colors.darkText, marginTop: 8, textAlign: 'center', }, statLabel: { fontSize: 12, color: colors.grayText, marginTop: 4, }, // Section Styles section: { marginHorizontal: 16, marginTop: 24, backgroundColor: colors.white, borderRadius: 20, padding: 20, elevation: 2, shadowColor: colors.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, sectionHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16, paddingBottom: 12, borderBottomWidth: 1, borderBottomColor: colors.border, }, sectionHeaderLeft: { flexDirection: 'row', alignItems: 'center', flex: 1, }, sectionIconContainer: { width: 40, height: 40, borderRadius: 12, backgroundColor: colors.primaryHighlight, justifyContent: 'center', alignItems: 'center', marginRight: 12, }, sectionTitle: { fontSize: 18, fontWeight: '700', color: colors.darkText, flex: 1, }, sectionContent: { gap: 12, }, editButton: { padding: 8, borderRadius: 8, backgroundColor: colors.primaryHighlight, }, // Info Row Styles infoRow: { borderRadius: 12, overflow: 'hidden', }, infoRowTouchable: { padding: 14, backgroundColor: colors.lightestGray, borderRadius: 12, }, infoRowContent: { flexDirection: 'row', alignItems: 'flex-start', }, infoIconContainer: { width: 32, height: 32, borderRadius: 8, backgroundColor: colors.white, justifyContent: 'center', alignItems: 'center', marginRight: 12, marginTop: 2, }, infoTextContainer: { flex: 1, gap: 4, }, infoLabel: { fontSize: 13, color: colors.grayText, fontWeight: '500', lineHeight: 18, }, infoValue: { fontSize: 15, color: colors.darkText, fontWeight: '600', lineHeight: 21, }, // Modal Styles modalOverlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'flex-end', }, modalContent: { backgroundColor: colors.white, borderTopLeftRadius: 24, borderTopRightRadius: 24, maxHeight: '90%', paddingTop: 20, }, modalHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 20, paddingBottom: 16, borderBottomWidth: 1, borderBottomColor: colors.border, }, modalTitle: { fontSize: 20, fontWeight: '700', color: colors.darkText, }, closeButton: { padding: 4, }, formContainer: { padding: 20, maxHeight: 500, }, inputGroup: { marginBottom: 20, }, inputLabel: { fontSize: 14, fontWeight: '600', color: colors.darkText, marginBottom: 8, }, input: { borderWidth: 1, borderColor: colors.border, borderRadius: 12, padding: 14, fontSize: 15, color: colors.darkText, backgroundColor: colors.white, }, inputError: { borderColor: colors.error, }, errorText: { fontSize: 12, color: colors.error, marginTop: 4, }, modalFooter: { flexDirection: 'row', padding: 20, gap: 12, borderTopWidth: 1, borderTopColor: colors.border, }, button: { flex: 1, paddingVertical: 14, borderRadius: 12, alignItems: 'center', justifyContent: 'center', flexDirection: 'row', gap: 8, }, cancelButton: { backgroundColor: colors.lightestGray, }, saveButton: { backgroundColor: colors.primary, }, cancelButtonText: { fontSize: 16, fontWeight: '600', color: colors.darkText, }, saveButtonText: { fontSize: 16, fontWeight: '600', color: colors.white, }, }); export default ProfileTab;