Summary
Since !91 (merged), issuing a card pays the package open fee from the user's USD wallet. The app still issued on one tap and never showed the fee. This MR shows the fee and asks the user to confirm before the card is issued.
-
BE:
- New
GET /card-account/cards/issue-feereturns{ fee, currency }. - The fee comes from
CardIssuanceService.getIssueFee(), which reuses the cached packageopen_costread. - Errors are mapped like the sibling routes.
- The route is declared before
GET :id.
- New
-
FE, card tab:
- Button: "Get your virtual card" when the user has no card, "Add a card" otherwise. Below it: "One-time fee: X USD from your USD wallet".
- Confirm sheet: pressing the button opens it ("Pay X USD and get card" / Cancel). Only Confirm issues the card, and the existing double-tap guard still applies.
- Fee not loaded: the sheet stays closed and the fee is refetched, so a card is never issued without the fee having been shown.
- Wallet too low: shows "You need at least X USD in your USD wallet to get a card."
- 5-card limit: shows "You've reached the limit of 5 cards." instead of hiding the button silently.
-
Copy: new empty-state body, new processing and failed hints, and the
Open_cardactivity label is now "Card fee".
Testing
- BE:
yarn jest src/modules/card-accountpasses 218 tests.yarn buildand eslint are clean. - FE:
pnpm type-checkis clean, the card-account component and API tests pass (74), and eslint is clean.
Notes
- 5-card limit text: it only appears after a failed attempt. The FE learns about the limit from the 422 response; it does not count cards up front.
- Fee still loading: pressing the button gives no visible feedback.
- Fee schema: accepts any string.
- Route-order test comment: it can be tidied; the route works.
- "Card fee top-up" activity label: not done. The card history can't yet tell the open-fee top-up apart from a normal top-up.