feat(journal): edit a placed bet
Adds an edit flow to the bet journal — an Edit button per row repurposes the inline entry form (edit mode), saving via a new UpdatePlacedBetUseCase that preserves the original placed-at and re-grades the outcome against the result (so a changed selection/event re-settles). A cancel affordance + an editing banner make the mode obvious; the submit button switches to "Save changes". - UpdatePlacedBetUseCase (loads existing for PlacedAt, validates the event, re-grades) + IBetJournalService.UpdateAsync + service impl; Journal page edit-mode state + per-row Edit button; en/ru resx. - 3 tests: unknown-bet, unknown-event, and preserve-PlacedAt + re-grade.
This commit is contained in:
@@ -259,14 +259,28 @@
|
||||
<p class="m-journal__form-error" data-test="journal-add-error">@_formError</p>
|
||||
}
|
||||
|
||||
@if (_editingId is not null)
|
||||
{
|
||||
<p class="m-journal__form-hint" data-test="journal-editing-banner">@L["Journal.Editing"]</p>
|
||||
}
|
||||
|
||||
<div class="m-journal__form-actions">
|
||||
@if (_editingId is not null)
|
||||
{
|
||||
<button type="button"
|
||||
class="m-chip m-journal__chip"
|
||||
@onclick="CancelEdit"
|
||||
data-test="journal-edit-cancel">
|
||||
@L["Journal.Action.Cancel"]
|
||||
</button>
|
||||
}
|
||||
<button type="button"
|
||||
class="m-chip m-journal__submit"
|
||||
@onclick="SubmitAsync"
|
||||
disabled="@_submitting"
|
||||
data-test="journal-add-submit">
|
||||
<span class="m-journal__chip-glyph @(_submitting ? "is-spinning" : null)" aria-hidden="true">+</span>
|
||||
<span>@L["Journal.Action.Submit"]</span>
|
||||
<span class="m-journal__chip-glyph @(_submitting ? "is-spinning" : null)" aria-hidden="true">@(_editingId is null ? "+" : "✓")</span>
|
||||
<span>@(_editingId is null ? L["Journal.Action.Submit"] : L["Journal.Action.SaveEdit"])</span>
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
@@ -359,6 +373,14 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button"
|
||||
class="m-chip m-journal__chip m-journal__chip--ghost"
|
||||
@onclick="@(() => BeginEdit(row))"
|
||||
data-test="@($"journal-edit-{row.Id}")"
|
||||
aria-label="@L["Journal.Action.EditBet"]">
|
||||
<span aria-hidden="true">✎</span>
|
||||
<span>@L["Journal.Action.EditBet"]</span>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="m-chip m-journal__chip m-journal__chip--ghost"
|
||||
@onclick="@(() => RequestDelete(row.Id))"
|
||||
@@ -702,6 +724,7 @@
|
||||
private bool _resolving;
|
||||
private string? _formError;
|
||||
private Guid? _pendingDeleteId;
|
||||
private Guid? _editingId;
|
||||
private AddBetForm _form = new();
|
||||
|
||||
// Kelly stake-helper state — page-local (not persisted with the bet). Bankroll
|
||||
@@ -851,10 +874,19 @@
|
||||
var ct = _loadCts?.Token ?? CancellationToken.None;
|
||||
try
|
||||
{
|
||||
await Service.AddAsync(_form, ct);
|
||||
if (_editingId is { } editId)
|
||||
{
|
||||
await Service.UpdateAsync(editId, _form, ct);
|
||||
Snackbar.Add(L["Journal.Edited"].Value, Severity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Service.AddAsync(_form, ct);
|
||||
Snackbar.Add(L["Journal.Submitted"].Value, Severity.Success);
|
||||
}
|
||||
_editingId = null;
|
||||
_form = new AddBetForm();
|
||||
_formError = null;
|
||||
Snackbar.Add(L["Journal.Submitted"].Value, Severity.Success);
|
||||
await LoadAsync();
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
@@ -891,6 +923,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginEdit(BetJournalRowVm row)
|
||||
{
|
||||
var b = row.Bet;
|
||||
_editingId = row.Id;
|
||||
_pendingDeleteId = null;
|
||||
_form = new AddBetForm
|
||||
{
|
||||
EventId = b.EventId.Value,
|
||||
Type = b.Selection.Type,
|
||||
Side = b.Selection.Side,
|
||||
Value = b.Selection.Value?.Value,
|
||||
Rate = b.Selection.Rate.Value,
|
||||
Stake = b.Stake,
|
||||
Notes = b.Notes,
|
||||
};
|
||||
_formError = null;
|
||||
}
|
||||
|
||||
private void CancelEdit()
|
||||
{
|
||||
_editingId = null;
|
||||
_form = new AddBetForm();
|
||||
_formError = null;
|
||||
}
|
||||
|
||||
private void RequestDelete(Guid id)
|
||||
{
|
||||
_pendingDeleteId = id;
|
||||
|
||||
Reference in New Issue
Block a user