Skip to content

Conversation

@nghiacc
Copy link
Contributor

@nghiacc nghiacc commented Feb 5, 2026

Support external payment for Goods and Services with XEC being in escrow, creating safe tradings.

Summary by CodeRabbit

  • New Features

    • Goods & Services offer category with external-payment orders (seller collateral, buyer "Confirm Receipt" action).
    • ShoppingHeader: currency filter, account popover and currency modal.
    • Tabbed currency selector (Fiat/Crypto) that remembers selected tab.
  • Improvements

    • Default trading filter excludes Goods & Services and prefers buy offers.
    • Offer creation accepts preselected currency/category and adapts UI/tickers accordingly.
    • Locale-aware price formatting and Goods & Services price display; external-payment notice in order/checkout flows.
  • Documentation

    • Added detailed Goods & Services payment flow docs and diagram.

nghiacc and others added 7 commits February 4, 2026 08:27
- Added GoodsServicesPaymentType enum to frontend constants (IN_APP, EXTERNAL)
- Added LIST_GOODS_SERVICES_PAYMENT_TYPE array with labels and descriptions for payment type selector
- Updated CreateOfferModal:
  - Added paymentTypeGoodsServices field to form interface and default values
  - Added radio button UI to select payment type when creating G&S offers
  - Included field in CreateOfferInput when submitting
- Updated PlaceAnOrderModal:
  - Detect external payment offers
  - Skip buyer deposit flow for external payment orders
  - Display informational banner about external payment process
- Updated order-detail page:
  - Detect external payment orders
  - Added handleBuyerConfirmReceipt() function for buyer to confirm receipt
  - Show different UI for external payment:
    - Seller view: Message about collateral being held, Dispute button only
    - Buyer view: "Confirm Receipt" button to release collateral back to seller
- Added GoodsServicesPaymentType enum to frontend constants (IN_APP, EXTERNAL)
- Added LIST_GOODS_SERVICES_PAYMENT_TYPE array with labels and descriptions for payment type selector
- Updated CreateOfferModal:
  - Added paymentTypeGoodsServices field to form interface and default values
  - Added radio button UI to select payment type when creating G&S offers
  - Included field in CreateOfferInput when submitting
- Updated PlaceAnOrderModal:
  - Detect external payment offers
  - Skip buyer deposit flow for external payment orders
  - Display informational banner about external payment process
- Updated order-detail page:
  - Detect external payment orders
  - Added handleBuyerConfirmReceipt() function for buyer to confirm receipt
  - Show different UI for external payment:
    - Seller view: Message about collateral being held, Dispute button only
    - Buyer view: "Confirm Receipt" button to release collateral back to seller
- Replace Shopping page header with ShoppingHeader component
- Add currency filter button with visual indicators (flag for fiat, eCash logo for XEC, ticker text for others)
- Redesign ShoppingCurrencyModal with Fiat/Crypto tabs
- Include XEC in Goods & Services crypto options
- Implement dynamic price ticker logic in CreateOfferModal
- Add availablePriceTickers useMemo with smart logic:
  * Fiat payment: Only selected fiat currency
  * Crypto payment: Selected crypto + USD oracle
  * USD stablecoins: Only stablecoin (no USD oracle)
  * Others: Custom currency only
- Auto-sync ticker when payment method changes
- Change default offer type to Sell
- Remove 'Offers' header text from Shopping tab
- Preserve 'eCash' branding with proper casing
Copilot AI review requested due to automatic review settings February 5, 2026 01:14
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds Goods & Services (OfferCategory) support and external-payment flows across UI and logic: new category enum, currency/ticker selection and formatting, tabbed currency modal, shopping header, filter defaults excluding G&S, and buyer "Confirm Receipt" action that releases seller collateral.

Changes

