feat: scan existing asset redirects to detail view instead of scan result card
When a user scans a barcode that matches an existing asset: - Redirect directly to the asset detail view (Assets tab) - Auto-checkin still runs in background if GPS available - Show a toast notification with the asset name When scanning a barcode not in database: - Switch back to Add Asset tab and show the create form - Deferred status update survives async startScanning No backend changes needed. Closes #39
This commit is contained in:
+37
-5
@@ -416,6 +416,10 @@
|
|||||||
.asset-item .ai-icon.cat-Other { background: #1a1b26; }
|
.asset-item .ai-icon.cat-Other { background: #1a1b26; }
|
||||||
.asset-item .ai-info { flex: 1; min-width: 0; }
|
.asset-item .ai-info { flex: 1; min-width: 0; }
|
||||||
.asset-item .ai-name { font-weight: 600; font-size: 15px; line-height: 1.35; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
.asset-item .ai-name { font-weight: 600; font-size: 15px; line-height: 1.35; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||||
|
.asset-item .ai-company { font-weight: 600; font-size: 14px; line-height: 1.3; }
|
||||||
|
.asset-item .ai-location-line { font-size: 12px; color: var(--text2); margin-top: 1px; display: flex; gap: 4px; flex-wrap: wrap; }
|
||||||
|
.asset-item .ai-location-line .tag { background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 4px; }
|
||||||
|
.asset-item .ai-building { font-size: 12px; color: var(--text1); margin-top: 2px; }
|
||||||
.asset-item .ai-address { font-size: 12px; color: var(--text2); margin-top: 2px; }
|
.asset-item .ai-address { font-size: 12px; color: var(--text2); margin-top: 2px; }
|
||||||
.asset-item .ai-location { font-size: 13px; color: var(--text1); font-weight: 500; margin-top: 3px; }
|
.asset-item .ai-location { font-size: 13px; color: var(--text1); font-weight: 500; margin-top: 3px; }
|
||||||
.asset-item .ai-meta { font-size: 12px; color: var(--text2); margin-top: 3px; }
|
.asset-item .ai-meta { font-size: 12px; color: var(--text2); margin-top: 3px; }
|
||||||
@@ -2431,7 +2435,14 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const asset = await api(`/api/assets/search?machine_id=${encodeURIComponent(machineId)}`);
|
const asset = await api(`/api/assets/search?machine_id=${encodeURIComponent(machineId)}`);
|
||||||
showScannedAsset(asset);
|
// Asset exists — go directly to its detail view
|
||||||
|
showToast(`${esc(asset.name)} — showing details`, false);
|
||||||
|
// Auto-checkin if GPS available (background, non-blocking)
|
||||||
|
if (AppState.gpsLat != null) {
|
||||||
|
doAutoCheckin(asset.id);
|
||||||
|
}
|
||||||
|
switchTab('tabAssets');
|
||||||
|
viewAsset(asset.id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === 'Asset not found' || e.message.includes('404')) {
|
if (e.message === 'Asset not found' || e.message.includes('404')) {
|
||||||
showNewAssetForm(machineId);
|
showNewAssetForm(machineId);
|
||||||
@@ -2498,7 +2509,12 @@
|
|||||||
|
|
||||||
function showNewAssetForm(machineId) {
|
function showNewAssetForm(machineId) {
|
||||||
currentScannedMachineId = machineId;
|
currentScannedMachineId = machineId;
|
||||||
setScanStatus('Machine ID not in database — create asset below', 'error');
|
switchTab('tabAddAsset');
|
||||||
|
// Defer status update so it runs after async startScanning completes
|
||||||
|
setTimeout(() => {
|
||||||
|
setScanStatus('Machine ID not in database — create asset below', 'error');
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
|
||||||
document.getElementById('newMachineId').value = machineId;
|
document.getElementById('newMachineId').value = machineId;
|
||||||
document.getElementById('newName').value = '';
|
document.getElementById('newName').value = '';
|
||||||
@@ -3702,9 +3718,7 @@
|
|||||||
<div class="asset-item" onclick="viewAsset(${a.id})">
|
<div class="asset-item" onclick="viewAsset(${a.id})">
|
||||||
<div class="ai-icon${iconWide}" style="background:${catColor}22;color:${catColor}">${icon}</div>
|
<div class="ai-icon${iconWide}" style="background:${catColor}22;color:${catColor}">${icon}</div>
|
||||||
<div class="ai-info">
|
<div class="ai-info">
|
||||||
<div class="ai-name">${esc(a.name)}</div>
|
${renderAssetCardContent(a)}
|
||||||
${a.address ? `<div class="ai-address">📍 ${esc(a.address)}</div>` : ''}
|
|
||||||
${(a.floor || a.building_number || a.building_name || a.room) ? `<div class="ai-location">${[a.floor, a.building_number, a.building_name, a.room].filter(Boolean).join(' · ')}</div>` : ''}
|
|
||||||
<div class="ai-meta">
|
<div class="ai-meta">
|
||||||
${esc(a.machine_id)}${a.serial_number ? ' · S/N: ' + esc(a.serial_number) : ''}
|
${esc(a.machine_id)}${a.serial_number ? ' · S/N: ' + esc(a.serial_number) : ''}
|
||||||
${a.make ? ' · ' + esc(a.make) : ''}
|
${a.make ? ' · ' + esc(a.make) : ''}
|
||||||
@@ -3717,6 +3731,24 @@
|
|||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderAssetCardContent(a) {
|
||||||
|
const parts = [];
|
||||||
|
const company = a.company || a.name;
|
||||||
|
parts.push(`<div class="ai-company">${esc(company)}</div>`);
|
||||||
|
const locParts = [];
|
||||||
|
if (a.location_area) locParts.push(`<span class="tag">${esc(a.location_area)}</span>`);
|
||||||
|
if (a.place) locParts.push(esc(a.place));
|
||||||
|
if (locParts.length) parts.push(`<div class="ai-location-line">${locParts.join(' · ')}</div>`);
|
||||||
|
const bldParts = [];
|
||||||
|
if (a.building_number) bldParts.push(`Bldg ${esc(a.building_number)}`);
|
||||||
|
if (a.trailer_number) bldParts.push(`Trailer ${esc(a.trailer_number)}`);
|
||||||
|
if (a.floor) bldParts.push(esc(a.floor));
|
||||||
|
if (a.room) bldParts.push(`Room ${esc(a.room)}`);
|
||||||
|
if (bldParts.length) parts.push(`<div class="ai-building">${bldParts.join(' · ')}</div>`);
|
||||||
|
if (a.address) parts.push(`<div class="ai-address">📍 ${esc(a.address)}</div>`);
|
||||||
|
return parts.join('');
|
||||||
|
}
|
||||||
|
|
||||||
function setFilter(category, status, make, disney_park) {
|
function setFilter(category, status, make, disney_park) {
|
||||||
assetFilters.category = category;
|
assetFilters.category = category;
|
||||||
assetFilters.status = status;
|
assetFilters.status = status;
|
||||||
|
|||||||
Reference in New Issue
Block a user