Conversation
|
🚅 Deployed to the BitcoinDeepaBot-TMA-pr-54 environment in Bitcoin Deepa DCA
|
WalkthroughAdds a new client-side BTC price ticker component and integrates it into the dashboard page above the balance card. The ticker subscribes to CoinCap’s BTC price via WebSocket, fetches a USD→LKR FX rate, converts and animates the price, and cleans up timers and sockets on unmount. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User Browser
participant D as Dashboard Page
participant T as BtcPriceTicker
participant FX as OpenExchangeRates API
participant WS as CoinCap WebSocket
participant Tim as 1s Timer
U->>D: Load /dashboard
D->>T: Mount <BtcPriceTicker />
T->>FX: GET USD→LKR rate
FX-->>T: Rate (USD/LKR)
T->>WS: Open wss for BTC price (USD)
WS-->>T: BTC price updates (USD) [stream]
T->>Tim: Start 1s interval
loop Every second
T->>T: Convert USD→LKR, compute trend
T-->>U: Render animated price (LKR)
end
note over T: On error fetching FX: console.log<br/>Loading UI until price available
U-->>T: Unmount (navigate/close)
T->>WS: Close socket
T->>Tim: Clear interval
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
|
You are nearing your monthly Qodo Merge usage quota. For more information, please visit here. PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You are nearing your monthly Qodo Merge usage quota. For more information, please visit here. PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||||
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
src/components/BtcPriceTicker.tsx (4)
61-66: Avoid remounting on every price updateUsing key={price} forces a full remount on each tick. You can still animate without remounting.
- <motion.div - key={price} + <motion.div initial={{ scale: 1 }} animate={{ scale: [1, 1.05, 1] }} transition={{ duration: 0.5 }} className={`text-sm font-medium ${trendClass}`} >
68-69: Align LKR symbol formatting with the rest of the appElsewhere in the dashboard, LKR is displayed as “රු.”. Use the same here for consistency.
- BTC Price: රු {price.toLocaleString("en-LK", { maximumFractionDigits: 0 })} + BTC Price: රු. {price.toLocaleString("en-LK", { maximumFractionDigits: 0 })}If the preferred product style is different, update the dashboard instances instead. Do you want me to sweep the repo and normalize all LKR displays?
28-35: Optional: Add reconnection/backoff for WebSocket resilienceRight now, a transient WS drop will freeze updates until a reload. Consider a simple reconnect with backoff capped at, say, 30s.
I can provide a tiny reconnect helper (with jitter) if you’d like.
53-56: Optional: Better empty/loading statesIf the FX rate fails to load, you’ll show “Loading” indefinitely. Consider displaying USD price as a fallback or a clear error state and retry.
src/app/dashboard/page.tsx (1)
285-289: Good UI placement; consider lazy/dynamic import to trim initial bundleThe ticker is purely client-side. To keep the page lean (and to ease a future move back to an SSR page), consider dynamic import with ssr: false.
Apply this diff to the import:
-import BtcPriceTicker from "@/components/BtcPriceTicker"; +// Lazy load the ticker to reduce initial bundle and avoid SSR constraints +const BtcPriceTicker = dynamic(() => import("@/components/BtcPriceTicker"), { ssr: false });And add (outside this hunk) at the top-level imports:
import dynamic from "next/dynamic";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/app/dashboard/page.tsx(2 hunks)src/components/BtcPriceTicker.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
All HTTP requests must use the
fetchywrapper from@/lib/fetchy
Files:
src/app/dashboard/page.tsxsrc/components/BtcPriceTicker.tsx
src/app/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place page and route components under
src/app/(Next.js App Router)
Files:
src/app/dashboard/page.tsx
src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Prefer server-side rendering where possible
Files:
src/app/dashboard/page.tsx
src/components/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable components under
src/components/
Files:
src/components/BtcPriceTicker.tsx
🧬 Code graph analysis (1)
src/app/dashboard/page.tsx (1)
src/components/BtcPriceTicker.tsx (1)
BtcPriceTicker(6-71)
🔇 Additional comments (3)
src/components/BtcPriceTicker.tsx (2)
6-12: Nice, focused client component with cleanup and trend UIEncapsulated state, cleanup, and simple animation look good.
13-24: Usefetchywrapper in BtcPriceTicker.tsx and confirm API providerI’ve verified that in
src/components/BtcPriceTicker.tsxthe only directfetchcall is on lines 16–18. All other directfetchoccurrences lie outside this PR’s scope. Please apply the following change to replace the nativefetchwith ourfetchywrapper and add basic response validation. Also, the PR description mentions “Open Exchange Rates” but the code currently callsopen.er-api.com(ExchangeRate-API). Confirm whether to update the description or switch to Open Exchange Rates’ endpoint.Files needing updates:
- src/components/BtcPriceTicker.tsx
Proposed diff:
import { motion } from "framer-motion"; +import fetchy from "@/lib/fetchy"; useEffect(() => { const fetchRate = async () => { try { - const res = await fetch("https://open.er-api.com/v6/latest/USD"); - const data = await res.json(); - setRate(data.rates.LKR); + const data = await fetchy.get<{ rates?: Record<string, number> }>( + "https://open.er-api.com/v6/latest/USD" + ); + const lkr = data?.rates?.LKR; + if (typeof lkr === "number") { + setRate(lkr); + } else { + console.error("LKR rate not found in response"); + } } catch (err) { console.error("Failed to fetch LKR rate", err); } }; fetchRate(); }, []);src/app/dashboard/page.tsx (1)
23-23: Correct placement and import of reusable componentImporting BtcPriceTicker from src/components aligns with the repo’s component placement guidelines.
| useEffect(() => { | ||
| if (!rate) return; | ||
| const ws = new WebSocket("wss://ws.coincap.io/prices?assets=bitcoin"); | ||
| ws.onmessage = (event) => { | ||
| const data = JSON.parse(event.data); | ||
| if (data.bitcoin) { | ||
| priceRef.current = parseFloat(data.bitcoin) * rate; | ||
| } | ||
| }; | ||
| const interval = setInterval(() => { | ||
| setPrevPrice((p) => price); | ||
| setPrice(priceRef.current); | ||
| }, 1000); | ||
| return () => { | ||
| ws.close(); | ||
| clearInterval(interval); | ||
| }; | ||
| }, [rate, price]); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix WebSocket re-creation loop and incorrect prevPrice update
Including price in the effect’s dependency array recreates the WebSocket and timer on every update (roughly every second), causing churn and potential rate limits. Also, setPrevPrice((p) => price) ignores the functional param and does not reliably capture the previously displayed price.
- Remove price from deps.
- Track the last displayed price with a ref and update prevPrice before setting the new price.
- Add basic ws.onerror logging and safer cleanup.
Add a ref for the displayed price somewhere near existing refs:
- const priceRef = useRef<number>(0);
+ const priceRef = useRef<number>(0); // latest incoming LKR price
+ const displayedPriceRef = useRef<number | null>(null); // last displayed LKR priceThen replace the effect as below:
-useEffect(() => {
- if (!rate) return;
- const ws = new WebSocket("wss://ws.coincap.io/prices?assets=bitcoin");
- ws.onmessage = (event) => {
- const data = JSON.parse(event.data);
- if (data.bitcoin) {
- priceRef.current = parseFloat(data.bitcoin) * rate;
- }
- };
- const interval = setInterval(() => {
- setPrevPrice((p) => price);
- setPrice(priceRef.current);
- }, 1000);
- return () => {
- ws.close();
- clearInterval(interval);
- };
-}, [rate, price]);
+useEffect(() => {
+ if (!rate) return;
+ const ws = new WebSocket("wss://ws.coincap.io/prices?assets=bitcoin");
+ ws.onmessage = (event: MessageEvent) => {
+ const data = JSON.parse(event.data);
+ if (data.bitcoin) {
+ priceRef.current = parseFloat(data.bitcoin) * rate;
+ }
+ };
+ ws.onerror = (e) => {
+ console.error("CoinCap WebSocket error", e);
+ };
+ const interval = setInterval(() => {
+ const next = priceRef.current;
+ if (typeof next === "number" && next > 0) {
+ setPrevPrice(displayedPriceRef.current);
+ setPrice(next);
+ displayedPriceRef.current = next;
+ }
+ }, 1000);
+ return () => {
+ try {
+ ws.close();
+ } finally {
+ clearInterval(interval);
+ }
+ };
+}, [rate]);Also applies to: 45-51
🤖 Prompt for AI Agents
In src/components/BtcPriceTicker.tsx around lines 26 to 44 (and similarly
45-51), the effect is recreating the WebSocket and timer every second because
price is in the dependency array and prevPrice is set incorrectly; remove price
from the deps so the effect only depends on rate, add a ref (e.g.,
displayedPriceRef) to hold the last displayed price, update
displayedPriceRef.current before calling setPrice and use that value to
setPrevPrice (instead of setPrevPrice(() => price)), add ws.onerror logging, and
make cleanup robust by checking ws.readyState before closing and always clearing
the interval. Ensure the effect returns the cleanup that closes the socket and
clears the interval and that any refs are updated inside the interval callback
so state updates are stable.
User description
Summary
Testing
npm test(fails: Missing script "test")npm run linthttps://chatgpt.com/codex/tasks/task_e_68a21bb20284832c9df3d3c93f1cd61b
PR Type
Enhancement
Description
Add real-time BTC price ticker with WebSocket connection
Convert USD to LKR using exchange rate API
Display animated price updates with trend indicators
Integrate ticker component into dashboard page
Diagram Walkthrough
File Walkthrough
BtcPriceTicker.tsx
Create BTC price ticker componentsrc/components/BtcPriceTicker.tsx
page.tsx
Integrate BTC ticker into dashboardsrc/app/dashboard/page.tsx
Summary by CodeRabbit