feat: edit hands from the viewer + "not my hand" disown
Addresses "no way to edit hands" and cleaning up misattributed ones:
- hand viewer (/hand/{id}) gets an "✎ Edit this hand" panel: position, cards,
board, your net, tag, lesson → Save (existing PATCH), plus Delete.
- "Not my hand" → POST /hand/{id}/disown → poker.disown_hand clears the flat hero
fields and rewrites structured with hero_involved=false, so a hand mislabeled as
Brian's becomes a clean observed hand (replay stops showing him as hero).
1 test. Full suite 156 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -282,8 +282,54 @@
|
||||
const h = await r.json();
|
||||
if(!h || !h.id){ document.getElementById('root').innerHTML='<p class="err">Hand not found.</p>'; return; }
|
||||
render(h);
|
||||
renderEditor(h);
|
||||
}catch(e){ document.getElementById('root').innerHTML='<p class="err">Couldn\'t load the hand.</p>'; }
|
||||
}
|
||||
|
||||
function renderEditor(h){
|
||||
const wrap = document.createElement('div');
|
||||
wrap.style.cssText = 'max-width:520px;margin:18px auto 0;border-top:1px solid #241a10;padding-top:12px;';
|
||||
const tags = ['','well_played','leak','cooler','confidence','notable'];
|
||||
wrap.innerHTML = `
|
||||
<details style="font-size:.9rem;">
|
||||
<summary style="cursor:pointer;color:var(--accent,#ff7a00);">✎ Edit this hand</summary>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;margin-top:10px;">
|
||||
<label>Position <input id="e_pos" value="${esc(h.position||'')}" placeholder="e.g. CO (blank if not yours)"></label>
|
||||
<label>Your cards <input id="e_hole" value="${esc(h.hole_cards||'')}" placeholder="e.g. As Ks (blank if not yours)"></label>
|
||||
<label>Board <input id="e_board" value="${esc(h.board||'')}" placeholder="e.g. Tc 8s Js 6d"></label>
|
||||
<label>Your net <input id="e_res" value="${h.result!=null?esc(h.result):''}" placeholder="+ / − chips (blank if not yours)"></label>
|
||||
<label>Tag <select id="e_tag">${tags.map(t=>`<option value="${t}" ${h.tag===t?'selected':''}>${t||'—'}</option>`).join('')}</select></label>
|
||||
<label>Lesson <input id="e_lesson" value="${esc(h.lesson||'')}"></label>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;margin-top:4px;">
|
||||
<button onclick="saveHand(${h.id})" style="border-color:var(--accent,#ff7a00);color:var(--accent,#ff7a00);">Save</button>
|
||||
<button onclick="disown(${h.id})" title="It was someone else's hand — clear it from you">Not my hand</button>
|
||||
<button onclick="delHand(${h.id})" style="margin-left:auto;color:#ff6b6b;">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</details>`;
|
||||
wrap.querySelectorAll('input,select').forEach(el=>{el.style.cssText='font:inherit;font-size:.86rem;padding:5px 8px;border-radius:6px;border:1px solid #241a10;background:#0b0b0b;color:#e8e8e8;margin-left:8px;';});
|
||||
wrap.querySelectorAll('label').forEach(el=>{el.style.cssText='display:flex;justify-content:space-between;align-items:center;color:#8a8a8a;';});
|
||||
wrap.querySelectorAll('button').forEach(el=>{el.style.cssText+=';font:inherit;font-size:.84rem;padding:6px 12px;border-radius:7px;border:1px solid #241a10;background:#141414;color:#e8e8e8;cursor:pointer;';});
|
||||
document.getElementById('root').appendChild(wrap);
|
||||
}
|
||||
const val = id => document.getElementById(id).value.trim();
|
||||
async function saveHand(id){
|
||||
const body = {position:val('e_pos'), hole_cards:val('e_hole'), board:val('e_board'),
|
||||
tag:val('e_tag'), lesson:val('e_lesson')};
|
||||
const res = val('e_res'); if(res!=='') body.result = Number(res);
|
||||
await fetch(`/hand/${id}`,{method:'PATCH',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
|
||||
load();
|
||||
}
|
||||
async function disown(id){
|
||||
if(!confirm("Mark this as someone else's hand? It'll be cleared from your stats.")) return;
|
||||
await fetch(`/hand/${id}/disown`,{method:'POST'});
|
||||
load();
|
||||
}
|
||||
async function delHand(id){
|
||||
if(!confirm('Delete this hand for good?')) return;
|
||||
await fetch(`/hand/${id}`,{method:'DELETE'});
|
||||
location.href='/hands';
|
||||
}
|
||||
load();
|
||||
</script>
|
||||
<script src="/nav.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user