Skip to content

Commit

Permalink
US-GraficoTotalAudienciasPeriodo (#192)
Browse files Browse the repository at this point in the history
* #191 - Adding total rooms chart for default period

* #191 - Adding functions to get data for year and month period

* #191 - Adding tests

* #191 - Adding background functions to filter data

* #191 - Adding filter of data and changing chart

* #191 - Improving user experience with feedback message

* #191 - Refactoring code to follow stylesheet

* #191 - Fixing warnings

* #191 - Updating messages
  • Loading branch information
joaopaulonsoares authored Aug 31, 2021
1 parent 8f3a423 commit a1eb27b
Show file tree
Hide file tree
Showing 13 changed files with 757 additions and 192 deletions.
396 changes: 216 additions & 180 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 @@ -20,9 +20,11 @@
"axios": "^0.21.1",
"babel-plugin-styled-components": "^1.12.0",
"date-fns": "^2.21.2",
"deepcopy": "^2.1.0",
"immutability-helper": "^3.1.1",
"next": "10.0.6",
"next-images": "^1.7.0",
"npm": "^7.11.1",
"npm": "^7.21.0",
"nprogress": "^0.2.0",
"polished": "^4.1.2",
"prop-types": "^15.7.2",
Expand Down
47 changes: 47 additions & 0 deletions src/components/ChartTotalRoomsWithFilter/auxfunctions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const deepcopy = require('deepcopy');

/* eslint-disable import/prefer-default-export */
async function removeColumnOfMatrix(matrix, indexToRemove) {
await matrix.forEach((column) => {
column.splice(indexToRemove, 1);
});

return matrix;
}

async function removeColumnsOfMatrix(matrix, column) {
const columnsTitle = matrix[0];
let i = 1; // Start in 1 because the 0 corresponds to the dates matrix index
let filteredMatrix = [];

if (!columnsTitle) {
return matrix;
}

while (i < columnsTitle.length) {
if (columnsTitle[i] === column) {
// eslint-disable-next-line no-await-in-loop
filteredMatrix = await removeColumnOfMatrix(matrix.slice(), i);
}
i += 1;
}

return filteredMatrix;
}

export async function filterDataOfTotalRoomsMatrix(matrix, colsToRemove) {
let i = 0;
let filteredMatrix = deepcopy(matrix);

if (colsToRemove.length === 0) {
return filteredMatrix;
}

while (i < colsToRemove.length) {
// eslint-disable-next-line no-await-in-loop
filteredMatrix = await removeColumnsOfMatrix(filteredMatrix, colsToRemove[i]);
i += 1;
}

return filteredMatrix;
}
229 changes: 229 additions & 0 deletions src/components/ChartTotalRoomsWithFilter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable react/require-default-props */
import React, { useState } from 'react';
import PropTypes from 'prop-types';

import {
Box, Radio, RadioGroup, FormControlLabel, FormControl, CircularProgress,
makeStyles, Typography, Checkbox,
} from '@material-ui/core';

import { withStyles } from '@material-ui/core/styles';
import TableDarkTheme from '../TableDarkTheme/index';
import ChartDataFrame from '../ChartDataFrame/index';
import GoogleChart from '../Charts/GoogleChart';
import convertArrayToJSON from '../../utils/format/convertArrayToJson/index';
import { filterDataOfTotalRoomsMatrix } from './auxfunctions';

const useStyles = makeStyles(() => ({
messageTypograph: {
fontFamily: 'Open Sans',
fontSize: '1.5rem',
fontWeight: 'bold',
paddingTop: '20px',
color: '#DA7F0B',
},
}));

const CustomRadio = withStyles({
root: {
color: 'white',
borderColor: 'blue',
'&$checked': {
color: 'white',
},
},
checked: {},
})((props) => <Radio color="default" {...props} />);

const WhiteCheckbox = withStyles({
root: {
color: 'white',
'&$checked': {
color: 'white',
},
},
checked: {},
})((props) => <Checkbox color="default" {...props} />);

function FormControlRadioOptions(props) {
const { handleChange, currentValue } = props;

return (
<FormControl component="fieldset">
<RadioGroup row aria-label="position" role="radio" name="position" defaultValue="chart" onChange={handleChange} value={currentValue}>
<FormControlLabel
value="chart"
control={<CustomRadio tabIndex="0" value="chart" color="primary" inputProps={{ 'aria-label': 'Botão de Seleção visualizar dados em gráfico' }} />}
label="Ver como Gráfico"
/>
<FormControlLabel
value="table"
control={<CustomRadio tabIndex="-1" value="table" color="primary" inputProps={{ 'aria-label': 'Botão de Seleção visualizar dados em tabela' }} />}
label="Ver como Tabela"
/>
</RadioGroup>
</FormControl>
);
}

function getColumns(data) {
return Object(data[0]).map((key) => ({
name: key,
selector: key,
sortable: true,
center: true,
}));
}

export default function ChartTotalRoomsWithFilter(props) {
const classes = useStyles();
const {
isLoaded, title, data, chartType, chartOptions, exportData,
apiLastUpdate, tool, height, apiUrl,
} = props;
const defaultData = data;
const columns = getColumns(data);
const [wayOfVisualizeData, setWayOfVisualizeData] = useState('chart');
const convertDataToJson = convertArrayToJSON(data);
const [columnsToNotShow, setColumnsToNotShow] = useState([]);
const [dataToShow, setDataToShow] = useState(data);

async function handleShowColumsChange(event) {
let columnsToNotBeShow = [];

if ((columnsToNotShow).includes(event.target.name)) { // Para passar a mostrar
// eslint-disable-next-line max-len
columnsToNotBeShow = columnsToNotBeShow.filter((column) => column === event.target.name);
setColumnsToNotShow(columnsToNotBeShow);
const tempDataToShow = await filterDataOfTotalRoomsMatrix(defaultData, columnsToNotBeShow);
setDataToShow(tempDataToShow);
} else { // Para passar a não mostrar
columnsToNotBeShow = ([...columnsToNotShow, event.target.name]);
setColumnsToNotShow(columnsToNotBeShow);
if (columnsToNotBeShow.length < 3) {
const tempDataToShow = await filterDataOfTotalRoomsMatrix(defaultData, columnsToNotBeShow);
setDataToShow(tempDataToShow);
}
}
}

function handleWayOfVisualizeDataChange(e) {
if (e.target.value === 'table') {
setWayOfVisualizeData('table');
} else {
setWayOfVisualizeData('chart');
}
}

return (
<ChartDataFrame
height={height}
title={title}
listView
exportData={exportData}
download
align="center"
apiUrl={apiUrl}
apiLastUpdate={apiLastUpdate}
tool={tool}
>
<div style={{ width: '100%' }}>
{isLoaded ? (
<>
<Box display="flex" flexDirection="row-reverse">
<FormControlRadioOptions
handleChange={handleWayOfVisualizeDataChange}
value={wayOfVisualizeData}
/>
</Box>
<>
{(wayOfVisualizeData === 'chart') ? (
<>
<Box height={height}>
{(columnsToNotShow.length !== 3) ? (
<GoogleChart
chartType={chartType}
data={dataToShow}
options={chartOptions}
/>
) : (
<Box display="flex" alignItems="center" justifyContent="center" width="100%" height="100%">
<Typography component="p" className={classes.messageTypograph}>
Selecione uma ou mais das opções abaixo para visualizar o gráfico.
</Typography>
</Box>
)}

</Box>
<Box width="100%" display="flex" justifyContent="center">
<FormControlLabel
control={<WhiteCheckbox checked={!(columnsToNotShow).includes('Canceladas')} onChange={handleShowColumsChange} name="Canceladas" />}
label="Canceladas"
/>
<FormControlLabel
control={<WhiteCheckbox checked={!(columnsToNotShow).includes('Realizadas')} onChange={handleShowColumsChange} name="Realizadas" />}
label="Realizadas"
/>
<FormControlLabel
control={<WhiteCheckbox checked={!(columnsToNotShow).includes('Total')} onChange={handleShowColumsChange} name="Total" />}
label="Total"
/>
</Box>
</>
) : (
<Box width="100%">
<TableDarkTheme
data={convertDataToJson}
columns={columns}
theme="darkLAB"
highlightOnHover
pointerOnHover
pagination
paginationRowsPerPageOptions={[5, 10, (data.length - 1)]}
defaultSortAsc={false}
/>
</Box>
)}
</>
</>
) : (
<Box display="flex" alignItems="center" justifyContent="center" width="100%" height="100%">
<CircularProgress color="secondary" />
</Box>
)}
</div>
</ChartDataFrame>
);
}

FormControlRadioOptions.propTypes = {
handleChange: PropTypes.func,
currentValue: PropTypes.string,
};

ChartTotalRoomsWithFilter.propTypes = {
isLoaded: PropTypes.bool,
title: PropTypes.string,
data: PropTypes.node,
chartType: PropTypes.string,
chartOptions: PropTypes.object,
exportData: PropTypes.array,
apiLastUpdate: PropTypes.string,
tool: PropTypes.string,
height: PropTypes.string,
apiUrl: PropTypes.string,
};

ChartTotalRoomsWithFilter.defaultProps = {
isLoaded: false,
title: 'Title',
data: {},
chartType: '',
chartOptions: {},
exportData: [],
apiLastUpdate: 'Carregando',
tool: '',
height: '35vh',
apiUrl: process.env.NEXT_PUBLIC_EDEMOCRACIA_SWAGGER_URL,
};
3 changes: 2 additions & 1 deletion src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AlertCachedData } from './Alert/index';
import ChartAndReport from './ChartAndReport/index';
import ChartDataFrame from './ChartDataFrame/index';
import ChartTotalRoomsWithFilter from './ChartTotalRoomsWithFilter/index';
import GoogleChart from './Charts/GoogleChart';
import Footer from './Footer/index';
import Header from './Header/index';
Expand All @@ -17,5 +18,5 @@ export {
AlertCachedData, ChartAndReport, ChartDataFrame, GoogleChart, Footer,
Header, NoDataForSelectedPeriod, RankingTable, SectionHeader,
SubSectionHeader, TableDarkTheme, ToolTip, TotalFrame,
AlertDataConsolidateInterval,
AlertDataConsolidateInterval, ChartTotalRoomsWithFilter,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
getRoomTotalsChartDataByDay, getRoomTotalsChartDataByMonth, getRoomTotalsChartDataByYear,
} from '../computeTotalRooms';

