-
Notifications
You must be signed in to change notification settings - Fork 0
Add Shopping tab, fiat rate fallback, and performance optimizations #391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Major Features: - Add Shopping tab with Goods & Services filtering - Implement Telegram alert system for fiat service monitoring - Add backend fiat rate fallback strategy - Optimize performance with prefetching and caching - Fix rate inversion and data structure issues Shopping Feature: - New Shopping tab with cart icon in navigation - Backend filtering via tickerPriceGoodsServices field - ShoppingFilterComponent for currency filtering - Dedicated shopping/page.tsx for Goods & Services offers Fiat Rate System: - Backend implements fallback (dev API → prod API on failure) - Frontend rate transformation (invert: 1 XEC = X USD → 1 USD = X XEC) - Support for 174 currencies with validation - Conditional loading: Goods & Services vs Crypto P2P offers - Smart skip logic for pure XEC offers (no conversion needed) Telegram Monitoring: - Bot: @p2p_dex_bot, Group ID: -1003006766820 - Critical alerts for zero rates and service failures - Error codes: FIAT_001 (zero rates), FIAT_002 (no data) - Comprehensive error context in alerts Performance Optimization: - Prefetch fiat rates on page load (Shopping, P2P Trading) - RTK Query caching reduces API calls by 90-95% - Modal open time: 200-500ms → 0ms (instant with cache) - 1 API call per session vs 10-20+ without optimization Bug Fixes: - Fixed unit quantity validation for Goods & Services - Fixed rate inversion (backend returns inverted rates) - Added XEC entries to rate data for conversion function - Fixed case sensitivity in currency lookups Files Modified: - src/app/page.tsx - Added prefetch - src/app/shopping/page.tsx - New Shopping page - src/app/wallet/page.tsx - Rate transformation - src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx - Smart loading + transformation - src/components/DetailInfo/OrderDetailInfo.tsx - Rate transformation - src/components/Footer/Footer.tsx - Shopping tab nav - src/components/FilterOffer/ShoppingFilterComponent.tsx - New filter - src/hooks/useOfferPrice.tsx - Rate transformation + cache - src/store/util.ts - Updated conversion logic - src/utils/telegram-alerts.ts - New alert system - src/app/api/alerts/telegram/route.ts - Alert endpoint Documentation (22 files): - ARCHITECTURE_FIAT_RATE_FLOW.md - System flow diagram - BACKEND_FIAT_FALLBACK_RECOMMENDATION.md - Implementation guide - BUGFIX_RATE_INVERSION.md - Rate transformation fix - PERFORMANCE_LAZY_LOADING_FIAT_RATES.md - Optimization details - RTK_QUERY_CACHE_VERIFICATION.md - Cache testing guide - TELEGRAM_ALERT_SYSTEM.md - Monitoring setup - And 16 more documentation files Breaking Changes: None Dependencies: No new dependencies added Tested: - Shopping page loads with filtered offers ✓ - Telegram alerts send successfully ✓ - Rate transformations work correctly ✓ - Zero compilation errors ✓ Pending Testing: - Modal instant open with cache - Currency filtering on Shopping page - Pagination on Shopping page
Additional changes and improvements: - Code formatting fixes across multiple components - Minor refinements to Shopping page implementation - Documentation updates and corrections - Telegram alert system refinements - Component optimizations and bug fixes Files updated: - Shopping page and filter components - Telegram API routes and alert utilities - Rate transformation logic in multiple components - Documentation files with corrections and updates - Footer navigation and wallet page improvements All changes maintain existing functionality while improving code quality.
Minor import reordering for consistency: - Moved PAYMENT_METHOD before getTickerText in import statement
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a Shopping page and filter UI, centralizes fiat-rate transformation and conditional fetching, introduces a FiatRateErrorBanner and Telegram alert utilities, refactors price logic into a shared useOfferPrice hook, updates footer navigation, many docs for fiat architecture/fallback/validation/testing, and bumps pnpm version. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant ShoppingPage as Shopping Page
participant RTK as RTK Query Cache
participant FiatAPI as Fiat Rates API (GraphQL)
participant Modal as PlaceAnOrderModal
User->>ShoppingPage: Navigate /shopping
ShoppingPage->>RTK: useGetAllFiatRateQuery(prefetch)
alt cache miss
RTK->>FiatAPI: getAllFiatRate
FiatAPI-->>RTK: fiatRates[]
end
RTK-->>ShoppingPage: cached rates
User->>Modal: Open PlaceAnOrderModal
Modal->>Modal: needsFiatRates?
alt needs fiat
Modal->>RTK: useGetAllFiatRateQuery(skip=false)
RTK-->>Modal: rates or error/empty
Modal->>Modal: transformFiatRates -> rateData
alt valid rateData
Modal->>Modal: convert & validate (incl. 5.46 XEC min)
Modal-->>User: show pricing UI
else invalid/empty/zeros
Modal->>Modal: show FiatRateErrorBanner
Modal->>RTK: (optionally) trigger Telegram alert via utils
end
else skip fetch
Modal-->>User: show crypto-only UI
end
sequenceDiagram
autonumber
participant OfferHook as useOfferPrice
participant RTK as RTK Query
participant Util as transformFiatRates
OfferHook->>OfferHook: determine needsFiatRates
alt needs fiat
OfferHook->>RTK: fetch fiat rates (skip=false)
RTK-->>OfferHook: fiatRates[]
OfferHook->>Util: transformFiatRates(fiatRates)
Util-->>OfferHook: rateData
OfferHook->>OfferHook: compute amountPer1MXEC, isGoodsServices
else skip
OfferHook->>OfferHook: compute without fiat rates
end
OfferHook-->>UI: price fields
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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 PR implements a comprehensive Shopping tab feature with robust fiat rate handling and performance optimizations. The changes establish a new shopping interface, enhance currency conversion reliability through intelligent caching and error detection, and implement automated monitoring for service failures.
Key changes include:
- Complete Shopping tab implementation with Goods & Services offer filtering
- Fixed critical rate inversion issue transforming backend rates to frontend needs (1 USD = X XEC)
- Performance optimizations reducing API calls by 90-95% through RTK Query prefetching
- Telegram alert system for monitoring fiat service failures with comprehensive error detection
Reviewed Changes
Copilot reviewed 41 out of 41 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Updates pnpm version to 10.17.0 for compatibility |
| docs/* | Creates 18 comprehensive documentation files covering implementation, testing, and monitoring |
| src/app/shopping/page.tsx | New Shopping page with infinite scroll and currency filtering |
| src/components/FilterOffer/ShoppingFilterComponent.tsx | Currency filter component using backend API field |
| src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx | Enhanced with error detection, rate transformation, and Telegram alerts |
| src/utils/telegram-alerts.ts | New alert utility for critical service failure notifications |
| src/hooks/useOfferPrice.tsx | Updated with rate transformation and conditional loading |
| src/components/Footer/Footer.tsx | Added Shopping tab navigation icon |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Outdated
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/telegram-ecash-escrow/src/components/OfferDetailInfo/OfferDetailInfo.tsx (1)
87-94: Prevent crash whenpaymentMethodsis absent.
post.offer?.paymentMethods.map(...)will throw ifpaymentMethodsis undefined/null. Add optional chaining.- <div className="payment-group-btns"> - {post.offer?.paymentMethods.map(method => { + <div className="payment-group-btns"> + {post.offer?.paymentMethods?.map?.(method => { return ( <Button key={method.id} className="cash-in-btn" size="small" color="success" variant="outlined"> {method.paymentMethod.name} </Button> ); - })} + })}apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
114-124: Avoid blank/stale values whenrateDatais null.Set sensible fallbacks so G&S XEC-priced offers show their XEC price and fiat-per-1M stays empty.
- React.useEffect(() => { - if (!rateData) return; + React.useEffect(() => { + if (!rateData) { + // Fallbacks when rates are unavailable + setAmountXECGoodsServices( + isGoodsServicesConversion ? 0 : (paymentInfo?.priceGoodsServices ?? 0) + ); + setAmountPer1MXEC(''); + return; + } const { amountXEC, amountCoinOrCurrency } = convertXECAndCurrency({ rateData: rateData, paymentInfo: paymentInfo, inputAmount: inputAmount }); setAmountXECGoodsServices(isGoodsServicesConversion ? amountXEC : paymentInfo?.priceGoodsServices); setAmountPer1MXEC(formatAmountFor1MXEC(amountCoinOrCurrency, paymentInfo?.marginPercentage, coinCurrency)); }, [rateData, paymentInfo, inputAmount, isGoodsServicesConversion, coinCurrency]);apps/telegram-ecash-escrow/src/app/wallet/page.tsx (2)
105-113: Variable shadowing: Wallet identifierconst Wallet shadows the component name Wallet, hurting readability and stack traces. Rename the context var.
-export default function Wallet() { +export default function Wallet() { @@ - const Wallet = useContext(WalletContextNode); + const walletCtx = useContext(WalletContextNode); @@ - const { XPI, chronik } = Wallet; + const { XPI, chronik } = walletCtx;Also applies to: 137-139
240-244: Amount conversion not updated on balance changeamountConverted updates only when rateData changes, not when totalValidAmount changes. Add totalValidAmount to dependencies (or compute inline).
-useEffect(() => { - convertXECToAmount(); -}, [rateData]); +useEffect(() => { + convertXECToAmount(); +}, [rateData, totalValidAmount]);Also applies to: 181-188
🧹 Nitpick comments (53)
docs/RTK_QUERY_CACHE_VERIFICATION.md (1)
185-197: Consider adding language identifiers to code blocks.The code blocks at lines 189-189 and 207-207 (within the debug steps sections) lack language specifiers, which reduces readability and prevents syntax highlighting.
Apply this pattern to improve the documentation:
-``` +```typescript // Add to modal component useEffect(() => { console.log('🔍 Modal Debug:', {Similarly for the other code block:
-``` +```typescript console.log('📊 Fiat rates loaded:', { originalRates: xecCurrency?.fiatRates?.slice(0, 3),As per static analysis hints.
docs/SESSION_SUMMARY_BACKEND_FALLBACK_DECISION.md (1)
72-75: Consider adding language identifiers to code blocks.The documentation contains code blocks without language specifiers at lines 72-75 and 95-115, which reduces syntax highlighting and readability.
Apply these improvements:
-```properties +```bash # Removed from .env NEXT_PUBLIC_FALLBACK_GRAPHQL_API=https://lixi.social/graphqlAnd for the pseudocode: ```diff -```typescript +```typescript // Backend resolver logic async function getAllFiatRate() {As per static analysis hints.
Also applies to: 95-115
docs/BACKEND_FIAT_FALLBACK_RECOMMENDATION.md (1)
33-62: Consider adding language identifiers to code blocks.Several code blocks lack language specifiers (lines 33-62, 68-80, 319-333), reducing readability.
Suggested improvements:
For the architecture diagram (lines 33-62):
-``` +```text ┌─────────────────┐For environment variables (lines 68-80):
-```bash +```bash # Primary fiat rate API (environment-specific)For the alert format (lines 319-333):
-```json +```json { "level": "WARNING",As per static analysis hints.
Also applies to: 68-80, 319-333
docs/BACKEND_FIAT_RATE_CONFIGURATION.md (3)
91-109: Consider using proper heading hierarchy instead of emphasis.Lines 91, 98, and 109 use bold emphasis (Option A:, Option B:, Option C:) instead of proper headings, which breaks the document outline and reduces accessibility.
Apply this pattern:
-**Option A: Environment Variable** +#### Option A: Environment Variable-**Option B: Configuration File** +#### Option B: Configuration File-**Option C: GraphQL Resolver** +#### Option C: GraphQL ResolverAs per static analysis hints.
21-21: Consider adding language identifiers to code blocks.Code blocks at lines 21, 124, and 231 lack language specifiers, reducing syntax highlighting.
For line 21 (URL):
-``` +```text https://aws-dev.abcpay.cash/bws/api/v3/fiatrates/For line 124 (URL): ```diff -``` +```text https://aws-dev.abcpay.cash/bws/api/v3/fiatrates/For line 231 (console output): ```diff -``` +```javascript 🔍 PlaceAnOrderModal mounted - Fiat API State: {As per static analysis hints.
Also applies to: 124-124, 231-231
259-274: Consider using proper heading hierarchy for problem sections.Lines 259, 264, 269, and 274 use bold emphasis for problem descriptions instead of proper headings.
Apply this pattern:
-**Problem 1: API Returns Different Schema** +#### Problem 1: API Returns Different SchemaSimilarly for Problems 2-4. This improves document structure and accessibility.
As per static analysis hints.
docs/FIAT_SERVICE_ERROR_DETECTION.md (2)
64-75: Consider adding language identifiers to code blocks.Code blocks at lines 64, 154, 285, and 305 lack language specifiers, which reduces syntax highlighting and readability.
Suggested improvements:
For the error banner example (lines 64-75):
-``` +```text ┌─────────────────────────────────────────────────────────┐For the alert example (line 154):
-```json +```json { "service": "Fiat Currency Service",For the console examples (lines 285, 305):
-```javascript +```javascript // Alert detectionAs per static analysis hints.
Also applies to: 154-154, 285-308
137-137: Consider removing extra spaces in inline code.Line 137 has extra spaces within the inline code span that may reduce readability.
Consider removing the spaces or reformatting as a code block if the structure is important:
- "expectedStructure": "[{currency: 'XEC', fiatRates: [{coin: 'USD', rate: 0.00002}]}]", + "expectedStructure": "[{currency:'XEC',fiatRates:[{coin:'USD',rate:0.00002}]}]",As per static analysis hints.
docs/BUGFIX_GOODS_SERVICES_VALIDATION_V2.md (2)
232-237: Add fenced code languages to satisfy markdownlint (MD040).Specify languages for code blocks:
- Use typescript for TS snippets.
- Use text for console/ascii examples.
- Use json for JSON blocks.
This resolves MD040 at the listed lines.
Also applies to: 254-258, 261-266, 284-289, 351-361
120-146: Guard against FP precision when checking 5.46 XEC minimum.Recommend rounding or epsilon when comparing to 5.46 to avoid float errors at boundary (e.g., 5.4599999).
Example:
const ltMin = amountXECGoodsServices > 0 && (Math.round(amountXECGoodsServices * 1e6) < Math.round(5.46 * 1e6)); if (ltMin) return `Total amount (${formatNumber(amountXECGoodsServices)} XEC) is less than minimum 5.46 XEC. Try increasing the quantity.`;docs/PERFORMANCE_LAZY_LOADING_FIAT_RATES.md (3)
30-64: Label code fences to pass markdownlint (MD040).Add language identifiers:
- Use text for diagrams.
- Use text for Before/After flow blocks.
Also applies to: 364-368, 372-377
79-87: Align cache TTL statements and sample config.Doc says “5 min TTL” but examples use RTK Query default (~60s). Either:
- Update text to 60s, or
- Set keepUnusedDataFor: 300 in examples.
Suggested snippet:
useGetAllFiatRateQuery(undefined, { pollingInterval: 0, refetchOnMountOrArgChange: false, refetchOnFocus: false, keepUnusedDataFor: 300_000 // 5 minutes (ms) });Also applies to: 175-187, 189-201, 255-268
320-327: Fix undefinedstartTimein logging example.Initialize with a ref or timestamp prior to query.
Example:
const startRef = React.useRef(Date.now()); // ... console.log('📊 Fiat Rate Cache Status:', { cacheHit: !isLoading && !isError && !!fiatData, needsFiatRates, skipped: !needsFiatRates, loadingTime: Date.now() - startRef.current });docs/ARCHITECTURE_FIAT_RATE_FLOW.md (3)
15-46: Add code fence languages (MD040).
- Use text for flow diagrams and user messages.
- Use typescript for TS examples.
- Use json for JSON alert payloads.
- Keep graphql for the schema block (already correct).
Also applies to: 168-171, 178-187, 233-265
7-8: Replace local filesystem path with repo-relative link.
/home/.../docs/ARCHITECTURE_FIAT_RATE_FLOW.mdisn’t portable. Link to the repo path (e.g., docs/ARCHITECTURE_FIAT_RATE_FLOW.md).
34-46: Clarify fallback routing to prod/dev APIs.Routing “dev → prod API” and “prod → dev API” is risky. Ensure:
- Explicit env gating and allowlist.
- Observability on fallback activations.
- Prefer server-side fallback to avoid exposing origins to clients.
apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx (1)
13-13: VerifyrenderTextWithLinksis XSS-safe.Ensure it does not use
dangerouslySetInnerHTML, sanitizes URLs, and renders via React elements with:
- rel="noopener noreferrer nofollow"
- target="_blank" only when needed
If not already, I can provide a safe implementation.
docs/IMPLEMENTATION_COMPLETE.md (1)
64-64: Consider adding language specifiers to code blocks.The code block at line 64 (and similar blocks throughout the document) would benefit from language specifiers for proper syntax highlighting in documentation viewers.
Apply these changes to improve documentation rendering:
-``` +```textOr for JSON blocks:
-``` +```jsondocs/TESTING_PLAN_SHOPPING_FILTER.md (1)
351-372: Add language specifier to bug report template.The bug report template code block would benefit from a language specifier.
-``` +```text **Bug**: [Brief description] ...</blockquote></details> <details> <summary>apps/telegram-ecash-escrow/src/components/OfferDetailInfo/OfferDetailInfo.tsx (1)</summary><blockquote> `36-36`: **Remove `key` from props (React reserves it and strips it).** `key` is not available in component props and its presence misleads types. Drop it from the prop type/destructure. ```diff -const OrderDetailInfo = ({ key, post }: { key: string; post: Post }) => { +const OrderDetailInfo = ({ post }: { post: Post }) => {docs/FALLBACK_IMPLEMENTATION_SUMMARY.md (2)
27-41: Add code-fence languages and fix malformed fences.Label fenced code blocks (env/ts) and replace stray ```` fences with proper triple-backtick blocks to satisfy MD040.
-```` +```md ... -```` +``` ... -```typescript +```ts const FALLBACK_GRAPHQL_ENDPOINT = process.env.NEXT_PUBLIC_FALLBACK_GRAPHQL_API || 'https://lixi.social/graphql';Also ensure the block closing at Line 50 uses ``` not ````, and apply appropriate languages for all fences. Also applies to: 50-50 --- `43-43`: **Resolve duplicate heading content.** Consolidate or rename repeated “How It Works” headings to satisfy MD024. </blockquote></details> <details> <summary>docs/FIAT_RATE_FALLBACK_STRATEGY.md (3)</summary><blockquote> `64-95`: **Label fenced code blocks.** Add languages (text, ts, env, sql, bash, javascript) to all fenced blocks to satisfy MD040. Also applies to: 154-156, 285-313, 328-365 --- `137-137`: **Fix inline code spacing.** Remove spaces inside inline code spans to satisfy MD038 (e.g., use `getAllFiatRate` not `` getAllFiatRate ``). --- `629-649`: **Deduplicate headings.** Merge or rename repeated “Security Considerations” and “Summary” headings to satisfy MD024. Also applies to: 687-696 </blockquote></details> <details> <summary>docs/TELEGRAM_ALERT_SYSTEM.md (1)</summary><blockquote> `313-330`: **Note on rate-limit cache scope.** The in-memory `alertCache` resets per server instance/deploy. Consider a shared store (Redis) if you need cross-instance throttling. </blockquote></details> <details> <summary>docs/BACKEND_CHANGE_REQUEST_GOODS_SERVICES_FILTER.md (2)</summary><blockquote> `111-121`: **Use appropriate indexes (GIN for arrays) and separate indexes.** Btree on `INTEGER[]` isn’t optimal for `@>`; prefer GIN. Keep a separate btree for `tickerPriceGoodsServices`. ```diff --- Proposed (current) -CREATE INDEX IF NOT EXISTS idx_offer_ticker_price_goods_services -ON offer(tickerPriceGoodsServices) -WHERE tickerPriceGoodsServices IS NOT NULL; - --- Optional: Composite index if often filtered with paymentMethodIds -CREATE INDEX IF NOT EXISTS idx_offer_payment_ticker -ON offer(paymentMethodIds, tickerPriceGoodsServices) -WHERE tickerPriceGoodsServices IS NOT NULL; +-- Index for currency filter +CREATE INDEX IF NOT EXISTS idx_offer_ticker_price_goods_services +ON offer (tickerPriceGoodsServices) +WHERE tickerPriceGoodsServices IS NOT NULL; + +-- GIN index for array containment on paymentMethodIds +CREATE INDEX IF NOT EXISTS idx_offer_payment_methods_gin +ON offer USING GIN (paymentMethodIds);Additionally, if queries frequently combine both predicates, consider a multicolumn index only if the planner benefits in your workload; otherwise rely on bitmap index scans.
317-325: Case-insensitive match.If inputs may vary in case, implement
UPPER(tickerPriceGoodsServices) = UPPER(:input)or use a CITEXT column to avoid function-call indexes.apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
16-21: Detect Goods & Services across all methods (not just index 0).Scan the array to avoid false negatives when order varies.
- const needsFiatRates = React.useMemo(() => { - const isGoodsServices = paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; + const needsFiatRates = React.useMemo(() => { + const isGoodsServices = Array.isArray(paymentInfo?.paymentMethods) + ? paymentInfo.paymentMethods.some(m => m?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES) + : paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; if (isGoodsServices) return true; return paymentInfo?.coinPayment && paymentInfo?.coinPayment !== 'XEC'; }, [paymentInfo]); @@ - const isGoodsServices = React.useMemo( - () => paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES, - [paymentInfo] - ); + const isGoodsServices = React.useMemo(() => { + return Array.isArray(paymentInfo?.paymentMethods) + ? paymentInfo.paymentMethods.some(m => m?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES) + : paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; + }, [paymentInfo]);Also applies to: 59-62
docs/BUGFIX_RATE_INVERSION.md (4)
96-98: Avoid duplicate XEC entries; standardize coin casingPushing both 'xec' and 'XEC' creates duplicates and downstream ambiguity. Standardize to one (recommend 'XEC') and normalize lookups case-insensitively.
-// Add XEC itself (1 XEC = 1 XEC) -transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); -transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); +// Add XEC itself (1 XEC = 1 XEC) +transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() });If consumers expect lowercase, flip accordingly but keep a single entry and normalize at read time.
88-93: Guard against tiny-but-positive rates to prevent huge inverted valuesZero is filtered, but very small rates will invert to huge numbers (Infinity risk from denormals). Add an epsilon threshold.
- .filter(item => item.rate && item.rate > 0) // Remove zero rates + .filter(item => { + const r = Number(item.rate); + return Number.isFinite(r) && r > 1e-12; // filter zero/NaN/Infinity/tiny rates + })
131-168: De-duplicate transformation logic via a shared utilSame inversion/filter/add-XEC logic appears in 4 places. Extract to a shared helper (e.g., transformRatesForCurrency(fiatData, baseCurrency): RateItem[]) to enforce consistency and simplify tests. I can draft it if you want.
204-226: Add languages to fenced code blocks (markdownlint MD040)Several code fences lack a language spec. Append a language (e.g., text) to fix lint and improve readability.
- Lines 206, 215: use ```text
- Also check lines 174, 183 for the same per linter hints.
Based on static analysis hints
Also applies to: 216-225
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (3)
127-133: Remove redundant branch; fetchNext onceBoth branches call fetchNextFilter. Simplify and avoid double triggers.
- const loadMoreItemsFilter = () => { - if (hasNextFilter && !isFetchingFilter) { - fetchNextFilter(); - } else if (hasNextFilter) { - fetchNextFilter(); - } - }; + const loadMoreItemsFilter = () => { + if (hasNextFilter && !isFetchingFilter) { + fetchNextFilter(); + } + };
191-209: Null-safe dataLength and mappingIf dataFilter is undefined while not loading, dataLength access throws. Default to empty array.
- dataLength={dataFilter.length} + dataLength={(dataFilter || []).length} ... - {dataFilter.map(item => { + {(dataFilter || []).map(item => {
83-85: Unused state: visiblevisible is set but never updated, making Slide always in sync with newPostAvailable only. Remove or wire a close handler.
apps/telegram-ecash-escrow/src/app/wallet/page.tsx (3)
190-216: Avoid state updates after unmount in async effectProtect setLoading/setWalletHistory with a mounted flag or AbortController to prevent memory leaks.
- useEffect(() => { - (async () => { + useEffect(() => { + let mounted = true; + (async () => { setLoading(true); await getTxHistoryChronikNode(chronik, XPI, walletState, 0) .then(({ chronikTxHistory }) => { - const orderedWalletParsedHistory = _.orderBy(chronikTxHistory, x => x.timeFirstSeen, 'desc'); + if (!mounted) return; + const orderedWalletParsedHistory = _.orderBy(chronikTxHistory, x => x.timeFirstSeen, 'desc'); @@ - setWalletHistory(walletParsedHistoryGroupByDate); + if (mounted) setWalletHistory(walletParsedHistoryGroupByDate); }) .catch(e => { console.log('Error when getTxHistoryChronikNode', e); }); - - setLoading(false); + if (mounted) setLoading(false); })(); - }, [walletState.walletStatusNode]); + return () => { + mounted = false; + }; + }, [walletState.walletStatusNode]);
345-347: Hard-coded localeUsing 'vi-VN' forces Vietnamese formatting. Consider user/setting-driven locale.
- {new Date(item.timeFirstSeen * 1000).toLocaleString('vi-VN')} + {new Date(item.timeFirstSeen * 1000).toLocaleString()}
221-233: Duplicate 'xec' entries and semanticsAfter inversion, currencyData='USD' yields an 'xec' entry with a small rate (USD per XEC). Then you push another 'xec' at rate 1. find('xec') will pick the first, which is fine for conversion, but duplicates are confusing and brittle. Keep a single 'XEC' or 'xec' entry; update convertXECToAmount accordingly.
Also applies to: 181-188
apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts (1)
49-57: Markdown formatting robustnessdetails may contain characters that break Markdown. Consider switching to parse_mode: 'HTML' with proper escaping, or escape Markdown-special chars in JSON.
apps/telegram-ecash-escrow/src/components/DetailInfo/OfferDetailInfo.tsx (1)
150-155: Consider renaming_isGoodsServicesfor clarity.The underscore prefix on
_isGoodsServicesis unconventional. If this is to avoid shadowing, consider a more descriptive name likeisGoodsServicesOfferorhookIsGoodsServicesto make the distinction clearer.Apply this diff if renaming is desired:
const { showPrice: hookShowPrice, amountPer1MXEC, amountXECGoodsServices, - isGoodsServices: _isGoodsServices + isGoodsServices: isGoodsServicesOffer } = useOfferPrice({ paymentInfo: offerData, inputAmount: 1 });Then update the usage on line 161:
- }, [offerData?.type, _isGoodsServices]); + }, [offerData?.type, isGoodsServicesOffer]);And on line 180:
- {_isGoodsServices ? ( + {isGoodsServicesOffer ? (apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (2)
5-19: Consider adding JSDoc comments to type definitions.While the types are clear, adding brief JSDoc comments would improve discoverability and maintainability, especially for
AlertPayloadandAlertResponse.Apply this diff to add documentation:
+/** + * Alert severity levels + */ type AlertSeverity = 'critical' | 'error' | 'warning' | 'info'; +/** + * Payload structure for sending alerts + */ interface AlertPayload { message: string; severity?: AlertSeverity; service: string; details?: any; } +/** + * Response structure from alert API + */ interface AlertResponse { success: boolean; messageSent: boolean; messageId?: number; error?: string; }
37-67: LGTM! Robust error handling.The function properly handles both API errors and network errors, always returning a consistent
AlertResponsestructure. The non-throwing behavior is appropriate for an alerting system that shouldn't break the UI.Consider using a more structured logging approach for production monitoring:
} catch (error) { - console.error('Error calling Telegram alert API:', error); + console.error('[TelegramAlert] API call failed:', { + error: error instanceof Error ? error.message : 'Unknown error', + stack: error instanceof Error ? error.stack : undefined, + timestamp: new Date().toISOString() + }); return {docs/BACKEND_CHANGE_QUICK_REFERENCE.md (1)
1-113: LGTM! Clear and comprehensive backend documentation.This quick reference provides excellent guidance for implementing the
tickerPriceGoodsServicesfilter. The structure is logical, examples are clear, and the frontend integration section helps bridge backend and frontend understanding.One small enhancement for the database index section:
Consider adding a note about index selectivity:
### 3. Database Index (Run this migration) ```sql CREATE INDEX idx_offer_ticker_price_goods_services ON offer(tickerPriceGoodsServices) WHERE tickerPriceGoodsServices IS NOT NULL;
+Note: The partial index (WHERE clause) improves performance by only indexing non-null values, which is appropriate since the filter is only used when a specific currency is selected.
</blockquote></details> <details> <summary>docs/SESSION_SUMMARY_TELEGRAM_ALERTS.md (2)</summary><blockquote> `101-107`: **Add language identifier to fenced code block.** The fenced code block showing the URL should specify a language for proper syntax highlighting. Apply this diff: ```diff -``` +```text https://aws-dev.abcpay.cash/bws/api/v3/fiatrates/--- `119-127`: **Add language identifier to bash code block.** The cURL command should be marked as a shell/bash code block. Apply this diff: ```diff -``` +```bash curl -X POST https://lixi.test/graphql \apps/telegram-ecash-escrow/src/components/FilterOffer/ShoppingFilterComponent.tsx (2)
58-61: Consider defining a specific type forfilterConfig.The
anytype forfilterConfigreduces type safety. Consider creating an interface or importing the appropriate type.import { OfferFilterInput } from '@bcpros/redux-store'; // or wherever this type is defined interface ShoppingFilterComponentProps { filterConfig: OfferFilterInput; setFilterConfig: (config: OfferFilterInput) => void; }This would provide better IntelliSense and catch potential errors at compile time.
103-116: Review debounce dependency for potential performance issue.The
debouncedHandlerrecreates on everyfilterConfigchange, which defeats the purpose of debouncing since the filter config updates with each keystroke. Consider extracting only the necessary dependencies or using a ref-based approach.const debouncedHandler = useCallback( debounce(value => { - setFilterConfig({ - ...filterConfig, - amount: value - }); + setFilterConfig(prev => ({ + ...prev, + amount: value + })); }, 500), - [filterConfig] + [setFilterConfig] );This prevents recreating the debounced function on every render, ensuring the 500ms debounce actually works as intended.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (2)
162-185: LGTM! Smart optimization for fiat rate fetching.The
needsFiatRateslogic properly determines when to skip the API call, avoiding unnecessary network requests for pure XEC orders. The query configuration withskip,refetchOnMountOrArgChange: false, andrefetchOnFocus: falseenables effective caching.Consider extracting the relevance check to a separate constant for readability:
const needsFiatRates = React.useMemo(() => { - const isRelevantParty = selectedWalletPath?.hash160 === order?.sellerAccount?.hash160 || isBuyOffer; + const isSellerOrBuyer = + selectedWalletPath?.hash160 === order?.sellerAccount?.hash160 || + isBuyOffer; - if (!isRelevantParty) return false; + if (!isSellerOrBuyer) return false;
407-425: Consider extracting button label logic to a helper.While the IIFE works, extracting this logic to a
useMemoor helper function would improve readability and testability.+ const orderTypeButton = useMemo(() => { + const baseLabel = order?.escrowOffer?.type === OfferType.Buy ? 'Buy' : 'Sell'; + const flipped = baseLabel === 'Buy' ? 'Sell' : 'Buy'; + const isGoodsServices = order?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; + + return { + seller: isGoodsServices ? flipped : baseLabel, + buyer: isGoodsServices ? baseLabel : flipped + }; + }, [order?.escrowOffer?.type, order?.paymentMethod?.id]); - {(() => { - const baseLabel = order?.escrowOffer?.type === OfferType.Buy ? 'Buy' : 'Sell'; - const flipped = baseLabel === 'Buy' ? 'Sell' : 'Buy'; - return ( - <> {order?.sellerAccount.id === selectedAccount?.id && ( <Button className="btn-order-type" size="small" color="error" variant="outlined"> - {order?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES ? flipped : baseLabel} + {orderTypeButton.seller} </Button> )} {order?.buyerAccount.id === selectedAccount?.id && ( <Button className="btn-order-type" size="small" color="success" variant="outlined"> - {order?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES ? baseLabel : flipped} + {orderTypeButton.buyer} </Button> )} - </> - ); - })()}apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
336-372: LGTM! Smart caching and skip logic.The
needsFiatRatesoptimization and query configuration enable effective caching from the Shopping page prefetch. The debug logging is helpful for troubleshooting fiat rate issues.Consider wrapping debug logs in a conditional to reduce noise in production:
+ const isDevelopment = process.env.NODE_ENV === 'development'; + useEffect(() => { + if (!isDevelopment) return; + console.log('🔍 PlaceAnOrderModal mounted - Fiat API State:', {
740-831: LGTM! Comprehensive conversion logic with good diagnostics.The function properly handles missing rate data and logs detailed conversion context. The zero-result detection (lines 784-801) is particularly important for catching fiat rate service issues.
Consider consolidating debug logs or using a logging utility:
// Create a logger utility const logConversion = (stage: string, data: any) => { if (process.env.NODE_ENV === 'development') { console.log(`[Conversion:${stage}]`, data); } }; // Then use it logConversion('input', { rateDataLength: rateData.length, // ... rest of data });
1009-1129: LGTM! Comprehensive error detection and alerting.The three-way error detection (no data, empty array, zero rates) properly catches all failure modes. The alert payload provides excellent diagnostic context for the team.
Consider adding alert throttling to prevent spam if the modal is opened/closed repeatedly:
// Add a ref to track last alert time const lastAlertTimeRef = useRef<number>(0); useEffect(() => { // ... existing error detection logic ... if (isFiatServiceDown) { const now = Date.now(); const timeSinceLastAlert = now - lastAlertTimeRef.current; // Only send alert if > 5 minutes since last alert if (timeSinceLastAlert < 5 * 60 * 1000) { console.log('⏱️ Alert throttled - last sent', timeSinceLastAlert, 'ms ago'); return; } lastAlertTimeRef.current = now; // ... send alert ... } }, [...]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (41)
README.md(1 hunks)apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts(1 hunks)apps/telegram-ecash-escrow/src/app/api/telegram/get-chat-ids/route.ts(1 hunks)apps/telegram-ecash-escrow/src/app/page.tsx(3 hunks)apps/telegram-ecash-escrow/src/app/shopping/page.tsx(1 hunks)apps/telegram-ecash-escrow/src/app/wallet/page.tsx(3 hunks)apps/telegram-ecash-escrow/src/components/CreateOfferModal/CreateOfferModal.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/DetailInfo/OfferDetailInfo.tsx(4 hunks)apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx(5 hunks)apps/telegram-ecash-escrow/src/components/FilterOffer/ShoppingFilterComponent.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/Footer/Footer.tsx(3 hunks)apps/telegram-ecash-escrow/src/components/OfferDetailInfo/OfferDetailInfo.tsx(3 hunks)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx(5 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(11 hunks)apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx(3 hunks)apps/telegram-ecash-escrow/src/store/util.ts(2 hunks)apps/telegram-ecash-escrow/src/utils/index.ts(1 hunks)apps/telegram-ecash-escrow/src/utils/linkHelpers.tsx(2 hunks)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts(1 hunks)docs/ARCHITECTURE_FIAT_RATE_FLOW.md(1 hunks)docs/BACKEND_CHANGE_QUICK_REFERENCE.md(1 hunks)docs/BACKEND_CHANGE_REQUEST_GOODS_SERVICES_FILTER.md(1 hunks)docs/BACKEND_FIAT_FALLBACK_RECOMMENDATION.md(1 hunks)docs/BACKEND_FIAT_RATE_CONFIGURATION.md(1 hunks)docs/BUGFIX_GOODS_SERVICES_VALIDATION.md(1 hunks)docs/BUGFIX_GOODS_SERVICES_VALIDATION_V2.md(1 hunks)docs/BUGFIX_RATE_INVERSION.md(1 hunks)docs/CRITICAL_FIAT_SERVICE_DOWN.md(1 hunks)docs/FALLBACK_IMPLEMENTATION_SUMMARY.md(1 hunks)docs/FIAT_RATE_FALLBACK_STRATEGY.md(1 hunks)docs/FIAT_SERVICE_ERROR_DETECTION.md(1 hunks)docs/IMPLEMENTATION_COMPLETE.md(1 hunks)docs/PERFORMANCE_LAZY_LOADING_FIAT_RATES.md(1 hunks)docs/README.md(1 hunks)docs/RTK_QUERY_CACHE_VERIFICATION.md(1 hunks)docs/SESSION_SUMMARY_BACKEND_FALLBACK_DECISION.md(1 hunks)docs/SESSION_SUMMARY_TELEGRAM_ALERTS.md(1 hunks)docs/TELEGRAM_ALERT_SYSTEM.md(1 hunks)docs/TELEGRAM_GROUP_SETUP.md(1 hunks)docs/TESTING_PLAN_SHOPPING_FILTER.md(1 hunks)package.json(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (3)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
useOfferPrice(13-133)apps/telegram-ecash-escrow/src/store/util.ts (1)
formatNumber(54-58)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)convertXECAndCurrency(153-194)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(72-79)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/components/OfferDetailInfo/OfferDetailInfo.tsx (2)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
useOfferPrice(13-133)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/components/FilterOffer/ShoppingFilterComponent.tsx (3)
apps/telegram-ecash-escrow/src/store/constants.ts (4)
COIN_USD_STABLECOIN_TICKER(18-18)ALL(143-143)ALL_CURRENCIES(141-141)LIST_USD_STABLECOIN(105-114)apps/telegram-ecash-escrow/src/store/type/types.ts (1)
FilterCurrencyType(1-4)apps/telegram-ecash-escrow/src/store/util.ts (2)
getNumberFromFormatNumber(68-78)isShowAmountOrSortFilter(60-62)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isConvertGoodsServices(111-115)
apps/telegram-ecash-escrow/src/store/util.ts (1)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isShowAmountOrSortFilter(60-62)apps/telegram-ecash-escrow/src/components/layout/MobileLayout.tsx (1)
MobileLayout(47-53)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (1)
OfferItem(125-351)
apps/telegram-ecash-escrow/src/components/DetailInfo/OfferDetailInfo.tsx (3)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
useOfferPrice(13-133)apps/telegram-ecash-escrow/src/store/util.ts (1)
formatNumber(54-58)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
🪛 markdownlint-cli2 (0.18.1)
docs/TESTING_PLAN_SHOPPING_FILTER.md
351-351: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/TELEGRAM_GROUP_SETUP.md
3-3: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
71-71: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
109-109: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
117-117: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
159-159: Bare URL used
(MD034, no-bare-urls)
162-162: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
238-238: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
268-268: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
339-339: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/IMPLEMENTATION_COMPLETE.md
64-64: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
137-137: Spaces inside code span elements
(MD038, no-space-in-code)
154-154: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/BACKEND_FIAT_FALLBACK_RECOMMENDATION.md
47-47: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
69-69: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
158-158: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/SESSION_SUMMARY_BACKEND_FALLBACK_DECISION.md
102-102: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
258-258: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/BUGFIX_GOODS_SERVICES_VALIDATION_V2.md
232-232: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
254-254: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
261-261: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
284-284: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
351-351: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/FIAT_SERVICE_ERROR_DETECTION.md
64-64: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
137-137: Spaces inside code span elements
(MD038, no-space-in-code)
154-154: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
285-285: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
305-305: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/RTK_QUERY_CACHE_VERIFICATION.md
189-189: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
207-207: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/BUGFIX_RATE_INVERSION.md
174-174: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
183-183: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
206-206: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
215-215: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/BACKEND_CHANGE_REQUEST_GOODS_SERVICES_FILTER.md
455-455: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
docs/FIAT_RATE_FALLBACK_STRATEGY.md
64-64: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
137-137: Spaces inside code span elements
(MD038, no-space-in-code)
154-154: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
285-285: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
305-305: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
328-328: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
340-340: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
356-356: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
629-629: Multiple headings with the same content
(MD024, no-duplicate-heading)
649-649: Multiple headings with the same content
(MD024, no-duplicate-heading)
687-687: Multiple headings with the same content
(MD024, no-duplicate-heading)
696-696: Multiple headings with the same content
(MD024, no-duplicate-heading)
docs/ARCHITECTURE_FIAT_RATE_FLOW.md
15-15: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
168-168: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
178-178: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
233-233: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/BACKEND_FIAT_RATE_CONFIGURATION.md
21-21: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
91-91: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
98-98: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
109-109: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
124-124: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
231-231: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
259-259: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
264-264: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
269-269: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
274-274: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
docs/FALLBACK_IMPLEMENTATION_SUMMARY.md
27-27: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
43-43: Multiple headings with the same content
(MD024, no-duplicate-heading)
50-50: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/SESSION_SUMMARY_TELEGRAM_ALERTS.md
101-101: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
105-105: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
170-170: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
192-192: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (39)
package.json (1)
46-46: Pin pnpm to 10.17.0: verify CI, Node engine & lockfile
- Ensure CI uses Corepack or pnpm/[email protected]
- Confirm
"node": ">=18.0.0"meets Next.js 14.2.25 minimum- Verify pnpm-lock.yaml is up to date and committed
apps/telegram-ecash-escrow/src/utils/index.ts (1)
14-16: LGTM!The reordering of exports is safe and has no functional impact. Export order doesn't affect behavior for named exports.
README.md (1)
16-26: LGTM!Adding a documentation index improves discoverability and provides clear navigation to technical documentation. This is a helpful addition for developers working with the codebase.
apps/telegram-ecash-escrow/src/components/Footer/Footer.tsx (3)
18-18: LGTM!The import is correctly added and used in the new Shopping tab component.
134-139: LGTM!The shopping page reset logic follows the same pattern as the existing home page and my-order page resets. Consistent implementation reduces maintenance burden.
176-191: LGTM!The Shopping tab integration is well-implemented:
- Grid layout correctly expanded to accommodate the new tab
- Tab structure matches existing patterns
- Icon, label, and navigation logic are consistent with other tabs
apps/telegram-ecash-escrow/src/store/util.ts (1)
117-135: Please confirm the structure and units of rateData.rate (e.g., is rate “XEC per USD” or “USD per XEC”?) so we can validate and correct the Goods & Services conversion math.docs/README.md (1)
1-177: Excellent documentation structure!The documentation index is well-organized with clear sections, a comprehensive table of contents, quick start guides for different roles, and current status summaries. This provides a good entry point for anyone working with the codebase.
apps/telegram-ecash-escrow/src/app/page.tsx (2)
88-93: Good performance optimization with prefetching.Prefetching fiat rates on the main page is a solid approach to improve modal load times. The configuration with
pollingInterval: 0prevents unnecessary polling, which is appropriate for cached data.
88-93: Option name is correct. TherefetchOnMountOrArgChangesetting matches RTK Query’s API and requires no change.Likely an incorrect or invalid review comment.
apps/telegram-ecash-escrow/src/utils/linkHelpers.tsx (2)
1-1: Good import consolidation.Consolidating imports from local utils improves code organization and reduces import surface area.
32-56: Improved readability with multi-line formatting.The anchor elements are now formatted across multiple lines, making the code more readable and maintainable.
docs/IMPLEMENTATION_COMPLETE.md (1)
1-266: Comprehensive and well-structured documentation.The implementation summary provides excellent coverage of:
- Changes made (backend and frontend)
- How the system works (before/after comparison)
- Testing instructions and GraphQL examples
- Benefits achieved
- Verification checklist
This will be very helpful for developers and testers.
docs/TESTING_PLAN_SHOPPING_FILTER.md (1)
1-398: Thorough and well-organized testing plan.The testing plan covers:
- 10 detailed test scenarios with clear steps and expected results
- GraphQL query verification with examples
- Common issues and troubleshooting
- Acceptance criteria and bug report template
This provides excellent guidance for QA and will help ensure comprehensive testing coverage.
docs/TELEGRAM_GROUP_SETUP.md (2)
66-99: Security note: Temporary helper endpoint.The documentation correctly instructs users to delete the helper endpoint after obtaining the chat ID (line 96-99). This is good security practice for temporary development utilities.
1-463: Excellent setup guide with multiple approaches.The documentation provides:
- Clear comparison between groups and channels
- Step-by-step setup instructions
- Five different methods for obtaining chat IDs (with Method A being the easiest)
- Troubleshooting guidance
- Best practices and usage examples
This comprehensive guide will help teams set up Telegram alerting correctly.
apps/telegram-ecash-escrow/src/app/api/telegram/get-chat-ids/route.ts (3)
25-25: Good use of cache: 'no-store'.Using
cache: 'no-store'ensures fresh data from Telegram on each request, which is appropriate for this setup utility.
43-86: Well-structured response with helpful instructions.The response includes:
- Organized chat lists by type (groups, channels, private)
- Clear step-by-step instructions
- Troubleshooting guidance
- Security reminder to delete the file
This makes the helper very user-friendly.
87-97: Good error handling and logging.The catch block properly logs errors and returns helpful error messages to the user, including troubleshooting hints.
docs/CRITICAL_FIAT_SERVICE_DOWN.md (2)
1-479: Comprehensive incident documentation.This critical issue document provides:
- Clear error details with examples
- Impact analysis across different features
- Frontend mitigations already implemented
- Detailed backend fix checklist with code examples
- Testing procedures
- Monitoring and alert recommendations
This is excellent incident documentation that will help the backend team resolve the issue quickly and prevent future occurrences.
42-52: Important configuration note for the backend team.The documentation highlights that the fiat rate API URL should point to the development endpoint. Ensure this is communicated clearly to the backend team and consider adding this to the main configuration documentation.
Consider verifying that this configuration is documented in the backend repository as well, not just in frontend docs.
docs/BUGFIX_GOODS_SERVICES_VALIDATION.md (1)
100-105: Ensure isGoodsServices scopes the XEC error message correctly in UIThe conditional looks right. Confirm amountXEC is computed only for non-Goods & Services to avoid stale values leaking the error.
apps/telegram-ecash-escrow/src/components/DetailInfo/OfferDetailInfo.tsx (2)
3-9: LGTM! Clean import reorganization.The import updates properly reflect the refactored architecture with the centralized
useOfferPricehook and the new text rendering utility. The React import changes correctly match the hooks actually used in the component.Also applies to: 27-27
177-201: LGTM! Price rendering logic is well-structured.The conditional rendering properly handles both Goods & Services and crypto offers. The check for
DEFAULT_TICKER_GOODS_SERVICESensures the fiat price is only shown when meaningful (i.e., when the ticker differs from XEC).apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (3)
3-13: LGTM! Imports align with refactored architecture.The import changes are consistent with the centralized hook pattern and properly reflect the component's dependencies.
Also applies to: 35-35
152-155: LGTM! Hook usage is correct.The
useOfferPricehook is properly integrated, with clear destructuring of the returned values. The naming is straightforward without unnecessary prefixes.
318-341: LGTM! Price display logic is consistent and correct.The price rendering properly handles both offer types with appropriate formatting and conditional display of fiat prices. The logic aligns well with the changes in OfferDetailInfo.tsx.
apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
72-115: LGTM! Convenience helpers are well-designed.The severity-specific helper functions provide excellent ergonomics while maintaining a consistent API. The parameter order (service, message, details) is intuitive and the JSDoc comments are clear.
docs/SESSION_SUMMARY_TELEGRAM_ALERTS.md (1)
1-284: LGTM! Comprehensive and well-organized session summary.This document provides excellent tracking of the Telegram alerts implementation, with clear status indicators, action items, and technical details. The file modification list and testing status tables are particularly helpful for understanding the scope of changes.
apps/telegram-ecash-escrow/src/components/FilterOffer/ShoppingFilterComponent.tsx (2)
76-101: LGTM! Filter handlers are well-structured.The handlers properly manage filter state, with
handleFilterCurrencycorrectly resetting dependent fields when a new currency is selected. The use oftickerPriceGoodsServicesaligns with the backend filter implementation.Minor suggestion for code clarity:
const handleFilterCurrency = (filterValue: FilterCurrencyType) => { let updatedConfig = { ...filterConfig }; - // For Goods & Services, we use tickerPriceGoodsServices field (backend filter) const selectedCurrency = filterValue?.value ?? ''; updatedConfig = { ...updatedConfig, - tickerPriceGoodsServices: selectedCurrency, // NEW: Backend filter field + tickerPriceGoodsServices: selectedCurrency, // Backend filter for G&S currency fiatCurrency: null, coin: null, amount: null };
126-232: LGTM! Render logic is well-structured.The conditional rendering properly handles both amount entry and currency selection modes. The integration with MUI components is clean and the FilterCurrencyModal integration looks correct.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (2)
3-3: LGTM! Imports properly reflect new functionality.The addition of
DEFAULT_TICKER_GOODS_SERVICESand the query hook destructuring align well with the fiat-rate integration.Also applies to: 29-29
324-380: LGTM! Rate transformation logic is consistent and correct.The rate inversion and transformation logic properly handles both Goods & Services and Crypto orders, with appropriate filtering for positive rates and addition of XEC entries. The implementation is consistent with similar transformations in PlaceAnOrderModal.tsx.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (6)
3-3: LGTM! Imports properly support new functionality.The additions of
DEFAULT_TICKER_GOODS_SERVICES,sendCriticalAlert, and the query hook align with the enhanced fiat rate handling and alerting capabilities.Also applies to: 22-22, 82-82
926-1001: LGTM! Well-documented rate transformation.The detailed comments explaining the rate inversion (lines 934-936) are excellent for maintainability. The transformation logic is consistent across the codebase and properly handles both offer types.
1186-1206: LGTM! Clear and prominent error messaging.The high-contrast error banner effectively communicates the service issue to users. The user-friendly message (avoiding technical jargon) is appropriate, with technical details sent to the team via Telegram.
1223-1236: LGTM! Appropriate validation for each offer type.The differential validation logic properly handles Goods & Services unit quantities versus direct XEC amounts. The 5.46 XEC minimum threshold ensures orders cover transaction fees. The error messages clearly guide users to adjust their input.
1295-1303: LGTM! Price display logic is consistent.The conditional rendering of fiat prices aligns with the pattern used in OfferDetailInfo.tsx and OfferItem.tsx, ensuring consistency across the application.
336-1163: Overall architecture observation: Excellent fiat rate optimization strategy.The combination of:
- Smart skip logic (
needsFiatRates) to avoid unnecessary API calls for pure XEC offers- RTK Query caching (
refetchOnMountOrArgChange: false,refetchOnFocus: false) to reuse prefetched data- Rate data transformation at the component level
- Comprehensive error detection and alerting
...results in a robust and performant fiat rate integration. The prefetch on the Shopping page combined with cache reuse here achieves the 200-500ms → 0ms modal load time improvement mentioned in the PR objectives.
apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts
Outdated
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/app/api/telegram/get-chat-ids/route.ts
Outdated
Show resolved
Hide resolved
…ction - Created transformFiatRates() utility in src/store/util.ts to eliminate code duplication - Updated 4 components to use the shared utility: PlaceAnOrderModal, useOfferPrice, wallet/page, OrderDetailInfo - Reduced duplicate rate transformation code from ~40 lines per component to single function call - Added comprehensive JSDoc documentation for transformFiatRates() - Removed/wrapped debug console.log statements with NODE_ENV checks to prevent production logging - Improved maintainability: Single source of truth for rate inversion logic Benefits: - DRY principle: 177 lines removed, 92 lines added (net -85 lines, ~32% code reduction) - Consistency: All components use identical transformation logic - Maintainability: Future rate transformation changes only need to be made in one place - Production-ready: Debug logs only execute in development mode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
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/app/wallet/page.tsx (1)
181-188: Incorrect fiat conversion math (uses XEC self-rate = 1)You’re multiplying XEC balance by the XEC self-rate (1), so the displayed fiat value equals XEC amount. Use the selected fiat’s XEC-per-fiat rate and divide.
- const rateArrayXec = rateData.find(item => item.coin === 'xec'); - const latestRateXec = rateArrayXec?.rate; - const amountConverted = totalValidAmount * latestRateXec; + const target = rateData.find(item => item.coin?.toUpperCase() === fiatCurrencyFilter.toUpperCase()); + const xecPerFiat = target?.rate; // e.g., 1 USD = 68027 XEC + if (!xecPerFiat || xecPerFiat <= 0) return 0; + const amountConverted = totalValidAmount / xecPerFiat; // XEC -> Fiat setAmountConverted(parseFloat(amountConverted.toFixed(2)));
♻️ Duplicate comments (1)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
22-26: XEC skip can blank price UI when showPrice is trueSkipping fetch for coinPayment === 'XEC' while showPriceInfo returns true leads to empty amountPer1MXEC/amountXECGoodsServices. Fix by either:
- Not skipping for XEC, or
- Returning false from showPriceInfo for coinPayment === 'XEC', or
- Synthesizing rateData with { coin: 'XEC', rate: 1 } when skipping.
Recommended minimal change: synthesize rateData for XEC to keep skip optimization without blank UI.
@@ - const needsFiatRates = React.useMemo(() => { + const needsFiatRates = React.useMemo(() => { const isGoodsServices = paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; if (isGoodsServices) return true; - return paymentInfo?.coinPayment && paymentInfo?.coinPayment !== 'XEC'; + return paymentInfo?.coinPayment && paymentInfo?.coinPayment !== 'XEC'; }, [paymentInfo]); @@ - const { data: fiatData } = useGetAllFiatRateQuery(undefined, { + const { data: fiatData } = useGetAllFiatRateQuery(undefined, { skip: !needsFiatRates, refetchOnMountOrArgChange: false, refetchOnFocus: false }); @@ React.useEffect(() => { + // Handle pure XEC offers without hitting the API + if (!needsFiatRates && paymentInfo?.coinPayment === 'XEC') { + setRateData([{ coin: 'XEC', rate: 1, ts: Date.now() }]); + return; + }Alternatively, add an early return in showPriceInfo for coinPayment === 'XEC' to hide the price UI.
Also applies to: 28-32, 47-56
🧹 Nitpick comments (7)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
85-87: Case-insensitive currency matchEnsure localCurrency matching is case-insensitive to avoid misses like 'usd' vs 'USD'.
- const currencyData = fiatData?.getAllFiatRate?.find( - item => item.currency === (paymentInfo?.localCurrency ?? 'USD') - ); + const lc = (paymentInfo?.localCurrency ?? 'USD')?.toUpperCase(); + const currencyData = fiatData?.getAllFiatRate?.find( + item => item.currency?.toUpperCase() === lc + );apps/telegram-ecash-escrow/src/store/util.ts (2)
172-179: Pass structured args to getCoinRate for clarityFollow-up to the typed signature: passing an object improves readability and reduces parameter order mistakes.
- const coinRate = getCoinRate( - isGoodsServicesConversion, - coinPayment, - priceGoodsServices, - priceCoinOthers, - tickerPriceGoodsServices, - rateData - ); + const coinRate = getCoinRate({ + isGoodsServicesConversion, + coinPayment, + priceGoodsServices, + priceCoinOthers, + tickerPriceGoodsServices, + rateData + });
224-256: Avoid duplicate XEC entries and normalize coin casing in transformed ratesPushing both 'xec' and 'XEC' duplicates entries. Normalize coin codes (e.g., toUpperCase) and add a single XEC entry. Also compute ts once.
-export function transformFiatRates(fiatRates: any[]): any[] | null { +export function transformFiatRates(fiatRates: Array<{ coin?: string; rate?: number; ts?: number }>): Array<{ coin: string; rate: number; ts: number }> | null { if (!fiatRates || fiatRates.length === 0) { return null; } - const transformedRates = fiatRates + const now = Date.now(); + const transformedRates = fiatRates .filter(item => item.rate && item.rate > 0) // Filter out zero/invalid rates .map(item => ({ - coin: item.coin, // Keep coin as-is (e.g., 'USD', 'EUR') + coin: (item.coin ?? '').toUpperCase(), rate: 1 / item.rate, // INVERT: If 1 XEC = 0.0000147 USD, then 1 USD = 68027 XEC - ts: item.ts + ts: item.ts ?? now })); - // Add XEC itself with rate 1 (1 XEC = 1 XEC) - transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); - transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); + // Add XEC itself with rate 1 (1 XEC = 1 XEC) + transformedRates.push({ coin: 'XEC', rate: 1, ts: now }); return transformedRates; }Consumers are already using case-insensitive lookups, so this is backward compatible.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (1)
328-352: Duplicate rate transform logic; extract a shared helper/hookThis block duplicates useOfferPrice’s rateData derivation. Extract a helper (e.g., getTransformedRatesForContext) or a small hook to centralize: choosing XEC vs localCurrency, case-insensitive matches, and transformFiatRates.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
728-743: Consider adding user-facing error state.While the function logs errors in development mode and returns 0 when
rateDatais unavailable, consider setting an explicit error state to provide user feedback in production. The error banner at lines 1111-1131 might already cover this, but explicit error propagation could improve UX.
754-771: Consider using a structured logging system.While the comprehensive error logging is valuable for debugging and only runs in development mode, consider migrating to a structured logging system (e.g., a logging library) for consistency across the codebase. This aligns with previous review feedback about console statements.
1148-1161: Consider simplifying validation logic.The validation logic is correct but the nested conditions and dual-path logic (Goods & Services vs. other offers) could be more readable. Consider extracting validation into separate functions for each offer type.
Example:
const validateGoodsServicesAmount = (quantity: number, totalXec: number) => { if (quantity <= 0) return 'Unit quantity must be greater than 0!'; if (totalXec > 0 && totalXec < 5.46) { return `Total amount (${formatNumber(totalXec)} XEC) is less than minimum 5.46 XEC. Try increasing the quantity.`; } return true; }; const validateCryptoAmount = (amount: number, xecAmount: number) => { if (amount < 0) return 'XEC amount must be greater than 0!'; if (xecAmount < 5.46) return 'You need to buy amount greater than 5.46 XEC'; return true; }; // In validate function: validate: value => { const numberValue = getNumberFromFormatNumber(value); const minValue = post?.postOffer?.orderLimitMin; const maxValue = post?.postOffer?.orderLimitMax; const amountValidation = isGoodsServices ? validateGoodsServicesAmount(numberValue, amountXECGoodsServices) : validateCryptoAmount(numberValue, amountXEC); if (amountValidation !== true) return amountValidation; if (minValue || maxValue) { if (numberValue < minValue || numberValue > maxValue) return `Amount must between ${formatNumber(minValue)} - ${formatNumber(maxValue)}`; } return true; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/telegram-ecash-escrow/src/app/wallet/page.tsx(4 hunks)apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx(5 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx(3 hunks)apps/telegram-ecash-escrow/src/store/util.ts(3 hunks)apps/telegram-ecash-escrow/src/utils/index.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
apps/telegram-ecash-escrow/src/store/util.ts (2)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
apps/telegram-ecash-escrow/src/app/wallet/page.tsx (2)
apps/telegram-ecash-escrow/src/store/util.ts (1)
transformFiatRates(238-256)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
apps/telegram-ecash-escrow/src/store/util.ts (2)
isConvertGoodsServices(111-115)transformFiatRates(238-256)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(238-256)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(72-79)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (2)
apps/telegram-ecash-escrow/src/store/util.ts (1)
transformFiatRates(238-256)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
🔇 Additional comments (8)
apps/telegram-ecash-escrow/src/utils/index.ts (1)
14-17: Re-export addition looks goodtransformFiatRates is correctly surfaced via the barrel; ordering is fine and non-breaking.
apps/telegram-ecash-escrow/src/store/util.ts (1)
164-166: Case-insensitive XEC lookup is correctThe case-insensitive search for 'XEC' avoids casing issues across data sources. LGTM.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (1)
388-406: UI label flipping logic is clearThe conditional Buy/Sell flip for Goods & Services vs crypto is correct and improves readability.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (5)
3-3: LGTM!The new imports are correctly added to support fiat rate handling, transformation, and Telegram alerting functionality.
Also applies to: 20-23, 83-83
337-359: LGTM!The
needsFiatRateslogic correctly determines when to fetch fiat rates, and the lazy query setup with caching parameters aligns with the performance optimization goals in the PR.
896-949: LGTM!The rate data transformation effect correctly handles both Goods & Services (using XEC currency) and Crypto Offers (using localCurrency). The use of the shared
transformFiatRatesutility addresses previous review feedback about code duplication.
1111-1131: LGTM!The error banner provides clear user feedback when the fiat service is unavailable, which is essential for Goods & Services offers that require currency conversion.
1200-1237: LGTM!The price display logic correctly handles both Goods & Services (showing XEC per unit and optional fiat price) and crypto offers (showing regular price), providing clear information to users.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/telegram-ecash-escrow/src/store/util.ts (1)
171-192: Fix fiat (USD/stablecoin) conversion with inverted ratestransformFiatRates now returns “1 TICKER = X XEC”, and adds XEC=1. Using latestRateXec (1) yields wrong results for the fiat path. Compute using the fiat ticker’s rate instead.
if (isGoodsServicesConversion || (coinPayment && coinPayment !== COIN_USD_STABLECOIN_TICKER)) { @@ amountCoinOrCurrency = (latestRateXec * CONST_AMOUNT_XEC) / coinRate; } else { - // Convert between XEC and fiat currency - amountXEC = inputAmount / latestRateXec; // amount currency to XEC - amountCoinOrCurrency = CONST_AMOUNT_XEC * latestRateXec; // amount curreny from 1M XEC + // Fiat stablecoin path (e.g., USD): use the fiat ticker's rate (XEC per 1 unit fiat) + const fiatTicker = (coinPayment || COIN_USD_STABLECOIN_TICKER).toUpperCase(); + const fiatRate = rateData.find(item => item.coin?.toUpperCase() === fiatTicker)?.rate; + if (!fiatRate) return { amountXEC: 0, amountCoinOrCurrency: 0 }; + // amount in XEC for the given fiat input + amountXEC = inputAmount * fiatRate; + // fiat amount for 1M XEC + amountCoinOrCurrency = CONST_AMOUNT_XEC / fiatRate; }apps/telegram-ecash-escrow/src/app/wallet/page.tsx (1)
182-188: Fix wallet fiat conversion after rate inversiontransformed rateData has fiatTicker.rate = XEC per 1 fiat, and 'xec' = 1. Using 'xec' returns identity. Use fiatCurrencyFilter and divide.
- const rateArrayXec = rateData.find(item => item.coin === 'xec'); - const latestRateXec = rateArrayXec?.rate; - const amountConverted = totalValidAmount * latestRateXec; - setAmountConverted(parseFloat(amountConverted.toFixed(2))); + const ticker = (fiatCurrencyFilter?.toUpperCase?.() || 'USD'); + const fiatRate = rateData.find(item => item.coin?.toUpperCase() === ticker)?.rate; + if (!fiatRate) { + setAmountConverted(0); + return; + } + // fiat amount = XEC amount / (XEC per 1 unit fiat) + const amountConverted = totalValidAmount / fiatRate; + setAmountConverted(parseFloat(amountConverted.toFixed(2)));apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (1)
243-249: Guard against missing numeric price — potential runtime error.order.price.match(...) can return null; accessing [0] will throw.
- const compactNumber = order?.price.match(/[\d.]+[BMK]?/); - const revertPriceOrder = revertCompactNumber(compactNumber[0]); + const compactNumber = order?.price?.match(/[\d.]+[BMK]?/); + if (!compactNumber) { + return; + } + const revertPriceOrder = revertCompactNumber(compactNumber[0]);apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)
776-789: Possible null dereference: escrowScript may be unset on first convert.convertToAmountXEC can run before calEscrowScript finishes. Guard before accessing script().
- const feeWithdraw = estimatedFee(Buffer.from(escrowScript.script().bytecode).toString('hex')); + const feeWithdraw = escrowScript + ? estimatedFee(hexEncode(escrowScript.script().bytecode)) + : 0;
♻️ Duplicate comments (3)
apps/telegram-ecash-escrow/src/store/util.ts (1)
117-145: Guard against null coinPayment and simplify getCoinRate inputIf isGoodsServicesConversion is true but ticker lookup fails, the function falls through and calls toLowerCase on a possibly null coinPayment. Add a null guard. Also consider refactoring to a single options object to reduce parameter count.
const getCoinRate = ( isGoodsServicesConversion, coinPayment, priceGoodsServices, priceCoinOthers, tickerPriceGoodsServices, rateData ) => { @@ - // Case-insensitive comparison to handle both uppercase and lowercase coin codes - return rateData.find(item => item.coin?.toLowerCase() === coinPayment.toLowerCase())?.rate; + // If coinPayment is not provided, do not attempt lookup + if (!coinPayment) { + return undefined; + } + // Case-insensitive comparison to handle both uppercase and lowercase coin codes + return rateData.find(item => item.coin?.toLowerCase() === coinPayment.toLowerCase())?.rate; };Optionally:
- Replace positional params with a typed options object for readability and maintainability. Based on learnings
Also applies to: 142-145
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
22-26: Prevent blank price UI for XEC offers by fetching ratesSkipping when coinPayment === 'XEC' leaves showPrice true but rateData empty. Fetch for XEC too.
const needsFiatRates = React.useMemo(() => { const isGoodsServices = paymentInfo?.paymentMethods?.[0]?.paymentMethod?.id === PAYMENT_METHOD.GOODS_SERVICES; if (isGoodsServices) return true; - return paymentInfo?.coinPayment && paymentInfo?.coinPayment !== 'XEC'; + return Boolean(paymentInfo?.coinPayment); }, [paymentInfo]);apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)
518-520: Replace raw console.error with structured logging.Use your logging util or gate by env. This was flagged earlier.
🧹 Nitpick comments (7)
apps/telegram-ecash-escrow/src/store/util.ts (1)
243-256: Type and normalize transformFiatRates; avoid duplicate XEC entriesGood centralization. Minor improvements:
- Return a typed array (e.g., { coin: string; rate: number; ts?: number }[]).
- Normalize coin casing once (e.g., upper-case) and only add a single 'XEC' entry to avoid duplicates.
-export function transformFiatRates(fiatRates: any[]): any[] | null { +type TransformedRate = { coin: string; rate: number; ts?: number }; +export function transformFiatRates(fiatRates: Array<{ coin?: string; rate?: number; ts?: number }> = []): TransformedRate[] | null { if (!fiatRates || fiatRates.length === 0) { return null; } - const transformedRates = fiatRates + const transformedRates: TransformedRate[] = fiatRates .filter(item => item.rate && item.rate > 0) // Filter out zero/invalid rates .map(item => ({ - coin: item.coin, // Keep coin as-is (e.g., 'USD', 'EUR') + coin: String(item.coin ?? '').toUpperCase(), rate: 1 / item.rate, // INVERT: If 1 XEC = 0.0000147 USD, then 1 USD = 68027 XEC ts: item.ts })); - // Add XEC itself with rate 1 (1 XEC = 1 XEC) - transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); - transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); + // Ensure a single XEC entry (1 XEC = 1 XEC) + if (!transformedRates.some(r => r.coin === 'XEC')) { + transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); + } return transformedRates; }apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (3)
324-361: De-duplicate rate selection logic across components.This XEC-vs-localCurrency branch is repeated here and in PlaceAnOrderModal. Extract a helper (e.g., getTransformedRateData({fiatData, isGoodsServices, localCurrency})) in store/util and reuse to reduce drift.
271-275: Fix memo dependencies for isShowDynamicValue.Include isBuyOffer and order.escrowOrderStatus to avoid stale value when showPrice remains constant.
- }, [showPrice]); + }, [showPrice, isBuyOffer, order?.escrowOrderStatus]);
392-406: Remove duplicated “order type” button block.The two blocks render the same labels; extract a small subcomponent or function to render once and reuse.
Also applies to: 420-439
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
896-949: De-duplicate rate selection/transformation logic.Same branching exists in OrderDetailInfo. Extract a shared helper (e.g., getTransformedRateData) to avoid drift and ease testing.
957-1062: Throttle Telegram alerts to avoid spamming.Guard to send once per offer/session.
Apply within the effect and add a ref:
// Add near component top const alertSentRef = React.useRef(false);- if (isFiatServiceDown) { + if (isFiatServiceDown && !alertSentRef.current) { + alertSentRef.current = true; const errorType = hasInvalidRates ? 'INVALID_DATA_ZERO_RATES' : 'NO_DATA_EMPTY_RESPONSE'; // ... }
1201-1207: Avoid magic number 5.46 — centralize as a constant.Use a named constant (e.g., MIN_ORDER_XEC) in store/constants and import here to keep validation/messages consistent.
Also applies to: 1148-1161, 791-795
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/telegram-ecash-escrow/src/app/wallet/page.tsx(4 hunks)apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx(5 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx(3 hunks)apps/telegram-ecash-escrow/src/store/util.ts(3 hunks)apps/telegram-ecash-escrow/src/utils/index.ts(1 hunks)docs/REFACTORING_RATE_TRANSFORMATION.md(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
apps/telegram-ecash-escrow/src/app/wallet/page.tsx (2)
apps/telegram-ecash-escrow/src/store/util.ts (1)
transformFiatRates(238-256)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(238-256)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(72-79)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/store/util.ts (2)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
apps/telegram-ecash-escrow/src/store/util.ts (2)
isConvertGoodsServices(111-115)transformFiatRates(238-256)
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx (2)
apps/telegram-ecash-escrow/src/store/util.ts (1)
transformFiatRates(238-256)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
🪛 markdownlint-cli2 (0.18.1)
docs/REFACTORING_RATE_TRANSFORMATION.md
121-121: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
🔇 Additional comments (3)
apps/telegram-ecash-escrow/src/utils/index.ts (1)
14-18: Re-exports look consistentNew exports are coherent with util.ts. No issues.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
351-359: Caching comment vs behavior — confirm RTK Query TTL.Comments mention “5 minutes” but only refetch flags are set here. Ensure endpoint keepUnusedDataFor or cache lifetime is configured in the API slice; otherwise default is likely 60s.
881-894: LGTM: convert only when rateData is available or not needed.Prevents premature conversion and race with fiat fetch.
apps/telegram-ecash-escrow/src/components/DetailInfo/OrderDetailInfo.tsx
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Show resolved
Hide resolved
There was a problem hiding this 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
♻️ Duplicate comments (5)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (4)
728-801: Remove or gate debug console statements before production.The conversion logic is correct, but development-only console statements remain in the code (lines 732-740, 755-770). While gated by
NODE_ENV !== 'production', these add noise and should be removed or replaced with a proper logging system.Consider removing the verbose console.error blocks or replacing them with a centralized logging utility:
- if (!rateData) { - // Show error if fiat rate is needed but not available - if (isGoodsServicesConversion || (post?.postOffer?.coinPayment && post?.postOffer?.coinPayment !== 'XEC')) { - if (process.env.NODE_ENV !== 'production') { - console.error('❌ [FIAT_ERROR] Rate data unavailable', { - errorCode: 'CONV_001', - component: 'PlaceAnOrderModal.convertToAmountXEC', - isGoodsServices: isGoodsServicesConversion, - coinPayment: post?.postOffer?.coinPayment, - rateData: null, - timestamp: new Date().toISOString() - }); - } - } + if (!rateData) { return 0; }Similar cleanup needed for lines 754-771.
Based on past review comments.
896-949: Remove development console.log statements.The rate data transformation logic is correct, but multiple
console.logandconsole.warnstatements remain (lines 908-917, 921-922, 935-939).Apply similar cleanup as suggested for
convertToAmountXECto remove verbose logging.Based on past review comments.
957-1061: Extract alert logic into a custom hook or utility.This 100+ line effect makes the component harder to maintain and test. The previous review suggestion to extract this into a custom hook (e.g.,
useFiatServiceMonitoring) remains valid and should be prioritized.Example structure (as suggested in previous review):
// In hooks/useFiatServiceMonitoring.ts export function useFiatServiceMonitoring({ fiatData, fiatRateError, isGoodsServicesConversion, post }) { useEffect(() => { // Detection and alerting logic here }, [/* dependencies */]); } // In PlaceAnOrderModal.tsx useFiatServiceMonitoring({ fiatData, fiatRateError, isGoodsServicesConversion, post });Additionally, remove the
console.errorstatement at lines 1049-1051 or replace with proper logging.Based on past review comments.
1063-1087: Extract duplicated error detection logic.The error detection logic here duplicates the logic in the alert effect (lines 957-1061). The previous review suggestion to extract this into a shared utility function remains valid.
Example (as suggested in previous review):
// In src/utils/fiat-service-errors.ts export function detectFiatServiceError( fiatData: any, fiatRateError: boolean ): { hasError: boolean; errorType: string | null } { // Check for no data const hasNoData = fiatRateError || !fiatData?.getAllFiatRate || fiatData?.getAllFiatRate?.length === 0; if (hasNoData) return { hasError: true, errorType: 'NO_DATA' }; // Check for zero rates const xecCurrency = fiatData?.getAllFiatRate?.find(item => item.currency === 'XEC'); if (xecCurrency?.fiatRates && xecCurrency.fiatRates.length > 0) { const majorCurrencies = ['USD', 'EUR', 'GBP']; const majorRates = xecCurrency.fiatRates.filter(r => majorCurrencies.includes(r.coin?.toUpperCase())); if (majorRates.length > 0 && majorRates.every(r => r.rate === 0)) { return { hasError: true, errorType: 'ZERO_RATES' }; } } return { hasError: false, errorType: null }; }Then use this utility in both the alert effect and error banner calculation.
Based on past review comments.
apps/telegram-ecash-escrow/src/store/util.ts (1)
117-146: Address previous review feedback: add null-guards and TypeScript types.The function still lacks TypeScript types and null-safety checks, as flagged in previous reviews. With the new Goods & Services logic, the risk is higher:
- Line 145:
coinPayment.toLowerCase()can throw ifcoinPaymentisnullorundefinedwhen the GS path doesn't return early- The function remains untyped, making it harder to catch type errors at compile time
- 6 parameters make the call-site harder to read
Apply this diff to add types and null-guards (adapting CodeRabbit's previous suggestion):
+type RateItem = { coin?: string; rate?: number }; +type GetCoinRateArgs = { + isGoodsServicesConversion: boolean; + coinPayment?: string | null; + priceGoodsServices?: number | null; + priceCoinOthers?: number | null; + tickerPriceGoodsServices?: string | null; + rateData: RateItem[]; +}; -const getCoinRate = ( - isGoodsServicesConversion, - coinPayment, - priceGoodsServices, - priceCoinOthers, - tickerPriceGoodsServices, - rateData -) => { +const getCoinRate = ({ + isGoodsServicesConversion, + coinPayment, + priceGoodsServices, + priceCoinOthers, + tickerPriceGoodsServices, + rateData +}: GetCoinRateArgs): number | undefined => { // For Goods & Services: priceGoodsServices is the PRICE (e.g., 1 USD) // We need to find the USD (or tickerPriceGoodsServices) rate from rateData if (isGoodsServicesConversion && tickerPriceGoodsServices) { // Find the rate for the ticker currency (e.g., USD rate) const tickerPriceGoodsServicesUpper = tickerPriceGoodsServices.toUpperCase(); - const tickerRate = rateData.find( - (item: { coin?: string; rate?: number }) => item.coin?.toUpperCase() === tickerPriceGoodsServicesUpper - )?.rate; + const tickerRate = rateData.find((item: RateItem) => item.coin?.toUpperCase() === tickerPriceGoodsServicesUpper)?.rate; if (tickerRate && priceGoodsServices && priceGoodsServices > 0) { // Return the fiat currency rate multiplied by the price // E.g., if 1 USD = 0.00002 XEC and item costs 1 USD, return 0.00002 return tickerRate * priceGoodsServices; } } if (coinPayment === COIN_OTHERS && priceCoinOthers && priceCoinOthers > 0) { return priceCoinOthers; } // Case-insensitive comparison to handle both uppercase and lowercase coin codes - return rateData.find(item => item.coin?.toLowerCase() === coinPayment.toLowerCase())?.rate; + const coinLower = typeof coinPayment === 'string' ? coinPayment.toLowerCase() : undefined; + if (!coinLower) return undefined; + return rateData.find(item => item.coin?.toLowerCase() === coinLower)?.rate; };Then update the call-site at lines 174-181 to use the options object:
- const coinRate = getCoinRate( - isGoodsServicesConversion, - coinPayment, - priceGoodsServices, - priceCoinOthers, - tickerPriceGoodsServices, - rateData - ); + const coinRate = getCoinRate({ + isGoodsServicesConversion, + coinPayment, + priceGoodsServices, + priceCoinOthers, + tickerPriceGoodsServices, + rateData + });Based on past review comments.
🧹 Nitpick comments (1)
apps/telegram-ecash-escrow/src/store/util.ts (1)
240-258: Consider using proper TypeScript types instead ofany[].The function logic is correct, but the type signature could be more precise to improve type safety:
+interface FiatRate { + coin: string; + rate: number; + ts?: number; +} + -export function transformFiatRates(fiatRates: any[]): any[] | null { +export function transformFiatRates(fiatRates: FiatRate[]): FiatRate[] | null { if (!fiatRates || fiatRates.length === 0) { return null; } const transformedRates = fiatRates .filter(item => item.rate && item.rate > 0) // Filter out zero/invalid rates .map(item => ({ coin: item.coin, // Keep coin as-is (e.g., 'USD', 'EUR') rate: 1 / item.rate, // INVERT: If 1 XEC = 0.0000147 USD, then 1 USD = 68027 XEC ts: item.ts })); // Add XEC itself with rate 1 (1 XEC = 1 XEC) transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); return transformedRates; }Also consider: adding only one XEC entry (either 'xec' or 'XEC') would be sufficient since the code performs case-insensitive lookups. This would avoid duplicate entries in the rate array.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/store/util.ts(3 hunks)docs/REFACTORING_RATE_TRANSFORMATION.md(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(240-258)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(72-79)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/store/util.ts (2)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
🔇 Additional comments (4)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (4)
3-3: LGTM! Imports are well-organized.The new imports are all used appropriately in the component:
DEFAULT_TICKER_GOODS_SERVICESfor Goods & Services display logictransformFiatRatesfor rate data transformationsendCriticalAlertfor Telegram alertinguseGetAllFiatRateQueryfor lazy fiat rate loadingAlso applies to: 20-23, 83-83
337-359: Excellent optimization with lazy loading and caching.The
needsFiatRateslogic correctly identifies when fiat rates are required:
- Goods & Services always need rates (priced in fiat)
- Crypto P2P offers only need rates when
coinPayment !== 'XEC'The RTK Query configuration is optimal:
skip: !needsFiatRatesprevents unnecessary API calls for pure XEC offersrefetchOnMountOrArgChange: falseleverages cached data from Shopping page- This achieves the stated 90-95% API call reduction
1110-1130: LGTM! Clear error messaging for users.The error banner provides clear, user-friendly feedback when the fiat service is unavailable:
- Prominent warning styling (red background)
- Non-technical message for end users
- Specific context (currency ticker) included
1147-1160: LGTM! Comprehensive validation and display logic for Goods & Services.The validation correctly handles Goods & Services offers:
- Unit quantity must be greater than 0
- Total XEC amount must meet 5.46 XEC minimum
- Clear error messages guide users to fix issues
The display logic is also well-implemented:
- Shows both XEC per unit and total XEC
- Conditionally displays fiat price when ticker is not XEC (lines 1219-1227)
- Provides clear pricing information to users
Also applies to: 1201-1227
- Refactor getCoinRate to use options object pattern (better maintainability) - Remove unauthenticated Telegram helper endpoint for security - Add authentication (x-alert-token) to Telegram alert endpoint - Add 10-second timeout to Telegram API requests - Add scrollableDiv container for InfiniteScroll component - Fix documentation typo: formatFormat → formatNumber - Return 500 instead of 200 when TELEGRAM_ALERT_CHANNEL_ID missing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (2)
apps/telegram-ecash-escrow/src/store/util.ts (2)
117-124: MakecoinPaymentnullable to match actual usage.The interface declares
coinPayment: string, but the value can benullorundefinedin practice (e.g., when destructured frompaymentInfoon line 168). This type mismatch creates a false sense of safety that leads to the runtime error flagged below.Apply this diff:
export interface GetCoinRateOptions { isGoodsServicesConversion: boolean; - coinPayment: string; + coinPayment: string | null | undefined; priceGoodsServices: number | null; priceCoinOthers: number | null; tickerPriceGoodsServices: string | null; rateData: Array<{ coin?: string; rate?: number }>; }This aligns with the previous review recommendation.
126-155: Critical: Null-guard forcoinPaymentstill missing despite previous review.Line 154's
coinPayment.toLowerCase()will throw aTypeErrorifcoinPaymentisnullorundefined. This can occur when:
isGoodsServicesConversionistrue(line 182 condition satisfied)- But
coinPaymentis falsy- The Goods & Services path (lines 136-147) doesn't return
- The
COIN_OTHERSpath (lines 149-151) doesn't return- Execution reaches line 154 with null
coinPaymentThe previous review explicitly provided a solution for this issue that was not implemented.
Apply this diff to add the null-guard as recommended in the previous review:
export const getCoinRate = ({ isGoodsServicesConversion, coinPayment, priceGoodsServices, priceCoinOthers, tickerPriceGoodsServices, rateData -}: GetCoinRateOptions): any | null => { +}: GetCoinRateOptions): number | undefined => { // For Goods & Services: priceGoodsServices is the PRICE (e.g., 1 USD) // We need to find the USD (or tickerPriceGoodsServices) rate from rateData if (isGoodsServicesConversion && tickerPriceGoodsServices) { // Find the rate for the ticker currency (e.g., USD rate) const tickerPriceGoodsServicesUpper = tickerPriceGoodsServices.toUpperCase(); const tickerRate = rateData.find( (item: { coin?: string; rate?: number }) => item.coin?.toUpperCase() === tickerPriceGoodsServicesUpper )?.rate; if (tickerRate && priceGoodsServices && priceGoodsServices > 0) { // Return the fiat currency rate multiplied by the price // E.g., if 1 USD = 0.00002 XEC and item costs 1 USD, return 0.00002 return tickerRate * priceGoodsServices; } } if (coinPayment === COIN_OTHERS && priceCoinOthers && priceCoinOthers > 0) { return priceCoinOthers; } - // Case-insensitive comparison to handle both uppercase and lowercase coin codes - return rateData.find(item => item.coin?.toLowerCase() === coinPayment.toLowerCase())?.rate; + // Guard against null/undefined coinPayment + const coinLower = typeof coinPayment === 'string' ? coinPayment.toLowerCase() : undefined; + if (!coinLower) return undefined; + + // Case-insensitive comparison to handle both uppercase and lowercase coin codes + return rateData.find(item => item.coin?.toLowerCase() === coinLower)?.rate; };
🧹 Nitpick comments (10)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (2)
127-133: Simplify redundant conditional logic.Both branches call
fetchNextFilter()whenhasNextFilteris true, making the!isFetchingcheck redundant. The else-if condition never executes differently.Apply this diff to simplify:
const loadMoreItemsFilter = () => { - if (hasNextFilter && !isFetchingFilter) { - fetchNextFilter(); - } else if (hasNextFilter) { + if (hasNextFilter && !isFetchingFilter) { fetchNextFilter(); } };
143-145: Add dispatch to useEffect dependencies.The effect uses
dispatchbut doesn't include it in the dependency array. While Redux dispatch is stable, it's best practice to include all referenced values.Apply this diff:
useEffect(() => { dispatch(setNewPostAvailable(false)); -}, []); +}, [dispatch]);apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts (1)
59-61: Guard against JSON serialization errors.
JSON.stringify(details)can throw ifdetailscontains circular references, BigInt values, or other unserializable objects, causing the entire alert to fail.Apply this diff to add error handling:
if (details) { - alertMessage += `*Details:*\n\`\`\`\n${JSON.stringify(details, null, 2)}\n\`\`\`\n\n`; + try { + alertMessage += `*Details:*\n\`\`\`\n${JSON.stringify(details, null, 2)}\n\`\`\`\n\n`; + } catch (stringifyError) { + alertMessage += `*Details:* [Unable to serialize: ${stringifyError instanceof Error ? stringifyError.message : 'unknown error'}]\n\n`; + } }apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
39-46: Improve error handling for missing token.The empty string fallback (
|| '') silently creates requests that will always fail with 401. Consider failing fast or logging a warning when the token is missing.Apply this diff:
export async function sendTelegramAlert(payload: AlertPayload): Promise<AlertResponse> { try { + const token = process.env.NEXT_PUBLIC_ALERT_API_TOKEN; + if (!token) { + console.error('NEXT_PUBLIC_ALERT_API_TOKEN not configured'); + return { + success: false, + messageSent: false, + error: 'Alert token not configured' + }; + } + const response = await fetch('/api/alerts/telegram', { method: 'POST', headers: { 'Content-Type': 'application/json', - 'x-alert-token': process.env.NEXT_PUBLIC_ALERT_API_TOKEN || '' + 'x-alert-token': token }, body: JSON.stringify(payload) });Note: This suggestion assumes you keep the current architecture. However, the critical security issue flagged above should be addressed first by moving alerts server-side.
apps/telegram-ecash-escrow/src/store/util.ts (2)
165-206: Add type annotations for function parameters.The function parameters (
rateData,paymentInfo,inputAmount) are untyped, which reduces type safety and IDE support. Consider adding explicit types or at least inline type annotations.Apply this diff to add types:
-export const convertXECAndCurrency = ({ rateData, paymentInfo, inputAmount }) => { +interface ConvertXECAndCurrencyParams { + rateData: Array<{ coin?: string; rate?: number }>; + paymentInfo: { + coinPayment?: string | null; + priceGoodsServices?: number | null; + tickerPriceGoodsServices?: string | null; + priceCoinOthers?: number | null; + }; + inputAmount: number; +} + +export const convertXECAndCurrency = ({ rateData, paymentInfo, inputAmount }: ConvertXECAndCurrencyParams) => { if (!rateData || !paymentInfo) return { amountXEC: 0, amountCoinOrCurrency: 0 };
235-267: Consider adding specific types instead ofany[].The function logic correctly implements the rate inversion as documented. However, using
any[]reduces type safety. Consider defining an explicit interface for rate items.Apply this diff to add types:
+interface FiatRateItem { + coin: string; + rate: number; + ts?: number; +} + /** * Transforms fiat rate data from backend format to frontend format. * * Backend returns: {coin: 'USD', rate: 0.0000147} meaning "1 XEC = 0.0000147 USD" * Frontend needs: {coin: 'USD', rate: 68027.21} meaning "1 USD = 68027.21 XEC" * * This function: * 1. Filters out zero/invalid rates * 2. Inverts all rates (rate = 1 / originalRate) * 3. Adds XEC entries with rate 1 for self-conversion * * @param fiatRates - Array of fiat rates from backend API * @returns Transformed rate array ready for conversion calculations, or null if input is invalid */ -export function transformFiatRates(fiatRates: any[]): any[] | null { +export function transformFiatRates(fiatRates: FiatRateItem[]): FiatRateItem[] | null { if (!fiatRates || fiatRates.length === 0) { return null; } const transformedRates = fiatRates .filter(item => item.rate && item.rate > 0) // Filter out zero/invalid rates .map(item => ({ coin: item.coin, // Keep coin as-is (e.g., 'USD', 'EUR') rate: 1 / item.rate, // INVERT: If 1 XEC = 0.0000147 USD, then 1 USD = 68027 XEC ts: item.ts })); // Add XEC itself with rate 1 (1 XEC = 1 XEC) transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); return transformedRates; }docs/BUGFIX_GOODS_SERVICES_VALIDATION.md (4)
11-13: Add a language to fenced code blockSpecify a language to satisfy MD040 and improve rendering.
-``` +```text ❌ "You need to buy amount greater than 5.46 XEC"Based on static analysis hints. --- `36-36`: **Use proper headings instead of bold lines (MD036) and avoid brittle line numbers** Convert bold “Location …” lines to headings and drop hard-coded line numbers which quickly go stale. ```diff -**Location 1: Form validation rules (lines 874-889)** +### Location 1: Form validation rules-**Location 2: Display error message (line 920)** +### Location 2: Display error messageBased on static analysis hints.
Also applies to: 85-85
87-97: Deduplicate headings (“Before/After”) to satisfy MD024There are multiple “#### Before ❌” and “#### After ✅” headings. Make them unique for Location 2.
-#### Before ❌ +#### Before (Location 2) ❌ … -#### After ✅ +#### After (Location 2) ✅Based on static analysis hints.
47-47: Polish error text for clarityConsider “You need to buy an amount greater than 5.46 XEC” or “You need to buy more than 5.46 XEC”.
- ? 'You need to buy amount greater than 5.46 XEC' + ? 'You need to buy an amount greater than 5.46 XEC'Also applies to: 73-73, 101-103
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts(1 hunks)apps/telegram-ecash-escrow/src/app/shopping/page.tsx(1 hunks)apps/telegram-ecash-escrow/src/store/util.ts(3 hunks)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts(1 hunks)docs/BUGFIX_GOODS_SERVICES_VALIDATION.md(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/telegram-ecash-escrow/src/store/util.ts (2)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (4)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isShowAmountOrSortFilter(60-62)apps/telegram-ecash-escrow/src/components/layout/MobileLayout.tsx (1)
MobileLayout(47-53)apps/telegram-ecash-escrow/src/components/Header/Header.tsx (1)
Header(85-200)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (1)
OfferItem(125-351)
🪛 markdownlint-cli2 (0.18.1)
docs/BUGFIX_GOODS_SERVICES_VALIDATION.md
11-11: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
36-36: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
85-85: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
87-87: Multiple headings with the same content
(MD024, no-duplicate-heading)
97-97: Multiple headings with the same content
(MD024, no-duplicate-heading)
🔇 Additional comments (3)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (2)
86-93: Good performance optimization with fiat rate prefetching.Prefetching fiat rates on mount ensures PlaceAnOrderModal can display prices immediately without waiting for API calls. The polling configuration and refetch strategy are appropriate.
190-204: scrollableDiv container properly implemented.The
scrollableDivcontainer now exists with appropriate overflow styling, correctly addressing the previous review feedback. ThescrollableTargetprop on InfiniteScroll properly references this container.apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts (1)
18-130: Past review comments have been successfully addressed.The implementation now includes:
- Request authentication via
x-alert-tokenheader (lines 28-33)- 10-second timeout with AbortController (lines 69-87, 112-119)
- Proper 500 responses for missing configuration (lines 35-43)
- Comprehensive error handling and logging
The endpoint is well-structured and handles edge cases appropriately.
Legacy G&S offers created before priceGoodsServices field was added show 0 XEC/unit. These offers had min/max in XEC directly. Changes: - Default legacy offers (priceGoodsServices = null/0) to 1 XEC per unit - Updated useOfferPrice hook to handle legacy price calculation - Updated PlaceAnOrderModal to use 1 XEC default for legacy offers - Ensures all G&S offers display a meaningful price Example legacy offer: 'I can provide any service' Min/max: 1,000 unit - 100,000,000 unit Price: Now shows '1 XEC / unit' instead of '0 XEC / unit'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (3)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (3)
83-83: Remove the unusedvisiblestate.The
visiblestate is initialized totruebut never updated, making it effectively unused. The Slide component will always display whennewPostAvailableis true.Apply this diff to remove the unused state:
- const [visible, setVisible] = useState(true); const dispatch = useLixiSliceDispatch(); // Prefetch fiat rates in the background for better modal performanceThen update line 161:
- <Slide direction="down" in={newPostAvailable && visible}> + <Slide direction="down" in={newPostAvailable}>
61-79: Improve badge positioning for responsive centering.Using
left: 40%doesn't guarantee proper centering across different screen widths.Apply this diff for responsive centering:
const StyledBadge = styled(Badge)` background: #0f98f2; position: absolute; z-index: 1; - left: 40%; + left: 50%; + transform: translateX(-50%); top: 1rem; cursor: pointer;
195-217: Consider adding error-state handling for query failures.While loading states are well-handled, there's no explicit UI feedback when
useInfiniteOfferFilterDatabaseQueryoruseGetAllFiatRateQueryencounter errors. Consider adding error boundaries or conditional error messages for a better user experience during API failures.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (4)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isShowAmountOrSortFilter(60-62)apps/telegram-ecash-escrow/src/components/layout/MobileLayout.tsx (1)
MobileLayout(47-53)apps/telegram-ecash-escrow/src/components/Header/Header.tsx (1)
Header(85-200)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (1)
OfferItem(125-351)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(249-267)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(73-80)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
apps/telegram-ecash-escrow/src/store/util.ts (2)
isConvertGoodsServices(111-115)transformFiatRates(249-267)
🔇 Additional comments (2)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (2)
86-93: LGTM! Effective fiat-rate prefetch for modal performance.Prefetching fiat rates on mount with
refetchOnMountOrArgChange: trueandpollingInterval: 0ensures fresh data is cached forPlaceAnOrderModalwithout unnecessary polling. This aligns with the PR's performance optimization goals.
191-208: LGTM! The scrollableDiv container issue has been resolved.The
scrollableTarget="scrollableDiv"prop now correctly references the container withid="scrollableDiv"(line 191), fixing the issue flagged in the previous review. The infinite scroll implementation is properly configured with appropriate loading states and scroll threshold.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Show resolved
Hide resolved
1. Remove redundant else-if in shopping/page.tsx loadMoreItemsFilter - Prevents duplicate fetchNextFilter() calls during fetch - Eliminates race condition when isFetchingFilter is true 2. Fix pure XEC offers in useOfferPrice.tsx - Set identity rate data (1 XEC = 1 XEC) for pure XEC offers - Prevents null rateData from causing blank/zero pricing - Added coinPayment to useEffect dependencies 3. Fix pure XEC offers in PlaceAnOrderModal.tsx - Set identity rate data for pure XEC coinPayment - Prevents conversion short-circuit returning 0 - Fixes 5.46 XEC validation error on pure XEC offers - Added coinPayment to useEffect dependencies All three issues resolved with case-insensitive XEC comparison.
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
777-789: Guard against null escrowScript to avoid runtime crashconvertToAmountXEC dereferences escrowScript before it’s guaranteed set; this can throw on first render.
- const feeWithdraw = estimatedFee(Buffer.from(escrowScript.script().bytecode).toString('hex')); + const feeWithdraw = escrowScript + ? estimatedFee(Buffer.from(escrowScript.script().bytecode).toString('hex')) + : 0; - const amountMargin = (amountXEC * post.postOffer.marginPercentage) / 100; + const amountMargin = (amountXEC * (post.postOffer.marginPercentage ?? 0)) / 100;
796-806: Prevent division by zero when amount is 0When amountNumber is 0, xecPerUnit becomes Infinity/NaN.
- const xecPerUnit = isGoodsServicesConversion ? amountXEC / amountNumber : legacyPrice; + const xecPerUnit = isGoodsServicesConversion + ? (amountNumber > 0 ? amountXEC / amountNumber : 0) + : legacyPrice;
694-721: Fix incorrect error binding for Account Number fieldThe error prop references accountName instead of accountNumber.
- error={errors.accountName ? true : false} + error={!!errors.accountNumber}
♻️ Duplicate comments (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
1081-1101: DRY up fiat error detection (shared util/hook)Banner logic duplicates the alert effect. Extract detection into a shared function/hook and reuse in both places.
518-518: Avoid raw console.error in production pathsUse a structured logger or gate logs behind NODE_ENV to keep consoles clean; you already show a user toast.
- console.error('Error creating escrow order:', e); + if (process.env.NODE_ENV !== 'production') { + console.error('Error creating escrow order:', e); + }
975-1079: Throttle/dedupe Telegram alerts and extract detection logicRisk of alert storms: effect can fire repeatedly while service is down. Also, detection logic is duplicated with the banner below.
Minimal throttle:
Add near other state declarations:
// keep last alert signature to avoid spamming const lastFiatAlertKeyRef = React.useRef<string | null>(null);Then inside this effect, before sendCriticalAlert:
- if (isFiatServiceDown) { + if (isFiatServiceDown) { + const errorKey = `${hasInvalidRates ? 'INVALID' : 'NODATA'}|${post.id}|${post?.postOffer?.tickerPriceGoodsServices}|${post?.postOffer?.priceGoodsServices}`; + if (lastFiatAlertKeyRef.current === errorKey) return;After successful send (inside then/catch path) set:
lastFiatAlertKeyRef.current = errorKey;Also consider extracting the detection into a shared util/hook (detectFiatServiceError/useFiatServiceMonitoring) and reuse here and in the banner. As per previous review comments.
🧹 Nitpick comments (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
1128-1148: Prefer MUI Alert for accessibility and consistencyReplace the custom Box with for better semantics and built‑in styling.
- {showErrorBanner && ( - <Box - sx={{ backgroundColor: '#d32f2f', color: '#ffffff', padding: 2, borderRadius: 1, marginBottom: 2, border: '1px solid #b71c1c' }} - > - <Typography variant="body2" sx={{ fontWeight: 'bold', color: '#ffffff', marginBottom: 1 }}> - ⚠️ Fiat Service Unavailable - </Typography> - <Typography variant="body2" sx={{ color: '#ffffff' }}> - Cannot calculate XEC amount for {post?.postOffer?.tickerPriceGoodsServices}-priced offers. {errorBannerMessage} - </Typography> - </Box> - )} + {showErrorBanner && ( + <Alert severity="error" sx={{ mb: 2 }}> + <Typography variant="body2" fontWeight="bold">Fiat Service Unavailable</Typography> + <Typography variant="body2"> + Cannot calculate XEC amount for {post?.postOffer?.tickerPriceGoodsServices}-priced offers. {errorBannerMessage} + </Typography> + </Alert> + )}
854-864: Add isGoodsServices to useMemo deps for showPriceAvoid stale showPrice if isGoodsServices changes.
- }, [post?.postOffer]); + }, [post?.postOffer, isGoodsServices]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts(1 hunks)apps/telegram-ecash-escrow/src/app/shopping/page.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx(4 hunks)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts(1 hunks)docs/REFACTORING_RATE_TRANSFORMATION.md(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts
🧰 Additional context used
🧬 Code graph analysis (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(249-267)formatNumber(54-58)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
sendCriticalAlert(72-79)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/hooks/useOfferPrice.tsx (1)
apps/telegram-ecash-escrow/src/store/util.ts (2)
isConvertGoodsServices(111-115)transformFiatRates(249-267)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (4)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isShowAmountOrSortFilter(60-62)apps/telegram-ecash-escrow/src/components/layout/MobileLayout.tsx (1)
MobileLayout(47-53)apps/telegram-ecash-escrow/src/components/Header/Header.tsx (1)
Header(85-200)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (1)
OfferItem(125-351)
🔇 Additional comments (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
931-939: Good fix: identity rates for pure XEC offersSetting 1:1 identity rates for XEC-only offers prevents the zero-conversion issue when the query is skipped. LGTM.
351-359: Verify getAllFiatRate cache TTL
Confirm that infiatCurrencyApi(in@bcpros/redux-store) thegetAllFiatRateendpoint is configured withkeepUnusedDataFor: 300(5 minutes) to match the “Keep cached data for 5 minutes” comment; if not, update the comment or endpoint configuration.
apps/telegram-ecash-escrow/src/app/api/alerts/telegram/route.ts
Outdated
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Show resolved
Hide resolved
Backend already handles Telegram alerts for fiat service failures, so client-side alert code is redundant and presents security concerns. Changes: - Removed sendCriticalAlert import from PlaceAnOrderModal.tsx - Replaced alert call with console.error logging for debugging - Deleted /src/utils/telegram-alerts.ts utility file - Deleted /src/app/api/alerts/telegram API route - Simplified error logging to essential diagnostic info Benefits: - More secure (no client-exposed alert tokens) - Cleaner architecture (backend handles monitoring) - Reduced client bundle size - Prevents potential alert endpoint abuse Note: Backend GraphQL resolver already sends alerts when fiat service issues are detected. Frontend now only logs errors for developer debugging purposes.
- Check if coinPayment is null/undefined before calling toLowerCase() - Return undefined if coinPayment is null/undefined - Prevents TypeError when coinPayment is not provided
There was a problem hiding this 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
♻️ Duplicate comments (2)
apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
37-73: Critical: Alert token still exposed in client-side code.The hardcoded token
'internal-alert-secret-token'on line 42 remains exposed in the browser bundle, allowing any user to extract it and abuse the alert endpoint. The comment dismissing this concern is insufficient—client-side secrets are trivially extractable via dev tools.This is the same critical security issue previously flagged. Please implement one of the recommended solutions from the earlier review:
- Move alert logic server-side with session-based authentication (preferred)
- Use session-based authentication without token requirements
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)
978-1058: Duplicate fiat-service error detection — extract to utility/hookBanner logic duplicates the alert effect. Centralize into a shared detector (e.g., detectFiatServiceError) to keep behavior in sync.
Would you like me to generate a small utility and the replacement calls?
Also applies to: 1039-1058
🧹 Nitpick comments (4)
apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts (1)
11-11: Replaceanywithunknownfor type safety.Using
anybypasses TypeScript's type checking. Useunknowninstead to maintain type safety while allowing arbitrary details.Apply this diff:
- details?: any; + details?: unknown;apps/telegram-ecash-escrow/src/store/util.ts (2)
117-156: Align types for getCoinRate options and return typecoinPayment can be null/undefined at runtime and you guard for it; also the function returns number|undefined, not any|null. Tighten types to prevent surprises.
-export interface GetCoinRateOptions { - isGoodsServicesConversion: boolean; - coinPayment: string; - priceGoodsServices: number | null; - priceCoinOthers: number | null; - tickerPriceGoodsServices: string | null; - rateData: Array<{ coin?: string; rate?: number }>; -} +export type RateItem = { coin?: string; rate?: number }; +export interface GetCoinRateOptions { + isGoodsServicesConversion: boolean; + coinPayment?: string | null; + priceGoodsServices?: number | null; + priceCoinOthers?: number | null; + tickerPriceGoodsServices?: string | null; + rateData: RateItem[]; +} @@ -}: GetCoinRateOptions): any | null => { +}: GetCoinRateOptions): number | undefined => { @@ - if (!coinPayment) return undefined; - return rateData.find(item => item.coin?.toLowerCase() === coinPayment.toLowerCase())?.rate; + if (!coinPayment) return undefined; + const coinLower = coinPayment.toLowerCase(); + return rateData.find(item => item.coin?.toLowerCase() === coinLower)?.rate;
236-268: Normalize coin casing and avoid duplicate XEC entries in transformed ratesPushing both 'xec' and 'XEC' creates duplicates and mixed casing. Normalize coins to a single case and add one XEC entry.
export function transformFiatRates(fiatRates: any[]): any[] | null { @@ - const transformedRates = fiatRates - .filter(item => item.rate && item.rate > 0) // Filter out zero/invalid rates - .map(item => ({ - coin: item.coin, // Keep coin as-is (e.g., 'USD', 'EUR') - rate: 1 / item.rate, // INVERT: If 1 XEC = 0.0000147 USD, then 1 USD = 68027 XEC - ts: item.ts - })); + const transformedRates = fiatRates + .filter(item => item?.rate && item.rate > 0) + .map(item => ({ + coin: String(item.coin).toUpperCase(), + rate: 1 / item.rate, + ts: item.ts + })); @@ - transformedRates.push({ coin: 'xec', rate: 1, ts: Date.now() }); - transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() }); + transformedRates.push({ coin: 'XEC', rate: 1, ts: Date.now() });If you adopt uppercase, consider updating find() sites to compare with toUpperCase() for consistency (optional).
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)
517-517: Prefer structured logging or gated logs in productionconsole.error here adds noise; UI already surfaces the error. Consider routing through your logger or gating by env.
- console.error('Error creating escrow order:', e); + if (process.env.NODE_ENV !== 'production') { + console.error('Error creating escrow order:', e); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)apps/telegram-ecash-escrow/src/store/util.ts(3 hunks)apps/telegram-ecash-escrow/src/utils/telegram-alerts.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(250-268)formatNumber(54-58)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
apps/telegram-ecash-escrow/src/store/util.ts (2)
apps/telegram-ecash-escrow/src/store/constants.ts (2)
COIN_OTHERS(16-16)COIN_USD_STABLECOIN_TICKER(18-18)apps/telegram-ecash-escrow/src/utils/index.ts (1)
transformFiatRates(17-17)
🔇 Additional comments (2)
apps/telegram-ecash-escrow/src/store/util.ts (1)
176-178: Case-insensitive XEC lookup: LGTMUsing a lower-cased match for 'xec' avoids casing bugs.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (1)
336-359: Fiat rate gating and caching: looks goodSkip logic for XEC-only and prefetch/caching controls are reasonable.
Please validate pure-XEC offers compute amounts correctly without network by trying an XEC-only offer (no fiat fetch) and confirming non-zero XEC amounts render.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Show resolved
Hide resolved
- Create reusable FiatRateErrorBanner component with configurable variants - Add error banner to P2P trading list (page.tsx) - Add error banner to Shopping list (shopping/page.tsx) - Replace custom banner in PlaceAnOrderModal with reusable component - Use consistent yellow 'warning' style across all pages - Consistent error detection logic (API error, no data, zero rates) - Improves UX by showing users when fiat conversion service is unavailable - Reduces code duplication with single source of truth for error display
There was a problem hiding this 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
♻️ Duplicate comments (4)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (2)
196-214: Resolved: scrollableTarget now wired to #scrollableDiv.The container with id="scrollableDiv" is present; InfiniteScroll will attach correctly.
132-136: Resolved: duplicate fetch path removed in loadMoreItemsFilter.Now only fetches when hasNext && !isFetching — prevents redundant requests.
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
799-806: Critical: Guard against divide-by-zero remains unresolved.Line 805 divides
amountXEC / amountNumberwithout checking ifamountNumber > 0. This issue was flagged in a previous review but has not been fixed.If the user enters 0 or clears the amount field,
amountNumberbecomes 0, producingNaNorInfinityforxecPerUnit. This can corrupt downstream calculations and state.Apply the guard:
- const xecPerUnit = isGoodsServicesConversion ? amountXEC / amountNumber : legacyPrice; + const xecPerUnit = + isGoodsServicesConversion && amountNumber > 0 + ? amountXEC / amountNumber + : legacyPrice;Rationale: The validation at line 1087 runs asynchronously and may not prevent this calculation from executing with invalid input during form interaction.
979-1037: Major: Alert logic and error detection still need extraction.This 59-line effect remains embedded in the component, making it harder to test and maintain. This issue was flagged in a previous review but has not been addressed.
Additionally, the error detection logic (lines 982-999) is duplicated with
FiatRateErrorBanner's internal logic (seeFiatRateErrorBanner.tsxlines 39-56). Both perform identical checks forhasNoDataandhasInvalidRates.Recommendation:
- Extract error detection into a shared utility (e.g.,
src/utils/fiat-service-errors.ts):export function detectFiatServiceError( fiatData: any, fiatRateError: boolean ): { hasError: boolean; errorType: string | null } { const hasNoData = fiatRateError || !fiatData?.getAllFiatRate || fiatData?.getAllFiatRate?.length === 0; if (hasNoData) return { hasError: true, errorType: 'NO_DATA' }; const xecCurrency = fiatData?.getAllFiatRate?.find(item => item.currency === 'XEC'); if (xecCurrency?.fiatRates && xecCurrency.fiatRates.length > 0) { const majorCurrencies = ['USD', 'EUR', 'GBP']; const majorRates = xecCurrency.fiatRates.filter(r => majorCurrencies.includes(r.coin?.toUpperCase()) ); if (majorRates.length > 0 && majorRates.every(r => r.rate === 0)) { return { hasError: true, errorType: 'ZERO_RATES' }; } } return { hasError: false, errorType: null }; }
- Extract alert logic into a custom hook:
// hooks/useFiatServiceMonitoring.ts export function useFiatServiceMonitoring({ fiatData, fiatRateError, isGoodsServicesConversion, postId, tickerPriceGoodsServices }) { useEffect(() => { const { hasError, errorType } = detectFiatServiceError(fiatData, fiatRateError); const isFiatServiceDown = hasError && isGoodsServicesConversion; if (isFiatServiceDown && process.env.NODE_ENV !== 'production') { console.error('❌ [FIAT_ERROR] Fiat service down:', { errorType, // ... logging details }); } }, [fiatData, fiatRateError, isGoodsServicesConversion, postId, tickerPriceGoodsServices]); }
- Use in PlaceAnOrderModal:
useFiatServiceMonitoring({ fiatData, fiatRateError, isGoodsServicesConversion, postId: post.id, tickerPriceGoodsServices: post?.postOffer?.tickerPriceGoodsServices });This eliminates duplication, improves testability, and makes the component more maintainable.
🧹 Nitpick comments (1)
apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx (1)
67-79: Prefer MUI Alert for semantics, theming, and a11y.Use Alert/AlertTitle instead of manual Box styling; adds role="alert" and better theme integration.
Apply:
-import { Box, Typography } from '@mui/material'; +import { Alert, AlertTitle, Typography } from '@mui/material'; @@ - // Determine colors based on variant - const colors = - variant === 'error' - ? { - backgroundColor: '#d32f2f', - color: '#ffffff', - border: '1px solid #b71c1c' - } - : { - backgroundColor: '#fff3cd', - color: '#856404', - border: '1px solid #ffeaa7' - }; - - return ( - <Box - sx={{ - ...colors, - padding: 2, - borderRadius: 1, - marginBottom: 2 - }} - > - <Typography variant="body2" sx={{ fontWeight: 'bold', marginBottom: 0.5 }}> - ⚠️ {variant === 'error' ? 'Fiat Service Unavailable' : 'Currency Conversion Service Unavailable'} - </Typography> + return ( + <Alert role="alert" aria-live="polite" severity={variant} sx={{ mb: 2 }}> + <AlertTitle> + ⚠️ {variant === 'error' ? 'Fiat Service Unavailable' : 'Currency Conversion Service Unavailable'} + </AlertTitle> <Typography variant="body2"> {goodsServicesOnly && tickerPriceGoodsServices ? ( <> Cannot calculate XEC amount for {tickerPriceGoodsServices}-priced offers. The currency conversion service is temporarily unavailable. Please try again later or contact support. </> ) : ( <> Some prices may not display correctly. The currency conversion service is temporarily unavailable. Please try again later. </> )} </Typography> - </Box> + </Alert> );Also applies to: 81-107
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/telegram-ecash-escrow/src/app/page.tsx(4 hunks)apps/telegram-ecash-escrow/src/app/shopping/page.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx(1 hunks)apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/telegram-ecash-escrow/src/app/page.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
apps/telegram-ecash-escrow/src/app/shopping/page.tsx (5)
apps/telegram-ecash-escrow/src/store/util.ts (1)
isShowAmountOrSortFilter(60-62)apps/telegram-ecash-escrow/src/components/layout/MobileLayout.tsx (1)
MobileLayout(47-53)apps/telegram-ecash-escrow/src/components/Header/Header.tsx (1)
Header(85-200)apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx (1)
FiatRateErrorBanner(32-108)apps/telegram-ecash-escrow/src/components/OfferItem/OfferItem.tsx (1)
OfferItem(125-351)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(250-268)formatNumber(54-58)apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx (1)
FiatRateErrorBanner(32-108)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
🔇 Additional comments (10)
apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx (1)
25-39: Component structure and memoization look good.apps/telegram-ecash-escrow/src/app/shopping/page.tsx (1)
201-219: Guard against undefineddataFilter
Replace direct access with safe defaults:- dataLength={dataFilter.length} + dataLength={(dataFilter?.length) ?? 0} … - {dataFilter.map(item => { + {(dataFilter ?? []).map(item => {Verify whether
useInfiniteOfferFilterDatabaseQueryguaranteesdatadefaults to[]and adjust guards accordingly.apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (8)
3-4: LGTM: Clean import additions.The new imports are well-organized and all are actively used in the component. The extraction of
useGetAllFiatRateQueryenables lazy loading with skip logic.Also applies to: 21-22, 83-83
337-359: LGTM: Smart skip logic reduces API calls for pure XEC offers.The
needsFiatRatesmemo correctly determines when fiat data is required:
- Always for Goods & Services (fiat-priced, needs XEC conversion)
- For Crypto offers, only when
coinPayment !== 'XEC'The case-insensitive comparison and cache configuration optimize performance. The skip logic pairs with the identity rate injection at lines 935-943 to handle pure XEC offers without fetching.
518-518: Improved error logging specificity.The error message now clearly indicates the context (escrow order creation failure), making debugging easier.
905-971: Excellent: Identity rate injection solves the pure XEC blocking issue.The rewritten rate data loading logic elegantly handles three scenarios:
- Goods & Services (lines 908-932): Fetches XEC fiat rates and transforms them for currency conversion.
- Pure XEC Crypto offers (lines 935-943): Injects identity rate (
1 XEC = 1 XEC) without fetching, avoiding unnecessary API calls.- Other Crypto offers (lines 946-963): Uses the user's selected
localCurrencyfor fiat conversion.The identity rate injection (lines 935-943) directly addresses the issue flagged in past reviews where skipping the fiat fetch would break pure XEC orders. Now, pure XEC offers have valid
rateDatawithout network overhead.The comprehensive logging in development mode aids debugging without cluttering production.
1060-1068: LGTM: Clean integration of error banner.The
FiatRateErrorBanneris correctly integrated with appropriate props:
goodsServicesOnly={true}ensures it only displays for fiat-priced offersvariant="warning"provides clear visual feedback without being overly alarming- Props are properly forwarded from the parent component's state
1085-1098: Improved validation for Goods & Services offers.The validation logic now appropriately handles Goods & Services by:
- Validating unit quantity > 0 (line 1087)
- Checking total XEC amount against the 5.46 minimum (line 1091)
- Providing actionable error messages (line 1092)
The guard
amountXECGoodsServices > 0at line 1091 prevents false positives when the conversion hasn't completed yet, though there's still a minor dependency on the asyncconvertToAmountXECcalculation.
1138-1174: LGTM: Enhanced price display logic.The display logic correctly handles both offer types:
- Error messages (lines 1139-1143): Shows appropriate minimum amount errors for Crypto offers vs. Goods & Services total validation.
- Goods & Services pricing (lines 1153-1166): Displays XEC per unit with conditional fiat price in parentheses, only when the ticker is not XEC.
- Fallback handling: Uses
DEFAULT_TICKER_GOODS_SERVICESfor comparison and 'USD' as a display fallback, which is appropriate given the conditional logic.The complexity is justified by the different requirements for Goods & Services vs. Crypto offers.
337-359: Guard against null reference on coinPayment.Line 344 calls
.toUpperCase()onpost.postOffer.coinPaymentwithout guarding for null/undefined. IfcoinPaymentis missing, this will throw a runtime error.Apply this defensive guard:
- return post?.postOffer?.coinPayment && post.postOffer.coinPayment.toUpperCase() !== 'XEC'; + return ( + post?.postOffer?.coinPayment && + post.postOffer.coinPayment.toUpperCase() !== 'XEC' + );Wait, the code already has the guard (
post?.postOffer?.coinPayment &&). Let me re-check... Yes, the short-circuit AND ensurescoinPaymentis truthy before calling.toUpperCase(). This is actually safe.Actually, the code is correct. The
&&operator short-circuits, so ifcoinPaymentis falsy,.toUpperCase()is never called. No issue here.
apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx
Show resolved
Hide resolved
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
779-783: Guard escrowScript and recompute when it becomes available.convertToAmountXEC calls escrowScript.script() without ensuring escrowScript is set, which can throw on first render. Also, conversion won’t re-run when escrowScript arrives.
Apply:
@@ - const feeWithdraw = estimatedFee(Buffer.from(escrowScript.script().bytecode).toString('hex')); + // Guard escrowScript; recompute once it becomes available + const feeWithdrawHex = escrowScript ? hexEncode(escrowScript.script().bytecode) : null; + const feeWithdraw = feeWithdrawHex ? estimatedFee(feeWithdrawHex) : 0; @@ - }, [amountValue, showPrice, rateData, needsFiatRates]); + }, [amountValue, showPrice, rateData, needsFiatRates, escrowScript]);This also removes Buffer usage on the client in favor of hexEncode.
Also applies to: 889-899
1243-1249: Fix potential crash: optional-chain startsWith.telegramUsername may be undefined; calling startsWith directly can throw.
- if (post?.account?.telegramUsername.startsWith('@')) { + if (post?.account?.telegramUsername?.startsWith('@')) {
🧹 Nitpick comments (2)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (2)
782-782: Avoid Buffer in client code.Next.js client bundles don’t guarantee Buffer. Use existing hexEncode to generate hex.
- const feeWithdraw = estimatedFee(Buffer.from(escrowScript.script().bytecode).toString('hex')); + const feeWithdraw = estimatedFee(hexEncode(escrowScript.script().bytecode));
1154-1161: Make ticker comparison case-insensitive (UI).If backend sends 'xec', current strict compare shows the fiat tag unnecessarily.
- (post.postOffer?.tickerPriceGoodsServices ?? DEFAULT_TICKER_GOODS_SERVICES) !== - DEFAULT_TICKER_GOODS_SERVICES ? ( + ((post.postOffer?.tickerPriceGoodsServices ?? DEFAULT_TICKER_GOODS_SERVICES) + .toUpperCase() !== DEFAULT_TICKER_GOODS_SERVICES) ? (
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx(13 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-19T08:26:58.003Z
Learnt from: nghiacc
PR: bcProFoundation/local-ecash#391
File: apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx:799-806
Timestamp: 2025-10-19T08:26:58.003Z
Learning: In apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx, the user is comfortable with the current validation approach where form validation prevents submission of invalid amounts. Additional defensive checks for divide-by-zero during intermediate typing states in useEffect are not required per user preference.
Applied to files:
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx
🧬 Code graph analysis (1)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (3)
apps/telegram-ecash-escrow/src/store/util.ts (3)
getNumberFromFormatNumber(68-78)transformFiatRates(250-268)formatNumber(54-58)apps/telegram-ecash-escrow/src/components/Common/FiatRateErrorBanner.tsx (1)
FiatRateErrorBanner(32-108)apps/telegram-ecash-escrow/src/store/constants.ts (1)
DEFAULT_TICKER_GOODS_SERVICES(103-103)
🔇 Additional comments (5)
apps/telegram-ecash-escrow/src/components/PlaceAnOrderModal/PlaceAnOrderModal.tsx (5)
888-899: Nice de-duplication using needsFiatRates.Switching the effect to reuse needsFiatRates removes drift risk.
901-968: Rate-data shaping is coherent.
- G&S: selects XEC base, transforms, and logs dev-only diagnostics.
- Pure XEC: identity rates without fetching.
- P2P non‑XEC: selects local currency and transforms.
LGTM.
1057-1065: Error banner usage is appropriate.Scoped to fiat-priced flows with proper loading and error props.
441-451: Request verification: fromHex on possibly missing keys.fromHex(selectedWalletPath?.publicKey/privateKey) can throw if keys are absent. If UI guarantees a selected wallet before “Create,” ignore; otherwise add guards.
Would you like a guard + toast fallback added here?
Also applies to: 438-440
337-359: Fiat-rate gating is correct; cache configuration is external and cannot be verified in this repository.The
needsFiatRateslogic andskipcondition are properly implemented at the callsite. However, the comment about "5-minute cache" refers to thekeepUnusedDataForsetting on thegetAllFiatRateendpoint definition, which resides in the external@bcpros/redux-storepackage. The settings applied here (refetchOnMountOrArgChange: false,refetchOnFocus: false) correctly prevent unnecessary refetches and allow cache reuse, but they don't control thekeepUnusedDataForpolicy.To confirm the 5-minute cache behavior is enforced as documented, verify that the endpoint in
@bcpros/redux-storedefineskeepUnusedDataFor: 300(or equivalent stale policy).
| })); | ||
|
|
||
| interface ShoppingFilterComponentProps { | ||
| filterConfig: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should define the type for the filter here
| } | ||
|
|
||
| if (path === '/shopping' && currentPath === '/shopping') { | ||
| console.log('reset shopping api query'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove console log after finish debug
This PR implements the Shopping tab feature with comprehensive fiat rate handling, performance optimizations, and monitoring.
Key Changes
Shopping Tab Implementation
Fiat Rate System
Performance Optimizations
Monitoring & Reliability
Documentation
Technical Details
Testing Notes
Related Issues
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Documentation
Chores