Cohort / File(s) Summary
Core constants & utils
apps/telegram-ecash-escrow/src/store/constants.ts, apps/telegram-ecash-escrow/src/store/util.ts
Add OfferCategory enum and LIST_OFFER_CATEGORY; add formatPriceByType price formatter.
Order detail & escrow flows
apps/telegram-ecash-escrow/src/app/order-detail/page.tsx
Detect isExternalPaymentOrder, add handleBuyerConfirmReceipt, and branch UI/actions for external vs direct XEC orders.
Offer creation modal
apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx
New props initialCurrency/initialOfferCategory; add offerCategory state, G&S-specific ticker/price logic, hide XEC where inappropriate, propagate category in form values.
Shopping/discovery UI
apps/telegram-ecash-escrow/src/app/page.tsx, apps/telegram-ecash-escrow/src/app/shopping/page.tsx
Introduce tradingFilterConfig to exclude Goods & Services by default and default to buy offers when unspecified; swap to ShoppingHeader.
Currency selector & header
apps/telegram-ecash-escrow/src/components/FilterList/ShoppingCurrencyModal.tsx, apps/telegram-ecash-escrow/src/components/Header/ShoppingHeader.tsx
Add tabbed Fiat/Crypto modal with sessionStorage tab persistence and per-tab search; new ShoppingHeader component with currency button and popover.
Place order modal
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Detect external payments to alter submission path (skip buyer deposit) and show External Payment notice; adjust price display for G&S.
Docs & diagrams
docs/GOODS_SERVICES_PAYMENT_FLOWS.md, docs/GOODS_SERVICES_PAYMENT_FLOWS.drawio
Add detailed decision tree and documentation for External vs Direct XEC payment flows and frontend/backend notes.
Small imports & types
apps/telegram-ecash-escrow/src/app/order-detail/page.tsx, apps/telegram-ecash-escrow/src/components/CreateOfferModal/...
Update imports to include OfferCategory and PAYMENT_METHOD; add offerCategory to OfferFormValues and new CreateOfferModal props.

Sequence Diagram(s)

sequenceDiagram
    participant Buyer
    participant System
    participant Signer as Signature Service
    participant Seller

    Buyer->>System: Click "Confirm Receipt" (external-payment / G&S)
    System->>Signer: Build BUYER_CONFIRM_RECEIPT payload
    Signer->>Buyer: Prompt wallet to sign
    Buyer->>Signer: Return signed payload
    Signer->>System: Deliver signed payload
    System->>System: Verify and submit action, update order status to RECEIVED
    System->>Seller: Trigger collateral release (on-chain)
    Seller->>System: Acknowledge release
    System->>Buyer: Show success toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • vince8x
  • eric-son12

Poem

🐇 I nibble code, arrange the market flow,
Tabs and tickers, flags that softly glow.
Buyers sign, sellers wait — collateral freed,
New categories dance, prices now agreed.
The rabbit hops on — marketplace in tow.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Feat/external payment goods services' directly refers to the main feature being implemented: support for external payment flows in Goods and Services transactions with XEC collateral escrow.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/external-payment-goods-services

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds support for external payment in the Goods & Services marketplace, where sellers can escrow XEC as collateral to guarantee delivery. The feature introduces a new offer category system to distinguish between traditional P2P XEC trading and goods/services marketplace transactions.

Changes:

  • Added OfferCategory enum to distinguish XEC_TRADING from GOODS_SERVICES marketplace offers
  • Implemented external payment flow where sellers escrow XEC as collateral instead of buyers depositing funds
  • Created new ShoppingHeader component with currency filter functionality and Shopping-specific UI
  • Added formatPriceByType utility function to handle currency-specific price formatting

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
apps/telegram-ecash-escrow/src/store/util.ts Added formatPriceByType function for currency-aware price formatting
apps/telegram-ecash-escrow/src/store/constants.ts Defined OfferCategory enum and related constants for offer categorization
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx Added external payment logic and buyer workflow for goods/services offers
apps/telegram-ecash-escrow/src/components/Header/ShoppingHeader.tsx New shopping-specific header with currency selection and user profile features
apps/telegram-ecash-escrow/src/components/FilterList/ShoppingCurrencyModal.tsx Refactored to support both fiat and crypto currency tabs for shopping
apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx Added offer category selection and dynamic price ticker logic for goods/services
apps/telegram-ecash-escrow/src/app/shopping/page.tsx Updated to use new ShoppingHeader and simplified filter configuration
apps/telegram-ecash-escrow/src/app/page.tsx Added logic to exclude goods/services offers from P2P trading view
apps/telegram-ecash-escrow/src/app/order-detail/page.tsx Implemented buyer confirm receipt flow for external payment orders
Comments suppressed due to low confidence (1)

