Skip to content

Commit

Permalink
Add a stacked bar of the mmessage trees by language
Browse files Browse the repository at this point in the history
  • Loading branch information
GuilleHoardings committed Feb 17, 2023
1 parent 4d4efb8 commit 20eb7f6
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 36 deletions.
99 changes: 66 additions & 33 deletions website/src/components/Stats/Stats.components.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Text, Box, Select, useColorModeValue } from "@chakra-ui/react";
import { ArcElement, Chart as ChartJS, Colors, Tooltip } from "chart.js";
import { TFunction, useTranslation } from "next-i18next";
import { Box, Select, useColorModeValue } from "@chakra-ui/react";
import { ArcElement, BarElement, CategoryScale, Chart as ChartJS, Colors, LinearScale, Tooltip } from "chart.js";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { Doughnut, Pie } from "react-chartjs-2";
import { Doughnut, Pie, Bar } from "react-chartjs-2";
import { getTypeSafei18nKey } from "src/lib/i18n";
import { getLocaleDisplayName } from "src/lib/languages";
import { colors } from "src/styles/Theme/colors";
import { SimpleTable } from "../SimpleTable/SimpleTable";
import { Stat as StatType } from "src/types/Stat";

ChartJS.register(ArcElement, Tooltip, Colors);
ChartJS.register(ArcElement, Tooltip, Colors, CategoryScale, BarElement, LinearScale);

const getDefaultChartOptions = (color: string) => ({
maintainAspectRatio: false,
Expand All @@ -28,11 +28,6 @@ type ChartProps = {
type?: typeof Pie | typeof Doughnut;
};

type KeyPairStatProps = {
stat: StatType;
titleFn?: (name: string) => string;
};

type MessageTreeStateStatsProps = {
titleFn: (name: string) => string;
stat: StatType & {
Expand All @@ -44,7 +39,7 @@ type MessageTreeStateStatsProps = {
};
};

const findLangRow = (rows: any, lang: string) => {
const findLangRow = (rows: string[][], lang: string): number => {
for (let i = 0; i < rows.length; i++) {
const row_lang = rows[i][0];
if (row_lang === lang) return i;
Expand All @@ -61,7 +56,7 @@ function getTableData(
count: number;
}[];
},
t: TFunction<"stats", undefined, "stats">
t
) {
// The headers come from the message tree State.
// These two states are not considered because they make
Expand Down Expand Up @@ -94,7 +89,7 @@ function getTableData(

let langRow = findLangRow(rows, lang);

if (langRow == -1) {
if (langRow === -1) {
// The language is not yet in the data. Add it
rows.push(Array(headers.length).fill(0));
langRow = rows.length - 1;
Expand Down Expand Up @@ -156,6 +151,59 @@ export const MessageTreeStateStats = ({ stat, titleFn }: MessageTreeStateStatsPr
);
};

export const MessageTreeStateStatsStacked = ({ stat, titleFn }: MessageTreeStateStatsProps) => {
const { t } = useTranslation("stats");
const langs = stat.stats.map((item) => item.lang);
const uniqueLangs = langs.filter((item, index) => langs.indexOf(item) === index);
const states = stat.stats.map((item) => item.state);
const uniqueStates = states.filter((item, index) => states.indexOf(item) === index);

const bar_options = {
plugins: {
title: {
display: true,
text: "Chart.js Bar Chart - Stacked",
},
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true,
},
},
};

const bar_datasets = [];
uniqueStates.forEach((state) => {
const data_state = stat.stats.filter((item) => item.state === state);

const lang_count = {};
data_state.forEach((item) => {
lang_count[item.lang] = item.count;
});

bar_datasets.push({
label: state,
data: uniqueLangs.map((item) => lang_count[item]),
});
});

const bar_data = {
labels: uniqueLangs,
datasets: bar_datasets,
};

return (
<>
<Box minH={330}>
<Bar options={bar_options} data={bar_data} />
</Box>
</>
);
};
export const Chart = ({ stat, titleFn, type: Component }: ChartProps) => {
const data = Object.keys(stat.stats);
const { t } = useTranslation("stats");
Expand All @@ -177,25 +225,7 @@ export const Chart = ({ stat, titleFn, type: Component }: ChartProps) => {
);
};

export const KeyPairStat = ({ stat, titleFn }: KeyPairStatProps) => {
const { t } = useTranslation("stats");
return (
<>
{Object.keys(stat.stats).map((item) => {
return (
<Text key={item}>
<Text className="capitalize" as="span" fontWeight="semibold">
{titleFn ? titleFn(item) : t(getTypeSafei18nKey(item))}
</Text>
: {t(getTypeSafei18nKey(stat.stats[item]))}
</Text>
);
})}
</>
);
};

export const MessageTreeStateStatsTable = ({ stat }: MessageTreeStateStatsProps) => {
export const MessageTreeStateStatsTable = ({ stat, titleFn }: MessageTreeStateStatsProps) => {
const { t } = useTranslation("stats");
const { headers, rows } = getTableData(stat, t);

Expand All @@ -210,7 +240,10 @@ export const statComponents: Record<string, React.FC<{ stat: StatType }>> = {
<MessageTreeStateStats stat={stat} titleFn={getLocaleDisplayName} />
),
message_trees_states_by_lang_table: ({ stat }: MessageTreeStateStatsProps) => (
<MessageTreeStateStatsTable stat={stat} />
<MessageTreeStateStatsTable stat={stat} titleFn={getLocaleDisplayName} />
),
message_trees_states_by_lang_stacked: ({ stat }: MessageTreeStateStatsProps) => (
<MessageTreeStateStatsStacked stat={stat} titleFn={getLocaleDisplayName} />
),
human_messages_by_lang: ({ stat }: ChartProps) => (
<Chart stat={stat} titleFn={getLocaleDisplayName} type={Doughnut} />
Expand Down
9 changes: 6 additions & 3 deletions website/src/components/Stats/Stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ export const Stats = ({ data }: StatsProps) => {

const keys = Object.keys(data.stats_by_name).filter((key) => key !== "users_accepted_tos");

// Add a second copy of the message_trees_states_by_lang
// for creating the table in addition to the chart
// Add two copies of the message_trees_states_by_lang for creating the
// stacked bar and the table in addition to the donough chart
keys.push("message_trees_states_by_lang_table");
keys.push("message_trees_states_by_lang_stacked");
data.stats_by_name["message_trees_states_by_lang_table"] = data.stats_by_name["message_trees_states_by_lang"];
data.stats_by_name["message_trees_states_by_lang_stacked"] = data.stats_by_name["message_trees_states_by_lang"];

const getStatByName = (name: string): Stat => {
return data.stats_by_name[name];
Expand All @@ -37,7 +39,8 @@ export const Stats = ({ data }: StatsProps) => {
{keys.map((key) => {
const stat = getStatByName(key);
const component = statComponents[key];
const colSpan = key === "message_trees_states_by_lang_table" ? 2 : 1;
const colSpan =
key === "message_trees_states_by_lang_table" || key === "message_trees_states_by_lang_stacked" ? 2 : 1;
return (
<GridItem key={key} colSpan={colSpan}>
<Card minH={500}>
Expand Down

0 comments on commit 20eb7f6

Please sign in to comment.