diff --git a/front/pages/internal/stats.tsx b/front/pages/internal/stats.tsx index 74075f99..32256178 100644 --- a/front/pages/internal/stats.tsx +++ b/front/pages/internal/stats.tsx @@ -11,8 +11,9 @@ import { fetchStatsAverage } from '@front/domain/money/actions/fetchStatsAverage import { fetchStatsDynamics } from '@front/domain/money/actions/fetchStatsDynamics' import { GroupBy } from '@shared/enum/GroupBy' import { getDefaultCurrency } from '@front/domain/user/selectors/getDefaultCurrency' +import { pageWithTranslation, Namespace } from '@front/domain/i18n' -export default class StatsPage extends React.Component { +class StatsPage extends React.Component { public static isSecure = true public static async getInitialProps({ reduxStore }: AppContext) { @@ -40,3 +41,10 @@ export default class StatsPage extends React.Component { return } } + +export default pageWithTranslation([ + Namespace.History, + Namespace.Months, + Namespace.Stats, + Namespace.Currency, +])(StatsPage) diff --git a/front/src/domain/i18n/Namespace.ts b/front/src/domain/i18n/Namespace.ts index 16a28559..82f02e24 100644 --- a/front/src/domain/i18n/Namespace.ts +++ b/front/src/domain/i18n/Namespace.ts @@ -9,4 +9,5 @@ export enum Namespace { Common = 'common', Months = 'months', Profile = 'profile', + Stats = 'stats', } diff --git a/front/src/features/history/History.tsx b/front/src/features/history/History.tsx index 656c1811..081adeef 100644 --- a/front/src/features/history/History.tsx +++ b/front/src/features/history/History.tsx @@ -11,7 +11,7 @@ import { useWindowSize } from '@front/ui/hooks/useWindowSize' import { pushRoute } from '../routing' import * as styles from './History.css' import { createMonths } from './helpers/createMonths' -import { createMonthTitle } from './helpers/createMonthTitle' +import { translatedMonthTitle } from '@front/helpers/translatedMonthTitle' import { TransactionList } from './components/transaction-list' import { useTranslation } from '@front/domain/i18n' @@ -24,7 +24,10 @@ export const History = () => { () => createMonths(t, firstTransactionDate, new Date()), [firstTransactionDate], ) - const defaultMonthTitle = useMemo(() => createMonthTitle(t, new Date()), []) + const defaultMonthTitle = useMemo( + () => translatedMonthTitle(t, new Date()), + [], + ) const { innerWidth } = useWindowSize() const isMobile = innerWidth && innerWidth < 768 diff --git a/front/src/features/history/helpers/createMonthTitle.ts b/front/src/features/history/helpers/createMonthTitle.ts deleted file mode 100644 index 363cfadb..00000000 --- a/front/src/features/history/helpers/createMonthTitle.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { format } from 'date-fns' - -export const createMonthTitle = (t: (key: string) => string, date: Date) => - `${t(`months:${format(date, 'MM')}`)} ${format(date, 'YYYY')}` diff --git a/front/src/features/history/helpers/createMonths.ts b/front/src/features/history/helpers/createMonths.ts index 6a845e89..cbcdaca2 100644 --- a/front/src/features/history/helpers/createMonths.ts +++ b/front/src/features/history/helpers/createMonths.ts @@ -1,8 +1,7 @@ import { startOfMonth, addMonths, endOfMonth } from 'date-fns' import { wantUTC } from '@front/helpers/wantUTC' - -import { createMonthTitle } from './createMonthTitle' +import { translatedMonthTitle } from '@front/helpers/translatedMonthTitle' export const createMonths = ( t: (key: string) => string, @@ -15,7 +14,7 @@ export const createMonths = ( while (now < to) { const next = wantUTC(startOfMonth)(wantUTC(addMonths)(now, 1)) groups.push({ - title: createMonthTitle(t, now), + title: translatedMonthTitle(t, now), from: now, to: wantUTC(endOfMonth)(now), }) diff --git a/front/src/features/statistics/Statistics.tsx b/front/src/features/statistics/Statistics.tsx index e36823fb..385a609d 100644 --- a/front/src/features/statistics/Statistics.tsx +++ b/front/src/features/statistics/Statistics.tsx @@ -7,6 +7,7 @@ import { Tabs, Tab } from '@front/ui/components/layout/tabs' import { GroupBy } from '@shared/enum/GroupBy' import { getDefaultCurrency } from '@front/domain/user/selectors/getDefaultCurrency' import { PageHeader } from '@front/ui/components/layout/page-header' +import { useTranslation } from '@front/domain/i18n' import { Yearly } from './features/yearly' import { Monthly } from './features/monthly' @@ -22,6 +23,7 @@ const maxLength = 5 export const Statistics = () => { const defaultCurrency = useMappedState(getDefaultCurrency) const [currency, setCurrency] = useState(defaultCurrency) + const { t } = useTranslation() const renderContent = useCallback( (title: string, group: GroupBy.Month | GroupBy.Year) => ( @@ -53,15 +55,18 @@ export const Statistics = () => { return ( - pushRoute('/app')} /> + pushRoute('/app')} + /> } > - {renderContent('Monthly', GroupBy.Month)} - {renderContent('Yearly', GroupBy.Year)} + {renderContent(t('stats:monthly'), GroupBy.Month)} + {renderContent(t('stats:yearly'), GroupBy.Year)} ) diff --git a/front/src/features/statistics/features/categories/Categories.tsx b/front/src/features/statistics/features/categories/Categories.tsx index 68ce1343..66633737 100644 --- a/front/src/features/statistics/features/categories/Categories.tsx +++ b/front/src/features/statistics/features/categories/Categories.tsx @@ -13,6 +13,7 @@ import { LoaderTable } from '@front/ui/components/layout/loader-table' import { Button, ButtonType } from '@front/ui/components/form/button' import { pushRoute } from '@front/features/routing' import { createRangeForGroup } from '@front/helpers/createRangeForGroup' +import { useTranslation } from '@front/domain/i18n' interface Props { className?: string @@ -29,6 +30,8 @@ export const Categories = ({ widthPercent, maxLength, }: Props) => { + const { t } = useTranslation() + const columns = useMemo( () => ({ category: { @@ -55,13 +58,16 @@ export const Categories = ({ // sort by `income` and take `maxLength` top groups const preparedData = useMemo( - () => stats.map(s => take(sortBy(s, t => -t.outcome), maxLength)), + () => + stats.map(s => + take(sortBy(s, transaction => -transaction.outcome), maxLength), + ), [stats, maxLength], ) return ( pushRoute(`/app/stats/categories/${group}`)} > - Details + {t('stats:actions.details')} } /> diff --git a/front/src/features/statistics/features/dynamics/Dynamics.tsx b/front/src/features/statistics/features/dynamics/Dynamics.tsx index 3827827f..19b00cd1 100644 --- a/front/src/features/statistics/features/dynamics/Dynamics.tsx +++ b/front/src/features/statistics/features/dynamics/Dynamics.tsx @@ -25,6 +25,8 @@ import { wantUTC } from '@front/helpers/wantUTC' import { Loader } from '@front/ui/components/layout/loader' import { mergeFetchingState } from '@front/helpers/mergeFetchingState' import { calculateGroupProgress } from '@shared/helpers/calculateGroupProgress' +import { translatedMonthTitle } from '@front/helpers/translatedMonthTitle' +import { useTranslation } from '@front/domain/i18n' import * as styles from './Dynamics.css' import { calculateGrowPercentage } from './helpers/calculateGrowPercentage' @@ -37,9 +39,11 @@ interface Props { // TODO: refactor it please export const Dynamics = ({ className, group, currency }: Props) => { + const { t } = useTranslation() + const period = group === GroupBy.Month - ? format(new Date(), 'MMMM') + ? translatedMonthTitle(t, new Date()) : format(new Date(), 'YYYY') const [from, to] = useMemo(() => { @@ -92,12 +96,17 @@ export const Dynamics = ({ className, group, currency }: Props) => { // TODO: add info about calculation in tooltip return ( -