apps/telegram-ecash-escrow/src/app/shopping/page.tsx:203

  • The removed 'span' element containing "Offers" text leaves the Typography component with only conditional children (isShowSortIcon, location names). When none of these conditions are met, this creates an empty Typography element. Consider adding default text or handling the empty case explicitly to maintain consistent UI.
            <Typography className="title-offer" variant="body1" component="div">
              {isShowSortIcon && (
                <SortIcon
                  style={{ cursor: 'pointer', color: `${isSorted ? '#0076C4' : ''}` }}
                  onClick={openSortDialog}
                />
              )}
              {(shoppingFilterConfig.stateName ||
                shoppingFilterConfig.countryName ||
                shoppingFilterConfig.cityName) && (
                <span>
                  {[shoppingFilterConfig.cityName, shoppingFilterConfig.stateName, shoppingFilterConfig.countryName]
                    .filter(Boolean)
                    .join(', ')}
                </span>
              )}
            </Typography>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@apps/telegram-ecash-escrow/src/app/order-detail/page.tsx`:
- Around line 397-408: The handler handleBuyerConfirmReceipt sets loading with
setLoading(true) but returns early when
currentData?.escrowOrder.escrowOrderStatus === EscrowOrderStatus.Complete
without resetting it; update the function to clear the loading state before
returning (call setLoading(false) right after dispatch) or refactor the handler
to use a try/finally around the async flow so setLoading(false) always runs;
locate handleBuyerConfirmReceipt, setLoading, and the escrowOrder status check
to apply the change.
- Around line 411-425: The action string passed to
updateEscrowOrderSignatoryTrigger does not match the signatory type: you create
buyerSignatory with SignOracleSignatory(buyerSk, ACTION.BUYER_RETURN, nonce) but
send 'BUYER_CONFIRM_RECEIPT'; change the action argument on
updateEscrowOrderSignatoryTrigger to use the enum value EscrowOrderAction.Return
(matching ACTION.BUYER_RETURN) so the signatory, action and backend validation
align (updateEscrowOrderSignatoryTrigger input.action ->
EscrowOrderAction.Return while keeping signatory: hexEncode(buyerSignatory) and
signatoryOwnerHash160: hexEncode(buyerPkh)).

In
`@apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx`:
- Around line 319-324: The initializer for isBuyOffer in CreateOfferModal is
inconsistent with the comment—update the state initializer so that if
offer?.type exists you use offer.type === OfferType.Buy, otherwise detect XEC
trading and default to Buy (set true) and default to Sell (false) for Goods &
Services; specifically change the useState callback that sets isBuyOffer to
check the current asset/market indicator used in this component (e.g.,
offer?.asset, selectedAsset, or whatever prop denotes XEC trading) and return
true when that indicates XEC, otherwise return false; if the comment was wrong
instead, update the comment to match the existing logic. Ensure you reference
OfferType, isBuyOffer, setIsBuyOffer and the CreateOfferModal initializer when
making the change.

In
`@apps/telegram-ecash-escrow/src/components/FilterList/ShoppingCurrencyModal.tsx`:
- Around line 119-120: The initial state for value uses
sessionStorage.getItem(keyFilterTab) during render which breaks SSR; change
initialization to be safe by either using a lazy useState initializer that
checks for typeof window !== 'undefined' before calling
sessionStorage.getItem(keyFilterTab) or initialize value to a safe default
(e.g., 0) and then populate it in a useEffect that reads sessionStorage and
calls setValue(Number(...)). Update the useState call for value/setValue and
ensure keyFilterTab is referenced inside the client-only check so no
sessionStorage access occurs during server render.

In `@apps/telegram-ecash-escrow/src/components/Header/ShoppingHeader.tsx`:
- Line 149: The address state in ShoppingHeader is initialized from
selectedWalletPath?.cashAddress and can become stale when the wallet changes;
update it by deriving address from selectedWalletPath on each render (use
useMemo to compute parsed = useMemo(() => parseCashAddressToPrefix(COIN.XEC,
selectedWalletPath?.cashAddress), [selectedWalletPath]) and remove the one-time
useState init) or keep useState but add a useEffect that calls
setAddress(parseCashAddressToPrefix(COIN.XEC, selectedWalletPath?.cashAddress))
whenever selectedWalletPath changes; reference the ShoppingHeader component, the
address and setAddress state variables, parseCashAddressToPrefix, and COIN.XEC
when applying the change.
- Around line 263-267: The onError handler in ShoppingHeader.tsx mutates the DOM
via e.currentTarget.parentElement!.innerHTML to inject an SVG; replace this with
React state: add a boolean state (e.g., imageErrored, setImageErrored) in the
ShoppingHeader component, change the onError to call setImageErrored(true) and
optionally hide the broken img, and update the render to conditionally show the
fallback SVG/MaterialIcon when imageErrored is true (instead of using
innerHTML). Ensure the handler references the existing img element's onError and
remove any direct DOM manipulation code.

In `@apps/telegram-ecash-escrow/src/store/util.ts`:
- Around line 291-319: In formatPriceByType, the noDecimalCurrencies array
incorrectly includes 'THB'; remove 'THB' from the noDecimalCurrencies list so
Thai Baht is formatted with two decimal places; update the noDecimalCurrencies
variable declaration (currently in formatPriceByType) to exclude 'THB' (keep
other entries like 'VND','JPY','KRW','TWD','PHP','IDR') so the function will use
the 2-decimal branch for THB.
🧹 Nitpick comments (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)

324-326: Type casting for offerCategory.

The type assertion (post?.postOffer as { offerCategory?: string }) works but indicates the PostQueryItem type may need updating to include offerCategory. Consider adding the field to the proper type definition for better type safety.

apps/telegram-ecash-escrow/src/components/FilterList/ShoppingCurrencyModal.tsx (1)

128-132: Use constant instead of magic number for payment method.

The magic number 5 should use PAYMENT_METHOD.GOODS_SERVICES for consistency and maintainability.

♻️ Proposed fix
+import { PAYMENT_METHOD } from '@bcpros/lixi-models';
 // ... in handleSelect function
   const filterCurrency: FilterCurrencyType = {
-    paymentMethod: 5, // PAYMENT_METHOD.GOODS_SERVICES
+    paymentMethod: PAYMENT_METHOD.GOODS_SERVICES,
     value: currency?.code ?? currency?.ticker ?? currency
   };
apps/telegram-ecash-escrow/src/app/order-detail/page.tsx (1)

153-156: Consider a legacy fallback for external-payment detection.

If older orders were created before offerCategory was persisted, this check could misclassify them. Consider falling back to a legacy marker (e.g., paymentMethod GOODS_SERVICES) when offerCategory is missing.

Developer and others added 3 commits February 5, 2026 15:48
- Replace Shopping page header with ShoppingHeader component
- Add currency filter button with visual indicators (flag for fiat, eCash logo for XEC, ticker text for others)
- Redesign ShoppingCurrencyModal with Fiat/Crypto tabs
- Include XEC in Goods & Services crypto options
- Implement dynamic price ticker logic in CreateOfferModal
- Add availablePriceTickers useMemo with smart logic:
  * Fiat payment: Only selected fiat currency
  * Crypto payment: Selected crypto + USD oracle
  * USD stablecoins: Only stablecoin (no USD oracle)
  * Others: Custom currency only
- Auto-sync ticker when payment method changes
- Change default offer type to Sell
- Remove 'Offers' header text from Shopping tab
- Preserve 'eCash' branding with proper casing
…payment

- Updated isExternalPayment in PlaceAnOrderModal to check paymentMethodId and coinPayment
- Updated isExternalPaymentOrder in order-detail page with same logic
- G&S + Crypto (XEC) now uses direct payment flow (buyer deposits → seller releases)
- Legacy G&S (paymentMethodId=5) remains as external payment
- G&S + other payments (Bank/App/Crypto non-XEC) remain as external payment
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx`:
- Around line 324-350: The isExternalPayment memo misclassifies a CRYPTO G&S
offer with a missing coinPayment as external; update the logic in the
PlaceAnOrderModal isExternalPayment computation so coinPayment is treated the
same as elsewhere (default missing/empty coinPayment to 'XEC') — e.g., set
coinPayment = (post?.postOffer?.coinPayment || 'XEC').toUpperCase() or adjust
the CRYPTO check to treat empty coinPayment as 'XEC', ensuring
PAYMENT_METHOD.CRYPTO with omitted coinPayment is recognized as direct XEC (not
external) for OfferCategory.GOODS_SERVICES.
🧹 Nitpick comments (1)
apps/telegram-ecash-escrow/src/app/order-detail/page.tsx (1)

