feat(prices): PriceFetchControl component + consent modal + best-effort UX #158
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#158
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Build the
PriceFetchControl.tsxcomponent (button + consent modal + spinner + attribution) used in the snapshot editor for priced categories.Contract reference
docs/api-contract-prices.md§1 (UX best-effort label), Annexe B (i18n mapping). ADR 0011 (best-effort UX rules).Fichiers concernés
src/components/balance/PriceFetchControl.tsx(new, ~150 lines)src/components/balance/PriceFetchControl.test.tsx(new, ~120 lines)src/components/balance/SnapshotEditPage.tsx(or équivalent — wire the new control next to each priced line)Depends on
Scope
src/components/balance/PriceFetchControl.tsx:{ symbol: string; date: string; categoryKind: 'simple' | 'priced'; assetType: 'stock' | 'crypto'; onPriceFetched: (price: number, currency: string) => void; }nullifuseIsPremium() === false(also ifcategoryKind !== 'priced')assetType === 'stock': badge "best-effort" + warning text viat('balance.priceFetching.bestEffortNotice')(premier usage de la session, dismissable)assetType === 'crypto': no warninguser_preferencesfor keyprice_fetching_consent) → render consent modalt('balance.priceFetching.consent.title')t('balance.priceFetching.consent.body')(mentions privacy proxy + maximus-api)t('balance.priceFetching.consent.accept')/consent.declineuser_preferenceskeyprice_fetching_consent = JSON.stringify({consented_at: new Date().toISOString(), version: 1}). Do NOT seed elsewhere.prices.fetchPrice(symbol, date); on success, attributiont('balance.priceFetching.attribution', {date: '...'})displayed near the input ; on error, toast viat('balance.priceFetching.errors.<key>')per Annexe BSnapshotEditPageforkind=pricedlines (1 control per line, beside the unit_price input)kind !== 'priced'Critères d'acceptation
Décisions prises ce soir
balance.priceFetching.*assetType,categoryKind) + state (consent, premium)Spec source
docs/api-contract-prices.md, ADR 0011maximus referenced this issue2026-05-04 00:38:30 +00:00