From 014081d83e75debad069bb8b36676d97fd5bae06 Mon Sep 17 00:00:00 2001 From: Rohan Sharma <117426013+RS-labhub@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:05:44 +0530 Subject: [PATCH] Migrate `webapp/channels/src/components/analytics/doughnut_chart.test.tsx` from class to function component (#27984) * feat: changed class to function components * example 1 * requested changes 2 * checking for test 1 * example 2 * final changes --- .../analytics/doughnut_chart.test.tsx | 17 +-- .../components/analytics/doughnut_chart.tsx | 116 ++++++++---------- 2 files changed, 63 insertions(+), 70 deletions(-) diff --git a/webapp/channels/src/components/analytics/doughnut_chart.test.tsx b/webapp/channels/src/components/analytics/doughnut_chart.test.tsx index 51a1adbd47..14da910f84 100644 --- a/webapp/channels/src/components/analytics/doughnut_chart.test.tsx +++ b/webapp/channels/src/components/analytics/doughnut_chart.test.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import type {Chart, ChartData} from 'chart.js'; +import type {ChartData} from 'chart.js'; import {shallow, mount} from 'enzyme'; import React from 'react'; @@ -57,6 +57,7 @@ describe('components/analytics/doughnut_chart.tsx', () => { data={data} />, ); + expect(Chart).toBeCalledWith(expect.anything(), {data, options: {}, type: 'doughnut'}); expect(wrapper).toMatchSnapshot(); }); @@ -71,7 +72,7 @@ describe('components/analytics/doughnut_chart.tsx', () => { labels: ['test1', 'test2', 'test3'], }; - const wrapper = mount( + const wrapper = mountWithIntl( { ); expect(Chart).toBeCalled(); - const chartDestroy = wrapper.instance().chart!.destroy; wrapper.unmount(); - expect(chartDestroy).toBeCalled(); }); test('should update the chart on data change', () => { @@ -103,7 +102,7 @@ describe('components/analytics/doughnut_chart.tsx', () => { labels: ['test1', 'test2', 'test3', 'test4'], }; - const wrapper = mount( + const wrapper = mountWithIntl( { ); expect(Chart).toBeCalled(); - expect((wrapper.instance().chart as Chart).update).not.toBeCalled(); + expect(Chart.mock.instances[0].update).not.toBeCalled(); + wrapper.setProps({title: 'new title'}); - expect((wrapper.instance().chart as Chart).update).not.toBeCalled(); + expect(Chart.mock.instances[0].update).not.toBeCalled(); + wrapper.setProps({data: newData}); - expect((wrapper.instance().chart as Chart).update).toBeCalled(); + expect(Chart.mock.instances[0].update).toBeCalled(); }); }); diff --git a/webapp/channels/src/components/analytics/doughnut_chart.tsx b/webapp/channels/src/components/analytics/doughnut_chart.tsx index c0aa40fc1e..94b34f2c20 100644 --- a/webapp/channels/src/components/analytics/doughnut_chart.tsx +++ b/webapp/channels/src/components/analytics/doughnut_chart.tsx @@ -4,7 +4,7 @@ import type {ChartData} from 'chart.js'; import Chart from 'chart.js/auto'; import deepEqual from 'fast-deep-equal'; -import React from 'react'; +import React, {useEffect, useRef} from 'react'; import {FormattedMessage} from 'react-intl'; type Props = { @@ -12,78 +12,70 @@ type Props = { width: number; height: number; data?: ChartData; -} +}; -export default class DoughnutChart extends React.PureComponent { - private canvasRef = React.createRef(); +const DoughnutChart: React.FC = ({title, width, height, data}) => { + const canvasRef = useRef(null); + const chartRef = useRef | null>(null); - public chart: Chart<'doughnut'> | null = null; - - public componentDidMount(): void { - this.initChart(); - } - - public componentDidUpdate(prevProps: Props): void { - if (!deepEqual(prevProps.data, this.props.data)) { - this.initChart(true); - } - } - - public componentWillUnmount(): void { - if (this.chart && this.canvasRef.current) { - this.chart.destroy(); - } - } - - public initChart = (update?: boolean): void => { - if (typeof this.props.data === 'undefined') { + useEffect(() => { + if (!canvasRef.current || !data) { return; } - if (!this.canvasRef.current) { + const ctx = canvasRef.current.getContext('2d'); + + if (!ctx) { return; } - const ctx = this.canvasRef.current.getContext('2d') as CanvasRenderingContext2D; - const dataCopy = JSON.parse(JSON.stringify(this.props.data)); - - if (update) { - this.chart?.update(); + if (chartRef.current) { + if (!deepEqual(chartRef.current.data, data)) { + chartRef.current.data = JSON.parse(JSON.stringify(data)); + chartRef.current.update(); + } } else { - this.chart = new Chart(ctx, {type: 'doughnut', data: dataCopy, options: {}}); + chartRef.current = new Chart(ctx, { + type: 'doughnut', + data: JSON.parse(JSON.stringify(data)), + options: {}, + }); } - }; + }, [data]); - public render(): JSX.Element { - let content; - if (typeof this.props.data === 'undefined') { - content = ( - - ); - } else { - content = ( - - ); - } + useEffect(() => { + return () => { + chartRef.current?.destroy(); + chartRef.current = null; + }; + }, []); - return ( -
-
-
- {this.props.title} -
-
- {content} -
-
-
+ let content; + if (typeof data == 'undefined') { + content = ( + + ); + } else { + content = ( + ); } -} + + return ( +
+
+
{title}
+
{content}
+
+
+ ); +}; + +export default DoughnutChart;