Skip to content
Snippets Groups Projects
Commit e84da6ac authored by jpp18's avatar jpp18
Browse files

Adds table and mockup route

parent 78e40009
Branches issue/722
No related tags found
No related merge requests found
......@@ -54,7 +54,7 @@ function App() {
<Route exact path={routes.formacao_licenciatura} render={props => <TrainingPageComponent {...props} />} />
<Route exact path={routes.formacao_pos_graduacao} render={props => <TrainingPageComponent {...props} />} />
<Route exact path={routes.nivel_formacao_docente} render={props => <TrainingPageComponent {...props} />} />
<Route exact path={routes.situacao_matricula} render={props => <OfferPageComponent {...props} />} />
<Route exact path={routes.situacao_matriculas} render={props => <OfferPageComponent {...props} />} />
<Route exact path={routes.contato} component={ContatoComponent} />
<Route exact path={routes.acessibilidade} component={AccessibilityComponent} />
<Route exact path={routes.mapa_site} component={SiteMapComponent} />
......@@ -65,5 +65,5 @@ function App() {
</Router>
);
}
//
export default App;
......@@ -27,6 +27,7 @@ import { getIndicator } from '../../data/groups';
import { getIndicatorsGroup } from '../../data/indicadores';
import MapComponent from '../Map/MapComponent';
import TableComponent from '../TableComponent';
import ExpandableGroupComponent from '../ExpandableGroupComponent';
import IndicatorsComponent from '../Dropdown/IndicatorsComponent';
import FiltersGroupComponent from '../Dropdown/FiltersGroupComponent';
......@@ -226,7 +227,7 @@ function OfferPageComponent(props) {
}
}
//const chartsDim = (indicator.chartsDim) ? indicator.chartsDim : routeDim
const groupInfo = getIndicator(path[2], indicatorName);
return (
<Grid container direction="column" className={`page-container ${contrastSet ? "high-contrast" : ""}`}>
{(filtersLoading === true || filtersLoading === undefined) ? null :
......@@ -259,7 +260,6 @@ function OfferPageComponent(props) {
currentindicador={indicator}
contrastSet={contrastSet}>
</FixedFiltersComponent>
{/* <SelectDimComponent setLocked={setMapBorderDimLocked} setDim={setMapBorderDim}></SelectDimComponent> */}
</Grid>
<Grid item xs={12} sm={12} md={12}>
<MapComponent
......@@ -283,7 +283,7 @@ function OfferPageComponent(props) {
<Grid item xs={12}>
{filtersLoading !== false ? null :
<ExpandableGroupComponent
groupInfo={getIndicator(path[2], indicatorName)}
groupInfo={groupInfo}
hashFilters={hashFilters}
location={chartLocation}
sideChart={true}
......@@ -298,12 +298,23 @@ function OfferPageComponent(props) {
{filtersLoading !== false ? null :
<ExpandableGroupComponent
groupInfo={getIndicator(path[2], indicatorName)}
groupInfo={groupInfo}
hashFilters={hashFilters}
contrastSet={contrastSet}
>
</ExpandableGroupComponent>
}
{filtersLoading !== false ? null :
groupInfo.tables.map((table, idx) => (
<TableComponent
hashFilters={hashFilters}
location={chartLocation}
tableInfo={table}
/>
))
}
</Grid>
)
}
......
import React, { useState, useEffect } from 'react';
import BaseTable, { Column, AutoResizer } from 'react-base-table'
import 'react-base-table/styles.css'
import Consult from './Consult'
import '../css/TableComponent.scss'
import BlockUi from 'react-block-ui';
import { Loader } from 'react-loaders';
import { downloadComponent } from '../data/shared'
import {
Grid, withStyles,
Table, TableBody,
TableCell, TableContainer,
TableHead, TableRow,
TableFooter, Paper
} from '@material-ui/core';
let ConsultHandler = new Consult()
import Consult from './Consult';
import '../css/TableComponent.scss';
function TableComponent(props) {
const { description, filtersEducation, filtersLocation } = props
const [componentId, setComponentId] = useState(null)
let ConsultHandler = new Consult();
let componentId = null;
let filtersEducation = null;
let filtersLocation = null;
let year = null;
function TableComponent(props) {
const { tableInfo, hashFilters, location } = props;
const [tableRows, setTableRows] = useState([]);
const [footerRow, setFooterRow] = useState([]);
const [tableData, setTableData] = useState([]);
const [loadingData, setLoadingData] = useState(true);
useEffect(() => {
if (componentId === null) {
setComponentId('table' + ConsultHandler.generateComponentId())
componentId = ConsultHandler.generateComponentId()
}
}, [componentId])
const [data, setData] = useState([])
const [baseData, setBaseData] = useState([])
const [columns, setColumns] = useState([])
const [loading, setLoading] = useState(true)
const [downloadingType, setDownloadingType] = useState(false) // Used to extend table before downloading it as image
useEffect(() => {
let isMounted = true // flag denoutes mounted status
const yearFilters = {min_year: {value: description.years[0]}, max_year: {value: description.years.length > 1 ? description.years[1] : description.years[0]}}
ConsultHandler.getMultipleRoutes(description.route, setBaseData, setLoading, 'array', description.dims, [filtersEducation, filtersLocation, yearFilters, description.extraFilters], [], isMounted)
return () => { isMounted = false }
}, [description, filtersEducation, filtersLocation])
useEffect(() => {
if (loading === false) {
let formattedData = []
let cols = [{ 'title': description.dimTitle, 'key': 'name', 'id': undefined, 'total': 0}]
if (description.extraDimCols) { // Single dim uses 2+ collumns, like in localoffer
description.extraDimCols.forEach((col) => {
cols.push({'title': [col.title], 'key': col.key})
})
}
for (let i = 0; i < description.route.length; i++) {
const result = baseData[i]
const dims = description.dims[i]
let dim1id = dims[0] + '_id'
let dim1name = dims[0] + '_name'
if (dims[0] === 'year') dim1id = dim1name = 'year'
let dim2id = dims[1] + '_id'
let dim2name = dims[1] + '_name'
if (dims[1] === 'year') dim2id = dim2name = 'year'
let totalCol = { 'title': 'Total', 'key': 'total' + i, 'total': 0}
result.forEach(d => {
let colKey = 't' + description.route[i] + d[dim2id]
let currentCol = cols.find(e => e.key === colKey)
if (!currentCol && dims.length > 1) {
currentCol = { 'title': d[dim2name], 'key': colKey, 'total': 0}
cols.push(currentCol)
}
const elementId1 = d[dim1id]
let row = formattedData.find(e => e.id === elementId1)
if (row === undefined) {
row = { 'name': d[dim1name], 'id': elementId1, 'total': 0 }
if (description.extraDimCols) { // Single dim uses 2+ collumns, like in localoffer
description.extraDimCols.forEach((col) => {
row[col.key] = d[col.key + '_name']
})
}
formattedData.push(row)
}
row[colKey] = d.total
row['total' + i] = (row['total' + i] !== undefined) ? row['total' + i] + d.total : d.total
totalCol.total += d.total
if (dims.length > 1 ) currentCol.total += d.total
})
cols.push(totalCol)
}
let totalRow = { 'name': 'Total', 'total': 0 }
const colWidthFactor = (description.extraDimCols) ? 1/(cols.length) : 1/(cols.length+1)
cols.forEach(c => {
totalRow.total += c.total
if (c.key !== 'name') {
totalRow[c.key] = (totalRow[c.key] !== undefined) ? totalRow[c.key] + c.total : c.total
c.widthFactor = colWidthFactor;
} else {
if (description.extraDimCols) c.widthFactor = colWidthFactor;
else c.widthFactor = colWidthFactor*2;
}
})
formattedData.push(totalRow)
setData(formattedData)
setColumns(cols)
}
}, [loading, baseData, description])
const tableYearFilters = { min_year: {value: tableInfo.years[0]}, max_year: {value: tableInfo.years[1]} }
filtersEducation = hashFilters.get[tableInfo.education]
filtersLocation = hashFilters.get.location
year = tableInfo.years[1]
ConsultHandler.fetchVar('tableData' + componentId, setTableData, setLoadingData, tableInfo.route, tableInfo.dim, [tableYearFilters, filtersLocation, filtersEducation, tableInfo.extraFilters]);
}, [filtersEducation, filtersLocation, tableInfo]);
// headers = {[
// "Dessert", "Calories", "Fat (g)", "Carbs (g)", "Protein"
// ]}
// rows = {[
// ['Frozen yoghurt', 159, 6.0, 24, 4.0],
// ['Ice cream sandwich', 237, 9.0, 37, 4.3],
// ['Eclair', 262, 16.0, 24, 6.0],
// ['Cupcake', 305, 3.7, 67, 4.3],
// ['Gingerbread', 356, 16.0, 49, 3.9],
// ]}
useEffect(() => {
if (downloadingType !== false) {
downloadComponent(componentId, downloadingType).then(setDownloadingType(false))
if(!loadingData) {
// Fill rows
let new_rows = []
let tableLength = tableData.length;
let i;
for(i = 0; i < tableLength; i++) {
let item = tableData[i];
let row = []
row.push(item["pos_training_name"]);
row.push(item["total"]);
new_rows.push(row);
}
}, [downloadingType])
function getTitle() {
let dataLocationDims = ['city', 'microregion', 'mesoregion', 'university']
if (description.education === 'basic') dataLocationDims.unshift('school')
else dataLocationDims.unshift('campi')
if (props.loading === true)
return 'Loading...'
const filters = props.filters
let name = "Paraná"
for (let i = 0; i < dataLocationDims.length; i++) {
const key = dataLocationDims[i]
if (filtersLocation[key] !== undefined && typeof filtersLocation[key].value === "number" && filtersLocation[key].value > 0) {
name = filtersLocation[key].data.find((e) => { return e.id === filtersLocation[key].value }).name
break;
setTableRows(new_rows)
// Fill footer
let size = tableInfo.headers.length;
let final = new Array(size).fill(0);
final[0] = "Total"
let j;
let n_rows = new_rows.length;
for(j = 0; j < n_rows; j++) {
let row = new_rows[j]
for(i = 1; i < size; i++) {
final[i] = parseInt(final[i]) + parseInt(row[i]) ;
}
}
let title = name + ', ' + description.years[0]
if (description.years && description.years.length === 2) title += ' - ' + description.years[1]
return title
setFooterRow(final);
}
function getCSV() {
let csv = [];
let row = [];
columns.forEach((col) => {
row.push(col.title);
});
csv.push(row.join(';'));
data.forEach((data) => {
row = [];
columns.forEach((col) => {
let value = data[col.key];
if (typeof value === 'undefined' || value === null) value = '';
value = value.toString().replace(/\"/g, '');
row.push(`"${value}"`);
});
csv.push(row.join(';'));
});
var link = document.createElement("a");
var file = new Blob([csv.join('\n')], {type: 'text/csv'});
var url = URL.createObjectURL(file);
link.href = url;
link.download = description.title + ".csv";
link.click();
}
}, [loadingData])
const StyledTableCell = withStyles(() => ({
head: {
backgroundColor: 'blue',
color: 'white',
},
footer: {
backgroundColor: 'blue',
color: 'white',
},
body: {
fontSize: 15,
},
}))(TableCell);
return (
(data === undefined) ? null :
<BlockUi id={componentId} tag="div" blocking={loading} loader={<Loader active type="ball-spin-fade-loader" color="deepskyblue"/>}>
<button className="download-button" onClick={() => setDownloadingType('pdf')}>PDF</button>
<button className="download-button" onClick={() => getCSV()}>CSV</button>
<div className="table-title-container">
<p className="table-title">{description.title}</p>
<p className="table-title">{getTitle()}</p>
</div>
<AutoResizer height={(data.length <= 12 || (downloadingType !== false && data.length < 500) ) ? (data.length * 40 + 50) : 530}>
{({ width, height }) => (
width = width-20,
<div className="table-container" key={'header-container' + description.title}>
{(description.route.length > 1 && columns.length > 0) ?
<BaseTable className="custom-column-header" width={width} height={50} rowHeight={40} key={description.title}>
<Column key='blank' width={width * columns[0].widthFactor} ></Column>
{description.tableTitles.map((title) => (
<Column key={title} width={(width - (width * columns[0].widthFactor))/description.route.length} title={title}></Column>
<Grid className={'root-container'} component={Paper}>
<Grid className="title-container">
<h4>{ tableInfo.title }</h4>
</Grid>
<Grid className="subtitle-container">
<p>{`${location} - ${year}`}</p>
</Grid>
<TableContainer className={'table-container'} component={Paper}>
<Table aria-label="customized table">
<TableHead>
<TableRow>
{tableInfo.headers.map((header, idxHeader) => (
<StyledTableCell key={idxHeader}>{ header }</StyledTableCell>
))}
</BaseTable>
: null}
<BaseTable width={width} height={height} data={data} rowHeight={40}>
{columns.map(col => (
<Column key={col.key} dataKey={col.key} width={width * col.widthFactor} title={col.title} />
</TableRow>
</TableHead>
<TableBody>
{tableRows.map((row, idx) => (
<TableRow key={idx}>
{row.map((item, idxRow) => (
<StyledTableCell key={idxRow}>{ item }</StyledTableCell>
))}
</BaseTable>
</div>
)}
</AutoResizer>
{description.notes.map((note, i) => (
<p className="table-note" key={"note-" + i}>{note}</p>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
{footerRow.map((header, idxHeader) => (
<StyledTableCell key={idxHeader}>{ header }</StyledTableCell>
))}
</BlockUi>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
<Grid className="source-container">
<p> { tableInfo.notes }</p>
</Grid>
</Grid>
)
}
......
.table-title {
color: #45D4E8;
margin-top: 0;
margin-bottom: 0;
/* font-family: "Univers LT Std";
font-style: bold; */
font-size: 17px;
/* min-width: max-content; */
text-align: center;
}
.root-container {
margin-bottom: 2%;
.table-title-container {
padding-top: 10px;
padding-bottom: 10px;
}
.table-container {
max-width: 96%;
margin: 2%;
.table-note {
font-size: 12px;
color: #5a5a5a;
line-height: 1.42;
padding: 5px 10px 5px 10px;
margin: 0;
.MuiTableHead-root {
.MuiTableRow-root {
border-top-left-radius: 30px;
border-top-right-radius: 30px;
}
.table-container {
padding: 10px;
}
.custom-column-header .BaseTable__header .BaseTable__header-row{
background-color: #ddd;
}
.download-button {
border: 1px solid #ccc !important;
border-bottom: 2px solid rgba(0,0,0,0.2) !important;
background-color: white;
border-bottom-left-radius: 4px !important;
border-bottom-right-radius: 4px !important;
border-radius: 4px;
display: inline-block;
cursor: pointer;
font-family: Arial;
font-size: 15px;
padding: 5px;
text-decoration:none;
margin: 5px;
.title-container {
font-size: 18px;
text-align: center;
}
.download-button:hover {
background-color:#eee;
.subtitle-container {
font-size: 16px;
text-align: center;
margin-top: -1%;
}
.download-button:active {
position: relative;
top: 1px;
.source-container {
margin-bottom: 4%;
margin-left: 2%;
color: grey;
font-size: 13px;
}
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ const groups = {
pieCharts: [
{
title: 'NÚMERO E PERCENTUAL DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO',
route: 'teacher',
route: ['teacher'],
dim: 'initial_training',
type: 'bar',
years: [2019, 2019],
......@@ -49,7 +49,7 @@ const groups = {
},
{
title: 'PERCENTUAL DE ADEQUAÇÃO DA FORMAÇÃO DOCENTE',
route: 'disciplines',
route: ['disciplines'],
dim: 'discipline',
type: 'bar',
years: [2012, 2019],
......@@ -61,7 +61,7 @@ const groups = {
pieCharts: [
{
title: 'PERCENTUAL DE ADEQUAÇÃO DA FORMAÇÃO DOCENTE',
route: 'disciplines',
route: ['disciplines'],
dim: 'discipline',
type: 'bar',
years: [2019, 2019],
......@@ -90,7 +90,7 @@ const groups = {
pieCharts: [
{
title: 'NÚMERO E PERCENTUAL DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO FORMAÇÃO',
route: 'teacher',
route: ['teacher'],
dim: 'licentiate_degree',
type: 'bar',
years: [2019, 2019],
......@@ -100,7 +100,7 @@ const groups = {
},
{
title: 'NÚMERO DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO',
route: 'teacher',
route: ['teacher'],
dim: 'licentiate_degree',
type: 'bar',
years: [2019, 2019],
......@@ -129,7 +129,7 @@ const groups = {
pieCharts: [
{
title: 'NÚMERO E PERCENTUAL DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO FORMAÇÃO',
route: 'teacher',
route: ['teacher'],
dim: 'pos_training',
type: 'bar',
years: [2019, 2019],
......@@ -162,12 +162,25 @@ const groups = {
pieCharts: [
{
title: 'NÚMERO E PERCENTUAL DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO FORMAÇÃO',
route: 'teacher',
route: ['teacher'],
dim: 'pos_training',
type: 'bar',
years: [2019, 2019],
notes: ['Fonte: Elaborado pelo Laboratório de Dados Educacionais a partir dos Microdados do Censo de Educação Superior/INEP 2018.'],
education: 'basic',
extraFilters: {state: {value: 41}},
}
],
tables: [
{
title: 'NÚMERO E PERCENTUAL DE DOCENTES SEGUNDO NÍVEL DE FORMAÇÃO FORMAÇÃO',
route: ['teacher'],
dim: 'pos_training',
type: 'bar',
years: [2019, 2019],
notes: ['Fonte: Elaborado pelo Laboratório de Dados Educacionais a partir dos Microdados do Censo de Educação Superior/INEP 2018.'],
education: 'basic',
headers: ['Disciplina', 'Quantidade'],
extraFilters: {state: {value: 41}},
}
],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment