Add a structured authenticity signal with a distinct banner, instead of burying it in card_note
The Charizard grade that prompted this had the model writing 'possible non-standard/proxy print' directly into card_note -- the only free-text field available -- since there was nowhere else for that observation to go. That's why it got no visual treatment: the UI renders card_note as a plain grey subtitle, identical to any ordinary card name. Added authenticity as its own top-level field (flag: none/worth_checking/ likely_not_genuine, plus an observation) alongside the four grading categories but explicitly separate from them -- this is about whether the card is a genuine product at all, not its condition, and PSA authenticates before it grades, so a flagged card's estimated_grade goes to null rather than a number. Prompted with concrete tells for both classes of concern: fan-made/proxy prints (fictional sets, non-existent number combos, home-printer texture, 'proxy' watermarks) and counterfeits of real cards (colour/font/holo mismatches against genuine copies). Trimming (already covered under CORNERS from an earlier fix) now also sets this field when flagged, so the UI has one place to check regardless of which specific issue triggered it. UI: a full banner (not a hint line) above the slab -- critical red for likely_not_genuine, warning amber for worth_checking -- plus a matching dot next to the card name in History so it's visible without opening the card. Both colours reuse --critical/--warning rather than the brand red, since this is exactly the 'distrust this' signal those are already reserved for. Migration tested against the live schema shape; existing rows get authenticity=None and render with no banner, as before.
This commit is contained in:
parent
d026cce91a
commit
2b3bbaf40f
5 changed files with 148 additions and 12 deletions
|
|
@ -182,7 +182,16 @@ function renderGradeBlock(g, opts = {}) {
|
|||
</tr>`;
|
||||
}).join('');
|
||||
|
||||
const auth = g.authenticity || null;
|
||||
const authBanner = (auth && auth.flag !== 'none') ? `
|
||||
<div class="authenticity-banner authenticity-${auth.flag === 'likely_not_genuine' ? 'high' : 'check'}">
|
||||
<div class="authenticity-title">${auth.flag === 'likely_not_genuine'
|
||||
? 'Possibly not a genuine card' : 'Worth double-checking'}</div>
|
||||
${auth.observation ? `<div class="authenticity-detail">${esc(auth.observation)}</div>` : ''}
|
||||
</div>` : '';
|
||||
|
||||
return `
|
||||
${authBanner}
|
||||
<div class="note note-warn">A photo can't show surface scratches, print lines, or light edge wear the
|
||||
way a grader's raking light does — and a seller's listing photo is often lit to hide them.
|
||||
Treat this as a rough screen, not a prediction of what it comes back as.</div>
|
||||
|
|
@ -398,13 +407,21 @@ function renderHistory() {
|
|||
const rows = state.history;
|
||||
$('#history-count').textContent = rows.length ? `${rows.length} graded` : '';
|
||||
$('#history-empty').hidden = rows.length > 0;
|
||||
$('#history-body').innerHTML = rows.map((g) => `
|
||||
$('#history-body').innerHTML = rows.map((g) => {
|
||||
const auth = g.authenticity;
|
||||
// A dot rather than repeating the full banner text — the row is
|
||||
// already tight, and opening the card gives the real explanation.
|
||||
const authDot = (auth && auth.flag !== 'none')
|
||||
? `<span class="authenticity-dot authenticity-${auth.flag === 'likely_not_genuine' ? 'high' : 'check'}"
|
||||
title="${esc(auth.flag === 'likely_not_genuine' ? 'Possibly not a genuine card' : 'Worth double-checking')}"></span>`
|
||||
: '';
|
||||
return `
|
||||
<tr data-history-row="${g.id}">
|
||||
<td>
|
||||
<div class="cardcell">
|
||||
${g.thumbnail ? `<img src="${g.thumbnail}" alt="">` : '<span class="thumb-blank"></span>'}
|
||||
<div>
|
||||
<div class="cardcell-name">${esc(g.label || g.card_note || 'Untitled card')}</div>
|
||||
<div class="cardcell-name">${authDot}${esc(g.label || g.card_note || 'Untitled card')}</div>
|
||||
<div class="cardcell-meta">${g.card_type ? `${esc(TYPE_LABEL[g.card_type] || 'Card')} · ` : ''}${g.image_count || 1} photo(s)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -420,7 +437,8 @@ function renderHistory() {
|
|||
<button class="btn btn-quiet btn-sm" data-history-delete="${g.id}">Delete</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`).join('');
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- spend */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue