<!DOCTYPE html>
<html lang="de">
<head>
    <title>EGENS Tool</title>
    
    <!-- Meta -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Parser for egens-CSV files">
    <meta name="author" content="David Mayer">
    <link rel="shortcut icon" href="favicon.png"> 
    <!-- Boostrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Boostrap Icons -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
    <!-- Boostrap 5 JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
    <!-- Papa Parser JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.2/papaparse.min.js"></script>
    <!-- jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
    <!-- DataTables Lib --> 
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs5/jszip-2.5.0/dt-1.13.1/b-2.3.3/b-html5-2.3.3/date-1.2.0/r-2.4.0/sl-1.5.0/datatables.min.css"/>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>
    <script type="text/javascript" src="https://cdn.datatables.net/v/bs5/jszip-2.5.0/dt-1.13.1/b-2.3.3/b-html5-2.3.3/date-1.2.0/r-2.4.0/sl-1.5.0/datatables.min.js"></script>
    <!-- DataTable Plugins -->
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js"></script>
    <script type="text/javascript" src="https://cdn.datatables.net/plug-ins/1.13.1/sorting/datetime-moment.js"></script>
    <!-- Chart.JS -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body class="p-3 overflow-hidden">      
    
    <div id="spinner" class="w-100 h-100 position-absolute justify-content-center align-items-center  bg-white" style="z-index: 999; top: 0; left: 0;">
        <div class="spinner-border text-primary" style="width: 4rem; height: 4rem; font-size: 1.5rem;" role="status">
            <span class="visually-hidden">Loading...</span>
        </div>        
    </div>
    <div class="modal fade" id="infoModal" tabindex="-1" aria-labelledby="infoModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h1 class="modal-title fs-5" id="modalLabel">Lädt...</h1>
            <button id="closeInfoModal1" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body pb-4 d-flex align-items-center justify-content-center">
            <div id="infoModalSpin" class="spinner-border text-primary" style="width: 2rem; height: 2rem; font-size: 1rem;" role="status">
                <span class="visually-hidden">Loading...</span>
            </div>
            <p id="infoModalCont" class="text-start p-0 m-0"></p>
          </div>
        </div>
      </div>
    </div>
    <div class="container bg-white rounded shadow p-4" style="z-index: 0;">
        <ul class="nav nav-pills nav-fill" id="myTab" role="tablist">
            <li class="nav-item">
                <a class="nav-link active" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="true">Übersicht</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" id="stats-tab" data-bs-toggle="tab" data-bs-target="#stats-tab-pane" type="button" role="tab" aria-controls="stats-tab-pane" aria-selected="false">Stats</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" id="home-tab" data-bs-toggle="tab" data-bs-target="#home-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="false">Upload</a>
            </li>
        </ul><!--//Nav Bar-->
        <div class="tab-content pt-5" id="myTabContent">
            <div class="tab-pane fade show active" id="profile-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">
                <div>
                    <div class="d-flex flex-row align-items-center justify-content-end gap-2 pb-2 ms-auto" style="max-width: 40rem;">
                        Zeitraum wählen:
                        <input class="form-control form-control-sm w-25" id="min" type="text" placeholder="Start Datum" style="z-index: 998;">
                        <input class="form-control form-control-sm w-25" id="max" type="text" placeholder="End Datum" style="z-index: 998;">    
                    </div>
                    <table id="resultTable" class="table table-striped w-100">
                    </table>
                </div>
            </div><!--//Tab-Panel Overview-->
            <div class="tab-pane fade" id="stats-tab-pane" role="tabpanel" aria-labelledby="stats-tab" tabindex="0">
                <div class="container text-center p-0 d-flex flex-row align-items-start">
                    <div class="w-50">
                        <canvas id="myChart"></canvas>
                    </div>
                    <div class="statsTable text-start w-50 d-flex justify-content-center">
                        <div class="w-75">
                            <div class="row">
                                <div class="col text-center pb-3">
                                    <h1>EGENS Zahlen</h1>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Durchläufe Gesamt:</p>
                                </div>
                                <div class="col text-center">
                                    <p><?= runs ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Negative Tests:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(69, 90, 100)"><?= ntests ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Positive Tests:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(75, 108, 129)"><?= ptests ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>NC:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(81, 126, 158)"><?= nc ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>PC:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(88, 145, 188)"><?= pc ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Invalide Tests:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(94, 163, 217)"><?= itests ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Invalide NC:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(100, 181, 246)"><?= inc ?></p>
                                </div>
                            </div>
                            <div class="row border-bottom">
                                <div class="col fw-bold">
                                    <p>Invalide PC:</p>
                                </div>
                                <div class="col text-center">
                                    <p style="color: rgb(114, 200, 246)"><?= ipc ?></p>
                                </div>
                            </div>
                            <div class="row ">
                                <div class="col fw-bold">
                                    <p>Retests:</p>
                                </div>
                                <div class="col text-center">
                                    <p><?= retests ?></p>
                                </div>
                            </div>
                        </div>
                    </div>
                        
                    </div>
                </div><!--//Tab-Panel Statistics-->
                <div class="tab-pane fade" id="home-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
                    <div class="d-flex flex-column">
                    <form id="uploadForm" class="w-100 h-100 d-flex flex-column justify-content-start align-items-center mx-auto needs-validation" style="max-width: 40rem;" novalidate>
                        <div class="w-100 mb-4">
                            <label class="form-label" for="formCSV">EGENS-CSV Datei</label>
                            <input class="form-control" id="formCSV" type="file" name="files" accept=".csv" required>
                            <div class="invalid-feedback">
                                Bitte wähle eine .CSV Datei aus.
                            </div><!--//Invalid val response-->
                        </div><!--//File Upload Wrapper-->         
                        <div class="w-100 mb-5">
                            <label class="form-label" for="locationSelect">Stations Standort</label>
                            <select class="form-select " id="locationSelect" aria-label=".form-select" required>
                                <option selected disabled value="">Wähle deinen Standort aus</option>
                                <option value="1">Berlin, alle Stationen</option>
                                <option value="2">Leipzig Airport (LEJ)</option>
                                <option value="3">München, Hauptbahnhof</option>
                            </select>
                            <div class="invalid-feedback">
                                Bitte wähle deinen Standort aus.
                            </div><!--//Invalid val response-->
                        </div><!--//Dropdown Wrapper-->
                        <button id="uploadBtn" class="btn btn-primary w-50 rounded-pill mt-4" type="submit">
                            Hochladen <span><i class="bi bi-cloud-upload"></i></span>
                        </button><!--//Submit form-->
                    </form><!--//Upload Form-->
                </div>
            </div><!--//Tab-Panel Upload-->
        </div><!--//Tab-Content Wrapper-->
    </div><!--//Container-sm-->
