Skip to content

Commit

Permalink
added a custom page with reports (#609)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Ovide committed Sep 11, 2020
1 parent bcf5e56 commit 07270cd
Show file tree
Hide file tree
Showing 7 changed files with 541 additions and 116 deletions.
370 changes: 304 additions & 66 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@
"@turf/turf": "latest",
"axios": "^0.20.0",
"blueimp-load-image": "^5.14.0",
"chart.js": "^2.9.3",
"classnames": "latest",
"dms2dec": "latest",
"firebase": "^7.19.1",
"firebase": "^7.20.0",
"localforage": "^1.9.0",
"lodash": "^4.17.20",
"mapbox-gl": "^1.12.0",
"md5": "^2.3.0",
"moment": "^2.27.0",
"prop-types": "^15.7.2",
"react": "latest",
"react-dom": "latest",
Expand Down
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,8 @@ class App extends Component {
{...props}
handleClose={history.goBack}
label={CustomPage.label}
geojson={this.state.geojson}
config={this.props.config}
/>
)}
/>
Expand Down
26 changes: 0 additions & 26 deletions src/custom/components/AnonymousPage.js

This file was deleted.

20 changes: 0 additions & 20 deletions src/custom/components/AnonymousPage.scss

This file was deleted.

219 changes: 219 additions & 0 deletions src/custom/components/ReportsPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import React, { Component } from "react";

import _ from "lodash";
import moment from "moment";
import Chart from "chart.js";

import { withStyles } from "@material-ui/core/styles";

// import StarsIcon from "@material-ui/icons/Stars";

import PageWrapper from "../../components/PageWrapper";

const styles = (theme) => ({});

class Reports extends Component {
constructor(props) {
super(props);
this.graphRef = React.createRef();
this.brandsRef = React.createRef();
this.categoryRef = React.createRef();
}

findCategoryLabel(branch, key) {
if (!branch) {
return null;
}
if (branch[key]) {
return branch[key].label;
} else {
let label = null;
_.find(branch, (child) => {
label = this.findCategoryLabel(child.children, key);
return !!label;
});

return label;
}
}

componentDidMount(months, ctx) {
const { geojson, config } = this.props;

if (geojson) {
const withCategories = _.filter(
geojson.features,
(f) => f.properties.categories
);

const brands = {};
const categories = {};
const days = {};
const months = {};
const years = {};

// reformat the info
_.forEach(withCategories, (entry) => {
const liveDate = entry.properties.moderated;
// const datePeriod = moment(liveDate).format("YYYYMMDD");
const day = moment(liveDate).startOf("day").toDate();
const month = moment(liveDate).startOf("month").toDate();
const year = moment(liveDate).startOf("year").toDate();

_.forEach(entry.properties.categories, (category) => {
const number = Number(category.number);

brands[category.brand] = brands[category.brand]
? brands[category.brand] + number
: number;

const catLabel = this.findCategoryLabel(
config.PHOTO_FIELDS.categories.data,
category.leafkey
);
categories[catLabel] = categories[catLabel]
? categories[catLabel] + number
: number;

days[day] = days[day] ? days[day] + number : number;
months[month] = months[month] ? months[month] + number : number;
years[year] = years[year] ? years[year] + number : number;
});
});

// draw by month
drawByMonth(months, this.graphRef.current);
drawByBrand(brands, this.brandsRef.current);
drawByCategory(categories, this.categoryRef.current);
}

// local functions
function drawByMonth(months, ctx) {
let sortedMonths = _.map(months, (amount, date) => {
return {
date: new Date(date),
amount,
};
});
sortedMonths = _.sortBy(sortedMonths, "date");

new Chart(ctx, {
type: "line",
data: {
labels: _.map(sortedMonths, (month) =>
moment(month.date).format("YYYY-MM")
),
datasets: [
{
label: "# of Pieces",
// data: _.map(sortedMonths, (month) => month.amount),
data: _.map(sortedMonths, (month) => ({
t: month.date,
y: month.amount,
})),
borderWidth: 1,
backgroundColor: _.map(sortedMonths, randomColor),
},
],
options: {
scales: {
xAxes: [
{
type: "time",
distribution: "linear",
time: {
unit: "month",
},
},
],
},
},
},
});
} // drawByMonth

function drawByBrand(brands, ctx) {
let sortedBrands = _.map(brands, (amount, brand) => {
return {
brand,
amount,
};
});
sortedBrands = _.sortBy(sortedBrands, "amount");
sortedBrands = _.reverse(sortedBrands);
const allTheRest = _.sumBy(
_.slice(sortedBrands, 10, sortedBrands.length),
"amount"
);
sortedBrands = _.slice(sortedBrands, 0, 10);
sortedBrands.push({ brand: "the others", amount: allTheRest });

new Chart(ctx, {
type: "bar",
data: {
labels: _.map(sortedBrands, (brand) => brand.brand),
datasets: [
{
label: "Worst brands",
data: _.map(sortedBrands, (brand) => brand.amount),
borderWidth: 1,
backgroundColor: _.map(sortedBrands, randomColor),
},
],
},
});
} // drawByMonth

function drawByCategory(categories, ctx) {
let sortedCategpries = _.map(categories, (amount, category) => {
return {
category,
amount,
};
});
sortedCategpries = _.sortBy(sortedCategpries, "amount");
sortedCategpries = _.reverse(sortedCategpries);
const allTheRest = _.sumBy(
_.slice(sortedCategpries, 8, sortedCategpries.length),
"amount"
);
sortedCategpries = _.slice(sortedCategpries, 0, 8);
sortedCategpries.push({ category: "the others", amount: allTheRest });

new Chart(ctx, {
type: "pie",
data: {
datasets: [
{
data: _.map(sortedCategpries, (category) => category.amount),
backgroundColor: _.map(sortedCategpries, randomColor),
},
],
labels: _.map(sortedCategpries, (category) => category.category),
},
options: {},
});
}

function randomColor() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return "rgb(" + r + "," + g + "," + b + ")";
}
}

