154 lines
4.4 KiB
JavaScript
154 lines
4.4 KiB
JavaScript
import { Alert, FlatList, StyleSheet, Text, View } from 'react-native';
|
|
import * as DocumentPicker from 'expo-document-picker';
|
|
import ScreenContainer from '../../components/ScreenContainer';
|
|
import PrimaryButton from '../../components/PrimaryButton';
|
|
import { colors } from '../../theme/colors';
|
|
import { useAuth } from '../../context/AuthContext';
|
|
import { useSync } from '../../context/SyncContext';
|
|
import { uploadDocument } from '../../api/documents';
|
|
import { downloadAndShareFile } from '../../utils/files';
|
|
import { API_BASE_URL } from '../../config/env';
|
|
|
|
function SectionCard({ title, rows, emptyText, actionLabel, onActionPress, onDownload, token, type }) {
|
|
return (
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>{title}</Text>
|
|
{actionLabel ? <PrimaryButton title={actionLabel} onPress={onActionPress} /> : null}
|
|
{rows.length === 0 ? (
|
|
<Text style={styles.emptyText}>{emptyText}</Text>
|
|
) : (
|
|
<FlatList
|
|
data={rows}
|
|
keyExtractor={(item) => `${type}-${item.id}`}
|
|
scrollEnabled={false}
|
|
ItemSeparatorComponent={() => <View style={{ height: 10 }} />}
|
|
renderItem={({ item }) => (
|
|
<View style={styles.itemCard}>
|
|
<Text style={styles.itemTitle}>{item.title || item.signed_filename}</Text>
|
|
<Text style={styles.itemMeta}>
|
|
{item.status || item.document_title || 'Documento'}
|
|
</Text>
|
|
<PrimaryButton
|
|
title="Descargar / Compartir"
|
|
variant="secondary"
|
|
onPress={() => onDownload(item, token)}
|
|
/>
|
|
</View>
|
|
)}
|
|
/>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
export default function DocumentsScreen() {
|
|
const { tokens } = useAuth();
|
|
const { documents, signedDocuments, syncNow, refreshLocalCache } = useSync();
|
|
|
|
const handleUpload = async () => {
|
|
const picked = await DocumentPicker.getDocumentAsync({
|
|
type: 'application/pdf',
|
|
copyToCacheDirectory: true,
|
|
});
|
|
|
|
if (picked.canceled) return;
|
|
const file = picked.assets[0];
|
|
const formData = new FormData();
|
|
formData.append('file', {
|
|
uri: file.uri,
|
|
name: file.name,
|
|
type: 'application/pdf',
|
|
});
|
|
|
|
try {
|
|
await uploadDocument(formData);
|
|
await syncNow();
|
|
refreshLocalCache();
|
|
Alert.alert('Documentos', 'PDF subido correctamente.');
|
|
} catch (error) {
|
|
Alert.alert('Documentos', error.response?.data?.error || 'No se pudo subir el PDF.');
|
|
}
|
|
};
|
|
|
|
const handleSync = async () => {
|
|
try {
|
|
await syncNow();
|
|
Alert.alert('Documentos', 'Documentos sincronizados.');
|
|
} catch (error) {
|
|
Alert.alert('Documentos', error.response?.data?.error || 'No se pudo sincronizar.');
|
|
}
|
|
};
|
|
|
|
const handleDownloadOriginal = async (item) => {
|
|
await downloadAndShareFile({
|
|
url: `${API_BASE_URL}/documents/${item.id}/download`,
|
|
token: tokens.accessToken,
|
|
filename: item.filename || `${item.title}.pdf`,
|
|
});
|
|
};
|
|
|
|
const handleDownloadSigned = async (item) => {
|
|
await downloadAndShareFile({
|
|
url: `${API_BASE_URL}/signatures/${item.id}/download`,
|
|
token: tokens.accessToken,
|
|
filename: item.signed_filename,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<ScreenContainer>
|
|
<PrimaryButton title="Sincronizar documentos" onPress={handleSync} variant="secondary" />
|
|
<SectionCard
|
|
title="Originales"
|
|
rows={documents}
|
|
emptyText="No hay documentos sincronizados en el teléfono."
|
|
actionLabel="Subir PDF"
|
|
onActionPress={handleUpload}
|
|
onDownload={handleDownloadOriginal}
|
|
token={tokens.accessToken}
|
|
type="original"
|
|
/>
|
|
<SectionCard
|
|
title="Firmados"
|
|
rows={signedDocuments}
|
|
emptyText="No hay documentos firmados sincronizados."
|
|
onDownload={handleDownloadSigned}
|
|
token={tokens.accessToken}
|
|
type="signed"
|
|
/>
|
|
</ScreenContainer>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
section: {
|
|
backgroundColor: colors.surface,
|
|
borderRadius: 18,
|
|
padding: 16,
|
|
gap: 12,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: colors.text,
|
|
},
|
|
emptyText: {
|
|
color: colors.textMuted,
|
|
},
|
|
itemCard: {
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
borderRadius: 14,
|
|
padding: 14,
|
|
gap: 8,
|
|
},
|
|
itemTitle: {
|
|
color: colors.text,
|
|
fontWeight: '700',
|
|
},
|
|
itemMeta: {
|
|
color: colors.textMuted,
|
|
fontSize: 12,
|
|
},
|
|
});
|