</body>
</html>
 
    html, body {height: 100%;}
    .logo {width: 100%; max-width: 2.8rem;}
    .btn-primary {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: .6rem;
    }
    .btn-primary span{font-size: 1.2rem;}
    .statsTable .col {margin-top: 1rem;}
    #resultTable_info {padding: 0;} 
    #spinner {display: flex;}
 
        //var SheetArr = JSON.parse(<?= sheetData ?>);
        //var SheetStats = JSON.parse(<?= sheetStats ?>);
        
        //Papa Parse
        var data;
        var resArray;
        function handleFileSelect(evt) {
            var file = evt.target.files[0];
            Papa.parse(file, {
                header: false,
                dynamicTyping: false,
                delimiter: "",
                delimitersToGuess: [',', '\n', ';', Papa.RECORD_SEP, Papa.UNIT_SEP],
                complete: function(results) {
                    data = results;
                    resArray = results.data;
                    resArray.shift();
                    resArray.pop();
                    console.log(resArray);
                }
            });
        }
        $(document).ready(function(){
            $("#formCSV").change(handleFileSelect);
            
            $('a[data-toggle="tab"]').on('shown.bs.tab', function(e){
                $($.fn.dataTable.tables(true)).DataTable()
                    .columns.adjust();
            });
        });
        $(window).on('load', function () {
            $('#spinner').fadeOut(400);
        }) 
        // DataTable setup
        var minDate, maxDate;
        $.fn.dataTable.ext.search.push(
            function( settings, data, dataIndex ) {
                var min = minDate.val();
                var max = maxDate.val();
                var date = new Date( data[9] );
        
                if (
                    ( min === null && max === null ) ||
                    ( min === null && date <= max ) ||
                    ( min <= date   && max === null ) ||
                    ( min <= date   && date <= max )
                ) {
                    return true;
                }
                return false;
            }
        );
        $(document).ready(function () {            
            minDate = new DateTime($('#min'), {
                format: 'YYYY-MM-DD HH:mm'
            });
            maxDate = new DateTime($('#max'), {
                format: 'YYYY-MM-DD HH:mm'
            });
            $.fn.dataTable.moment( 'YYYY-MM-DD HH:mm:ss' );
            var table = $('#resultTable').DataTable({
                scroller: true,
                scrollY: '50vh',
                scrollX: true,
                scrollCollapse: true,
                data: SheetArr,
                width: '100%',
                paging: true,
                language: {
                    url: 'https://cdn.datatables.net/plug-ins/1.13.1/i18n/de-DE.json'
                },
                order: [[9, 'desc']],
                dom:'<<"d-flex flex-row align-items-center justify-content-between pb-2" <"d-flex flex-row align-items-center gap-3" Bl> <"d-flex flex-row align-items-center gap-3" f <"refresh">> > <t> <"d-flex flex-row align-items-start justify-content-between pt-3" i p>>',
                lengthMenu: [ 10, 25, 50, 100 ],
                fnInitComplete: function(){
                    $('div.refresh').html('<a class="btn btn-light" href="https://admin.coronatest.de/pending-egens-tool" target=\"_top\">Refresh <i class="bi bi-arrow-clockwise"></i></a>');
                },
                buttons: [
                    { extend: 'csv', text: 'CSV <i class="bi bi-filetype-csv"></i>' },
                    { extend: 'excel', text: 'XLSX <i class="bi bi-filetype-xlsx"></i>' },
                    { extend: 'pdf', text: 'PDF <i class="bi bi-filetype-pdf"></i>' }
                ],
                columns: [
                    { 
                        title: 'Seriennummer', 
                    },
                    { 
                        title: 'Slot',
                    },
                    { 
                        title: 'Test',
                    },
                    {
                        title: 'ID',
                    },
                    { 
                        title: 'Ergebnis', 
                    },
                    {
                        title: 'FAM',
                    },
                    { 
                        title: 'VIC',
                    },
                    { 
                        title: 'ROX',
                    },
                    { 
                        title: 'CY5',
                    },
                    { 
                        title: 'Uhrzeit',
                    },
                ],
                columnDefs: [{
                    targets: '_all',
                    defaultContent: "<i class='text-muted' >N/A<i>"
                }],
            });
            
            // Refilter the table
            $('#min, #max').on('change', function () {
                table.draw();
            });
        });
        // Custom Bootstrap validation
        (() => {
            'use strict'
            // Fetch form
            const forms = document.querySelectorAll('.needs-validation')
            // Loop, prevent submission
            Array.from(forms).forEach(form => {
                form.addEventListener('submit', event => {
                    if (!form.checkValidity()) {
                        event.preventDefault()
                        event.stopPropagation()
                    }
                    form.classList.add('was-validated')
                }, false)
            })
        })()
        //Handle Submit
        document.querySelector("#uploadForm").addEventListener("submit", 
        function(e) {
            e.preventDefault();
            if ( $('#uploadForm')[0].checkValidity() ) {
              $("#infoModal").modal("show");
              $('#infoModalSpin').fadeIn(400);
              google.script.run.withSuccessHandler(function (value) {
                showModal(value);
              } ).uploadArray(resArray);
            } else {
              return
            }
        });
        //Upload Modal
        function showModal(value) {
          $('#uploadForm').get(0).reset() 
          $('#infoModalSpin').fadeOut(1);
          $("#infoModalCont").fadeIn(400);
          $("#modalLabel").text("Hinweis");          
          $("#infoModalCont").text(value);
        };
        $("#closeInfoModal1").click(function () {
          $("#infoModalCont").fadeOut(400);
          $("#modalLabel").text("Lädt...");
        });
        //Appscripts Reload
        function reLoad() {
            google.script.run
            .withSuccessHandler(function(url){
                window.open(url,'_top');
            })
            .getScriptURL();
        }
        //Chart.JS
        const ctx = document.getElementById('myChart');
        new Chart(ctx, {
            type: 'doughnut',
            data: {
                labels: ['Negative Tests', 'Positive Tests', 'NC', 'PC', 'Invalide Tests', 'Invalide NC', 'Invalide PC'],
                datasets: [{
                    data: SheetStats,
                                backgroundColor: ['rgb(69, 90, 100)','rgb(75, 108, 129)','rgb(81, 126, 158)','rgb(88, 145, 188)','rgb(94, 163, 217)','rgb(100, 181, 246)','rgb(114, 200, 246)'],
                    borderWidth: 1
                }]
            },
            options: {
                responsive: true,
                plugins: {
                    legend: {
                        position: 'none',
                    }
                }
            },
        });
11 errors 7 warnings
Line 36: Missing semicolon.
Line 136: 'arrow function syntax (=>)' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).
Line 136: Bad invocation.
Line 137: Missing semicolon.
Line 140: 'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).
Line 140: Missing semicolon.
Line 143: 'arrow function syntax (=>)' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).
Line 144: 'arrow function syntax (=>)' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).
Line 146: Missing semicolon.
Line 147: Missing semicolon.
Line 149: Missing semicolon.
Line 150: Missing semicolon.
Line 151: Missing semicolon.
Line 152: Missing semicolon.
Line 165: Missing semicolon.
Line 171: Missing semicolon.
Line 176: Unnecessary semicolon.
Line 193: 'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers