269 lines
8.7 KiB
TypeScript
269 lines
8.7 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
Modal,
|
|
Image,
|
|
ActivityIndicator,
|
|
SafeAreaView,
|
|
} from 'react-native';
|
|
import Pdf from 'react-native-pdf';
|
|
import { useAppTheme } from '@theme';
|
|
import { ScreenHeader } from '@components';
|
|
import { ClipboardIcon, CloseIcon, ChevronRightIcon } from '@icons';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import { getFullUrl, isPdf } from '@utils/helper';
|
|
import { getStyles } from './documentsScreen.styles';
|
|
import { KycDocUploadResponseDocument } from '@interfaces';
|
|
import { formatDate } from '@utils/formatters';
|
|
import { useAppDispatch, useAppSelector } from '@store';
|
|
import { fetchMyKyc } from '../kycScreen';
|
|
|
|
export const DocumentsScreen: React.FC = () => {
|
|
const { colors } = useAppTheme();
|
|
const styles = getStyles(colors);
|
|
const navigation = useNavigation();
|
|
const dispatch = useAppDispatch();
|
|
|
|
const [selectedDoc, setSelectedDoc] =
|
|
useState<KycDocUploadResponseDocument | null>(null);
|
|
const [isModalLoading, setIsModalLoading] = useState<boolean>(true);
|
|
const { myKycResponse } = useAppSelector(state => state.kyc);
|
|
|
|
useEffect(() => {
|
|
dispatch(fetchMyKyc());
|
|
}, []);
|
|
|
|
const getStatusBadgeConfig = (status: string) => {
|
|
switch (status?.toUpperCase()) {
|
|
case 'APPROVED':
|
|
case 'VERIFIED':
|
|
return {
|
|
bg: colors.successLight,
|
|
text: colors.success,
|
|
label: 'APPROVED',
|
|
};
|
|
case 'PENDING':
|
|
return {
|
|
bg: colors.warningLight,
|
|
text: colors.warning,
|
|
label: 'PENDING',
|
|
};
|
|
case 'REJECTED':
|
|
return {
|
|
bg: colors.errorLight,
|
|
text: colors.error,
|
|
label: 'REJECTED',
|
|
};
|
|
default:
|
|
return {
|
|
bg: colors.primaryLight,
|
|
text: colors.primary,
|
|
label: status?.toUpperCase() || 'ACTIVE',
|
|
};
|
|
}
|
|
};
|
|
|
|
const handleOpenDocModal = (doc: KycDocUploadResponseDocument) => {
|
|
setIsModalLoading(true);
|
|
setSelectedDoc(doc);
|
|
};
|
|
|
|
const approvedCount = myKycResponse?.documents?.filter(
|
|
d => d.status === 'APPROVED',
|
|
).length;
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{/* Screen Header */}
|
|
<ScreenHeader
|
|
title="My Documents"
|
|
showBack={true}
|
|
onBack={() => navigation.goBack()}
|
|
/>
|
|
|
|
<ScrollView
|
|
contentContainerStyle={styles.scrollContainer}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
{/* Document Status Overview Banner */}
|
|
<View style={styles.summaryCard}>
|
|
<View style={styles.summaryLeft}>
|
|
<Text style={styles.summaryTitle}>Document Verification</Text>
|
|
<Text style={styles.summarySub}>
|
|
{approvedCount} of {myKycResponse?.documents?.length} Documents
|
|
Verified
|
|
</Text>
|
|
</View>
|
|
<View style={styles.summaryBadge}>
|
|
<Text style={styles.summaryBadgeText}>
|
|
{approvedCount === myKycResponse?.documents?.length
|
|
? 'VERIFIED'
|
|
: 'PENDING'}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<Text style={styles.sectionTitle}>Uploaded Documents</Text>
|
|
|
|
{myKycResponse?.documents?.length === 0 ? (
|
|
<View style={styles.emptyContainer}>
|
|
<ClipboardIcon size={48} color={colors.placeholder} />
|
|
<Text style={styles.emptyTitle}>No Documents Found</Text>
|
|
<Text style={styles.emptySub}>
|
|
Your uploaded documents will appear here.
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
myKycResponse?.documents?.map(doc => {
|
|
const statusConfig = getStatusBadgeConfig(doc.status);
|
|
const formattedDocName =
|
|
doc.documentType === 'Pan' ? 'PAN Card' : doc.documentType;
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
key={doc.id}
|
|
style={styles.docCard}
|
|
activeOpacity={0.7}
|
|
onPress={() => handleOpenDocModal(doc)}
|
|
>
|
|
{/* Header Row */}
|
|
<View style={styles.cardHeader}>
|
|
<View style={styles.cardHeaderLeft}>
|
|
<View style={styles.iconContainer}>
|
|
<ClipboardIcon size={22} color={colors.primary} />
|
|
</View>
|
|
<View style={styles.docTypeContainer}>
|
|
<Text style={styles.docTitle} numberOfLines={1}>
|
|
{formattedDocName}
|
|
</Text>
|
|
<Text style={styles.docNumber}>
|
|
Doc #: {doc.documentNumber}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View
|
|
style={[
|
|
styles.statusBadge,
|
|
{ backgroundColor: statusConfig.bg },
|
|
]}
|
|
>
|
|
<Text
|
|
style={[styles.statusText, { color: statusConfig.text }]}
|
|
>
|
|
{statusConfig.label}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Details Section */}
|
|
<View style={styles.detailsRow}>
|
|
<View style={styles.detailItem}>
|
|
<Text style={styles.detailLabel}>Uploaded On</Text>
|
|
<Text style={styles.detailValue}>
|
|
{formatDate(doc.createdAt)}
|
|
</Text>
|
|
</View>
|
|
|
|
{doc.verifiedAt && (
|
|
<View style={styles.detailItem}>
|
|
<Text style={styles.detailLabel}>Verified On</Text>
|
|
<Text style={styles.detailValue}>
|
|
{formatDate(doc.verifiedAt)}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
|
|
<View style={styles.divider} />
|
|
|
|
{/* View Button Footer */}
|
|
<View style={styles.viewButton}>
|
|
<Text style={styles.viewButtonText}>View Document</Text>
|
|
<ChevronRightIcon size={16} color={colors.primary} />
|
|
</View>
|
|
</TouchableOpacity>
|
|
);
|
|
})
|
|
)}
|
|
</ScrollView>
|
|
|
|
{/* Full Screen View Modal */}
|
|
<Modal
|
|
visible={!!selectedDoc}
|
|
animationType="slide"
|
|
statusBarTranslucent
|
|
onRequestClose={() => setSelectedDoc(null)}
|
|
>
|
|
<SafeAreaView style={styles.modalContainer}>
|
|
{/* Modal Header */}
|
|
<View style={styles.modalHeader}>
|
|
<View style={styles.modalHeaderInfo}>
|
|
<Text style={styles.modalTitle} numberOfLines={1}>
|
|
{selectedDoc?.documentType === 'Pan'
|
|
? 'PAN Card'
|
|
: selectedDoc?.documentType}{' '}
|
|
Preview
|
|
</Text>
|
|
<Text style={styles.modalSubtitle} numberOfLines={1}>
|
|
{selectedDoc?.fileName}
|
|
</Text>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={styles.closeButton}
|
|
activeOpacity={0.7}
|
|
onPress={() => setSelectedDoc(null)}
|
|
>
|
|
<CloseIcon size={20} color={colors.text} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Modal Body / Viewer */}
|
|
<View style={styles.viewerContainer}>
|
|
{isModalLoading && (
|
|
<View style={styles.loadingContainer}>
|
|
<ActivityIndicator size="large" color={colors.primary} />
|
|
<Text style={styles.loadingText}>Loading file preview...</Text>
|
|
</View>
|
|
)}
|
|
|
|
{selectedDoc &&
|
|
isPdf(selectedDoc.fileName || selectedDoc.fileUrl) ? (
|
|
<Pdf
|
|
trustAllCerts={false}
|
|
source={{
|
|
uri: getFullUrl(selectedDoc.fileUrl),
|
|
cache: true,
|
|
}}
|
|
onLoadComplete={() => setIsModalLoading(false)}
|
|
onError={error => {
|
|
setIsModalLoading(false);
|
|
console.log('PDF Load Error:', error);
|
|
}}
|
|
style={styles.pdfViewer}
|
|
/>
|
|
) : (
|
|
selectedDoc && (
|
|
<Image
|
|
source={{ uri: getFullUrl(selectedDoc.fileUrl) }}
|
|
style={styles.imageViewer}
|
|
resizeMode="contain"
|
|
onLoadStart={() => setIsModalLoading(true)}
|
|
onLoadEnd={() => setIsModalLoading(false)}
|
|
onError={() => setIsModalLoading(false)}
|
|
/>
|
|
)
|
|
)}
|
|
</View>
|
|
</SafeAreaView>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default DocumentsScreen;
|