give
/
src
/
Campaigns
/
resources
/
admin
/
components
/
CampaignDetailsPage
/
Components
/
GoalProgressChart
/
index.tsx
give
/
src
/
Campaigns
/
resources
/
admin
/
components
/
CampaignDetailsPage
/
Components
/
GoalProgressChart
Last commit date
index.tsx
1 year ago
styles.module.scss
1 year ago
index.tsx
89 lines
| 1 | import {__} from '@wordpress/i18n'; |
| 2 | import Chart from 'react-apexcharts'; |
| 3 | import React from 'react'; |
| 4 | |
| 5 | import styles from './styles.module.scss'; |
| 6 | import {amountFormatter, getCampaignOptionsWindowData} from '@givewp/campaigns/utils'; |
| 7 | import type {Campaign} from '@givewp/campaigns/admin/components/types'; |
| 8 | |
| 9 | const {currency} = getCampaignOptionsWindowData(); |
| 10 | const currencyFormatter = amountFormatter(currency); |
| 11 | |
| 12 | type GoalProgressChartProps = { |
| 13 | value: number; |
| 14 | goal: number; |
| 15 | goalType: Partial<Campaign>['goalType']; |
| 16 | }; |
| 17 | |
| 18 | const goalTypeLabels = { |
| 19 | amount: __('Amount raised', 'give'), |
| 20 | donations: __('Number of donations', 'give'), |
| 21 | donors: __('Number of donors', 'give'), |
| 22 | amountFromSubscriptions: __('Recurring amount raised', 'give'), |
| 23 | subscriptions: __('Number of recurring donations', 'give'), |
| 24 | donorsFromSubscriptions: __('Number of recurring donors', 'give'), |
| 25 | }; |
| 26 | |
| 27 | const GoalProgressChart = ({value, goal, goalType}: GoalProgressChartProps) => { |
| 28 | const progress = Math.ceil((value / goal) * 100); |
| 29 | const percentage = Math.min(progress, 100); |
| 30 | |
| 31 | const isCurrencyGoal = ['amount', 'amountFromSubscriptions'].includes(goalType); |
| 32 | const formattedValue = isCurrencyGoal ? currencyFormatter.format(value) : value.toString(); |
| 33 | const formattedGoal = isCurrencyGoal ? currencyFormatter.format(goal) : goal.toString(); |
| 34 | |
| 35 | return ( |
| 36 | <div className={styles.goalProgressChart}> |
| 37 | <div className={styles.chartContainer}> |
| 38 | <Chart |
| 39 | options={{ |
| 40 | chart: { |
| 41 | height: 1024, |
| 42 | type: 'radialBar', |
| 43 | }, |
| 44 | plotOptions: { |
| 45 | radialBar: { |
| 46 | hollow: { |
| 47 | margin: 15, |
| 48 | size: '60%', |
| 49 | }, |
| 50 | dataLabels: { |
| 51 | /** |
| 52 | * The "name" is the top label, here it is the value/amount |
| 53 | * The "value" is the percent progress |
| 54 | * |
| 55 | * Note: These are visually inverted (using offsetY) to match the design |
| 56 | */ |
| 57 | name: { |
| 58 | offsetY: 20, |
| 59 | show: true, |
| 60 | color: '#4B5563', |
| 61 | fontSize: '12px', |
| 62 | }, |
| 63 | value: { |
| 64 | offsetY: -20, |
| 65 | color: '#060C1A', |
| 66 | fontSize: '24px', |
| 67 | show: true, |
| 68 | }, |
| 69 | }, |
| 70 | }, |
| 71 | }, |
| 72 | colors: ['#459948'], |
| 73 | labels: [formattedValue], |
| 74 | }} |
| 75 | series={[percentage]} |
| 76 | type="radialBar" |
| 77 | /> |
| 78 | </div> |
| 79 | <div className={styles.goalDetails}> |
| 80 | <div className={styles.goal}>{__('Goal', 'give')}</div> |
| 81 | <div className={styles.amount}>{formattedGoal}</div> |
| 82 | <div className={styles.goalType}>{goalTypeLabels[goalType]}</div> |
| 83 | </div> |
| 84 | </div> |
| 85 | ); |
| 86 | }; |
| 87 | |
| 88 | export default GoalProgressChart; |
| 89 |