fix(web): allow cancelling pending applications; drop contradictory message guard
PR Checks / test-and-build (pull_request) Successful in 7m50s

Address review feedback from PR #119:

- LeaveClubMembershipAsync: was rejecting Pending rows because the SQL
  required status = 'Active', so clicking "Отозвать заявку" on a Pending
  membership surfaced a misleading "Active membership X not found"
  InvalidOperationException. Now the method first tries Active -> Left
  and falls back to Pending -> Rejected so the same UI flow covers both
  states.
- PublicClub.razor TrySubmitApplicationAsync: removed the empty-input
  guard that contradicted the "(необязательно)" label and the server
  side (AuthorizedMembershipService already trims and accepts null).

No tests broken (493 still passing), no public-API changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 11:33:28 +03:00
parent 6cb2fbe610
commit 22e9859fdf
2 changed files with 16 additions and 8 deletions
@@ -167,12 +167,6 @@ else if (club is not null)
if (club is null)
return;
if (string.IsNullOrWhiteSpace(applicationMessage))
{
applicationError = "Введите сообщение или оставьте поле пустым.";
return;
}
try
{
isSubmittingApplication = true;
+16 -2
View File
@@ -2707,6 +2707,7 @@ public sealed class SessionService(
public async Task LeaveClubMembershipAsync(Guid membershipId, Guid playerId)
{
await using var conn = await dataSource.OpenConnectionAsync();
// Active membership: withdraw by setting status = 'Left'.
var rows = await conn.ExecuteAsync(
"""
UPDATE club_memberships
@@ -2714,9 +2715,22 @@ public sealed class SessionService(
WHERE id = @MembershipId AND player_id = @PlayerId AND status = 'Active'
""",
new { MembershipId = membershipId, PlayerId = playerId });
if (rows == 0)
if (rows > 0)
{
throw new InvalidOperationException($"Active membership {membershipId} not found for player.");
return;
}
// Pending application: cancel by setting status = 'Rejected' so the user can re-apply later.
var cancelled = await conn.ExecuteAsync(
"""
UPDATE club_memberships
SET status = 'Rejected', decided_at = now()
WHERE id = @MembershipId AND player_id = @PlayerId AND status = 'Pending'
""",
new { MembershipId = membershipId, PlayerId = playerId });
if (cancelled == 0)
{
throw new InvalidOperationException($"Membership {membershipId} is not Active or Pending for this player.");
}
}