Compared to the average {group}

+

{t(`stats:dynamics.compared-${group}`)}

- - + +
diff --git a/front/src/features/statistics/features/monthly/Monthly.tsx b/front/src/features/statistics/features/monthly/Monthly.tsx index 2c3015e8..29cfc0cb 100644 --- a/front/src/features/statistics/features/monthly/Monthly.tsx +++ b/front/src/features/statistics/features/monthly/Monthly.tsx @@ -1,4 +1,4 @@ -import { endOfYear, format, startOfYear, getYear, parse } from 'date-fns' +import { endOfYear, startOfYear, getYear, parse } from 'date-fns' import { useState, useMemo } from 'react' import { useMappedState } from 'redux-react-hook' import { useMedia } from 'use-media' @@ -16,6 +16,8 @@ import { ControlHeader } from '@front/ui/components/controls/control-header' import { YearPicker } from '@front/ui/components/form/year-picker' import { getFirstTransactionDate } from '@front/domain/money/selectors/getFirstTransactionDate' import { wantUTC } from '@front/helpers/wantUTC' +import { useTranslation } from '@front/domain/i18n' +import { translatedMonthTitle } from '@front/helpers/translatedMonthTitle' const groupBy = GroupBy.Month @@ -28,6 +30,7 @@ export const Monthly = ({ className, currency }: Props) => { const firstTransactionDate = useMappedState(getFirstTransactionDate) const fetching = useMappedState(getStatsDynamicsFetchingStatus) const isSmall = useMedia({ maxWidth: 768 }) + const { t } = useTranslation() const [year, setYear] = useState(getYear(new Date())) @@ -45,7 +48,7 @@ export const Monthly = ({ className, currency }: Props) => { return (
- + { ({ - name: format(start, 'MMMM'), + name: translatedMonthTitle(t, start, false), data: { - income, - outcome, + income: { + label: t('history:incomes'), + value: income, + }, + outcome: { + label: t('history:outcomes'), + value: outcome, + }, }, }))} fitToContainer={isSmall} diff --git a/front/src/features/statistics/features/sources/Sources.tsx b/front/src/features/statistics/features/sources/Sources.tsx index c68cf0a2..8e8411ad 100644 --- a/front/src/features/statistics/features/sources/Sources.tsx +++ b/front/src/features/statistics/features/sources/Sources.tsx @@ -13,6 +13,7 @@ import { LoaderTable } from '@front/ui/components/layout/loader-table' import { createRangeForGroup } from '@front/helpers/createRangeForGroup' import { Button, ButtonType } from '@front/ui/components/form/button' import { pushRoute } from '@front/features/routing' +import { useTranslation } from '@front/domain/i18n' interface Props { className?: string @@ -29,6 +30,8 @@ export const Sources = ({ widthPercent, maxLength, }: Props) => { + const { t } = useTranslation() + const columns = useMemo( () => ({ source: { @@ -55,13 +58,16 @@ export const Sources = ({ // sort by `income` and take `maxLength` top groups const preparedData = useMemo( - () => stats.map(s => take(sortBy(s, t => -t.income), maxLength)), + () => + stats.map(s => + take(sortBy(s, transaction => -transaction.income), maxLength), + ), [stats, maxLength], ) return ( pushRoute(`/app/stats/sources/${group}`)} > - Details + {t('stats:actions.details')} } /> diff --git a/front/src/features/statistics/features/yearly/Yearly.tsx b/front/src/features/statistics/features/yearly/Yearly.tsx index 0f0ffd82..3606505a 100644 --- a/front/src/features/statistics/features/yearly/Yearly.tsx +++ b/front/src/features/statistics/features/yearly/Yearly.tsx @@ -15,6 +15,7 @@ import { GroupBy } from '@shared/enum/GroupBy' import { ControlHeader } from '@front/ui/components/controls/control-header' import { useMemoState } from '@front/domain/store' import { wantUTC } from '@front/helpers/wantUTC' +import { useTranslation } from '@front/domain/i18n' const groupBy = GroupBy.Year @@ -27,6 +28,7 @@ export const Yearly = ({ className, currency }: Props) => { const firstTransactionDate = useMappedState(getFirstTransactionDate) const fetching = useMappedState(getStatsDynamicsFetchingStatus) const isSmall = useMedia({ maxWidth: 768 }) + const { t } = useTranslation() const from = useMemo(() => wantUTC(startOfYear)(firstTransactionDate), [ firstTransactionDate, @@ -41,7 +43,7 @@ export const Yearly = ({ className, currency }: Props) => { return (
- + {stats.nonEmpty() && ( { dataSets={stats.get().map(({ start, income, outcome }) => ({ name: format(start, 'YYYY'), data: { - income, - outcome, + income: { + label: t('history:incomes'), + value: income, + }, + outcome: { + label: t('history:outcomes'), + value: outcome, + }, }, }))} fitToContainer={isSmall} diff --git a/front/src/helpers/translatedMonthTitle.ts b/front/src/helpers/translatedMonthTitle.ts new file mode 100644 index 00000000..7852c5a7 --- /dev/null +++ b/front/src/helpers/translatedMonthTitle.ts @@ -0,0 +1,15 @@ +import { format } from 'date-fns' + +export const translatedMonthTitle = ( + t: (key: string) => string, + date: Date, + withYear = true, +) => { + const month = `${t(`months:${format(date, 'MM')}`)}` + + if (withYear) { + return `${month} ${format(date, 'YYYY')}` + } + + return month +} diff --git a/front/src/ui/components/chart/bar-chart/BarChart.tsx b/front/src/ui/components/chart/bar-chart/BarChart.tsx index 9c6aa4c5..0dd57a90 100644 --- a/front/src/ui/components/chart/bar-chart/BarChart.tsx +++ b/front/src/ui/components/chart/bar-chart/BarChart.tsx @@ -1,4 +1,4 @@ -import { capitalize, flatten, uniq } from 'lodash' +import { flatten, uniq } from 'lodash' import { Bar } from 'react-chartjs-2' import { useMemo } from 'react' @@ -6,7 +6,10 @@ import { createOptions } from './helpers/createOptions' import { getColor } from './helpers/getColor' interface Data { - [key: string]: number + [key: string]: { + label: string + value: number + } } interface DataSet { @@ -33,8 +36,8 @@ export const BarChart = ({ labels: uniq(flatten(dataSets.map(set => set.name))), datasets: uniq(flatten(dataSets.map(set => Object.keys(set.data)))).map( (name, index) => ({ - label: capitalize(name), - data: dataSets.map(set => set.data[name]), + label: dataSets[index].data[name].label, + data: dataSets.map(set => set.data[name].value), backgroundColor: getColor(index), }), ), diff --git a/front/src/ui/components/chart/stat/Stat.tsx b/front/src/ui/components/chart/stat/Stat.tsx index bd52de5b..9d284058 100644 --- a/front/src/ui/components/chart/stat/Stat.tsx +++ b/front/src/ui/components/chart/stat/Stat.tsx @@ -1,6 +1,8 @@ import { Statistic, Icon } from 'antd' import { Option } from 'tsoption' +import { useTranslation } from '@front/domain/i18n' + interface Props { title: string value: Option @@ -34,9 +36,11 @@ export const Stat = ({ ) } + const { t } = useTranslation() + return (