194 lines
5.6 KiB
TypeScript
194 lines
5.6 KiB
TypeScript
import React from 'react';
|
|
import { View, Text, TextInput, TouchableOpacity, Alert } from 'react-native';
|
|
import { useAppTheme } from '@theme';
|
|
import Svg, { Path } from 'react-native-svg';
|
|
import { pick, types, errorCodes } from '@react-native-documents/picker';
|
|
import { getStyles } from './KycDocumentCard.styles';
|
|
|
|
export interface KycDocument {
|
|
id: string;
|
|
name: string;
|
|
idNumber: string;
|
|
fileName: string | null;
|
|
fileUri?: string | null;
|
|
fileType?: string | null;
|
|
status?: string;
|
|
}
|
|
|
|
interface KycDocumentCardProps {
|
|
document: KycDocument;
|
|
index: number;
|
|
onUpdate?: (updatedFields: Partial<KycDocument>) => void;
|
|
onRemove?: () => void;
|
|
readOnly?: boolean;
|
|
}
|
|
|
|
const UploadIcon = ({ size = 18, color = '#666' }) => (
|
|
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
<Path
|
|
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12"
|
|
stroke={color}
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</Svg>
|
|
);
|
|
|
|
export const KycDocumentCard: React.FC<KycDocumentCardProps> = ({
|
|
document,
|
|
index,
|
|
onUpdate,
|
|
onRemove,
|
|
readOnly = false,
|
|
}) => {
|
|
const { colors } = useAppTheme();
|
|
const styles = getStyles(colors);
|
|
|
|
const handleSelectFile = async () => {
|
|
if (readOnly) return;
|
|
try {
|
|
const [result] = await pick({
|
|
type: [types.pdf, types.images],
|
|
allowMultiSelection: false,
|
|
});
|
|
|
|
onUpdate?.({
|
|
fileName: result.name ?? `document_${Date.now()}`,
|
|
fileUri: result.uri,
|
|
fileType: result.type ?? 'application/octet-stream',
|
|
});
|
|
} catch (err: any) {
|
|
if (err?.code === errorCodes.OPERATION_CANCELED) {
|
|
// User dismissed the picker — no action needed
|
|
return;
|
|
}
|
|
Alert.alert('File Picker Error', err?.message ?? 'Failed to open document picker.');
|
|
}
|
|
};
|
|
|
|
const renderStatusBadge = (status?: string) => {
|
|
if (!status) return null;
|
|
const normalized = status.toLowerCase();
|
|
let bgColor = '#FFF9E6';
|
|
let textColor = '#B27B00';
|
|
let label = status;
|
|
|
|
if (normalized === 'verified' || normalized === 'approved') {
|
|
bgColor = '#E6F4EA';
|
|
textColor = '#137333';
|
|
label = 'Verified';
|
|
} else if (normalized === 'rejected' || normalized === 'failed') {
|
|
bgColor = '#FCE8E6';
|
|
textColor = '#C5221F';
|
|
label = 'Rejected';
|
|
} else if (normalized === 'pending' || normalized === 'submitted' || normalized === 'under_review') {
|
|
bgColor = '#FFF9E6';
|
|
textColor = '#B27B00';
|
|
label = 'Pending';
|
|
}
|
|
|
|
return (
|
|
<View
|
|
style={{
|
|
backgroundColor: bgColor,
|
|
paddingHorizontal: 8,
|
|
paddingVertical: 4,
|
|
borderRadius: 4,
|
|
alignSelf: 'center',
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
color: textColor,
|
|
fontSize: 10,
|
|
fontWeight: 'bold',
|
|
textTransform: 'uppercase',
|
|
}}
|
|
>
|
|
{label}
|
|
</Text>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<View style={styles.cardContainer}>
|
|
<View style={styles.headerRow}>
|
|
<Text style={styles.docNumberText}>Document {index + 1}</Text>
|
|
{readOnly && renderStatusBadge(document.status)}
|
|
{!readOnly && onRemove && (
|
|
<TouchableOpacity
|
|
style={styles.removeButton}
|
|
onPress={onRemove}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.removeButtonText}>Remove</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
|
|
{/* Document Name / Type */}
|
|
<View style={styles.fieldContainer}>
|
|
<Text style={styles.label}>Document Name / Type</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
placeholder="e.g. National ID or Trade License"
|
|
placeholderTextColor={colors.placeholder}
|
|
value={document.name}
|
|
onChangeText={(text) => onUpdate?.({ name: text })}
|
|
autoCapitalize="sentences"
|
|
editable={!readOnly}
|
|
/>
|
|
</View>
|
|
|
|
{/* Document Identification Number */}
|
|
<View style={styles.fieldContainer}>
|
|
<Text style={styles.label}>Document Identification Number</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
placeholder="e.g. GSTIN/Aadhar/ID code"
|
|
placeholderTextColor={colors.placeholder}
|
|
value={document.idNumber}
|
|
onChangeText={(text) => onUpdate?.({ idNumber: text })}
|
|
autoCapitalize="characters"
|
|
editable={!readOnly}
|
|
/>
|
|
</View>
|
|
|
|
{/* Document Attachment */}
|
|
<View style={styles.fieldContainer}>
|
|
<Text style={styles.label}>Document Attachment File (JPG, PNG, PDF)</Text>
|
|
<TouchableOpacity
|
|
style={[
|
|
styles.uploadBox,
|
|
document.fileName ? styles.uploadBoxActive : null,
|
|
readOnly ? { borderStyle: 'solid', opacity: 0.8 } : null,
|
|
]}
|
|
onPress={handleSelectFile}
|
|
activeOpacity={0.8}
|
|
disabled={readOnly}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.uploadText,
|
|
document.fileName ? styles.fileNameText : null,
|
|
]}
|
|
numberOfLines={1}
|
|
>
|
|
{document.fileName ? document.fileName : 'SELECT DOCUMENT FILE...'}
|
|
</Text>
|
|
{!readOnly && <UploadIcon color={document.fileName ? colors.primary : colors.textSecondary} />}
|
|
</TouchableOpacity>
|
|
{!readOnly && (
|
|
<Text style={styles.helperText}>
|
|
Supported: pdf, png, jpg, or jpeg under 200kb only.
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default KycDocumentCard;
|