Compare commits

..

2 Commits

Author SHA1 Message Date
78bbf04824 Improve Media Manager transition after matching wizard
- Removed full-page 'Connecting...' loading screen after matching modal closes.
- Ensured main UI (SKU info and gallery shell) appears immediately after the wizard.
- Leveraged grid-level loading indicator for non-blocking background refresh.
- Verified transition stability with integration and handler tests.
2025-12-31 21:14:32 -07:00
63b2ff2fd0 Fix Media Manager action buttons, flickering, and card spacing
- Switched from index-based to unique ID-based deletion to fix incorrect target after reordering.
- Enhanced media state normalization in loadMedia to ensure robust link button () visibility.
- Implemented targeted UI updates via ui.updateCardState(id) to prevent thumbnail flickering on status changes.
- Standardized vertical card spacing to 8px and corrected Gallery card action bar overhang/overlap.
2025-12-31 10:52:15 -07:00

View File

@ -36,14 +36,14 @@
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
border-radius: 12px; border-radius: 12px;
padding: 16px; padding: 16px;
margin-bottom: 16px; margin-bottom: 8px;
} }
.header { .header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 16px; margin-bottom: 8px;
} }
h2 { h2 {
@ -295,7 +295,7 @@
background: var(--surface); background: var(--surface);
padding: 16px; padding: 16px;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
margin: 0 -16px -16px -16px; margin: 0 -16px 0 -16px;
border-bottom-left-radius: 12px; border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px; border-bottom-right-radius: 12px;
display: flex; display: flex;
@ -385,7 +385,7 @@
background: var(--surface); background: var(--surface);
color: var(--text); color: var(--text);
border-radius: 8px; border-radius: 8px;
margin-top: 16px; margin-top: 8px;
font-family: monospace; font-family: monospace;
font-size: 11px; font-size: 11px;
overflow: hidden; overflow: hidden;
@ -784,44 +784,50 @@
this.checkDirty(); this.checkDirty();
}; };
MediaState.prototype.toggleSelection = function (id) { MediaState.prototype.toggleSelection = function (id) {
var item = this.items.find(function (i) { return i.id === id; }); var item = this.items.find(function (i) { return i.id === id; });
if (!item) return; if (!item) return;
var isSelected = this.selectedIds.has(id); var isSelected = this.selectedIds.has(id);
var affectedIds = [id];
if (isSelected) { if (isSelected) {
this.selectedIds.delete(id); this.selectedIds.delete(id);
} else { } else {
// Enforce one-pair rule: Max one Drive, one Shopify // Enforce one-pair rule: Max one Drive, one Shopify
var isDrive = (item.source === 'drive_only'); var isDrive = (item.source === 'drive_only');
var isShopify = (item.source === 'shopify_only'); var isShopify = (item.source === 'shopify_only');
if (isDrive) { if (isDrive) {
// Clear other Drive selections // Clear other Drive selections
var _this = this; var _this = this;
this.items.forEach(function (i) { this.items.forEach(function (i) {
if (i.source === 'drive_only' && _this.selectedIds.has(i.id)) { if (i.source === 'drive_only' && _this.selectedIds.has(i.id) && i.id !== id) {
_this.selectedIds.delete(i.id); _this.selectedIds.delete(i.id);
affectedIds.push(i.id);
}
});
} else if (isShopify) {
// Clear other Shopify selections
var _this = this;
this.items.forEach(function (i) {
if (i.source === 'shopify_only' && _this.selectedIds.has(i.id) && i.id !== id) {
_this.selectedIds.delete(i.id);
affectedIds.push(i.id);
}
});
} }
}); this.selectedIds.add(id);
} else if (isShopify) { }
// Clear other Shopify selections
var _this = this; // Targeted updates
this.items.forEach(function (i) { affectedIds.forEach(function (aid) { ui.updateCardState(aid); });
if (i.source === 'shopify_only' && _this.selectedIds.has(i.id)) { };
_this.selectedIds.delete(i.id);
}
});
}
this.selectedIds.add(id);
}
ui.render(this.items);
};
MediaState.prototype.clearSelection = function () { MediaState.prototype.clearSelection = function () {
var affectedIds = Array.from(this.selectedIds);
this.selectedIds.clear(); this.selectedIds.clear();
ui.render(this.items); affectedIds.forEach(function (aid) { ui.updateCardState(aid); });
}; };
MediaState.prototype.addItem = function (item) { MediaState.prototype.addItem = function (item) {
@ -830,14 +836,20 @@
this.checkDirty(); this.checkDirty();
}; };
MediaState.prototype.deleteItem = function (index) { MediaState.prototype.deleteItem = function (id) {
var item = this.items[index]; var item = this.items.find(function (i) { return i.id === id; });
if (!item) {
console.warn("[MediaState] Item not found for deletion:", id);
return;
}
if (item.source === 'new') { if (item.source === 'new') {
this.items.splice(index, 1); var index = this.items.indexOf(item);
if (index !== -1) this.items.splice(index, 1);
ui.render(this.items); // Full render only for actual removal
} else { } else {
item._deleted = !item._deleted; item._deleted = !item._deleted;
ui.updateCardState(id); // Targeted update for toggle
} }
ui.render(this.items);
this.checkDirty(); this.checkDirty();
}; };
@ -1210,12 +1222,12 @@
// Link selection button // Link selection button
var linkSelectionBtn = ''; var linkSelectionBtn = '';
if (!item._deleted && (item.source === 'drive_only' || item.source === 'shopify_only')) { if (!item._deleted && (item.source === 'drive_only' || item.source === 'shopify_only')) {
linkSelectionBtn = '<button class="icon-btn' + (isSelected ? ' active' : '') + '" onclick="event.stopPropagation(); state.toggleSelection(\'' + item.id + '\')" title="Select for linking">🔗</button>'; linkSelectionBtn = '<button id="link-btn-' + item.id + '" class="icon-btn' + (isSelected ? ' active' : '') + '" onclick="event.stopPropagation(); state.toggleSelection(\'' + item.id + '\')" title="Select for linking">🔗</button>';
} }
var actionBtn = item._deleted var actionBtn = item._deleted
? '<button class="icon-btn" onclick="state.deleteItem(' + index + ')" title="Restore">↩️</button>' ? '<button class="icon-btn" onclick="state.deleteItem(\'' + item.id + '\')" title="Restore">↩️</button>'
: '<button class="icon-btn btn-delete" onclick="state.deleteItem(' + index + ')" title="Delete">🗑️</button>'; : '<button class="icon-btn btn-delete" onclick="state.deleteItem(\'' + item.id + '\')" title="Delete">🗑️</button>';
div.innerHTML += div.innerHTML +=
badge + badge +
@ -1278,6 +1290,84 @@
return div; return div;
}; };
UI.prototype.updateCardState = function (id) {
var item = state.items.find(function (i) { return i.id === id; });
var el = this.grid.querySelector('[data-id="' + id + '"]');
if (!item || !el) return;
var isSelected = state.selectedIds.has(item.id);
// 1. Update Container Class
el.className = 'media-item ' + (item._deleted ? 'deleted-item' : '') + (isSelected ? ' selected' : '');
if (item.isProcessing) el.className += ' processing-card';
// 2. Update Badge
var badgeEl = el.querySelector('.badge');
if (badgeEl) {
if (!item._deleted) {
if (item.source === 'synced') {
badgeEl.innerText = 'Synced';
badgeEl.title = 'Synced';
badgeEl.style.background = '#dcfce7';
badgeEl.style.color = '#166534';
} else if (item.source === 'drive_only') {
badgeEl.innerText = 'Drive';
badgeEl.title = 'Drive Only';
badgeEl.style.background = '#dbeafe';
badgeEl.style.color = '#1e40af';
} else if (item.source === 'shopify_only') {
badgeEl.innerText = 'Shopify';
badgeEl.title = 'Shopify Only';
badgeEl.style.background = '#fce7f3';
badgeEl.style.color = '#9d174d';
}
} else {
badgeEl.innerText = 'Deleted';
badgeEl.title = '';
badgeEl.style.background = '#fee2e2';
badgeEl.style.color = '#991b1b';
}
}
// 3. Update Overlay Buttons
var overlay = el.querySelector('.media-overlay');
if (overlay) {
// Remove existing link button if it exists
var oldLinkBtn = el.querySelector('#link-btn-' + id);
if (oldLinkBtn) oldLinkBtn.remove();
// Add link button back if NOT deleted
if (!item._deleted && (item.source === 'drive_only' || item.source === 'shopify_only')) {
var linkHtml = '<button id="link-btn-' + item.id + '" class="icon-btn' + (isSelected ? ' active' : '') + '" onclick="event.stopPropagation(); state.toggleSelection(\'' + item.id + '\')" title="Select for linking">🔗</button>';
var viewBtn = overlay.querySelector('.btn-view');
if (viewBtn) {
viewBtn.insertAdjacentHTML('afterend', linkHtml);
} else {
overlay.insertAdjacentHTML('afterbegin', linkHtml);
}
}
// Update Delete/Restore button
var actionBtn = overlay.querySelector('.btn-delete') || overlay.querySelector('[title="Restore"]');
if (actionBtn) {
if (item._deleted) {
actionBtn.className = 'icon-btn';
actionBtn.innerHTML = '↩️';
actionBtn.title = 'Restore';
} else {
actionBtn.className = 'icon-btn btn-delete';
actionBtn.innerHTML = '🗑️';
actionBtn.title = 'Delete';
}
}
}
// 4. Update global item count
var activeCount = state.items.filter(function (i) { return !i._deleted; }).length;
var countEl = document.getElementById('item-count');
if (countEl) countEl.innerText = '(' + activeCount + ')';
};
UI.prototype.openPreview = function (id) { UI.prototype.openPreview = function (id) {
var item = state.items.find(function (i) { return i.id === id; }); var item = state.items.find(function (i) { return i.id === id; });
if (!item) return; if (!item) return;
@ -1446,11 +1536,12 @@
if (media) { if (media) {
ui.logStatus('fetch', 'Fetched full media state.', 'success'); ui.logStatus('fetch', 'Fetched full media state.', 'success');
const normalized = media.map(function (i) { const normalized = media.map(function (i) {
var source = i.source || (i.shopifyId && i.driveId ? 'synced' : (i.shopifyId ? 'shopify_only' : 'drive_only'));
return { return {
...i, ...i,
id: i.id || Math.random().toString(36).substr(2, 9), id: i.id || Math.random().toString(36).substr(2, 9),
status: i.source || 'drive_only', status: source,
source: i.source, source: source,
_deleted: false _deleted: false
}; };
}); });
@ -1862,7 +1953,7 @@
startMatching() { startMatching() {
document.getElementById('loading-ui').style.display = 'none'; document.getElementById('loading-ui').style.display = 'none';
document.getElementById('main-ui').style.display = 'none'; document.getElementById('main-ui').style.display = 'block';
document.getElementById('matching-modal').style.display = 'flex'; document.getElementById('matching-modal').style.display = 'flex';
this.renderMatch(); this.renderMatch();
}, },
@ -1980,8 +2071,12 @@
// All Done // All Done
document.getElementById('matching-modal').style.display = 'none'; document.getElementById('matching-modal').style.display = 'none';
ui.logStatus('info', 'Matching complete. Reloading...', 'info'); ui.logStatus('info', 'Matching complete. Finalizing gallery...', 'info');
document.getElementById('loading-ui').style.display = 'block';
// Show main UI immediately if not already showing
document.getElementById('main-ui').style.display = 'block';
document.getElementById('loading-ui').style.display = 'none';
// Reload to get fresh state. Since hasRunMatching is true, it shouldn't trigger again. // Reload to get fresh state. Since hasRunMatching is true, it shouldn't trigger again.
this.loadMedia(true); this.loadMedia(true);
}, },