render() {
const { classes, label, handleClose } = this.props;

return (
<PageWrapper label={label} handleClose={handleClose} hasLogo={false}>
<canvas ref={this.graphRef} />
<canvas ref={this.brandsRef} />
<canvas ref={this.categoryRef} />
</PageWrapper>
);
}
}

export default withStyles(styles)(Reports);
16 changes: 13 additions & 3 deletions src/custom/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import DashboardIcon from "@material-ui/icons/Dashboard";
import HelpIcon from "@material-ui/icons/Help";
import FeedbackIcon from "@material-ui/icons/Feedback";
import LibraryBooksIcon from "@material-ui/icons/LibraryBooks";
import AssessmentIcon from "@material-ui/icons/Assessment";

import _ from "lodash";

Expand All @@ -22,6 +23,7 @@ import MultiFields from "../components/PhotoPage/MultiFields";

import { data } from "./categories";
import { CUSTOM_STRING } from "./strings.js";
import ReportsPage from "./components/ReportsPage";

const primaryColor = styles.primary;
const secondaryColor = styles.secondary;
Expand Down Expand Up @@ -155,10 +157,10 @@ export default {
placeholder: "eg. 1",
regexValidation: "^[0-9]+",
},
multicategories: {
categories: {
component: MultiFields.MultiFieldsWithStyles,
nakedComponent: MultiFields.MultiFieldsOriginal,
name: "multicategories",
name: "categories",
placeholder: "Add photo categories",
data: data,
noOptionsMessage: "No more categories",
Expand Down Expand Up @@ -193,7 +195,15 @@ export default {
},
},
PAGES,
CUSTOM_PAGES: [],
CUSTOM_PAGES: [
{
path: "/reports",
page: ReportsPage,
label: "Reports",
icon: <AssessmentIcon />,
visible: (user, online) => true,
},
],
getStats,
SECURITY: {
UPLOAD_REQUIRES_LOGIN: true,
Expand Down

0 comments on commit 07270cd

Please sign in to comment.