11'use client' ;
22
3- import { useEffect , useRef , useMemo , useState } from 'react' ;
3+ import { useEffect , useRef , useState } from 'react' ;
44import {
55 IChartApi ,
66 ISeriesApi ,
@@ -13,55 +13,46 @@ import {
1313 PERIOD_BUTTONS ,
1414 PERIOD_CONFIG ,
1515} from '@/lib/constants' ;
16- import { convertOHLCData } from '@/lib/utils' ;
16+ import { convertOHLCData , convertOHLCToCandlestickData } from '@/lib/utils' ;
1717const { getCoinOHLC } = await import ( '@/lib/coingecko.actions' ) ;
1818
1919export default function CandlestickChart ( {
2020 data,
2121 coinId,
2222 height = 360 ,
2323 children,
24+ liveOhlcv = null ,
2425 mode = 'historical' ,
2526} : CandlestickChartProps ) {
2627 const chartContainerRef = useRef < HTMLDivElement | null > ( null ) ;
2728 const chartRef = useRef < IChartApi | null > ( null ) ;
2829 const candleSeriesRef = useRef < ISeriesApi < 'Candlestick' > | null > ( null ) ;
29- const resizeObserverRef = useRef < ResizeObserver | null > ( null ) ;
30-
31- const [ period , setPeriod ] = useState < Period > (
32- mode === 'live' ? 'daily' : 'monthly'
33- ) ;
34- const [ ohlcData , setOhlcData ] = useState < OHLCData [ ] > ( data ) ;
30+ const [ period , setPeriod ] = useState < Period > ( 'daily' ) ;
31+ const [ ohlcData , setOhlcData ] = useState < OHLCData [ ] > ( data ?? [ ] ) ;
3532 const [ loading , setLoading ] = useState ( false ) ;
3633
37- // In live mode, use data prop directly; in historical mode, use state
38- const activeData = mode === 'live' ? data : ohlcData ;
39-
40- // Memoize converted data to avoid recalculating on every render
41- const chartData = useMemo ( ( ) => convertOHLCData ( activeData ) , [ activeData ] ) ;
34+ console . log ( '==== Candlestick Chart Live OHLCV:' , liveOhlcv ) ;
4235
36+ // Fetch historical data
4337 const fetchOHLCData = async ( selectedPeriod : Period ) => {
4438 setLoading ( true ) ;
4539 try {
4640 const config = PERIOD_CONFIG [ selectedPeriod ] ;
47-
4841 const newData = await getCoinOHLC (
4942 coinId ,
5043 config . days ,
5144 'usd' ,
5245 config . interval ,
5346 'full'
5447 ) ;
55-
56- setOhlcData ( newData ) ;
57- } catch ( error ) {
58- console . error ( 'Error fetching OHLC data:' , error ) ;
48+ setOhlcData ( newData ?? [ ] ) ;
49+ } catch ( err ) {
50+ console . error ( err ) ;
5951 } finally {
6052 setLoading ( false ) ;
6153 }
6254 } ;
6355
64- // Handle period change (only in historical mode)
6556 const handlePeriodChange = ( newPeriod : Period ) => {
6657 if ( mode === 'live' || newPeriod === period ) return ;
6758 setPeriod ( newPeriod ) ;
@@ -73,71 +64,67 @@ export default function CandlestickChart({
7364 const container = chartContainerRef . current ;
7465 if ( ! container ) return ;
7566
76- // Show time for shorter periods with hourly interval
7767 const showTime = [ 'daily' , 'weekly' , 'monthly' ] . includes ( period ) ;
78-
79- // Initialize chart
8068 const chart = createChart ( container , {
8169 ...getChartConfig ( height , showTime ) ,
8270 width : container . clientWidth ,
8371 } ) ;
72+ const series = chart . addSeries ( CandlestickSeries , getCandlestickConfig ( ) ) ;
8473
85- // Add candlestick series
86- const candleSeries = chart . addSeries (
87- CandlestickSeries ,
88- getCandlestickConfig ( )
89- ) ;
90- candleSeries . setData ( chartData ) ;
91-
92- // Fit content to display all data
74+ series . setData ( convertOHLCData ( ohlcData ) ) ;
9375 chart . timeScale ( ) . fitContent ( ) ;
9476
95- // Store refs
9677 chartRef . current = chart ;
97- candleSeriesRef . current = candleSeries ;
78+ candleSeriesRef . current = series ;
9879
99- // Handle responsive resizing using ResizeObserver (more efficient than window resize)
100- resizeObserverRef . current = new ResizeObserver ( ( entries ) => {
101- if ( ! entries . length || ! chartRef . current ) return ;
102-
103- const { width } = entries [ 0 ] . contentRect ;
104- chartRef . current . applyOptions ( { width } ) ;
80+ const observer = new ResizeObserver ( ( entries ) => {
81+ if ( ! entries . length ) return ;
82+ chart . applyOptions ( { width : entries [ 0 ] . contentRect . width } ) ;
10583 } ) ;
84+ observer . observe ( container ) ;
10685
107- resizeObserverRef . current . observe ( container ) ;
108-
109- // Cleanup function
11086 return ( ) => {
111- resizeObserverRef . current ? .disconnect ( ) ;
112- chartRef . current ? .remove ( ) ;
87+ observer . disconnect ( ) ;
88+ chart . remove ( ) ;
11389 chartRef . current = null ;
11490 candleSeriesRef . current = null ;
11591 } ;
116- // eslint-disable-next-line react-hooks/exhaustive-deps
11792 } , [ height ] ) ;
11893
119- // Update chart data when chartData or period changes
94+ // Update chart when data or liveOhlcv changes
12095 useEffect ( ( ) => {
121- if ( candleSeriesRef . current && chartRef . current && chartData . length > 0 ) {
122- // Update the chart
123- candleSeriesRef . current . setData ( chartData ) ;
124- chartRef . current . timeScale ( ) . fitContent ( ) ;
125-
126- // Update time visibility based on period
127- const showTime = [ 'daily' , 'weekly' , 'monthly' ] . includes ( period ) ;
128- chartRef . current . applyOptions ( {
129- timeScale : {
130- timeVisible : showTime ,
131- } ,
132- } ) ;
133- }
134- } , [ chartData , period , mode ] ) ;
96+ if ( ! candleSeriesRef . current ) return ;
97+
98+ // Convert timestamps from milliseconds to seconds while keeping full OHLC structure
99+ const convertedToSeconds = ohlcData . map ( ( item ) => [
100+ Math . floor ( item [ 0 ] / 1000 ) , // timestamp in seconds
101+ item [ 1 ] , // open
102+ item [ 2 ] , // high
103+ item [ 3 ] , // low
104+ item [ 4 ] , // close
105+ ] as OHLCData ) ;
106+ console . log ( '==== Updating convertedToSeconds:' , convertedToSeconds ) ;
107+
108+ const merged = liveOhlcv
109+ ? [ ...convertedToSeconds , liveOhlcv ]
110+ : [ ...convertedToSeconds ] ;
111+
112+ console . log ( '==== Updating merged:' , merged ) ;
113+ // Sort ascending by time
114+ merged . sort ( ( a , b ) => a [ 0 ] - b [ 0 ] ) ;
115+
116+ const converted = convertOHLCData ( merged ) ;
117+
118+ console . log ( '==== Updating Candlestick Data:' , converted ) ;
119+
120+ candleSeriesRef . current . setData ( converted ) ;
121+ chartRef . current ?. timeScale ( ) . fitContent ( ) ;
122+ } , [ ohlcData , liveOhlcv , period ] ) ;
135123
136124 return (
137125 < div className = 'candlestick-container' >
138126 < div className = 'candlestick-header' >
139127 < div className = 'flex-1' > { children } </ div >
140- { /* Only show period buttons in historical mode */ }
141128 { mode === 'historical' && (
142129 < div className = 'candlestick-button-group' >
143130 { PERIOD_BUTTONS . map ( ( { value, label } ) => (
@@ -157,8 +144,6 @@ export default function CandlestickChart({
157144 </ div >
158145 ) }
159146 </ div >
160-
161- { /* Chart Container */ }
162147 < div
163148 ref = { chartContainerRef }
164149 className = 'candlestick-chart-container'
0 commit comments