feat(prices): PriceFetchControl + consent modal + best-effort UX (#158) #167

Merged
maximus merged 7 commits from issue-158-pricefetchcontrol into main 2026-04-28 01:35:24 +00:00
Owner

Summary

  • New PriceFetchControl.tsx component with button + consent modal + spinner + attribution + best-effort warning (stock only)
  • Hidden if useIsPremium() === false or categoryKind !== 'priced'
  • Consent persisted per-profile in user_preferences.price_fetching_consent ({consented_at, version: 1} shape)
  • Best-effort warning shown once per session (in-memory dismiss via module-level _bestEffortDismissedThisSession)
  • Manual unit_price input remains active in all error paths
  • Wired into SnapshotLineRow → SnapshotEditor → SnapshotEditPage next to priced-line inputs
  • 17 vitest tests (all passing)

Decisions

  • MEDIUM: No @testing-library/react or jsdom — tests are pure unit tests of logic/mocks, not DOM rendering (logged in decisions-log.md)
  • MEDIUM: asset_type not in balance_categories schema — defaulting to 'stock' with // TODO comment (follow-up needed)
  • LOW: user_preferences is per-profile by architecture (separate SQLite DB per profile), no profile_id needed in key

Stacked on (must merge first)

This branch contains merges from upstream autopilot PRs that have not yet landed:

  • #163 (issue-160-i18n-changelog)
  • #164 (issue-157-use-is-premium)
  • #166 (issue-156-balance-service-prices)

After those land, this PR will rebase down to only the PriceFetchControl-specific changes.

Closes #158

Generated autonomously by /autopilot run of 2026-04-27

## Summary - New `PriceFetchControl.tsx` component with button + consent modal + spinner + attribution + best-effort warning (stock only) - Hidden if `useIsPremium() === false` or `categoryKind !== 'priced'` - Consent persisted per-profile in `user_preferences.price_fetching_consent` (`{consented_at, version: 1}` shape) - Best-effort warning shown once per session (in-memory dismiss via module-level `_bestEffortDismissedThisSession`) - Manual unit_price input remains active in all error paths - Wired into SnapshotLineRow → SnapshotEditor → SnapshotEditPage next to priced-line inputs - 17 vitest tests (all passing) ## Decisions - **MEDIUM**: No `@testing-library/react` or jsdom — tests are pure unit tests of logic/mocks, not DOM rendering (logged in `decisions-log.md`) - **MEDIUM**: `asset_type` not in `balance_categories` schema — defaulting to `'stock'` with `// TODO` comment (follow-up needed) - **LOW**: `user_preferences` is per-profile by architecture (separate SQLite DB per profile), no `profile_id` needed in key ## Stacked on (must merge first) This branch contains merges from upstream autopilot PRs that have not yet landed: - #163 (issue-160-i18n-changelog) - #164 (issue-157-use-is-premium) - #166 (issue-156-balance-service-prices) After those land, this PR will rebase down to only the PriceFetchControl-specific changes. Closes #158 Generated autonomously by /autopilot run of 2026-04-27
maximus added 7 commits 2026-04-27 12:36:41 +00:00
feat(prices): i18n FR/EN keys + CHANGELOG entries
All checks were successful
PR Check / rust (push) Successful in 26m25s
PR Check / frontend (push) Successful in 2m34s
PR Check / rust (pull_request) Successful in 26m20s
PR Check / frontend (pull_request) Successful in 2m54s
ab7e0a3362
Closes #160
feat(prices): useIsPremium hook from license.edition
All checks were successful
PR Check / rust (push) Successful in 26m18s
PR Check / frontend (push) Successful in 2m37s
PR Check / rust (pull_request) Successful in 25m0s
PR Check / frontend (pull_request) Successful in 2m41s
98f68f7a1f
- Reads useLicense().state.edition === 'premium'
- Ergonomic only — server enforces independently (ADR 0011)
- 3 vitest tests (premium, base, free)
- CLAUDE.md hook count 12 -> 13

Closes #157
feat(prices): balance.service prices section with rate-limit + dedup + retries
All checks were successful
PR Check / rust (push) Successful in 27m27s
PR Check / frontend (push) Successful in 2m49s
PR Check / rust (pull_request) Successful in 28m58s
PR Check / frontend (pull_request) Successful in 2m57s
920f81fce5
- prices.fetchPrice wraps invoke('fetch_price', ...) with local rate-limit (1/2s), in-flight dedup, exp backoff on 5xx (2/4/8s, max 3 retries), no retry on 4xx/429, hard 100/session cap
- 9 vitest tests with vi.useFakeTimers() (happy, 401/403/404, 429 no-retry, 5xx retries, dedup, pacing, session cap)
- Annexe B i18n mapping wired (PriceError → balance.priceFetching.errors.* keys)
- Session cap checked before rate-limit/dedup; failures do not consume budget (MEDIUM decision)

Closes #156

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(prices): PriceFetchControl component + consent modal + best-effort UX
All checks were successful
PR Check / rust (push) Successful in 30m45s
PR Check / frontend (push) Successful in 3m12s
PR Check / rust (pull_request) Successful in 28m50s
PR Check / frontend (pull_request) Successful in 3m15s
043e9bf622
- New component renders button + consent modal + spinner + attribution
- Best-effort warning shown once per session for stock categories
- Hidden if not premium or category kind != 'priced'
- Consent persisted per-profile in user_preferences.price_fetching_consent
- Manual unit_price input remains active in all paths
- 17 vitest tests (no RTL/jsdom — logged MEDIUM in decisions-log.md)
- Wired into SnapshotLineRow/SnapshotEditor/SnapshotEditPage
- asset_type hardcoded to 'stock' pending category schema extension (MEDIUM)

Closes #158
maximus added the
autopilot:pending-human
status:approved
type:feature
labels 2026-04-27 12:36:45 +00:00
maximus added 1 commit 2026-04-28 01:35:07 +00:00
chore: drop decisions-log.md (autopilot scratch, conflicts with main cleanup)
All checks were successful
PR Check / rust (push) Successful in 23m37s
PR Check / frontend (push) Successful in 2m36s
PR Check / rust (pull_request) Successful in 23m18s
PR Check / frontend (pull_request) Successful in 2m27s
da4eef2bdd
maximus merged commit d140ed938a into main 2026-04-28 01:35:24 +00:00
maximus deleted branch issue-158-pricefetchcontrol 2026-04-28 01:35:25 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#167
No description provided.