156-159: Consider extending the type definition instead of using type assertion.

The inline type assertion (currentData?.escrowOrder?.escrowOffer as { offerCategory?: string }) suggests offerCategory is not yet defined in the EscrowOffer type. This works but bypasses TypeScript's type safety.

Consider updating the EscrowOffer type definition to include the offerCategory field, which would provide compile-time safety across the codebase.

- Updated PlaceAnOrderModal.tsx to clarify external vs direct payment flows with detailed comments.
- Added new diagram (GOODS_SERVICES_PAYMENT_FLOWS.drawio) to visually represent payment flows.
- Created GOODS_SERVICES_PAYMENT_FLOWS.md to provide comprehensive documentation on payment scenarios, UI behavior, and backend validation.
- Included decision tree and error messages for better user guidance.
- Improve markdown formatting with consistent spacing
- Add blank lines between sections for better readability
- Reorganize code examples for clarity
Fixes from code review:

1. CreateOfferModal.tsx:
   - Fix isBuyOffer initialization to default to Buy for XEC trading and
     Sell for Goods & Services (aligning comment with code)

2. PlaceAnOrderModal.tsx:
   - Fix coinPayment default to 'XEC' to prevent misclassification of
     direct XEC G&S offers as external payment

3. order-detail/page.tsx:
   - Fix coinPayment default to 'XEC' (same issue as above)
   - Add comment clarifying BUYER_CONFIRM_RECEIPT enum usage

Previously resolved (already in codebase):
- THB removed from noDecimalCurrencies in formatPriceByType
- NaN handling added to formatPriceByType
- 'Hala' typo fixed to 'Hello' in ShoppingHeader
- sessionStorage SSR safety added
- PAYMENT_METHOD constant used instead of magic number 5
- Loading state reset in early return added
- innerHTML XSS pattern replaced with React state for flag errors
- Unused variables removed
- address state uses useMemo for wallet changes
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@docs/GOODS_SERVICES_PAYMENT_FLOWS.md`:
- Around line 82-95: The doc currently shows coinPayment defaulting to an empty
string, but runtime treats a missing coinPayment as 'XEC', so update the snippet
to default missing offer?.coinPayment to 'XEC' before uppercasing and comparing;
ensure the variable coinPayment used in the G&S + XEC check (with
PAYMENT_METHOD.CRYPTO and coinPayment === 'XEC') reflects that default so the
Case 3 classification matches runtime behavior.
- Around line 112-131: The fenced code blocks under the "External Payment Order
(Buyer View)" and "Direct XEC Payment Order (Buyer View)" sections (and the
later flow diagram around lines 165-195) are missing a language tag and trigger
MD040; update each triple-backtick fence to use ```text (e.g., the blocks
showing "Status: ESCROW ..." and the flow chart) so all fenced code blocks
include the language specifier; search for other ``` blocks in
GOODS_SERVICES_PAYMENT_FLOWS.md and add "text" to each opening fence to satisfy
MD040.

… G&S offers

When creating a Goods & Services offer, the confirmation page was hardcoded to
display 'XEC' as the Payment currency, even if the user selected a different
currency (e.g., VND) for the price ticker.

Fixed by displaying the actual selected tickerPriceGoodsServices value instead
of the hardcoded 'XEC'.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx (1)

678-689: ⚠️ Potential issue | 🟡 Minor

Bug: getValues('coinOthers') in dependency array won't trigger re-renders.

getValues returns the value at call time but doesn't subscribe to changes. The effect won't re-run when coinOthers changes in the form. Use the watched value instead.

🔧 Proposed fix
   setCoinCurrency(currency ?? (coin?.includes(COIN_OTHERS) ? getValues('coinOthers') : coin) ?? GOODS_SERVICES_UNIT);
-  }, [currencyValue, coinValue, getValues('coinOthers'), offerCategory]);
+  }, [currencyValue, coinValue, coinOthersValue, offerCategory]);

Also update the logic inside to use coinOthersValue:

-  setCoinCurrency(currency ?? (coin?.includes(COIN_OTHERS) ? getValues('coinOthers') : coin) ?? GOODS_SERVICES_UNIT);
+  setCoinCurrency(currency ?? (coin?.includes(COIN_OTHERS) ? coinOthersValue : coin) ?? GOODS_SERVICES_UNIT);

@nghiacc nghiacc requested review from Copilot and vince8x and removed request for vince8x February 5, 2026 10:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

apps/telegram-ecash-escrow/src/app/shopping/page.tsx:203

  • The label "Offers" has been removed from line 188, leaving the title section with no clear heading when no location filters are applied. This could make the UI less clear for users. Consider keeping "Offers" as a default label or adding it conditionally when no location is set.
            <Typography className="title-offer" variant="body1" component="div">
              {isShowSortIcon && (
                <SortIcon
                  style={{ cursor: 'pointer', color: `${isSorted ? '#0076C4' : ''}` }}
                  onClick={openSortDialog}
                />
              )}
              {(shoppingFilterConfig.stateName ||
                shoppingFilterConfig.countryName ||
                shoppingFilterConfig.cityName) && (
                <span>
                  {[shoppingFilterConfig.cityName, shoppingFilterConfig.stateName, shoppingFilterConfig.countryName]
                    .filter(Boolean)
                    .join(', ')}
                </span>
              )}
            </Typography>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Handle NaN values from invalid string inputs
if (isNaN(numPrice)) return '0';

// Currencies with no decimal places (THB uses 2 decimal places per ISO 4217)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions "THB uses 2 decimal places per ISO 4217" but THB is not included in the noDecimalCurrencies array. This comment seems to be explaining why THB is NOT in the list, but the phrasing is confusing and could be misinterpreted as an error. Consider rewording to clarify, for example: "Currencies with no decimal places (note: THB is not included as it uses 2 decimal places per ISO 4217)"

Suggested change
// Currencies with no decimal places (THB uses 2 decimal places per ISO 4217)
// Currencies with no decimal places (note: THB is not included as it uses 2 decimal places per ISO 4217)

Copilot uses AI. Check for mistakes.
};

const handleSelect = (currency: { code: string; name: string }) => {
const handleSelect = (currency: any) => {
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handleSelect function parameter has a loose type annotation 'any'. Consider using a more specific type union like '{ code: string; name: string } | { ticker: string; name: string }' to improve type safety and make the expected structure clearer.

Copilot uses AI. Check for mistakes.
Comment on lines +337 to +344
const [offerCategory, setOfferCategory] = useState<'XEC' | 'GOODS_SERVICES'>(() => {
// Use initialOfferCategory if provided
if (initialOfferCategory) return initialOfferCategory;
if ((offer as any)?.offerCategory === OfferCategory.GOODS_SERVICES) {
return 'GOODS_SERVICES';
}
if (offer?.paymentMethods[0]?.paymentMethod.id === PAYMENT_METHOD.GOODS_SERVICES) {
return 'GOODS_SERVICES';
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The offerCategory state variable uses string literals ('XEC' | 'GOODS_SERVICES') while the form field uses the OfferCategory enum. This inconsistency could lead to confusion. Consider using the enum type for the state variable as well: useState<OfferCategory | 'XEC'> or define 'XEC' as part of the enum for consistency. This would make the code more maintainable and type-safe.

Suggested change
const [offerCategory, setOfferCategory] = useState<'XEC' | 'GOODS_SERVICES'>(() => {
// Use initialOfferCategory if provided
if (initialOfferCategory) return initialOfferCategory;
if ((offer as any)?.offerCategory === OfferCategory.GOODS_SERVICES) {
return 'GOODS_SERVICES';
}
if (offer?.paymentMethods[0]?.paymentMethod.id === PAYMENT_METHOD.GOODS_SERVICES) {
return 'GOODS_SERVICES';
const [offerCategory, setOfferCategory] = useState<OfferCategory | 'XEC'>(() => {
// Use initialOfferCategory if provided
if (initialOfferCategory) return initialOfferCategory;
if ((offer as any)?.offerCategory === OfferCategory.GOODS_SERVICES) {
return OfferCategory.GOODS_SERVICES;
}
if (offer?.paymentMethods[0]?.paymentMethod.id === PAYMENT_METHOD.GOODS_SERVICES) {
return OfferCategory.GOODS_SERVICES;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant