Initial LinkedSign platform
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
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,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user