Commit 58b208b0 by jhrabal

gui

parent 4220d743
...@@ -53,7 +53,7 @@ export default ({ labels, colors, values, percents, currency, i18n, useChartColo ...@@ -53,7 +53,7 @@ export default ({ labels, colors, values, percents, currency, i18n, useChartColo
</div> </div>
<div className="values"> <div className="values">
<div className="value" style={ useChartColors ? { color: color } : null }> <div className="value" style={ useChartColors ? { color: color } : null }>
{ formatMoney(value, currency, i18n) } { value }
</div> </div>
{ percent } { percent }
</div> </div>
......
{
"changed": {},
"translated": {
"emptyListMain": {
"id": "components.FetchedContent.emptyListMain",
"message": "Prázdný seznam",
"defaultMessage": "This list is empty",
"version": 1549353832408
},
"emptyListSecondary": {
"id": "components.FetchedContent.emptyListSecondary",
"message": "Nemáme zde co zobrazit. Chcete přidat nějaké položky?",
"defaultMessage": "We have nothing to display here. Do you want to add some items?",
"version": 1549353832408
},
"errorMain": {
"id": "components.FetchedContent.errorMain",
"message": "Něco se pokazilo",
"defaultMessage": "Something went wrong",
"version": 1549404083272
},
"errorSecondary": {
"id": "components.FetchedContent.errorSecondary",
"message": "Nemůžeme získat data",
"defaultMessage": "We were unable to fetch the data",
"version": 1549404083272
},
"errorTryAgainButton": {
"id": "components.FetchedContent.errorTryAgainButton",
"message": "Zkusit znova",
"defaultMessage": "Try again",
"version": 1549404083272
}
}
}
\ No newline at end of file
...@@ -2,23 +2,11 @@ import React, { Component } from 'react'; ...@@ -2,23 +2,11 @@ import React, { Component } from 'react';
import { Bar, HorizontalBar } from 'react-chartjs-2'; import { Bar, HorizontalBar } from 'react-chartjs-2';
import palette from 'utils/palette'; import palette from 'utils/palette';
import { injectIntl } from 'react-intl';
import messages from './messages.js';
const options = {
responsive: true,
animation: false,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
display: false,
callbacks: {
label: () => ""
}
},
};
function emptyLabels() { function emptyLabels() {
...@@ -38,8 +26,8 @@ function emptyValues() { ...@@ -38,8 +26,8 @@ function emptyValues() {
} }
export default (props) => { export default injectIntl((props) => {
let { className, values } = props; let { className, values, intl } = props;
let empty = false; let empty = false;
if (!values) { if (!values) {
...@@ -60,9 +48,30 @@ export default (props) => { ...@@ -60,9 +48,30 @@ export default (props) => {
}] }]
}; };
const options = {
responsive: true,
animation: false,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
display: false,
callbacks: {
title: function(tooltipItem, data) {
return intl.formatMessage(messages.title, { rating: data.labels[tooltipItem[0].index] });
},
label: function(tooltipItem, data) {
return intl.formatMessage(messages.value, { count: data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] });
}
}
},
};
return ( return (
<div className={ className } style={{ minHeight: 300 }}> <div className={ className } style={{ minHeight: 300 }}>
<Bar data={ data } options={ options } /> <Bar data={ data } options={ options } />
</div> </div>
); );
}; });
\ No newline at end of file \ No newline at end of file
export default {
title: {
id: "components.RatingBarChart.title",
defaultMessage: "Rating {rating}"
},
value: {
id: "components.RatingBarChart.value",
defaultMessage: "Count: {count}"
},
}
\ No newline at end of file
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Doughnut } from 'react-chartjs-2'; import { Doughnut } from 'react-chartjs-2';
import DoughnutChartLegend from 'components/DoughnutChartLegend'; import DoughnutChartLegend from 'components/DoughnutChartLegend';
import { formatDate, formatMoney, formatNumber, formatPercent } from 'lib/i18n'; import { formatNumber, formatPercent } from 'lib/i18n';
import palette from 'utils/palette'; import palette from 'utils/palette';
import { injectIntl } from 'react-intl'; import { injectIntl } from 'react-intl';
...@@ -10,8 +10,8 @@ import messages from './messages.js'; ...@@ -10,8 +10,8 @@ import messages from './messages.js';
require('./style.scss'); require('./style.scss');
const draftColor = "#BABABA", plannedColor = "#08acff", finishedColor = "#00c900", overdueColor = "#ff0707", emptyColor = "#DEDEDE"; const chartColors = palette(["#4EC3E0", "#1287ED"], 10);
const emptyColors = palette(["#BEBEBE"], 4); const emptyColors = palette(["#BEBEBE"], 10);
let options = { let options = {
cutoutPercentage: 65, cutoutPercentage: 65,
...@@ -30,7 +30,7 @@ let options = { ...@@ -30,7 +30,7 @@ let options = {
function renderTooltip(i18n, labels, currency, empty) { function renderTooltip(i18n, labels, currency, empty) {
if (empty) { if (empty) {
return () => { return () => {
return formatMoney(0, currency, i18n); return formatNumber(0, i18n);
}; };
} }
return (tooltipItem, data) => { return (tooltipItem, data) => {
...@@ -39,18 +39,21 @@ function renderTooltip(i18n, labels, currency, empty) { ...@@ -39,18 +39,21 @@ function renderTooltip(i18n, labels, currency, empty) {
return previousValue + currentValue; return previousValue + currentValue;
}); });
let currentValue = dataset.data[tooltipItem.index]; let currentValue = dataset.data[tooltipItem.index];
return formatMoney(currentValue, currency, i18n) + " (" + formatPercent(currentValue / total * 100, i18n) + ")"; return currentValue + " (" + formatPercent(currentValue / total * 100, i18n) + ")";
} }
} }
function renderTitle(intl, labels, empty) {
return (tooltipItem, data) => {
return data.labels[tooltipItem[0].index];
}
}
export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10", ...props }) => { export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10", ...props }) => {
let {
draftLabel = intl.formatMessage(messages.draftLabel),
activeLabel = intl.formatMessage(messages.activeLabel),
finishedLabel = intl.formatMessage(messages.finishedLabel),
overdueLabel = intl.formatMessage(messages.overdueLabel)
} = props;
let sums = []; let sums = [];
let vals = []; let vals = [];
...@@ -60,74 +63,27 @@ export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10 ...@@ -60,74 +63,27 @@ export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10
let total = 0, val = 0; let total = 0, val = 0;
let percents = []; let percents = [];
if (!data || empty) { for (let i = 10; i > 0; i--) {
if (draftLabel) { labels.push(intl.formatMessage(messages.rating, { rating: i }));
labels.push(draftLabel);
colors.push(emptyColors[0]);
sums.push(1);
vals.push(0);
}
if (activeLabel) {
labels.push(activeLabel);
colors.push(emptyColors[1]);
sums.push(1);
vals.push(0);
}
if (finishedLabel) {
labels.push(finishedLabel);
colors.push(emptyColors[2]);
sums.push(1);
vals.push(0);
} }
if (overdueLabel) { if (!data || empty) {
labels.push(overdueLabel); colors = emptyColors;
colors.push(emptyColors[3]); for (let i = 10; i > 0; i--) {
sums.push(1); sums.push(1);
vals.push(0); vals.push(0);
} }
sums.map(s => percents.push(0)); sums.map(s => percents.push(0));
} else { } else {
if (draftLabel) { colors = chartColors;
labels.push(draftLabel); for (let i = 10; i > 0; i--) {
colors.push(draftColor); val = data[i] || 0;
val = data.draft || 0;
sums.push(val); sums.push(val);
vals.push(val); vals.push(val);
total += val; total += val;
} }
if (activeLabel) {
labels.push(activeLabel);
colors.push(plannedColor);
val = data.active || 0;
sums.push(val);
vals.push(val);
total += val;
}
if (finishedLabel) {
labels.push(finishedLabel);
colors.push(finishedColor);
val = data.finished || 0;
sums.push(val);
vals.push(val);
total += val;
}
if (overdueLabel) {
labels.push(overdueLabel);
colors.push(overdueColor);
val = data.overdue || 0;
vals.push(val);
sums.push(val);
total += val;
}
if (total == 0) { if (total == 0) {
sums.forEach(s => percents.push(0)); sums.forEach(s => percents.push(0));
sums = sums.map(s => 1); sums = sums.map(s => 1);
...@@ -150,17 +106,18 @@ export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10 ...@@ -150,17 +106,18 @@ export default injectIntl(({ data, empty, currency, i18n, intl, className = "p10
}; };
let tooltip = renderTooltip(i18n, labels, currency, total == 0 || empty || !data); let tooltip = renderTooltip(i18n, labels, currency, total == 0 || empty || !data);
let title = renderTitle(intl, labels, total == 0 || empty || !data);
return ( return (
<div className={ className }> <div className={ className }>
<div className="status-chart"> <div className="status-chart">
<div> <div>
<div className="status-chart-div"> <div className="status-chart-div">
<Doughnut data={ chartData } options={ { ...options, tooltips: { callbacks: { label: tooltip }} } } redraw={ true }/> <Doughnut data={ chartData } options={ { ...options, tooltips: { callbacks: { label: tooltip, title: title }} } } redraw={ true }/>
</div> </div>
</div> </div>
<div> <div>
<DoughnutChartLegend labels={ labels } colors={ colors } values={ vals } percents={ percents } currency={ currency } i18n={ i18n } useChartColors/> <DoughnutChartLegend labels={ labels } colors={ colors } values={ vals } percents={ percents } i18n={ i18n } useChartColors/>
</div> </div>
</div> </div>
</div> </div>
......
export default {
rating: {
id: "components.StatusChart.rating",
defaultMessage: "Rating {rating}"
},
}
\ No newline at end of file
export default {
draftLabel: {
id: "components.StatusChart.draftLabel",
defaultMessage: "Draft"
},
activeLabel: {
id: "components.StatusChart.activeLabel",
defaultMessage: "Active"
},
finishedLabel: {
id: "components.StatusChart.finishedLabel",
defaultMessage: "Finished"
},
overdueLabel: {
id: "components.StatusChart.overdueLabel",
defaultMessage: "Overdue"
},
}
\ No newline at end of file
...@@ -8,7 +8,7 @@ import { fetchStatsAction, fetchRatingsAction, selector } from './redux.js'; ...@@ -8,7 +8,7 @@ import { fetchStatsAction, fetchRatingsAction, selector } from './redux.js';
import { PageTitle, ActivityIndicator, Info, MessagePanel, SummaryPanel, ToolbarButton, Toolbar, ToolbarSection, ToolbarButtons, ToolbarRow, PageSwitcher } from 'lib/components'; import { PageTitle, ActivityIndicator, Info, MessagePanel, SummaryPanel, ToolbarButton, Toolbar, ToolbarSection, ToolbarButtons, ToolbarRow, PageSwitcher } from 'lib/components';
//components //components
import StatusChart from 'components/StatusChart'; import RatingPieChart from 'components/RatingPieChart';
import RatingBarChart from 'components/RatingBarChart'; import RatingBarChart from 'components/RatingBarChart';
import CopyrightInfo from 'components/CopyrightInfo'; import CopyrightInfo from 'components/CopyrightInfo';
import FetchedContent, { ErrorInfo } from 'components/FetchedContent'; import FetchedContent, { ErrorInfo } from 'components/FetchedContent';
...@@ -18,7 +18,6 @@ import { injectIntl } from 'react-intl'; ...@@ -18,7 +18,6 @@ import { injectIntl } from 'react-intl';
import { formatMoney, formatDate, formatNumber } from 'lib/i18n'; import { formatMoney, formatDate, formatNumber } from 'lib/i18n';
import { settingsSelector } from 'utils/settings'; import { settingsSelector } from 'utils/settings';
import { Doughnut, HorizontalBar } from 'react-chartjs-2';
import palette from 'utils/palette'; import palette from 'utils/palette';
import icons from 'constants/icons'; import icons from 'constants/icons';
import messages from './messages.js'; import messages from './messages.js';
...@@ -161,6 +160,25 @@ DashboardBarChart = connect(settingsSelector((state, props) => state.getIn(["hom ...@@ -161,6 +160,25 @@ DashboardBarChart = connect(settingsSelector((state, props) => state.getIn(["hom
DashboardBarChart = injectIntl(DashboardBarChart); DashboardBarChart = injectIntl(DashboardBarChart);
class DashboardPieChart extends Component {
render() {
let { data, status, i18n, intl, className } = this.props;
if (!data) {
data = {};
}
return (
<div>
{ status == "failed" ? <ErrorInfo /> : <RatingPieChart data={ data.values } empty={ !data.ratings } /> }
<ActivityIndicator show={ status == "pending" } type="overlay" />
</div>
); }
}
DashboardPieChart = connect(settingsSelector((state, props) => state.getIn(["home", "stats"]).toJS()), (dispatch) => ({}))(DashboardPieChart);
DashboardPieChart = injectIntl(DashboardPieChart);
class Home extends Component { class Home extends Component {
...@@ -235,6 +253,7 @@ class Home extends Component { ...@@ -235,6 +253,7 @@ class Home extends Component {
</div> </div>
<div className="p10"> <div className="p10">
<DashboardBarChart i18n={ i18n } onRefresh={ this.init }/> <DashboardBarChart i18n={ i18n } onRefresh={ this.init }/>
<DashboardPieChart i18n={ i18n } onRefresh={ this.init }/>
</div> </div>
</div> </div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment