Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix "invalid scale configuration" error and more #1003

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import {
hasStatisticsError,
} from "../../../../selectors/eventDetailsSelectors";
import TimeSeriesStatistics from "../../../shared/TimeSeriesStatistics";
import { useAppDispatch, useAppSelector } from "../../../../store";
import { useAppSelector } from "../../../../store";
import { fetchEventStatisticsValueUpdate } from "../../../../slices/eventDetailsSlice";
import { useTranslation } from "react-i18next";
import { createChartOptions } from "../../../../utils/statisticsUtils";

/**
* This component manages the statistics tab of the event details modal
Expand All @@ -19,16 +20,10 @@ const EventDetailsStatisticsTab = ({
header: string,
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();

const statistics = useAppSelector(state => getStatistics(state));
const hasError = useAppSelector(state => hasStatisticsError(state));

// TODO: Get rid of the wrappers when modernizing redux is done
const fetchEventStatisticsValueUpdateWrapper = (eventId: any, providerId: any, from: any, to: any, dataResolution: any, timeMode: any) => {
dispatch(fetchEventStatisticsValueUpdate({eventId, providerId, from, to, dataResolution, timeMode}));
}

/* generates file name for download-link for a statistic */
const statisticsCsvFileName = (statsTitle: string) => {
const sanitizedStatsTitle = statsTitle
Expand Down Expand Up @@ -68,13 +63,13 @@ const EventDetailsStatisticsTab = ({
timeMode={stat.timeMode}
dataResolution={stat.dataResolution}
statDescription={stat.description}
onChange={fetchEventStatisticsValueUpdateWrapper}
onChange={fetchEventStatisticsValueUpdate}
exportUrl={stat.csvUrl}
exportFileName={statisticsCsvFileName}
totalValue={stat.totalValue}
sourceData={stat.values}
chartLabels={stat.labels}
chartOptions={stat.options}
chartOptions={createChartOptions(stat.timeMode, stat.dataResolution)}
/>
</div>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
} from "../../../../selectors/seriesDetailsSelectors";
import { fetchSeriesStatisticsValueUpdate } from "../../../../slices/seriesDetailsSlice";
import TimeSeriesStatistics from "../../../shared/TimeSeriesStatistics";
import { useAppDispatch, useAppSelector } from "../../../../store";
import { useAppSelector } from "../../../../store";
import { createChartOptions } from "../../../../utils/statisticsUtils";

const SeriesDetailsStatisticTab = ({
seriesId,
Expand All @@ -16,16 +17,10 @@ const SeriesDetailsStatisticTab = ({
header: string,
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();

const statistics = useAppSelector(state => getStatistics(state));
const hasError = useAppSelector(state => hasStatisticsError(state));

// TODO: Get rid of the wrappers when modernizing redux is done
const fetchSeriesStatisticsValueUpdateWrapper = (seriesId: any, providerId: any, from: any, to: any, dataResolution: any, timeMode: any) => {
dispatch(fetchSeriesStatisticsValueUpdate({seriesId, providerId, from, to, dataResolution, timeMode}));
}

/* generates file name for download-link for a statistic */
const statisticsCsvFileName = (statsTitle: string) => {
const sanitizedStatsTitle = statsTitle
Expand Down Expand Up @@ -65,13 +60,13 @@ const SeriesDetailsStatisticTab = ({
timeMode={stat.timeMode}
dataResolution={stat.dataResolution}
statDescription={stat.description}
onChange={fetchSeriesStatisticsValueUpdateWrapper}
onChange={fetchSeriesStatisticsValueUpdate}
exportUrl={stat.csvUrl}
exportFileName={statisticsCsvFileName}
totalValue={stat.totalValue}
sourceData={stat.values}
chartLabels={stat.labels}
chartOptions={stat.options}
chartOptions={createChartOptions(stat.timeMode, stat.dataResolution)}
/>
</div>
) : (
Expand Down
10 changes: 7 additions & 3 deletions src/components/shared/BarChart.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from "react";
import { Bar } from "react-chartjs-2";
import type { ChartDataset, ChartOptions } from 'chart.js';
import type { ChartData, ChartOptions } from 'chart.js';
import { Chart, registerables } from 'chart.js'

Chart.register(...registerables)


/**
* This component provides a bar chart for visualising (statistics) data
Expand All @@ -10,11 +14,11 @@ const BarChart = ({
axisLabels,
options
}: {
values: ChartDataset<'bar'>,
values: number[],
axisLabels: string[],
options: ChartOptions<'bar'>,
}) => {
const data = {
const data: ChartData<'bar'> = {
labels: axisLabels,
datasets: [
{
Expand Down
91 changes: 50 additions & 41 deletions src/components/shared/TimeSeriesStatistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import {
import { localizedMoment } from "../../utils/dateUtils";
import { parseISO } from "date-fns";
import { useTranslation } from "react-i18next";
import type { ChartDataset, ChartOptions } from 'chart.js';
import type { ChartOptions } from 'chart.js';
import { AsyncThunk } from "@reduxjs/toolkit";
import { AsyncThunkConfig } from "@reduxjs/toolkit/dist/createAsyncThunk";
import { useAppDispatch } from "../../store";
import { DataResolution, TimeMode } from "../../slices/statisticsSlice";


/**
Expand Down Expand Up @@ -42,18 +46,19 @@ const TimeSeriesStatistics = ({
providerId: string,
fromDate: string,
toDate: string,
timeMode: any, // startOf | "custom" ???
dataResolution: string[],
timeMode: TimeMode,
dataResolution: DataResolution,
statDescription: string,
onChange: (id: any, providerId: any, from: any, to: any, dataResolution: any, timeMode: any) => void,
onChange: AsyncThunk<undefined, { id: string, providerId: string, from: string | Date, to: string | Date, dataResolution: DataResolution, timeMode: TimeMode, }, AsyncThunkConfig>,
exportUrl: string,
exportFileName: (statsTitle: string) => string,
totalValue: string,
sourceData: ChartDataset<'bar'>,
totalValue: number,
sourceData: number[],
chartLabels: string[],
chartOptions: ChartOptions<'bar'>,
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();

// Style for radio buttons
const radioButtonStyle = {
Expand All @@ -80,30 +85,30 @@ const TimeSeriesStatistics = ({
// change formik values and get new statistic values from API
const change = (
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
timeMode: string,
from: Date | string,
to: Date | string,
dataResolution: unknown
timeMode: TimeMode,
from: string | Date,
to: string | Date,
dataResolution: DataResolution
) => {
if (timeMode === "year" || timeMode === "month") {
from = moment(from).clone().startOf(timeMode).format("YYYY-MM-DD");
to = moment(from).clone().endOf(timeMode).format("YYYY-MM-DD");
setFormikValue("fromDat0e", from);
setFormikValue("toDate", to);
setFormikValue("dataResolution", fixedDataResolutions[timeMode]);
dataResolution = fixedDataResolutions[timeMode];
setFormikValue("dataResolution", fixedDataResolutions(timeMode));
dataResolution = fixedStatisticDataResolutions(timeMode);
}

onChange(resourceId, providerId, from, to, dataResolution, timeMode);
dispatch(onChange({id: resourceId, providerId, from, to, dataResolution, timeMode}));
};

// change time mode in formik and get new values from API
const changeTimeMode = async (
newTimeMode: string,
newTimeMode: TimeMode,
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
from: Date | string,
to: Date | string,
dataResolution: unknown
from: string,
to: string,
dataResolution: DataResolution
) => {
setFormikValue("timeMode", newTimeMode);
change(setFormikValue, newTimeMode, from, to, dataResolution);
Expand All @@ -113,9 +118,9 @@ const TimeSeriesStatistics = ({
const changeFrom = async (
newFrom: Date,
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
timeMode: string,
to: Date | string,
dataResolution: unknown,
timeMode: TimeMode,
to: string,
dataResolution: DataResolution,
) => {
setFormikValue("fromDate", newFrom);
change(setFormikValue, timeMode, newFrom, to, dataResolution);
Expand All @@ -125,21 +130,21 @@ const TimeSeriesStatistics = ({
const changeTo = async (
newTo: Date,
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
timeMode: string,
from: Date | string,
dataResolution: unknown
timeMode: TimeMode,
from: string,
dataResolution: DataResolution
) => {
setFormikValue("toDate", newTo);
change(setFormikValue, timeMode, from, newTo, dataResolution);
};

// change custom time granularity in formik and get new values from API
const changeGranularity = async (
granularity: unknown,
granularity: DataResolution,
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
timeMode: string,
from: Date | string,
to: Date | string,
timeMode: TimeMode,
from: string,
to: string,
) => {
setFormikValue("dataResolution", granularity);
change(setFormikValue, timeMode, from, to, granularity);
Expand All @@ -159,12 +164,12 @@ const TimeSeriesStatistics = ({
const selectPrevious = (
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
from: string,
timeMode: keyof typeof formatStrings,
dataResolution: unknown,
timeMode: TimeMode,
dataResolution: DataResolution,
) => {
const newFrom = moment(from)
// @ts-expect-error TS(2769): No overload matches this call.
.subtract(1, timeMode + "s")
// According to the moment.js docs, string is supported as a second argument here
.subtract(1, timeMode + "s" as moment.unitOfTime.DurationConstructor)
.format("YYYY-MM-DD");
const to = newFrom;
change(setFormikValue, timeMode, newFrom, to, dataResolution);
Expand All @@ -174,12 +179,12 @@ const TimeSeriesStatistics = ({
const selectNext = (
setFormikValue: (field: string, value: any) => Promise<void | FormikErrors<any>>,
from: string,
timeMode: keyof typeof formatStrings,
dataResolution: unknown,
timeMode: TimeMode,
dataResolution: DataResolution,
) => {
const newFrom = moment(from)
// @ts-expect-error TS(2769): No overload matches this call.
.add(1, timeMode + "s")
// According to the moment.js docs, string is supported as a second argument here
.add(1, timeMode + "s" as moment.unitOfTime.DurationConstructor)
.format("YYYY-MM-DD");
const to = newFrom;
change(setFormikValue, timeMode, newFrom, to, dataResolution);
Expand All @@ -192,7 +197,11 @@ const TimeSeriesStatistics = ({
initialValues={{
timeMode: timeMode,
dataResolution: dataResolution,
// Typescript complains that the method "startOf" cannot take "custom" as a parameter, but in practice
// this does not seem to be a problem
//@ts-ignore
fromDate: moment(fromDate).startOf(timeMode).format("YYYY-MM-DD"),
//@ts-ignore
toDate: moment(toDate).endOf(timeMode).format("YYYY-MM-DD"),
}}
onSubmit={(values) => {}}
Expand All @@ -209,6 +218,12 @@ const TimeSeriesStatistics = ({
/>
</div>

{/* statistics total value */}
<div className="total">
<span>{t("STATISTICS.TOTAL") /* Total */}</span>
<span>{": " + totalValue}</span>
</div>

{/* radio buttons for selecting the mode of choosing the timeframe of statistic */}
<div className="mode">
{timeModes.map((mode, key) => (
Expand Down Expand Up @@ -243,12 +258,6 @@ const TimeSeriesStatistics = ({
))}
</div>

{/* statistics total value */}
<div className="total">
<span>{t("STATISTICS.TOTAL") /* Total */}</span>
<span>{": " + totalValue}</span>
</div>

{/* timeframe selection */}

{(formik.values.timeMode === "year" ||
Expand Down
22 changes: 10 additions & 12 deletions src/components/statistics/Statistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
fetchStatisticsPageStatistics,
fetchStatisticsPageStatisticsValueUpdate,
} from "../../slices/statisticsSlice";
import { createChartOptions } from "../../utils/statisticsUtils";

const Statistics: React.FC = () => {
const { t } = useTranslation();
Expand All @@ -39,18 +40,15 @@ const Statistics: React.FC = () => {
const hasError = useAppSelector(state => hasStatisticsError(state));
const isLoadingStatistics = useAppSelector(state => isFetchingStatistics(state));

// TODO: Get rid of the wrappers when modernizing redux is done
const fetchStatisticsPageStatisticsValueUpdateWrapper = (organizationId: any, providerId: any, from: any, to: any, dataResolution: any, timeMode: any) => {
dispatch(fetchStatisticsPageStatisticsValueUpdate({organizationId, providerId, from, to, dataResolution, timeMode}))
}

// fetch user information for organization id, then fetch statistics
useEffect(() => {
// fetch user information for organization id, then fetch statistics
dispatch(fetchUserInfo()).then(() => {
dispatch(fetchStatisticsPageStatistics(organizationId)).then();
})
dispatch(fetchUserInfo())
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
dispatch(fetchStatisticsPageStatistics(organizationId)).then();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [organizationId]);

const toggleNavigation = () => {
setNavigation(!displayNavigation);
Expand All @@ -71,7 +69,7 @@ const Statistics: React.FC = () => {
};

return (
<span>
<span>
<Header />
<NavBar>
{/* Include Burger-button menu */}
Expand Down Expand Up @@ -128,13 +126,13 @@ const Statistics: React.FC = () => {
timeMode={stat.timeMode}
dataResolution={stat.dataResolution}
statDescription={stat.description}
onChange={fetchStatisticsPageStatisticsValueUpdateWrapper}
onChange={fetchStatisticsPageStatisticsValueUpdate}
exportUrl={stat.csvUrl}
exportFileName={statisticsCsvFileName}
totalValue={stat.totalValue}
sourceData={stat.values}
chartLabels={stat.labels}
chartOptions={stat.options}
chartOptions={createChartOptions(stat.timeMode, stat.dataResolution)}
/>
</div>
) : (
Expand Down
11 changes: 8 additions & 3 deletions src/configs/statisticsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ export const statisticTimeModes = [
];

// data resolutions (or time granularity) for statistics with year or month timeframe
export const fixedStatisticDataResolutions = {
month: "daily",
year: "monthly",
export const fixedStatisticDataResolutions = (timeMode: "month" | "year") => {
if (timeMode === "month") {
return "daily"
}
if (timeMode === "year") {
return "monthly"
}
return "monthly"
};

// available data resolutions (or time granularity) for statistics with custom timeframe
Expand Down
Loading
Loading