Add Cancel button to character-creation Revise flows

Clicking Revise on basic records, techniques, or J/Q/K assignment now
offers a Cancel button that throws away any edits made since Revise and
restores the previously-saved values. Basic-records cancel is a pure
client-side toggle; techniques/face cancel re-submit a snapshot taken at
Revise time (since Revise immediately unsubmits/unassigns server-side).
Also added Cancel to the recruit-creation basic-records revise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 09:09:24 -07:00
parent 45fefc0c71
commit 5a9d712c95
3 changed files with 88 additions and 3 deletions

View File

@@ -40,6 +40,11 @@
editingBasic = true;
}
// Discard any edits made since clicking Revise and return to the saved view.
function cancelReviseBasic() {
editingBasic = false;
}
// Like/Hate tasks are assigned automatically when character creation starts.
// This is a fallback for games that entered the phase before assignments existed.
onMount(async () => {
@@ -63,6 +68,10 @@
let tech1 = '', tech2 = '', tech3 = '';
let savingTechs = false;
let techError = '';
// True while editing previously-submitted techniques (vs. first-time entry),
// so we know to offer a Cancel button. techSnapshot holds the saved values.
let revisingTechs = false;
let techSnapshot = [];
async function submitTechniques() {
savingTechs = true;
@@ -71,6 +80,7 @@
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/submit-techniques`, 'POST', {
tech1, tech2, tech3
});
revisingTechs = false;
} catch(e) {
techError = e.message;
} finally {
@@ -79,12 +89,33 @@
}
async function reviseTechniques() {
techSnapshot = [...createdTechniques];
[tech1 = '', tech2 = '', tech3 = ''] = createdTechniques;
revisingTechs = true;
techError = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/unsubmit-techniques`, 'POST');
} catch(e) {
techError = e.message;
revisingTechs = false;
}
}
// Throw away edits and re-submit the techniques as they were before Revise.
async function cancelReviseTechniques() {
savingTechs = true;
techError = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/submit-techniques`, 'POST', {
tech1: techSnapshot[0] || '',
tech2: techSnapshot[1] || '',
tech3: techSnapshot[2] || ''
});
revisingTechs = false;
} catch(e) {
techError = e.message;
} finally {
savingTechs = false;
}
}
@@ -127,6 +158,9 @@
let jackTech = '', queenTech = '', kingTech = '';
let assigningFace = false;
let faceError = '';
// True while revising a previously-assigned J/Q/K layout, so we offer Cancel.
let revisingFace = false;
let faceSnapshot = {};
async function assignFaceTechniques() {
assigningFace = true;
@@ -137,6 +171,7 @@
queen: queenTech,
king: kingTech
});
revisingFace = false;
} catch(e) {
faceError = e.message;
} finally {
@@ -145,14 +180,39 @@
}
async function reviseFaceTechniques() {
faceSnapshot = {
jack: state.player.tech_jack,
queen: state.player.tech_queen,
king: state.player.tech_king
};
jackTech = state.player.tech_jack;
queenTech = state.player.tech_queen;
kingTech = state.player.tech_king;
revisingFace = true;
faceError = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/unassign-face-techniques`, 'POST');
} catch(e) {
faceError = e.message;
revisingFace = false;
}
}
// Throw away edits and re-assign the J/Q/K layout as it was before Revise.
async function cancelReviseFaceTechniques() {
assigningFace = true;
faceError = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/assign-face-techniques`, 'POST', {
jack: faceSnapshot.jack,
queen: faceSnapshot.queen,
king: faceSnapshot.king
});
revisingFace = false;
} catch(e) {
faceError = e.message;
} finally {
assigningFace = false;
}
}
@@ -245,7 +305,12 @@
{#if devMode}<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.good_at_math = getSuggestion('good_at_math')}>Suggest</button>{/if}
</div>
</div>
<button type="submit" class="btn btn-primary btn-full" disabled={savingBasic}>Save Records</button>
<div class="input-row mt-4">
<button type="submit" class="btn btn-primary btn-full" disabled={savingBasic}>Save Records</button>
{#if basicComplete}
<button type="button" class="btn btn-secondary" disabled={savingBasic} on:click={cancelReviseBasic}>Cancel</button>
{/if}
</div>
</form>
{/if}
</div>
@@ -350,6 +415,9 @@
</div>
</div>
<button type="submit" class="btn btn-primary btn-full glow-effect" disabled={savingTechs}>Submit Techniques to Swap Pool</button>
{#if revisingTechs}
<button type="button" class="btn btn-secondary btn-full mt-4" disabled={savingTechs} on:click={cancelReviseTechniques}>Cancel keep my original techniques</button>
{/if}
</form>
{:else if phase === 'character_creation'}
<div class="submitted-techniques text-center mt-4">
@@ -470,6 +538,13 @@
>
{assigningFace ? 'Assigning...' : 'Assign to Cards'}
</button>
{#if revisingFace}
<button
class="btn btn-secondary w-full mt-4"
disabled={assigningFace}
on:click={cancelReviseFaceTechniques}
>Cancel keep my original assignment</button>
{/if}
</div>
</div>
{:else}

View File

@@ -56,6 +56,11 @@
editingBasic = true;
}
// Discard any edits made since clicking Revise and return to the saved view.
function cancelReviseBasic() {
editingBasic = false;
}
$: basicComplete = !!(me.avatar_look && me.avatar_smell && me.first_words && me.good_at_math);
$: likeDone = !me.other_like_from_player_id || !!me.other_like;
$: hateDone = !me.other_hate_from_player_id || !!me.other_hate;
@@ -191,7 +196,12 @@
{#if devMode}<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.good_at_math = getSuggestion('good_at_math')}>Suggest</button>{/if}
</div>
</div>
<button type="submit" class="btn btn-primary btn-full" disabled={savingBasic}>Save Records</button>
<div class="input-row mt-4">
<button type="submit" class="btn btn-primary btn-full" disabled={savingBasic}>Save Records</button>
{#if basicComplete}
<button type="button" class="btn btn-secondary" disabled={savingBasic} on:click={cancelReviseBasic}>Cancel</button>
{/if}
</div>
</form>
{/if}
</div>