window.Upload = {
frontFile: null,
backFile: null,
isProcessing: false,
init: function () {
var self = this;
// Doc type selector — show/hide back upload
var docTypeSelect = Utils.$('#doc-type-select');
docTypeSelect.addEventListener('change', function () {
self._updateLayout();
self._updateProcessButton();
});
// Front drop zone
this._setupDropZone('front');
// Back drop zone
this._setupDropZone('back');
// Process button
Utils.$('#btn-process').addEventListener('click', function () {
self.processDocument();
});
this._updateLayout();
},
_setupDropZone: function (side) {
var self = this;
var dropZone = Utils.$('#drop-zone-' + side);
var fileInput = Utils.$('#file-input-' + side);
// Click to browse (skip in camera-only mode)
dropZone.addEventListener('click', function (e) {
if (e.target.classList.contains('btn-remove')) return;
if (e.target.classList.contains('btn-camera')) return;
if (dropZone.classList.contains('camera-only')) return;
if (!self.isProcessing) fileInput.click();
});
dropZone.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
if (dropZone.classList.contains('camera-only')) return;
if (!self.isProcessing) fileInput.click();
}
});
// File input change
fileInput.addEventListener('change', function () {
if (fileInput.files.length > 0) {
self._setFile(side, fileInput.files[0]);
}
fileInput.value = '';
});
// Drag and drop
dropZone.addEventListener('dragover', function (e) {
e.preventDefault();
if (!dropZone.classList.contains('camera-only')) {
dropZone.classList.add('drag-active');
}
});
dropZone.addEventListener('dragleave', function () {
dropZone.classList.remove('drag-active');
});
dropZone.addEventListener('drop', function (e) {
e.preventDefault();
dropZone.classList.remove('drag-active');
if (dropZone.classList.contains('camera-only')) return;
if (!self.isProcessing && e.dataTransfer.files.length > 0) {
self._setFile(side, e.dataTransfer.files[0]);
}
});
// Remove button
var removeBtn = Utils.$('.btn-remove', dropZone);
if (removeBtn) {
removeBtn.addEventListener('click', function (e) {
e.stopPropagation();
self._clearFile(side);
});
}
// Camera buttons (may be multiple: one in content, one in camera-only)
var cameraBtns = dropZone.querySelectorAll('.btn-camera');
for (var i = 0; i < cameraBtns.length; i++) {
cameraBtns[i].addEventListener('click', function (e) {
e.stopPropagation();
if (!self.isProcessing) {
Camera.open(side);
}
});
}
},
_setFile: function (side, file) {
var check = Utils.validateFile(file);
if (!check.valid) {
Utils.showToast(check.error, 'error');
return;
}
if (side === 'front') {
this.frontFile = file;
} else {
this.backFile = file;
}
// Show preview
var dropZone = Utils.$('#drop-zone-' + side);
var content = Utils.$('.drop-zone-content', dropZone);
var preview = Utils.$('.drop-zone-preview', dropZone);
var thumb = Utils.$('.preview-thumb', dropZone);
var nameEl = Utils.$('.preview-name', dropZone);
content.classList.add('hidden');
var cameraOnly = Utils.$('.drop-zone-camera-only', dropZone);
if (cameraOnly) cameraOnly.classList.add('hidden');
preview.classList.remove('hidden');
thumb.src = URL.createObjectURL(file);
nameEl.textContent = file.name;
this._updateProcessButton();
},
_clearFile: function (side) {
if (side === 'front') {
this.frontFile = null;
} else {
this.backFile = null;
}
var dropZone = Utils.$('#drop-zone-' + side);
var content = Utils.$('.drop-zone-content', dropZone);
var preview = Utils.$('.drop-zone-preview', dropZone);
var thumb = Utils.$('.preview-thumb', dropZone);
var cameraOnly = Utils.$('.drop-zone-camera-only', dropZone);
var docType = Utils.$('#doc-type-select').value;
if (side === 'front' && docType === 'product_serial' && cameraOnly) {
content.classList.add('hidden');
cameraOnly.classList.remove('hidden');
} else {
content.classList.remove('hidden');
if (cameraOnly) cameraOnly.classList.add('hidden');
}
preview.classList.add('hidden');
if (thumb.src) {
URL.revokeObjectURL(thumb.src);
thumb.src = '';
}
this._updateProcessButton();
},
_updateLayout: function () {
var docType = Utils.$('#doc-type-select').value;
var backGroup = Utils.$('#back-upload-group');
var frontLabel = Utils.$('.upload-label');
var isSerial = docType === 'product_serial';
if (docType === 'sa_id_card') {
backGroup.classList.remove('hidden');
} else {
backGroup.classList.add('hidden');
this._clearFile('back');
}
if (frontLabel) {
frontLabel.innerHTML = isSerial
? 'Product Image *'
: 'Front Image *';
}
// Serial mode: camera-only for front drop zone
var frontDropZone = Utils.$('#drop-zone-front');
if (isSerial) {
this._clearFile('front');
frontDropZone.classList.add('camera-only');
} else {
var frontPreview = Utils.$('.drop-zone-preview', frontDropZone);
if (frontPreview.classList.contains('hidden')) {
Utils.$('.drop-zone-content', frontDropZone).classList.remove('hidden');
}
var frontCameraOnly = Utils.$('.drop-zone-camera-only', frontDropZone);
if (frontCameraOnly) frontCameraOnly.classList.add('hidden');
frontDropZone.classList.remove('camera-only');
}
},
_updateProcessButton: function () {
var btn = Utils.$('#btn-process');
btn.disabled = !this.frontFile || this.isProcessing;
},
processDocument: function () {
if (!this.frontFile || this.isProcessing) return;
var self = this;
var docType = Utils.$('#doc-type-select').value;
this.isProcessing = true;
this._updateProcessButton();
Results.showLoading(this.frontFile);
var startTime = performance.now();
var isSerial = docType === 'product_serial';
var apiCall = isSerial
? Api.scanSerial(this.frontFile)
: Api.processDocument(this.frontFile, docType, this.backFile);
apiCall
.then(function (result) {
var duration = performance.now() - startTime;
if (isSerial) {
Results.renderSerial(result, self.frontFile);
} else {
Results.render(result, self.frontFile);
}
History.add(History.buildEntry(result, self.frontFile, duration, null));
Utils.showToast(isSerial ? 'Serial number processed' : 'Document processed successfully', 'success');
})
.catch(function (err) {
var duration = performance.now() - startTime;
Results.showError(err.message);
History.add(History.buildEntry(null, self.frontFile, duration, err.message));
if (err.status === 401) {
Utils.$('#api-key-input').classList.add('error');
Utils.showToast('Authentication failed. Check your API key.', 'error');
} else if (err.status === 429) {
Utils.showToast('Rate limit exceeded. Wait a moment and try again.', 'warning');
} else {
Utils.showToast(err.message, 'error');
}
})
.finally(function () {
self.isProcessing = false;
self._updateProcessButton();
});
},
};