EdgeSpend: Phaze gift card improvements and error resilience#5937
EdgeSpend: Phaze gift card improvements and error resilience#5937
Conversation
baaedaa to
bc6baf7
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: baaedaa456
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Keep existing cached orders visible — don't clear state on error | ||
| setLoadError(true) |
There was a problem hiding this comment.
Clear displayed orders when account refresh fails
Keeping existing state on fetch failure can expose the previous account’s cards after an account switch. clearOrderCache() only resets module-level caches, but the activeOrders / redeemedOrders React state is not reset when account.id changes, and this catch block now only sets loadError. If the first refresh for the new account fails (for example, network/API failure), the scene can continue rendering stale orders from the prior user session.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed. Added a ref-based account ID check after useState declarations that resets activeOrders, redeemedOrders, isLoading, and loadError when the account changes mid-session.
| } | ||
|
|
||
| // Don't attempt API calls while offline | ||
| if (!isConnected) return |
There was a problem hiding this comment.
Exit initial loading state when offline on focus
This early return bypasses loadOrdersFromApi, so its finally (which clears isLoading) never runs. On first entry to the scene (or after cache reset, where loading starts true), visiting while offline leaves an indefinite spinner with no actionable state until connectivity changes, effectively blocking the gift card list offline.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed. The early return for !isConnected now calls setIsLoading(false) before returning, so the scene falls through to the offline error state instead of spinning indefinitely.
| } | ||
|
|
||
| // Don't attempt API calls while offline | ||
| if (!isConnected) return |
There was a problem hiding this comment.
Infinite loader on first offline visit to list scene
Medium Severity
When the scene is opened for the first time while offline, the early return on !isConnected prevents loadOrdersFromApi from ever being called. Since isLoading is only set to false inside that function's finally block, it remains true and the UI shows FillLoader indefinitely with no offline indication. Before this change, the API call would be attempted, fail, and the finally block would clear isLoading, letting the scene fall through to the "No Gift Cards" or error state.
Additional Locations (2)
There was a problem hiding this comment.
Fixed. Same as above — setIsLoading(false) is now called in the !isConnected early return path.
| (id, i) => `Identity ${i + 1}:\n${JSON.stringify(id, null, 2)}` | ||
| ) | ||
| .join('\n\n') | ||
| ) |
There was a problem hiding this comment.
Debug modal exposes userApiKey authentication credential in plain text
Low Severity
The handleShowIdentities function uses JSON.stringify on full identity objects (both current StoredIdentity and legacy PhazeUser), which include the userApiKey field — an authentication credential sent as the user-api-key header in Phaze API requests. Since this modal is designed for sharing with support, the credential could leak inadvertently. The userApiKey should be redacted or omitted before display.
Additional Locations (1)
There was a problem hiding this comment.
No longer applicable. The handleShowIdentities modal and raw identity JSON display were removed in favor of a dedicated GiftCardAccountInfoScene that only shows email and user ID — no userApiKey is exposed.
bc6baf7 to
5b978c9
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| return 'failed' | ||
| if (order.vouchers.length > 0) return 'available' | ||
| if (order.txid != null) return 'confirming' | ||
| return 'pending' |
There was a problem hiding this comment.
Pending card status is unreachable dead code
Medium Severity
The 'pending' return in getCardStatus is unreachable for any displayed order. The relevantOrders filter requires order.vouchers.length > 0 || order.txid != null, but getCardStatus only falls through to 'pending' when both vouchers.length === 0 AND txid == null — exactly the condition the filter excludes. This means the "Pending Delivery, Please Wait..." label and its shimmer overlay can never appear. All non-failed orders without vouchers show "Awaiting Payment Confirmations..." instead, contradicting the PR's stated intent to distinguish both states.
Additional Locations (2)
There was a problem hiding this comment.
Fixed. getCardStatus now checks for Phaze API status === 'processing' (payment confirmed, generating vouchers) and returns 'pending' in that case, before falling through to the txid check which returns 'confirming'.
5b978c9 to
551823f
Compare
Add asTolerantArray helper that skips malformed items instead of throwing on the entire array. Apply it to brand lists and voucher arrays so a single bad entry doesn't break the whole UI. Also add 'failed' to recognized order statuses and make deliveryAddress optional with an empty-string default.
9625034 to
a2fb45e
Compare
Expose isError/error from useGiftCardProvider so scenes can detect provider initialization failures. On GiftCardListScene, stop clearing orders on API errors (keep last-known-good data visible), pause polling when offline and auto-resume on reconnect, and show an informational warning banner that auto-clears on success. On GiftCardMarketScene, gate the brand query on network connectivity so it auto-retries when online, and show a warning instead of an infinite loader when the initial fetch fails. On GiftCardPurchaseScene, guard against empty delivery addresses and show a warning when the provider fails to initialize.
Add isCreatingOrder to the early-return guard in handleNextPress so a second tap during the brief window before React disables the button cannot trigger duplicate order creation.
Distinguish between awaiting blockchain confirmations (txid exists but no voucher yet), pending voucher delivery, and failed/expired orders. Failed cards are dimmed like redeemed cards.
Display the Phaze quoteId at the top of the kebab menu modal for easier debugging and support reference.
Extend the gift card tx details card with a Quote ID row and a single copy button on the right side that copies all data at once. Dividers stop short of the copy button. The redeem row remains separate with its own chevron. Document backward-compat: orderId stores quoteId in prior versions.
d799b3a to
39150e5
Compare
New scene to view Phaze account credentials behind a confirmation wall. Shows quoteId context when accessed from a specific card. After the user confirms a ConfirmContinueModal warning about redemption risk, identity data (email, user ID) is revealed with copy buttons.
Add a 'Get Help' row to the gift card kebab menu that navigates to the new Gift Card Account Information scene with the quoteId. Also surface a 'Get Help' button on failed cards, reusing the existing redeem button pattern.
Add a Gift Card Account Info row in the developer mode section of SettingsScene that navigates to the new account information scene.
Set networkFeeOption to high and lock the fee tile so users cannot lower the fee priority. Gift card orders are time-sensitive with expiring quotes, so high priority reduces the risk of missed deadlines.
Populate quoteId, productId, and orderId correctly in the saved action now that the core type has explicit fields. Update GiftCardDetailsCard with backward-compat detection: if quoteId is absent, treat orderId as the quoteId per legacy behavior.
39150e5 to
d6f22c2
Compare


CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
Requires
edge-core-jswith updatedEdgeTxActionGiftCardtype (addsquoteIdandproductIdfields).Description
Context
Asana: "EdgeSpend - Various Improvements/Fixes". Addresses several Phaze gift card UX and robustness issues across purchase, list, market, and detail scenes.
Changes
asTolerantArrayhelper so a single malformed brand or voucher entry doesn't break the entire list. MakesdeliveryAddressoptional and adds'failed'to recognized order statuses.isError/errorfromuseGiftCardProvider. OnGiftCardListScene, stops clearing orders on API errors (keeps last-known-good data), pauses polling when offline, auto-resumes on reconnect, shows informational warning banners, and disables the purchase button when offline or the API is down. OnGiftCardMarketScene, gates brand query on connectivity and shows a warning instead of an infinite loader. OnGiftCardPurchaseScene, guards against empty delivery addresses and shows a warning when the provider fails. Distinguishes network connectivity errors from Phaze service errors with separate messaging.isCreatingOrderguard inhandleNextPressto prevent duplicate order creation.GiftCardDetailsCardwith Quote ID, Product ID, and Order ID rows. A single copy button on the right copies all data at once. Backward-compat: ifquoteIdis absent in the core type, treatsorderIdas the quoteId per legacy behavior.ConfirmContinueModalwarning that reveals Phaze account credentials (email, user ID). Accessible from the kebab menu "Get Help" row (with quoteId context) and from a developer settings row (without quoteId).networkFeeOptiontohighand locks the fee tile during gift card purchases to reduce the risk of quote expiration.quoteId,productId, andorderIdcorrectly in the savedEdgeTxActionGiftCardnow that the core type has explicit fields.Requirements
If you have made any visual changes to the GUI. Make sure you have: