Parent approval map never shows a domestic child's requested states (wishlistRegions unbound; orange 'requested' style gated to minor mode; no region approval store) #727

Closed
opened 2026-07-20 01:39:13 +00:00 by spikerj · 1 comment
Owner

Repro (live, 2026-07-20): child @toddcan (domestic travel only) filled his profile and picked states — his doc has `Travel.WishlistRegions = ["US-ID","US-LA"]`, `Sponsorship.Enabled = true` (parent-enabled at 01:29Z, saved cleanly — the #431 approval-chain fix is live), `ParentalControls` correctly linked to the parent, `Permissions.ApprovedCountries = []`. Parent's children tab shows no states at all — nothing orange to approve.

Root cause — three stacked frontend/model defects (backend saves are all fine):

  1. The parent map is bound to the wrong array at the wrong scope. `children-tab.component.html` (~121-129) passes `[wishlistCountries]="child.travel.wishlistCountries"` with no `scope`/`countryCode` inputs, so `app-country-map` defaults to `scope="world"` and renders world countries. A domestic-only child's picks live in `child.travel.wishlistRegions` (hyphenated codes, e.g. `US-ID`), which is never passed and would need `scope="country"` + `[countryCode]` to load the states GeoJSON (compare the correct child-side wiring in `travel-tab.component.html:77-90`). Net: domestic children's `wishlistCountries` is empty ⇒ parent map highlights nothing.

  2. Orange 'requested' can never render for the parent. `country-map.component.ts` `getFeatureStyle()` (~425-430) renders the orange `requested` color only when `mode()==='minor'`; in `parent-approve` mode an unapproved wishlist entry falls through to blue — even though the parent-approve legend advertises an orange 'requested' swatch (`getLegendItems()` ~648). Legend/style mismatch.

  3. States have nowhere to be approved. `FeaturePermissions` has only `approvedCountries`; there is no region/state approval store. Backend note: the server never computes 'pending' — `GET /api/Profile/parental/children` returns both wishlist + approved lists and the SPA diffs them; `PUT /api/Profile/parental/permissions/{childUserId}` overwrites `ApprovedCountries` wholesale and is code-agnostic (flat `List`).

Suggested fix (frontend-only is possible):

  • Children tab: for domestic children render the map with `scope="country"`, `[countryCode]` = child's home country, `[wishlistCountries]="child.travel.wishlistRegions"` (or a merged view with a country/domestic toggle mirroring the child's travel tab).
  • `country-map`: in `parent-approve` mode render wishlist-not-approved as orange `requested` (matches the legend already shipped).
  • Approval store: reuse the existing flat `approvedCountries` list for hyphenated region codes ('approved destinations' semantics — zero backend/schema change, the wholesale-overwrite write path and the client set-diff both already handle arbitrary codes). Alternatively add a parallel `approvedRegions` field for symmetry with the wishlist split, at the cost of a backend DTO+model change. Recommend the former; the frontend already partitions hyphenated codes (`TravelStateService.load()`), so keep that convention consistent when diffing.

Not implicated: sponsorship staff approval (separate `api/sponsor` queue — `Sponsorship.ApprovedByStaff=false` is expected until staff approves), the #431 owned-nav fix (deployed, saves clean), `GetChildrenQueryHandler` gates (child passes `IsMinor && ParentalControls.ParentKeycloakUserId` match — verified live).

**Repro (live, 2026-07-20):** child @toddcan (domestic travel only) filled his profile and picked states — his doc has \`Travel.WishlistRegions = [\"US-ID\",\"US-LA\"]\`, \`Sponsorship.Enabled = true\` (parent-enabled at 01:29Z, saved cleanly — the #431 approval-chain fix is live), \`ParentalControls\` correctly linked to the parent, \`Permissions.ApprovedCountries = []\`. Parent's children tab shows **no states at all** — nothing orange to approve. **Root cause — three stacked frontend/model defects (backend saves are all fine):** 1. **The parent map is bound to the wrong array at the wrong scope.** \`children-tab.component.html\` (~121-129) passes \`[wishlistCountries]=\"child.travel.wishlistCountries\"\` with no \`scope\`/\`countryCode\` inputs, so \`app-country-map\` defaults to \`scope=\"world\"\` and renders world countries. A domestic-only child's picks live in \`child.travel.wishlistRegions\` (hyphenated codes, e.g. \`US-ID\`), which is **never passed** and would need \`scope=\"country\"\` + \`[countryCode]\` to load the states GeoJSON (compare the correct child-side wiring in \`travel-tab.component.html:77-90\`). Net: domestic children's \`wishlistCountries\` is empty ⇒ parent map highlights nothing. 2. **Orange 'requested' can never render for the parent.** \`country-map.component.ts\` \`getFeatureStyle()\` (~425-430) renders the orange \`requested\` color only when \`mode()==='minor'\`; in \`parent-approve\` mode an unapproved wishlist entry falls through to blue — even though the parent-approve **legend** advertises an orange 'requested' swatch (\`getLegendItems()\` ~648). Legend/style mismatch. 3. **States have nowhere to be approved.** \`FeaturePermissions\` has only \`approvedCountries\`; there is no region/state approval store. Backend note: the server never computes 'pending' — \`GET /api/Profile/parental/children\` returns both wishlist + approved lists and the SPA diffs them; \`PUT /api/Profile/parental/permissions/{childUserId}\` overwrites \`ApprovedCountries\` wholesale and is code-agnostic (flat \`List<string>\`). **Suggested fix (frontend-only is possible):** - Children tab: for domestic children render the map with \`scope=\"country\"\`, \`[countryCode]\` = child's home country, \`[wishlistCountries]=\"child.travel.wishlistRegions\"\` (or a merged view with a country/domestic toggle mirroring the child's travel tab). - \`country-map\`: in \`parent-approve\` mode render wishlist-not-approved as orange \`requested\` (matches the legend already shipped). - Approval store: reuse the existing flat \`approvedCountries\` list for hyphenated region codes ('approved destinations' semantics — zero backend/schema change, the wholesale-overwrite write path and the client set-diff both already handle arbitrary codes). Alternatively add a parallel \`approvedRegions\` field for symmetry with the wishlist split, at the cost of a backend DTO+model change. Recommend the former; the frontend already partitions hyphenated codes (\`TravelStateService.load()\`), so keep that convention consistent when diffing. **Not implicated:** sponsorship staff approval (separate \`api/sponsor\` queue — \`Sponsorship.ApprovedByStaff=false\` is expected until staff approves), the #431 owned-nav fix (deployed, saves clean), \`GetChildrenQueryHandler\` gates (child passes \`IsMinor && ParentalControls.ParentKeycloakUserId\` match — verified live).
Author
Owner

Verified complete: spikersoft-angular PR #453 merged ('surface a domestic child's requested states on the parent approval map') — 1:1 with the reported bug. Closing.

Verified complete: spikersoft-angular PR #453 merged ('surface a domestic child's requested states on the parent approval map') — 1:1 with the reported bug. Closing.
Sign in to join this conversation.