From Profile → Children → (child) → Sponsorship, a parent can flip the "Allow donors to sponsor {child}'s travel" toggle on even when the child's profile is not complete. The corresponding admin flow at /admin/sponsorship-management correctly rejects approval with an error like:
Profile incomplete — missing: Handle, Bio, Sex, Nationality, Phone Number, Government ID Type, Government ID Number, Street Address, City, State / Province, Postal Code, Home Country, At least 1 photo, At least 1 language
The parent-side toggle should enforce the same prerequisite. Otherwise an incomplete child profile can be marked Sponsorship.Enabled = true, which then queues it as a pending profile in the admin's sponsorship management view (e.g. "Bobby Spiker — Awaiting approval") despite not meeting the criteria.
Steps to reproduce
Sign in as a parent.
Open your profile page → Children tab → expand a child whose profile is incomplete (e.g. Bobby Spiker, missing Bio / Phone Number / Address / etc.).
Toggle on "Allow donors to sponsor Bobby's travel".
Observe that the toggle saves successfully and the child appears in /admin/sponsorship-management under Pending Approval.
Compare to the admin's Approve flow on that same profile — it returns Profile incomplete — missing: … and refuses.
Expected behavior
When the parent attempts to enable sponsorship for a child, the backend should run the same ProfileCompletionValidator check that SponsorController.ApproveSponsorProfile runs. If the child profile is incomplete, the toggle request should fail with a 400 and a missingItems payload, and the UI should surface the same
Profile incomplete — missing: …
message so the parent knows what to fix on the child's profile. Disabling sponsorship (enabled = false) should always be allowed regardless of completion state.
Affected code
Backend: SpikerSoft.Business/Domain/Profile/Commands/ToggleChildSponsorship/ToggleChildSponsorshipCommandHandler.cs — currently writes Sponsorship.Enabled = request.Enabled with no completion check.
Frontend: projects/spikersoft/src/app/_components/profile/profile.component.ts → toggleChildSponsorship — needs to surface missingItems in the snackbar (mirroring SponsorshipManagementComponent.approveProfile).
## Summary
From **Profile → Children → (child) → Sponsorship**, a parent can flip the **"Allow donors to sponsor {child}'s travel"** toggle on even when the child's profile is **not complete**. The corresponding admin flow at `/admin/sponsorship-management` correctly rejects approval with an error like:
> Profile incomplete — missing: Handle, Bio, Sex, Nationality, Phone Number, Government ID Type, Government ID Number, Street Address, City, State / Province, Postal Code, Home Country, At least 1 photo, At least 1 language
The parent-side toggle should enforce the same prerequisite. Otherwise an incomplete child profile can be marked `Sponsorship.Enabled = true`, which then queues it as a pending profile in the admin's sponsorship management view (e.g. "Bobby Spiker — Awaiting approval") despite not meeting the criteria.
## Steps to reproduce
1. Sign in as a parent.
2. Open your profile page → Children tab → expand a child whose profile is incomplete (e.g. Bobby Spiker, missing Bio / Phone Number / Address / etc.).
3. Toggle on "Allow donors to sponsor Bobby's travel".
4. Observe that the toggle saves successfully and the child appears in `/admin/sponsorship-management` under **Pending Approval**.
5. Compare to the admin's **Approve** flow on that same profile — it returns `Profile incomplete — missing: …` and refuses.
## Expected behavior
When the parent attempts to enable sponsorship for a child, the backend should run the same `ProfileCompletionValidator` check that `SponsorController.ApproveSponsorProfile` runs. If the child profile is incomplete, the toggle request should fail with a 400 and a `missingItems` payload, and the UI should surface the same
> Profile incomplete — missing: …
message so the parent knows what to fix on the child's profile. Disabling sponsorship (`enabled = false`) should always be allowed regardless of completion state.
## Affected code
- Backend: `SpikerSoft.Business/Domain/Profile/Commands/ToggleChildSponsorship/ToggleChildSponsorshipCommandHandler.cs` — currently writes `Sponsorship.Enabled = request.Enabled` with no completion check.
- Backend (reference): `SpikerSoft.Api/Domain/Sponsor/SponsorController.ApproveSponsorProfile` — already calls `ProfileCompletionValidator.Validate(profile)` and returns `BadRequest(new { error, missingItems, percentage })`.
- Frontend: `projects/spikersoft/src/app/_components/profile/profile.component.ts → toggleChildSponsorship` — needs to surface `missingItems` in the snackbar (mirroring `SponsorshipManagementComponent.approveProfile`).
Added ProfileIncompleteException next to ProfileCompletionResult so the validator's structured result can flow up through the command pipeline.
ToggleChildSponsorshipCommandHandler now runs ProfileCompletionValidator.Validate(childProfile) whenever Enabled == true and throws ProfileIncompleteException if the child profile fails the same 19-criteria check used by admin approval. Disabling stays unconditional.
ProfileController.ToggleChildSponsorship catches the new exception and returns 400 BadRequest with { error, missingItems, percentage } — identical shape to SponsorController.ApproveSponsorProfile, so any other client picks up the same payload contract.
Updated ToggleChildSponsorshipCommandHandlerTests (5 tests, all green): replaced the 'enable on empty profile' test with one against a fully-complete child, plus a new test asserting ProfileIncompleteException (with MissingItems populated) when enabling against an incomplete child, plus a test that disabling still works on an incomplete profile.
Frontend (spikersoft-angular@6ecd6a0)
profile.component.ts → toggleChildSponsorship error handler now reads err.error.missingItems and surfaces "{Child}'s profile incomplete — missing: …" in the snackbar (same wording pattern as SponsorshipManagementComponent.approveProfile), then calls loadChildren() so the slide toggle reverts to the persisted state.
New unit test in profile.component.spec.ts covers the missing-items snackbar message and the children refresh.
Verification
dotnet test --filter ToggleChildSponsorshipCommandHandlerTests|ProfileCompletionValidatorTests — 34/34 passed.
Fixed.
**Backend** (`spikersoft-backend@4f6cddc`)
- Added `ProfileIncompleteException` next to `ProfileCompletionResult` so the validator's structured result can flow up through the command pipeline.
- `ToggleChildSponsorshipCommandHandler` now runs `ProfileCompletionValidator.Validate(childProfile)` whenever `Enabled == true` and throws `ProfileIncompleteException` if the child profile fails the same 19-criteria check used by admin approval. Disabling stays unconditional.
- `ProfileController.ToggleChildSponsorship` catches the new exception and returns `400 BadRequest` with `{ error, missingItems, percentage }` — identical shape to `SponsorController.ApproveSponsorProfile`, so any other client picks up the same payload contract.
- Updated `ToggleChildSponsorshipCommandHandlerTests` (5 tests, all green): replaced the 'enable on empty profile' test with one against a fully-complete child, plus a new test asserting `ProfileIncompleteException` (with `MissingItems` populated) when enabling against an incomplete child, plus a test that disabling still works on an incomplete profile.
**Frontend** (`spikersoft-angular@6ecd6a0`)
- `profile.component.ts → toggleChildSponsorship` error handler now reads `err.error.missingItems` and surfaces `"{Child}'s profile incomplete — missing: …"` in the snackbar (same wording pattern as `SponsorshipManagementComponent.approveProfile`), then calls `loadChildren()` so the slide toggle reverts to the persisted state.
- New unit test in `profile.component.spec.ts` covers the missing-items snackbar message and the children refresh.
**Verification**
- `dotnet test --filter ToggleChildSponsorshipCommandHandlerTests|ProfileCompletionValidatorTests` — 34/34 passed.
- `npm run test-spikersoft` — 1754/1761 passed (7 unrelated pre-existing skips), 0 failures.
Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
From Profile → Children → (child) → Sponsorship, a parent can flip the "Allow donors to sponsor {child}'s travel" toggle on even when the child's profile is not complete. The corresponding admin flow at
/admin/sponsorship-managementcorrectly rejects approval with an error like:The parent-side toggle should enforce the same prerequisite. Otherwise an incomplete child profile can be marked
Sponsorship.Enabled = true, which then queues it as a pending profile in the admin's sponsorship management view (e.g. "Bobby Spiker — Awaiting approval") despite not meeting the criteria.Steps to reproduce
/admin/sponsorship-managementunder Pending Approval.Profile incomplete — missing: …and refuses.Expected behavior
When the parent attempts to enable sponsorship for a child, the backend should run the same
ProfileCompletionValidatorcheck thatSponsorController.ApproveSponsorProfileruns. If the child profile is incomplete, the toggle request should fail with a 400 and amissingItemspayload, and the UI should surface the samemessage so the parent knows what to fix on the child's profile. Disabling sponsorship (
enabled = false) should always be allowed regardless of completion state.Affected code
SpikerSoft.Business/Domain/Profile/Commands/ToggleChildSponsorship/ToggleChildSponsorshipCommandHandler.cs— currently writesSponsorship.Enabled = request.Enabledwith no completion check.SpikerSoft.Api/Domain/Sponsor/SponsorController.ApproveSponsorProfile— already callsProfileCompletionValidator.Validate(profile)and returnsBadRequest(new { error, missingItems, percentage }).projects/spikersoft/src/app/_components/profile/profile.component.ts → toggleChildSponsorship— needs to surfacemissingItemsin the snackbar (mirroringSponsorshipManagementComponent.approveProfile).Fixed.
Backend (
spikersoft-backend@4f6cddc)ProfileIncompleteExceptionnext toProfileCompletionResultso the validator's structured result can flow up through the command pipeline.ToggleChildSponsorshipCommandHandlernow runsProfileCompletionValidator.Validate(childProfile)wheneverEnabled == trueand throwsProfileIncompleteExceptionif the child profile fails the same 19-criteria check used by admin approval. Disabling stays unconditional.ProfileController.ToggleChildSponsorshipcatches the new exception and returns400 BadRequestwith{ error, missingItems, percentage }— identical shape toSponsorController.ApproveSponsorProfile, so any other client picks up the same payload contract.ToggleChildSponsorshipCommandHandlerTests(5 tests, all green): replaced the 'enable on empty profile' test with one against a fully-complete child, plus a new test assertingProfileIncompleteException(withMissingItemspopulated) when enabling against an incomplete child, plus a test that disabling still works on an incomplete profile.Frontend (
spikersoft-angular@6ecd6a0)profile.component.ts → toggleChildSponsorshiperror handler now readserr.error.missingItemsand surfaces"{Child}'s profile incomplete — missing: …"in the snackbar (same wording pattern asSponsorshipManagementComponent.approveProfile), then callsloadChildren()so the slide toggle reverts to the persisted state.profile.component.spec.tscovers the missing-items snackbar message and the children refresh.Verification
dotnet test --filter ToggleChildSponsorshipCommandHandlerTests|ProfileCompletionValidatorTests— 34/34 passed.npm run test-spikersoft— 1754/1761 passed (7 unrelated pre-existing skips), 0 failures.Closing.