import React, { useRef, useImperativeHandle, forwardRef } from 'react';
import { VChartComponent } from '../../index';
import { useTikTokData, exportChartImage } from './model';
import type { TikTokDashboardProps } from './meta';
import { DEFAULT_PROPS } from './meta';
/**
* TikTok Analytics Dashboard Component
*
* A custom Lark aPaaS component that displays TikTok video analytics
* using VChart visualizations.
*/
export const TikTokDashboard = forwardRef<any, TikTokDashboardProps>((props, ref) => {
const {
tableId,
chartType = DEFAULT_PROPS.chartType!,
refreshInterval = DEFAULT_PROPS.refreshInterval!,
height = DEFAULT_PROPS.height!,
className = '',
onChartClick,
onDataLoad,
onError
} = props;
const chartRef = useRef<any>(null);
// Fetch and manage data
const { data, loading, error, refresh } = useTikTokData(tableId, refreshInterval);
// Expose methods to parent component
useImperativeHandle(ref, () => ({
refresh: async () => {
const freshData = await refresh();
onDataLoad?.({
recordCount: freshData.length,
timestamp: new Date().toISOString()
});
return freshData;
},
exportImage: async (format: 'png' | 'svg' | 'jpeg' = 'png') => {
if (!chartRef.current) {
throw new Error('Chart not initialized');
}
return await exportChartImage(chartRef.current, format);
},
getData: () => data
}));
// Handle data load event
React.useEffect(() => {
if (!loading && data.length > 0) {
onDataLoad?.({
recordCount: data.length,
timestamp: new Date().toISOString()
});
}
}, [data, loading, onDataLoad]);
// Handle error event
React.useEffect(() => {
if (error) {
onError?.({
message: error.message,
code: 'DATA_FETCH_ERROR'
});
}
}, [error, onError]);
// Handle chart click events
const handleChartClick = (event: any) => {
if (onChartClick && event.datum) {
onChartClick({
videoId: event.datum.videoId || '',
title: event.datum.title || event.datum.fullTitle || '',
value: event.datum.views || event.datum.value || 0,
type: event.datum.type || 'unknown'
});
}
};
// Loading state
if (loading) {
return (
<div className={`tiktok-dashboard-loading ${className}`} style={{
padding: '40px',
textAlign: 'center',
height: `${height}px`
}}>
<div style={{ fontSize: '16px', color: '#999' }}>Loading TikTok analytics...</div>
</div>
);
}
// Error state
if (error) {
return (
<div className={`tiktok-dashboard-error ${className}`} style={{
padding: '40px',
textAlign: 'center',
height: `${height}px`,
color: '#ff4d4f'
}}>
<div style={{ fontSize: '16px', marginBottom: '12px' }}>Failed to load data</div>
<div style={{ fontSize: '14px', color: '#999' }}>{error.message}</div>
<button
onClick={() => refresh()}
style={{
marginTop: '20px',
padding: '8px 16px',
fontSize: '14px',
border: '1px solid #ff4d4f',
borderRadius: '4px',
background: '#fff',
color: '#ff4d4f',
cursor: 'pointer'
}}
>
Retry
</button>
</div>
);
}
// Empty state
if (data.length === 0) {
return (
<div className={`tiktok-dashboard-empty ${className}`} style={{
padding: '40px',
textAlign: 'center',
height: `${height}px`
}}>
<div style={{ fontSize: '16px', color: '#999' }}>No data available</div>
<div style={{ fontSize: '14px', color: '#ccc', marginTop: '8px' }}>
Make sure the table contains TikTok video data
</div>
</div>
);
}
// Render chart
return (
<div className={`tiktok-dashboard ${className}`} style={{ width: '100%' }}>
<VChartComponent
ref={chartRef}
data={data}
chartType={chartType}
height={height}
width="100%"
onError={(err) => {
onError?.({
message: err.message,
code: 'CHART_RENDER_ERROR'
});
}}
className="tiktok-dashboard-chart"
/>
{/* Metadata footer */}
<div style={{
marginTop: '12px',
padding: '8px',
fontSize: '12px',
color: '#999',
borderTop: '1px solid #f0f0f0'
}}>
<div>Total videos: {data.length}</div>
<div>Last updated: {new Date().toLocaleString()}</div>
</div>
</div>
);
});
TikTokDashboard.displayName = 'TikTokDashboard';
export default TikTokDashboard;