import * as apisMock from '../../../../mocks/audiencias/index';

describe('Test getRoomTotalsChartDataByDay function', () => {
const testMonth = 4;
const testYear = 2021;

test('getRoomTotalsChartDataByDay return data with 30 days(april)', async () => {
const resultArray = await getRoomTotalsChartDataByDay(
testMonth, testYear, apisMock.roomsApiMock.DAILY.results,
);
expect(resultArray.length).toBe(30);
});

test('getRoomTotalsChartDataByDay return data with 31 days(may)', async () => {
const resultArray = await getRoomTotalsChartDataByDay(
(testMonth + 1), testYear, apisMock.roomsApiMock.DAILY.results,
);
expect(resultArray.length).toBe(31);
});
});

describe('Test getRoomTotalsChartDataByMonth function', () => {
const testYear = 2021;

test('getRoomTotalsChartDataByMonth return data with 12 months', async () => {
const resultArray = await getRoomTotalsChartDataByMonth(
testYear, apisMock.roomsApiMock.MONTHLY.results,
);

expect(resultArray).not.toBe(null);
expect(resultArray.length).not.toBe(1);
expect(resultArray.length).toBe(12);
});

test('getRoomTotalsChartDataByMonth catch with undefined values', async () => {
const resultArray = await getRoomTotalsChartDataByMonth(
testYear, undefined,
);
expect(resultArray.length).toBe(0);
});
});

describe('Test getRoomTotalsChartDataByYear function', () => {
test('getRoomTotalsChartDataByYear return data with 6 years', async () => {
const resultArray = await getRoomTotalsChartDataByYear(
apisMock.roomsApiMock.YEARLY.results,
);
expect(resultArray).not.toBe(null);
expect(resultArray.length).not.toBe(1);
expect(resultArray[0][0]).toBe('2016');
expect(resultArray.length).toBe(6);
});

test('getRoomTotalsChartDataByYear catch with undefined values', async () => {
const resultArray = await getRoomTotalsChartDataByYear(
undefined,
);
expect(resultArray.length).toBe(0);
});
});
Loading

0 comments on commit a1eb27b

Please sign in to comment.