fix: reset flow now fetches photo before deleting, shows preview + manual entry

- resetPhoto() now downloads the photo blob before calling the reset endpoint,
  then re-shows it in the detail view with preview and manual entry
- resetAndReupload() same treatment, with fallback to server fetch
- Added Reset button to ALL server results (not just duplicates)
- Preview in Previous Photos cards with lightbox (prev-thumb + openLightbox)
This commit is contained in:
2026-05-25 20:48:20 -04:00
parent 23f479dd0c
commit db45b386fa
+60 -6
View File
@@ -604,11 +604,37 @@ function renderPrevCard(p) {
}
async function resetPhoto(photoId) {
if (!confirm('Reset this entry? The photo will be deleted from the database and can be re-uploaded as new.')) return;
if (!confirm('Reset this entry and re-process from scratch?')) return;
// Find the card to get the original filename
const card = document.querySelector(`#reEng${photoId}`)?.closest('.prev-photo-card');
const filename = card?.querySelector('.prev-filename')?.textContent?.trim() || 'photo.jpg';
try {
const resp = await fetch(`/api/photos/${photoId}/reset`, { method: 'POST' });
if (!resp.ok) throw new Error('Reset failed');
loadPreviousPhotos();
// 1. Fetch the original file BEFORE reset deletes it
const fileResp = await fetch(`/api/photos/${photoId}/file`);
if (!fileResp.ok) throw new Error('Could not load photo file');
const blob = await fileResp.blob();
// 2. Reset in DB (deletes DB record + file from disk)
const resetResp = await fetch(`/api/photos/${photoId}/reset`, { method: 'POST' });
if (!resetResp.ok) throw new Error('Reset failed');
// 3. Rebuild a File object and scan it like a fresh upload
const file = new File([blob], filename, { type: blob.type || 'image/jpeg' });
const photoData = await scanPhoto(file);
photoData.file = file;
// 4. Clear current state and add to gallery
resetAll();
allPhotos = [photoData];
updateSummary();
renderGallery();
// 5. Show the detail view with preview image + manual entry
showDetail(0);
document.getElementById('serverSection').style.display = 'none';
document.getElementById('detail').scrollIntoView({ behavior: 'smooth' });
} catch (e) {
alert('Reset failed: ' + e.message);
}
@@ -618,9 +644,31 @@ async function resetAndReupload(photoId) {
if (!photoId) { alert('No photo ID available'); return; }
if (!confirm('Reset this entry and re-process as fresh?')) return;
try {
// Try to use local file first, fall back to fetching from server
let file = null;
if (selectedIdx >= 0 && allPhotos[selectedIdx]?.file) {
file = allPhotos[selectedIdx].file;
} else {
const fileResp = await fetch(`/api/photos/${photoId}/file`);
if (fileResp.ok) {
const blob = await fileResp.blob();
file = new File([blob], 'photo.jpg', { type: blob.type || 'image/jpeg' });
}
}
if (!file) throw new Error('No photo file available');
await fetch(`/api/photos/${photoId}/reset`, { method: 'POST' });
// Re-trigger the upload
uploadSelected();
// Scan and show in detail view
const photoData = await scanPhoto(file);
photoData.file = file;
resetAll();
allPhotos = [photoData];
updateSummary();
renderGallery();
showDetail(0);
document.getElementById('serverSection').style.display = 'none';
document.getElementById('detail').scrollIntoView({ behavior: 'smooth' });
} catch (e) {
alert('Reset failed: ' + e.message);
}
@@ -905,6 +953,12 @@ async function uploadSelected() {
'<div id="manualResult" style="margin-top:4px;"></div>' +
'</div>';
// Reset button — always available to start fresh
html += '<div style="margin-top:10px;padding-top:10px;border-top:1px solid var(--border);text-align:center;">' +
'<button class="btn btn-outline btn-xs" onclick="resetAndReupload(' + (data.photo_id || 'null') + ')" style="color:var(--amber);border-color:var(--amber);">🔄 Reset & Re-process from scratch</button>' +
'<div style="font-size:10px;color:var(--text3);margin-top:4px;">Clears DB entry and lets you re-analyze with manual entry</div>' +
'</div>';
div.innerHTML = html;
} catch (e) {
div.innerHTML = '<div class="empty">❌ Upload failed: ' + esc(e.message) + '</div>';