From e84da6ac6e6597de7994ad3a688592be54129b92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Picolo?= <jpp18@inf.ufpr.br>
Date: Thu, 25 Feb 2021 09:27:12 -0300
Subject: [PATCH] Adds table and mockup route

---
 src/App.js                                 |   4 +-
 src/components/Pages/OfferPageComponent.js |  19 +-
 src/components/TableComponent.js           | 327 ++++++++-------------
 src/css/TableComponent.scss                |  85 ++----
 src/data/groups.js                         |  27 +-
 5 files changed, 192 insertions(+), 270 deletions(-)

diff --git a/src/App.js b/src/App.js
index 23a3043..d80810e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -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;
diff --git a/src/components/Pages/OfferPageComponent.js b/src/components/Pages/OfferPageComponent.js
index 62c7536..d0ecdab 100644
--- a/src/components/Pages/OfferPageComponent.js
+++ b/src/components/Pages/OfferPageComponent.js
@@ -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>
     )
 }
diff --git a/src/components/TableComponent.js b/src/components/TableComponent.js
index eed78e1..a49c64a 100644
--- a/src/components/TableComponent.js
+++ b/src/components/TableComponent.js
@@ -1,221 +1,142 @@
 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)
-
-    useEffect(() => {
-        if (componentId === null) {
-            setComponentId('table' + 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]}}
+let ConsultHandler = new Consult();
+let componentId = null;
+let filtersEducation = null;
+let filtersLocation = null;
+let year = null;
 
-        ConsultHandler.getMultipleRoutes(description.route, setBaseData, setLoading, 'array', description.dims, [filtersEducation, filtersLocation, yearFilters, description.extraFilters], [], isMounted)
-
-        return () => { isMounted = false }
-    }, [description, filtersEducation, filtersLocation])
+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);
+
+    if (componentId === null) {
+        componentId = ConsultHandler.generateComponentId()
+    }
 
     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'
+        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],
+    // ]}
 
-                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)
+    useEffect(() => {
+        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);
             }
-            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;
+            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]) ;
                 }
-            })
-            formattedData.push(totalRow)
-
-            setData(formattedData)
-            setColumns(cols)
-        }
-    }, [loading, baseData, description])
-
-    useEffect(() => {
-        if (downloadingType !== false) {
-            downloadComponent(componentId, downloadingType).then(setDownloadingType(false))
-        }
-    }, [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;
             }
+            setFooterRow(final);
         }
 
-        let title = name + ', ' + description.years[0]
-        if (description.years && description.years.length === 2) title += ' - ' + description.years[1]
-        return title
-    }
-
-    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>
-                                    ))}
-                                </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} />
-                                ))}
-                            </BaseTable>
-                        </div>
-                    )}
-                </AutoResizer>
-
-                {description.notes.map((note, i) => (
-                    <p className="table-note" key={"note-" + i}>{note}</p>
-                ))}
-            </BlockUi>
+        <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>
+                            ))}
+                        </TableRow>
+                    </TableHead>
+                    <TableBody>
+                    {tableRows.map((row, idx) => (
+                        <TableRow key={idx}>
+                        {row.map((item, idxRow) => (
+                            <StyledTableCell key={idxRow}>{ item }</StyledTableCell>
+                        ))}
+                        </TableRow>
+                    ))}
+                    </TableBody>
+                    <TableFooter>
+                        <TableRow>
+                            {footerRow.map((header, idxHeader) => (
+                                <StyledTableCell key={idxHeader}>{ header }</StyledTableCell>
+                            ))}
+                        </TableRow>
+                    </TableFooter>
+                </Table>
+            </TableContainer>
+
+            <Grid className="source-container">
+                <p> { tableInfo.notes }</p>
+            </Grid>
+        </Grid>
     )
 }
 
diff --git a/src/css/TableComponent.scss b/src/css/TableComponent.scss
index 6315560..0f01b1b 100644
--- a/src/css/TableComponent.scss
+++ b/src/css/TableComponent.scss
@@ -1,56 +1,33 @@
-.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-container {
+        max-width: 96%;
+        margin: 2%;
+    
+        .MuiTableHead-root {
+            .MuiTableRow-root {
+                border-top-left-radius: 30px;
+                border-top-right-radius: 30px;
+            }
+        }
+    }
+    
+    .title-container {
+        font-size: 18px;
+        text-align: center;
+    }
 
-.table-title-container {
-    padding-top: 10px;
-    padding-bottom: 10px;
-}
+    .subtitle-container {
+        font-size: 16px;
+        text-align: center;
+        margin-top: -1%;
+    }
 
-.table-note {
-    font-size: 12px;
-    color: #5a5a5a;
-    line-height: 1.42;
-    padding: 5px 10px 5px 10px;
-    margin: 0;
-}
-
-.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;
-}
-
-.download-button:hover {
-    background-color:#eee;
-}
-
-.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
diff --git a/src/data/groups.js b/src/data/groups.js
index d75d8e3..7cd451b 100644
--- a/src/data/groups.js
+++ b/src/data/groups.js
@@ -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}},
                 }
             ],
-- 
GitLab