diff --git a/www/i18n/en.json b/www/i18n/en.json index 5d2889ba4..1f578dfa7 100644 --- a/www/i18n/en.json +++ b/www/i18n/en.json @@ -226,7 +226,7 @@ "footprint-label": "Footprint (kg CO₂)", "surveys": "Surveys", "leaderboard": "Leaderboard", - "survey-response-rate": "Survey Response Rate", + "survey-response-rate": "Survey Response Rate (%)", "comparison": "Comparison", "you": "You", "others": "Others in group", @@ -235,7 +235,9 @@ "ev-return-trip": "EV Return trip", "gas-car-trip": "Gas Car trip", "response": "Response", - "no-response": "No Response" + "no-response": "No Response", + "you-are-in": "You're in", + "place": " place!" }, "details": { diff --git a/www/js/appTheme.ts b/www/js/appTheme.ts index b66f493e6..f777167c6 100644 --- a/www/js/appTheme.ts +++ b/www/js/appTheme.ts @@ -32,7 +32,10 @@ const AppTheme = { }, success: '#00a665', // lch(60% 55 155) warn: '#f8cf53', //lch(85% 65 85) - danger: '#f23934', // lch(55% 85 35) + danger: '#f23934', // lch(55% 85 35), + silver: '#d9d9d9', + skyblue: '#7fcaea', + navy: '#0077aa', }, roundness: 5, }; diff --git a/www/js/components/Chart.tsx b/www/js/components/Chart.tsx index 2ff236b5b..b604eb254 100644 --- a/www/js/components/Chart.tsx +++ b/www/js/components/Chart.tsx @@ -31,6 +31,8 @@ export type Props = { isHorizontal?: boolean; timeAxis?: boolean; stacked?: boolean; + hideLegend?: boolean; + reverse?: boolean; }; const Chart = ({ records, @@ -43,6 +45,8 @@ const Chart = ({ isHorizontal, timeAxis, stacked, + hideLegend = false, + reverse = true, }: Props) => { const { colors } = useTheme(); const [numVisibleDatasets, setNumVisibleDatasets] = useState(1); @@ -149,7 +153,7 @@ const Chart = ({ }, font: { size: 11 }, // default is 12, we want a tad smaller }, - reverse: true, + reverse: reverse, stacked, }, x: { @@ -196,6 +200,9 @@ const Chart = ({ }), }, plugins: { + legend: { + display: hideLegend, + }, ...(lineAnnotations?.length && { annotation: { clip: false, diff --git a/www/js/metrics/SurveyDoughnutCharts.tsx b/www/js/metrics/SurveyDoughnutCharts.tsx new file mode 100644 index 000000000..2eee4850e --- /dev/null +++ b/www/js/metrics/SurveyDoughnutCharts.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { View, Text } from 'react-native'; +import { useTranslation } from 'react-i18next'; +import { useAppTheme } from '../appTheme'; +import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; +import { Doughnut } from 'react-chartjs-2'; + +ChartJS.register(ArcElement, Tooltip, Legend); + +const SurveyDoughnutCharts = () => { + const { colors } = useAppTheme(); + const { t } = useTranslation(); + const myResonseRate = 68; + const othersResponseRate = 41; + + const renderDoughnutChart = (rate) => { + const data = { + datasets: [ + { + data: [rate, 100 - rate], + backgroundColor: [colors.navy, colors.silver], + borderColor: [colors.navy, colors.silver], + borderWidth: 1, + }, + ], + }; + return ( + + + {rate}% + + + + ); + }; + + return ( + + {t('main-metrics.survey-response-rate')} + + {renderDoughnutChart(myResonseRate)} + {renderDoughnutChart(othersResponseRate)} + + + ); +}; + +const styles: any = { + chartTitle: { + alignSelf: 'center', + fontWeight: 'bold', + fontSize: 14, + marginBottom: 20, + }, + chartWrapper: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + }, + textWrapper: { + position: 'absolute', + width: 150, + height: 150, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, +}; + +export default SurveyDoughnutCharts; diff --git a/www/js/metrics/SurveyLeaderboardCard.tsx b/www/js/metrics/SurveyLeaderboardCard.tsx index d849b6e7c..7b346a9c3 100644 --- a/www/js/metrics/SurveyLeaderboardCard.tsx +++ b/www/js/metrics/SurveyLeaderboardCard.tsx @@ -1,14 +1,59 @@ import React, { useState } from 'react'; -import { View, ScrollView, useWindowDimensions } from 'react-native'; -import { Card, useTheme } from 'react-native-paper'; +import { View, Text } from 'react-native'; +import { Card } from 'react-native-paper'; import { cardStyles } from './MetricsTab'; import { useTranslation } from 'react-i18next'; import ToggleSwitch from '../components/ToggleSwitch'; +import BarChart from '../components/BarChart'; +import { useAppTheme } from '../appTheme'; +import SurveyComparisonChart from './SurveyDoughnutCharts'; const SurveyLeaderboardCard = () => { - const { colors } = useTheme(); + const { colors } = useAppTheme(); const { t } = useTranslation(); const [tab, setTab] = useState('leaderboard'); + const myLabel = '#3'; + + const getLeaderboardLabelColor = (l) => { + if (l === myLabel) { + return colors.skyblue; + } else { + return colors.silver; + } + }; + + const renderBarChart = () => { + const records = [ + { label: '#1', x: 91, y: '#1: 🏆' }, + { label: '#2', x: 72, y: '#2: 🥈' }, + { label: '#3', x: 68, y: '#3: 🥉' }, + { label: '#4', x: 57, y: '#4:' }, + { label: '#5', x: 50, y: '#5:' }, + { label: '#6', x: 40, y: '#6:' }, + { label: '#7', x: 30, y: '#7:' }, + ]; + return ( + + {t('main-metrics.survey-response-rate')} + getLeaderboardLabelColor(l)} + getColorForChartEl={(l) => getLeaderboardLabelColor(l)} + hideLegend={true} + reverse={false} + /> + + {t('main-metrics.you-are-in')} + {myLabel} + {t('main-metrics.place')} + + + ); + }; return ( @@ -36,10 +81,24 @@ const SurveyLeaderboardCard = () => { )} /> - {tab === 'leaderboard' ? t('main-metrics.leaderboard') : t('main-metrics.comparison')} + {tab === 'leaderboard' ? renderBarChart() : } ); }; +const styles: any = { + chartTitle: { + alignSelf: 'center', + fontWeight: 'bold', + fontSize: 14, + }, + statusTextWrapper: { + alignSelf: 'center', + display: 'flex', + flexDirection: 'row', + fontSize: 16, + }, +}; + export default SurveyLeaderboardCard; diff --git a/www/js/metrics/SurveyTripCategoriesCard.tsx b/www/js/metrics/SurveyTripCategoriesCard.tsx index f6c31c71e..836457e40 100644 --- a/www/js/metrics/SurveyTripCategoriesCard.tsx +++ b/www/js/metrics/SurveyTripCategoriesCard.tsx @@ -1,11 +1,18 @@ import React from 'react'; -import { Card, useTheme } from 'react-native-paper'; +import { Card } from 'react-native-paper'; import { cardStyles } from './MetricsTab'; import { useTranslation } from 'react-i18next'; +import BarChart from '../components/BarChart'; +import { useAppTheme } from '../appTheme'; const SurveyTripCategoriesCard = () => { - const { colors } = useTheme(); + const { colors } = useAppTheme(); const { t } = useTranslation(); + const records = [ + { label: 'EV Roaming trip', x: 'EV Roaming trip', y: 91 }, + { label: 'EV Return trip', x: 'EV Return trip', y: 72 }, + { label: 'Gas Car trip', x: 'Gas Car trip', y: 68 }, + ]; return ( @@ -17,7 +24,19 @@ const SurveyTripCategoriesCard = () => { subtitleStyle={[cardStyles.titleText(colors), cardStyles.subtitleText]} style={cardStyles.title(colors)} /> - Trip Categories + + colors.navy} + getColorForChartEl={() => colors.navy} + hideLegend={true} + reverse={false} + /> + ); };