PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 All 257 releases
give / src / Admin / components / Charts / TimeSeriesChart.tsx

TimeSeriesChart.tsx in GiveWP – Donation Plugin and Fundraising Platform 4.18.0, at src/Admin/components/Charts/TimeSeriesChart.tsx

140 lines 3.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, {useEffect, useState} from 'react';
2 import Chart from 'react-apexcharts';
3 import {ApexOptions} from 'apexcharts';
4 import apiFetch from '@wordpress/api-fetch';
5 import {getDate} from '@wordpress/date';
6 import { formatTimestamp } from '@givewp/admin/common';
7
8 /**
9 * @since 4.4.0
10 */
11 type TimeSeriesChartProps = {
12 endpoint: string;
13 amountFormatter: Intl.NumberFormat;
14 title?: string;
15 };
16
17 /**
18 * @since 4.4.0
19 */
20 type Donation = {
21 createdAt: string;
22 amount: {
23 value: string;
24 };
25 };
26
27 /**
28 * @since 4.4.0
29 */
30 type DataPoint = {
31 x: string;
32 y: number;
33 };
34
35 /**
36 * @since 4.4.0
37 * Generates a range of dates around a target date for displaying a single donation graph.
38 */
39 const getCenteredGraphRange = (targetDate: string) => {
40 const result = [];
41 const date = new Date(targetDate);
42
43 for (let i = -3; i <= 3; i++) {
44 const currentDate = new Date(date);
45 currentDate.setDate(date.getDate() + i);
46 result.push(currentDate.toISOString().split('T')[0]);
47 }
48 return result;
49 };
50
51 /**
52 * @since 4.4.0
53 */
54 const normalizeData = (donations: Donation[]): DataPoint[] => {
55 const map = new Map<string, number>();
56
57 // Group donations by date with sum amounts - fill missing dates with 0.
58 donations.forEach((donation) => {
59 const date = getDate(donation.createdAt);
60 const amount = parseFloat(donation.amount.value);
61 map.set(date.toISOString().split('T')[0], (map.get(date.toISOString().split('T')[0]) || 0) + amount);
62 });
63
64 // Set graph range & points for single donations.
65 if (map.size === 1) {
66 const donationDate = donations[0]?.createdAt.split(' ')[0];
67 const graphRange = getCenteredGraphRange(donationDate);
68
69 return graphRange.map((date) => ({
70 x: date,
71 y: map.get(date) || 0,
72 }));
73 }
74
75 // Convert to sorted array of data points.
76 return Array.from(map.entries())
77 .map(([date, amount]) => ({
78 x: date,
79 y: amount,
80 }))
81 .sort((a, b) => a.x.localeCompare(b.x));
82 };
83
84 /**
85 * @since 4.13.0 updated the date format
86 * @since 4.4.0
87 */
88 export default function TimeSeriesChart({endpoint, amountFormatter, title = ''}: TimeSeriesChartProps) {
89 const [series, setSeries] = useState([{name: title, data: []}]);
90
91 useEffect(() => {
92 apiFetch<Donation[]>({path: endpoint}).then((data) => {
93 const normalized = normalizeData(data);
94 setSeries([{name: title, data: normalized}]);
95 });
96 }, [endpoint]);
97
98 const options: ApexOptions = {
99 chart: {
100 type: 'area' as const,
101 toolbar: {show: false},
102 zoom: {enabled: false},
103 },
104 xaxis: {
105 type: 'datetime',
106 labels: {
107 formatter: (val) => formatTimestamp(val, false),
108 },
109 },
110 yaxis: {
111 min: 0,
112 labels: {
113 formatter: (val) => amountFormatter.format(val),
114 },
115 },
116 dataLabels: {enabled: false},
117 stroke: {
118 curve: 'smooth',
119 width: 2,
120 colors: ['#60a1e2'],
121 },
122 fill: {
123 type: 'gradient',
124 gradient: {
125 shadeIntensity: 1,
126 opacityFrom: 0.3,
127 opacityTo: 0,
128 stops: [0, 100],
129 },
130 },
131 tooltip: {
132 x: {
133 format: 'MMM dd, yyyy',
134 },
135 },
136 };
137
138 return <Chart options={options} series={series} type="area" height="250" />;
139 }
140