164 lines
5.3 KiB
TypeScript
164 lines
5.3 KiB
TypeScript
import { buildApiUrl, API_BASE_URL, API_ENDPOINTS } from "../config/api";
|
|
import { DocumentoChecksum, DocumentosChecksumsResponse, ReservaDocumentos } from "../types";
|
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import * as FileSystem from "expo-file-system/legacy";
|
|
|
|
const DOCUMENTOS_DIR = `${FileSystem.documentDirectory}documentos/`;
|
|
|
|
// Devolve o caminho local de um documento
|
|
const getLocalPath = (idDocumento: string, caminhoFicheiro: string): string => {
|
|
const fileName = caminhoFicheiro.split("/").pop() || `documento_${idDocumento}.pdf`;
|
|
return `${DOCUMENTOS_DIR}${idDocumento}_${fileName}`;
|
|
};
|
|
|
|
// Garante que o diretório de documentos existe
|
|
const ensureDir = async (): Promise<void> => {
|
|
const info = await FileSystem.getInfoAsync(DOCUMENTOS_DIR);
|
|
if (!info.exists) {
|
|
await FileSystem.makeDirectoryAsync(DOCUMENTOS_DIR, { intermediates: true });
|
|
}
|
|
};
|
|
|
|
// Constrói URL completa a partir de um caminho relativo
|
|
const buildUrl = (path: string | null | undefined): string => {
|
|
if (!path) return "";
|
|
if (path.startsWith("http")) return path;
|
|
const base = API_BASE_URL.replace(/\/pt\/app$/, "");
|
|
return `${base}${path.startsWith("/") ? path : `/${path}`}`;
|
|
};
|
|
|
|
// Checksum guardado localmente para um documento
|
|
export const getStoredChecksum = async (idDocumento: string): Promise<string | null> => {
|
|
try {
|
|
return await AsyncStorage.getItem(`@cruiseLovers:documento:${idDocumento}:checksum`);
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Guarda o checksum localmente
|
|
export const saveStoredChecksum = async (idDocumento: string, checksum: string): Promise<void> => {
|
|
try {
|
|
await AsyncStorage.setItem(`@cruiseLovers:documento:${idDocumento}:checksum`, checksum);
|
|
} catch {
|
|
// silencioso
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Devolve o URI local de um documento se este já estiver descarregado, ou null caso contrário.
|
|
*/
|
|
export const getLocalDocumentUri = async (idDocumento: string, caminhoFicheiro: string): Promise<string | null> => {
|
|
try {
|
|
const localPath = getLocalPath(idDocumento, caminhoFicheiro);
|
|
const info = await FileSystem.getInfoAsync(localPath);
|
|
return info.exists ? localPath : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Faz download de um único documento
|
|
export const downloadDocumento = async (documento: DocumentoChecksum): Promise<string | null> => {
|
|
try {
|
|
const url = buildUrl(documento.caminhoFicheiro);
|
|
if (!url) return null;
|
|
|
|
await ensureDir();
|
|
|
|
const localPath = getLocalPath(documento.idDocumento, documento.caminhoFicheiro);
|
|
|
|
const result = await FileSystem.downloadAsync(url, localPath);
|
|
|
|
if (result.status < 200 || result.status >= 300) {
|
|
console.error(`Download falhou com status ${result.status}`);
|
|
return null;
|
|
}
|
|
|
|
if (documento.checksum) {
|
|
await saveStoredChecksum(documento.idDocumento, documento.checksum);
|
|
}
|
|
|
|
return localPath;
|
|
} catch (error) {
|
|
console.error("Erro ao fazer download:", error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Busca checksums do servidor
|
|
export const getDocumentosChecksums = async (token: string): Promise<DocumentosChecksumsResponse | null> => {
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append("token", token);
|
|
|
|
const response = await fetch(buildApiUrl(API_ENDPOINTS.GET_DOCUMENTOS_CHECKSUMS), {
|
|
method: "POST",
|
|
headers: { Accept: "application/json" },
|
|
body: formData,
|
|
});
|
|
|
|
return (await response.json()) as DocumentosChecksumsResponse;
|
|
} catch (error) {
|
|
console.error("Erro ao buscar checksums de documentos:", error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Verifica quais documentos precisam ser (re)descarregados
|
|
export const verificarDocumentosParaDownload = async (
|
|
reservaDocumentos: ReservaDocumentos[]
|
|
): Promise<DocumentoChecksum[]> => {
|
|
const para: DocumentoChecksum[] = [];
|
|
|
|
for (const reserva of reservaDocumentos) {
|
|
for (const doc of reserva.documentos) {
|
|
if (!doc.caminhoFicheiro || !doc.checksum) continue;
|
|
|
|
const storedChecksum = await getStoredChecksum(doc.idDocumento);
|
|
const localPath = getLocalPath(doc.idDocumento, doc.caminhoFicheiro);
|
|
const info = await FileSystem.getInfoAsync(localPath);
|
|
|
|
if (doc.checksum !== storedChecksum || !info.exists) {
|
|
para.push(doc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return para;
|
|
};
|
|
|
|
/** Remove documentos descarregados e checksums (ex.: no logout). */
|
|
export const clearDownloadedDocuments = async (): Promise<void> => {
|
|
try {
|
|
const keys = await AsyncStorage.getAllKeys();
|
|
const docKeys = keys.filter((key) => key.startsWith("@cruiseLovers:documento:"));
|
|
if (docKeys.length > 0) {
|
|
await AsyncStorage.multiRemove(docKeys);
|
|
}
|
|
const info = await FileSystem.getInfoAsync(DOCUMENTOS_DIR);
|
|
if (info.exists) {
|
|
await FileSystem.deleteAsync(DOCUMENTOS_DIR, { idempotent: true });
|
|
}
|
|
} catch (error) {
|
|
console.error("Erro ao limpar documentos locais:", error);
|
|
}
|
|
};
|
|
|
|
// Descarrega múltiplos documentos
|
|
export const downloadDocumentos = async (
|
|
documentos: DocumentoChecksum[],
|
|
onProgress?: (current: number, total: number) => void
|
|
): Promise<{ sucesso: number; falhas: number }> => {
|
|
let sucesso = 0;
|
|
let falhas = 0;
|
|
|
|
for (let i = 0; i < documentos.length; i++) {
|
|
if (onProgress) onProgress(i + 1, documentos.length);
|
|
const resultado = await downloadDocumento(documentos[i]);
|
|
resultado ? sucesso++ : falhas++;
|
|
}
|
|
|
|
return { sucesso, falhas };
|
|
};
|