diff --git a/CLAUDE.md b/CLAUDE.md index 97fbdc7..f8b9adf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -420,6 +420,30 @@ const response = await api.get('/endpoint'); → **Frontend**: Clear node_modules, check Node.js version (16+), Vite auto-ports → **Database**: Verify SSH tunnel, Oracle listener, credentials, test `/health` +### Known Issues & Fixes + +#### Mobile File Upload ERR_NETWORK (Android/iOS) +**Problem**: File uploads (OCR, attachments) fail with `ERR_NETWORK` (status 0) on mobile browsers, but work on desktop. + +**Cause**: Android/iOS browsers invalidate File object references after accessing properties (`file.name`, `file.size`, `file.type`) due to **SnapshotState** in the W3C File API. See [Chromium Bug #40703873](https://issues.chromium.org/40703873). + +**Solution**: Clone the file into memory immediately after selection, before accessing any properties: +```javascript +const handleFile = async (file) => { + // Validations first... + + // FIX: Clone file to memory to avoid SnapshotState invalidation + const arrayBuffer = await file.arrayBuffer() + const clonedFile = new File([arrayBuffer], file.name, { + type: file.type, + lastModified: file.lastModified + }) + selectedFile.value = clonedFile +} +``` + +**Applied in**: `src/modules/data-entry/components/ocr/OCRUploadZone.vue` + --- ## 🔧 Tech Stack diff --git a/src/modules/data-entry/components/ocr/OCRUploadZone.vue b/src/modules/data-entry/components/ocr/OCRUploadZone.vue index 25fce18..15c4e1d 100644 --- a/src/modules/data-entry/components/ocr/OCRUploadZone.vue +++ b/src/modules/data-entry/components/ocr/OCRUploadZone.vue @@ -217,7 +217,7 @@ const onFileSelected = (event) => { } } -const handleFile = (file) => { +const handleFile = async (file) => { // Validate file type const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'] if (!allowedTypes.includes(file.type)) { @@ -232,8 +232,24 @@ const handleFile = (file) => { } error.value = null - selectedFile.value = file - emit('file-selected', file) + + // FIX pentru Android: Clonăm fișierul în memorie IMEDIAT după selectare + // pentru a evita invalidarea referinței de către browser (SnapshotState issue) + // See: https://issues.chromium.org/40703873 + try { + const arrayBuffer = await file.arrayBuffer() + const clonedFile = new File([arrayBuffer], file.name, { + type: file.type, + lastModified: file.lastModified + }) + selectedFile.value = clonedFile + emit('file-selected', clonedFile) + } catch (e) { + // Fallback pentru browsere care nu suportă arrayBuffer + console.warn('File clone failed, using original:', e) + selectedFile.value = file + emit('file-selected', file) + } } const processOCR = async () => {