Skip to content

feat(frontend/recs): default-seed payment/term from GlobalConfig (closes #223)#243

Merged
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
feat/issue-223-default-seed-per-cell
May 3, 2026
Merged

feat(frontend/recs): default-seed payment/term from GlobalConfig (closes #223)#243
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
feat/issue-223-default-seed-per-cell

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented May 3, 2026

Summary

Closes #223. After PR #231 merged `pickBestVariantPerCell`, this PR replaces its effective-savings tiebreaker with config-match, and fixes the two adjacent surfaces that hardcoded `'all-upfront'`.

Three surfaces changed:

  • `pickBestVariantPerCell` (select-all tiebreaker) — now prefers the variant matching `(GlobalConfig.DefaultTerm, GlobalConfig.DefaultPayment)` over highest effective savings. Falls back to highest-effective when no variant matches.
  • `defaultBulkPurchaseState.payment` (bulk toolbar init) — seeded from `GlobalConfig.DefaultPayment` after page-load bootstrap; no longer hardcodes `'all-upfront'`.
  • `resolvePerRecPaymentSeed` fallback — prefers `GlobalConfig.DefaultPayment` when the service supports it, before falling back to `paymentOptionsFor[0]`.

Bootstrap approach: `loadRecommendations()` adds `api.getConfig()` as a siloed third leg of its `Promise.all` (`.catch(() => null)` — a missing config endpoint cannot block rec load). Resolved values populate module-level `cachedGlobalDefaultTerm / Payment`.

Exported for testing: `pickBestVariantPerCell` (pure function, no DOM side effects) and `seedGlobalDefaults(term, payment)` (test injection hook).

Test plan

  • `npx jest --testPathPatterns=recommendations` passes (1420 tests)
  • `npx tsc --noEmit` clean (pre-existing `styles.css` TS2882 is unrelated, present on base branch)
  • `npm run build` succeeds
  • New describe block `'issue feat(frontend/recs): default-select per-cell variant matching configured term + payment #223: pickBestVariantPerCell config-match tiebreaker'` — 4 tests covering: config-match preference, highest-effective fallback, multi-cell independence, and 3yr/partial-upfront as configured default

Summary by CodeRabbit

  • Bug Fixes
    • Improved consistency of default payment and term option selections across the application.
    • Enhanced fallback behavior for configuration defaults when stored user preferences are unavailable.
    • Optimized selection logic to prefer configured defaults with improved fallback mechanisms.

 #223)

Three surfaces previously hardcoded `'all-upfront'` as the payment
default regardless of operator configuration. All three now seed from
the resolved `GlobalConfig.DefaultTerm + DefaultPayment`:

1. `loadRecommendations` adds `api.getConfig()` as a siloed third leg
   of the bootstrap `Promise.all` (failure is `.catch(() => null)` so
   a missing config endpoint cannot block rec load). Resolved values
   populate module-level `cachedGlobalDefaultTerm / Payment` vars.

2. `defaultBulkPurchaseState.payment` is mutated post-fetch so the
   bulk-toolbar first-visit fallback reflects the operator's setting.
   `loadBulkPurchaseState()` localStorage fallback also switched from
   the literal `'all-upfront'` to `cachedGlobalDefaultPayment`.

3. `resolvePerRecPaymentSeed` fallback now prefers
   `cachedGlobalDefaultPayment` when it is supported for the rec's
   (provider, service, term), falling back to `paymentOptionsFor[0]`
   only if the configured payment is unavailable for that combination.

4. `pickBestVariantPerCell` (select-all tiebreaker, added by #224)
   is replaced: it now prefers the variant matching
   `(cachedGlobalDefaultTerm, cachedGlobalDefaultPayment)` and falls
   back to highest-effective-savings only when no variant matches.
   Function is now exported for direct unit testing.

`seedGlobalDefaults(term, payment)` exported for test injection.
Four new unit tests cover the config-match tiebreaker and fallback.
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-quarter Within the quarter impact/many Affects most users effort/m Days type/feat New capability labels May 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9403f58e-f325-4f33-a1f4-e8beb6ded82d

📥 Commits

Reviewing files that changed from the base of the PR and between c8a78cb and d95194a.

📒 Files selected for processing (2)
  • frontend/src/__tests__/recommendations.test.ts
  • frontend/src/recommendations.ts

📝 Walkthrough

Walkthrough

This PR implements default-variant selection for recommendations based on GlobalConfig settings. The change fetches GlobalConfig on page load, caches the default term and payment, and uses those values to pre-select matching variants across the recommendation list, bulk purchase toolbar, and purchase modal, with fallback to the highest-effective variant when no config-matching option exists.

Changes

GlobalConfig-Driven Default Variant Selection

Layer / File(s) Summary
Caching Setup
frontend/src/recommendations.ts:29-43
Module-level cachedGlobalDefaultTerm and cachedGlobalDefaultPayment are introduced with historical fallback values; exported seedGlobalDefaults() function enables test-time overrides.
API Integration
frontend/src/recommendations.ts:92-119
loadRecommendations() fetches api.getConfig() in parallel with recommendations and account lists; on success, the cached defaults are updated with validated values from cfgResponse.global.
Variant Selection Logic
frontend/src/recommendations.ts:198-247
pickBestVariantPerCell() is exported and refactored to prefer, per cell, the variant matching both cachedGlobalDefaultTerm and cachedGlobalDefaultPayment; if no match exists, it falls back to the highest-effective-savings tie-breaker.
UI Integration
frontend/src/recommendations.ts:1342-1344, 2160-2166
loadBulkPurchaseState() and resolvePerRecPaymentSeed() fallback logic updated to use cachedGlobalDefaultPayment instead of hardcoded 'all-upfront'.
Test Coverage
frontend/src/__tests__/recommendations.test.ts:4-14, 2238-2320
API mock extended to resolve getConfig({ global: {} }); new test block validates config-match preference, highest-effective fallback, multi-cell independence, and correctness under different seedGlobalDefaults() scenarios.

Sequence Diagram

sequenceDiagram
    participant App as Page Load
    participant API as API Layer
    participant Cache as GlobalConfig Cache
    participant Selector as Variant Selector
    participant UI as UI Components
    
    App->>API: loadRecommendations()
    par
        API->>API: getRecommendations()
        API->>API: listAccounts()
        API->>API: getConfig()
    end
    
    API->>Cache: Update cached defaults<br/>(term, payment)
    API->>Selector: pickBestVariantPerCell(recs)
    Selector->>Cache: Read cachedGlobalDefaultTerm<br/>cachedGlobalDefaultPayment
    Selector->>Selector: Match variant per cell
    alt Variant match found
        Selector->>Selector: Select config-matching variant
    else No match
        Selector->>Selector: Fall back to highest-effective
    end
    
    Selector->>UI: Return pre-selected variants
    
    par
        API->>Cache: loadBulkPurchaseState() reads<br/>cachedGlobalDefaultPayment
        API->>Cache: resolvePerRecPaymentSeed() reads<br/>cachedGlobalDefaultPayment
    end
    
    UI->>UI: Render with consistent defaults
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through config trees,
Pre-picking variants with ease and grace,
No more re-clicks on each fresh load—
The defaults remember, the UI knows its place! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: default-seeding payment/term from GlobalConfig to address issue #223.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #223: config-match variant pre-selection with fallback, GlobalConfig payment seeding in bulk toolbar and modal, exports for testing, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #223 objectives: variant pre-selection logic, GlobalConfig seeding, and necessary test infrastructure; no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-223-default-seed-per-cell

Review rate limit: 1/5 review remaining, refill in 42 minutes and 14 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 3, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/many Affects most users priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/feat New capability urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant