From b0008014f6d4661ae407b7f62ea2aca95a5344b7 Mon Sep 17 00:00:00 2001 From: Jordy van Zeeland Date: Fri, 30 Sep 2022 16:30:18 +0200 Subject: [PATCH] UI design --- ras/api/models.py | 18 ++++ ras/api/static/books2.csv | 128 +++++++++++----------- ras/api/urls.py | 1 + ras/api/views.py | 55 ++++++++-- ras/frontend/src/App.js | 169 +++++++++++++++++++++++++++++- ras/frontend/static/js/main.js | 2 +- ras/frontend/templates/index.html | 73 ++++++++++++- 7 files changed, 369 insertions(+), 77 deletions(-) diff --git a/ras/api/models.py b/ras/api/models.py index 3a9cd5e..0c71571 100644 --- a/ras/api/models.py +++ b/ras/api/models.py @@ -22,4 +22,22 @@ class Books(models.Model): max_length=100, null=False, blank=False + ) + + pages = models.TextField( + max_length=100, + null=False, + blank=False + ) + + readed = models.TextField( + max_length=100, + null=False, + blank=False + ) + + rating = models.TextField( + max_length=100, + null=False, + blank=False ) \ No newline at end of file diff --git a/ras/api/static/books2.csv b/ras/api/static/books2.csv index 0c51108..a4c0e86 100644 --- a/ras/api/static/books2.csv +++ b/ras/api/static/books2.csv @@ -1,65 +1,65 @@ book;author;genre;pages;readed;rating -Omnia in Omnibus;Lisa Pennings;Sciencefiction;166;05-2013;4 -Het leven van Pi;Yann Martel;Roman;317;10-2020;4 -Ze komt nooit meer terug;Hans Koppel;Thriller;220;10-2020;5 -Vriendschapsverzoek;Laura Marshall;Thriller;368;10-2020;4 -De analist;John Katzenbach;Thriller;518;11-2020;4 -Komt een vrouw bij de hacker;Maria Genova;Thriller;224;11-2020;4 -Niemand hoort het;Linwood Barclay;Thriller;304;11-2020;5 -Lift;Linwood Barclay;Thriller;480;11-2020;3 -Kijk niet weg;Linwood Barclay;Thriller;400;12-2020;5 -Het duistere net;Carmen Mola;Thriller;415;12-2020;5 -De 50/50-moorden;Steve Mosby;Thriller;344;12-2020;3 -Zonder een woord;Linwood Barclay;Thriller;368;01-2021;5 -Geen veilige plek;Linwood Barclay;Thriller;368;01-2021;3 -Op slot;Chris McGeorge;Thriller;320;01-2021;5 -Alles is eventueel / 1408;Stephen King;Thriller;462;02-2021;3 -Waarom je niet zomaar moet stemmen waar je ouders op stemmen;Titia Hoogendoorn&Nienke Schuitemaker;Non-fictie;125;02-2021;4 -Geloof je ogen;Linwood Barclay;Thriller;384;02-2021;4 -Voor ik ga slapen;SJ Watson;Thriller;333;03-2021;5 -Echo;Tamara Geraeds;Thriller;280;03-2021;5 -Niemand vertellen;Harlan Coben;Thriller;302;03-2021;4 -Ik zie je;Michael Berg;Thriller;320;04-2021;4 -Toevluchtsoord;Jerome Loubry;Thriller;355;04-2021;5 -In een donker donker bos;Ruth Ware;Thriller;320;04-2021;3 -Een voor een;Ruth Ware;Thriller;368;04-2021;4 -Vrees het ergste;Linwood Barclay;Thriller;400;05-2021;4 -Het poppenhuis;W.R. Dantz;Thriller;270;05-2021;3 -Malorie;Josh Malerman;Thriller;320;05-2021;4 -Opgejaagd;Gabriel Bergmoser;Thriller;256;06-2021;4 -Reset;Blake Crouch;Thriller;352;06-2021;4 -Wacht maar af;Loes den Hollander;Thriller;300;06-2021;4 -De Russische connectie;Gerrit Barendrecht;Thriller;320;06-2021;4 -Wat jij niet ziet;M.J. Arlidge;Thriller;95;07-2021;3 -Het ongeluk;Linwood Barclay;Thriller;382;07-2021;4 -Slapen in een zee van sterren;Christopher Paolini;Sciencefiction;880;07-2021;2 -Tik Tak;Chris McGeorge;Thriller;320;07-2021;4 -Gegijzeld;Clare Mackintosh;Thriller;397;08-2021;5 -Eindbestemming;Marjolein van der Gaag&Marcella Kleine;Thriller;158;08-2021;4 -Een kille rilling;Bernard Minier;Thriller;582;09-2021;4 -De nachtdienst;Esther Verhoef;Thriller;365;09-2021;5 -Kiekeboe;Chris McGeorge;Thriller;352;10-2021;3 -Noorderlicht;Mariska Overman;Thriller;313;10-2021;4 -De kleine getuige;Jilliane Hoffman;Thriller;368;11-2021;4 -De marathon;Stephen King;Thriller;261;11-2021;4 -Het appartement;Tatiana de Rosnay;Roman;215;11-2021;4 -De intrigant;Patricia Snel;Thriller;189;12-2021;4 -Een schuldig huis;Robert Goddard;Thriller;384;12-2021;5 -Te koop;Eva Monte;Thriller;350;12-2021;3 -Prison Break S1B1;Paul T. Scheuring;Thriller;221;01-2022;5 -Prison Break S1B2;Ed van Eeden;Thriller;272;01-2022;4 -Prison Break S1B3;Paul T. Scheuring;Thriller;285;01-2022;4 -Herfstlied;Simone van der Vlugt;Thriller;277;02-2022;5 -De gastenlijst;Lucy Foley;Thriller;352;02-2022;2 -Anomalie;Herve le Tellier;Thriller;302;02-2022;2 -Prison Break S2B1;Paul T. Scheuring;Thriller;207;03-2022;4 -Prison Break S2B2;Paul T. Scheuring;Thriller;205;03-2022;4 -Prison Break S2B3;Paul T. Scheuring;Thriller;245;03-2022;4 -Ik weet je wachtwoord;Daniel Verlaan;Non-fictie;347;04-2022;5 -De vrouw die een jaar in bed ging liggen;Sue Townsend;Roman;368;04-2022;3 -Moord in de bibliotheek;Agatha Christie;Thriller;256;04-2022;3 -Geestdrift;Daniel Hecht;Thriller;509;05-2022;1 -Moord in de Orient Expres;Agatha Christie;Thriller;222;05-2022;4 -Crash;Jack Bowman;Thriller;344;05-2022;3 -Erken mij;Esther Verhoef;Thriller;91;06-2022;4 -Gestrand;Sarah Goodwin;Thriller;352;06-2022;5 +Omnia in Omnibus;Lisa Pennings;Sciencefiction;166;2013-05-01;4 +Het leven van Pi;Yann Martel;Roman;317;2020-10-01;4 +Ze komt nooit meer terug;Hans Koppel;Thriller;220;2020-10-01;5 +Vriendschapsverzoek;Laura Marshall;Thriller;368;2020-10-01;4 +De analist;John Katzenbach;Thriller;518;2020-11-01;4 +Komt een vrouw bij de hacker;Maria Genova;Thriller;224;2020-11-01;4 +Niemand hoort het;Linwood Barclay;Thriller;304;2020-11-01;5 +Lift;Linwood Barclay;Thriller;480;2020-11-01;3 +Kijk niet weg;Linwood Barclay;Thriller;400;2020-12-01;5 +Het duistere net;Carmen Mola;Thriller;415;2020-12-01;5 +De 50/50-moorden;Steve Mosby;Thriller;344;2020-12-01;3 +Zonder een woord;Linwood Barclay;Thriller;368;2021-01-01;5 +Geen veilige plek;Linwood Barclay;Thriller;368;2021-01-01;3 +Op slot;Chris McGeorge;Thriller;320;2021-01-01;5 +Alles is eventueel / 1408;Stephen King;Thriller;462;2021-02-01;3 +Waarom je niet zomaar moet stemmen waar je ouders op stemmen;Titia Hoogendoorn&Nienke Schuitemaker;Non-fictie;125;2021-02-01;4 +Geloof je ogen;Linwood Barclay;Thriller;384;2021-02-01;4 +Voor ik ga slapen;SJ Watson;Thriller;333;2021-03-01;5 +Echo;Tamara Geraeds;Thriller;280;2021-03-01;5 +Niemand vertellen;Harlan Coben;Thriller;302;2021-03-01;4 +Ik zie je;Michael Berg;Thriller;320;2021-04-01;4 +Toevluchtsoord;Jerome Loubry;Thriller;355;2021-04-01;5 +In een donker donker bos;Ruth Ware;Thriller;320;2021-04-01;3 +Een voor een;Ruth Ware;Thriller;368;2021-04-01;4 +Vrees het ergste;Linwood Barclay;Thriller;400;2021-05-01;4 +Het poppenhuis;W.R. Dantz;Thriller;270;2021-05-01;3 +Malorie;Josh Malerman;Thriller;320;2021-05-01;4 +Opgejaagd;Gabriel Bergmoser;Thriller;256;2021-06-01;4 +Reset;Blake Crouch;Thriller;352;2021-06-01;4 +Wacht maar af;Loes den Hollander;Thriller;300;2021-06-01;4 +De Russische connectie;Gerrit Barendrecht;Thriller;320;2021-06-01;4 +Wat jij niet ziet;M.J. Arlidge;Thriller;95;2021-07-01;3 +Het ongeluk;Linwood Barclay;Thriller;382;2021-07-01;4 +Slapen in een zee van sterren;Christopher Paolini;Sciencefiction;880;2021-07-01;2 +Tik Tak;Chris McGeorge;Thriller;320;2021-07-01;4 +Gegijzeld;Clare Mackintosh;Thriller;397;2021-08-01;5 +Eindbestemming;Marjolein van der Gaag&Marcella Kleine;Thriller;158;2021-08-01;4 +Een kille rilling;Bernard Minier;Thriller;582;2021-09-01;4 +De nachtdienst;Esther Verhoef;Thriller;365;2021-09-01;5 +Kiekeboe;Chris McGeorge;Thriller;352;2021-10-01;3 +Noorderlicht;Mariska Overman;Thriller;313;2021-10-01;4 +De kleine getuige;Jilliane Hoffman;Thriller;368;2021-11-01;4 +De marathon;Stephen King;Thriller;261;2021-11-01;4 +Het appartement;Tatiana de Rosnay;Roman;215;2021-11-01;4 +De intrigant;Patricia Snel;Thriller;189;2021-12-01;4 +Een schuldig huis;Robert Goddard;Thriller;384;2021-12-01;5 +Te koop;Eva Monte;Thriller;350;2021-12-01;3 +Prison Break S1B1;Paul T. Scheuring;Thriller;221;2022-01-01;5 +Prison Break S1B2;Ed van Eeden;Thriller;272;2022-01-01;4 +Prison Break S1B3;Paul T. Scheuring;Thriller;285;2022-01-01;4 +Herfstlied;Simone van der Vlugt;Thriller;277;2022-02-01;5 +De gastenlijst;Lucy Foley;Thriller;352;2022-02-01;2 +Anomalie;Herve le Tellier;Thriller;302;2022-02-01;2 +Prison Break S2B1;Paul T. Scheuring;Thriller;207;2022-03-01;4 +Prison Break S2B2;Paul T. Scheuring;Thriller;205;2022-03-01;4 +Prison Break S2B3;Paul T. Scheuring;Thriller;245;2022-03-01;4 +Ik weet je wachtwoord;Daniel Verlaan;Non-fictie;347;2022-04-01;5 +De vrouw die een jaar in bed ging liggen;Sue Townsend;Roman;368;2022-04-01;3 +Moord in de bibliotheek;Agatha Christie;Thriller;256;2022-04-01;3 +Geestdrift;Daniel Hecht;Thriller;509;2022-05-01;1 +Moord in de Orient Expres;Agatha Christie;Thriller;222;2022-05-01;4 +Crash;Jack Bowman;Thriller;344;2022-05-01;3 +Erken mij;Esther Verhoef;Thriller;91;2022-06-01;4 +Gestrand;Sarah Goodwin;Thriller;352;2022-06-01;5 diff --git a/ras/api/urls.py b/ras/api/urls.py index 0e2ae9e..42cb452 100644 --- a/ras/api/urls.py +++ b/ras/api/urls.py @@ -3,5 +3,6 @@ from .views import * urlpatterns = [ path('books/genres', books_per_genre_per_month), + path('books/genres/count', countGenres), path('ratings', avg_ratings_per_month) ] \ No newline at end of file diff --git a/ras/api/views.py b/ras/api/views.py index 6d878cb..89b18a2 100644 --- a/ras/api/views.py +++ b/ras/api/views.py @@ -1,13 +1,22 @@ +from sqlite3 import connect from rest_framework.decorators import api_view from rest_framework.response import Response from .models import Books import pandas as pd +import ras.settings +from sqlalchemy import create_engine from .serializers import BooksSerializer from django.db.models import Q from django.templatetags.static import static import json +def getBooksData(): + engine = create_engine('mysql+mysqldb://' + ras.settings.DATABASES['default']['USER'] + ':' + ras.settings.DATABASES['default']['PASSWORD'] + '@' + ras.settings.DATABASES['default']['HOST'] + ':3306/' + ras.settings.DATABASES['default']['NAME']) + df = pd.read_sql('SELECT * FROM api_books', engine, parse_dates={'readed': {'format': '%m-%Y'}}) + + return df + @api_view(['GET']) def books_per_genre_per_month(request): @@ -16,16 +25,18 @@ def books_per_genre_per_month(request): if datayear: data = [] - - # Get CSV file with book data - df = pd.read_csv("api/static/books2.csv", encoding = "utf-8", header = 0, sep=';') + + df = getBooksData() + + df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d') + df['readed'] = df['readed'].dt.strftime('%m-%Y') # Filter data on year df = df.where(df['readed'].str.contains(datayear)) # Filter array on genre and date booksPerMonth = df.groupby(['genre','readed'])['genre'].count().reset_index(name="count") - booksPerMonth = booksPerMonth.sort_values(by='readed') + booksPerMonth = booksPerMonth.sort_values(by=['readed', 'count'], ascending=False) for index, row in booksPerMonth.iterrows(): data.append({ @@ -46,7 +57,10 @@ def avg_ratings_per_month(request): data = [] # Get CSV file with book data - df = pd.read_csv("api/static/books2.csv", encoding = "utf-8", header = 0, sep=';') + df = getBooksData() + + df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d') + df['readed'] = df['readed'].dt.strftime('%m-%Y') # Filter data on year df = df.where(df['readed'].str.contains(datayear)) @@ -62,4 +76,33 @@ def avg_ratings_per_month(request): return Response(data) else: - return Response("No year header included") \ No newline at end of file + return Response("No year header included") + +@api_view(['GET']) +def countGenres(request): + datayear = request.META.get('HTTP_YEAR') + + if datayear: + data = [] + + # Get CSV file with book data + df = getBooksData() + + df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d') + df['readed'] = df['readed'].dt.strftime('%m-%Y') + + df = df.where(df['readed'].str.contains(datayear)) + genres = df.groupby('genre')['genre'].count().reset_index(name="count") + genres = genres.sort_values(by='count', ascending=False) + + for index, row in genres.iterrows(): + + data.append({ + "genre": row['genre'], + "count": int(row['count']) + }) + + return Response(data) + else: + return Response("No year header included") + diff --git a/ras/frontend/src/App.js b/ras/frontend/src/App.js index 4f1a1e2..8b77db6 100644 --- a/ras/frontend/src/App.js +++ b/ras/frontend/src/App.js @@ -3,6 +3,56 @@ import React, { Component } from "react"; export default class App extends Component { constructor(props) { super(props); + this.state = { + year: new Date().getFullYear(), + } + + this.yearsArray = []; + } + + changeYear(event) { + this.setState({ + year: event.target.value + }) + } + + initDoughnut(data) { + + var labels = []; + var counts = []; + + data.forEach((count) => { + if (!labels.includes(count.genre)) { + labels.push(count.genre) + } + + counts.push(count.count) + }) + + $("canvas#chartGenres").remove(); + $("div.genresPercent").append(''); + + var ctx = document.getElementById("chartGenres"); + var myChart = new Chart(ctx, { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ + label: '# of Tomatoes', + data: counts, + backgroundColor: [ + '#696ffc', '#7596fa', '#92adfe', '#abc0ff' + ], + borderWidth: 3, + borderColor: '#1f2940' + }] + }, + options: { + //cutoutPercentage: 40, + responsive: true, + + } + }); } initChart(data, ratings, year) { @@ -99,6 +149,9 @@ export default class App extends Component { ---------------------------------- */ + $("canvas#chart").remove(); + $("div.books-per-month").append(''); + new Chart(document.getElementById('chart'), { type: 'bar', data: { @@ -142,9 +195,43 @@ export default class App extends Component { }); } + componentDidUpdate() { + fetch('/api/books/genres', { + "method": "GET", + "headers": { + "year": this.state.year + } + }) + .then(response => response.json()) + .then(books => { + fetch('/api/ratings', { + "method": "GET", + "headers": { + "year": this.state.year + } + }) + .then(response => response.json()) + .then(ratings => { + this.initChart(books, ratings, this.state.year); + }) + + }) + + fetch('/api/books/genres/count', { + "method": "GET", + "headers": { + "year": this.state.year + } + }) + .then(response => response.json()) + .then(data => { + this.initDoughnut(data); + }) + } + componentDidMount() { - var currentyear = new Date("2021-09-29").getFullYear() + var currentyear = this.state.year ? this.state.year : new Date().getFullYear() fetch('/api/books/genres', { "method": "GET", @@ -162,19 +249,93 @@ export default class App extends Component { }) .then(response => response.json()) .then(ratings => { - console.log(ratings); this.initChart(books, ratings, currentyear); }) }) + + fetch('/api/books/genres/count', { + "method": "GET", + "headers": { + "year": this.state.year + } + }) + .then(response => response.json()) + .then(data => { + this.initDoughnut(data); + }) } render() { return ( -
-
+
+ +
+
+
+
+
+
+ Jaar: + +
+
+ +
+
+
+
+ +
+
+
+
+
+ Boeken + 17 + -20% +
+
+
+
+ Bladzijdes + 512 + +5% +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ ) } } \ No newline at end of file diff --git a/ras/frontend/static/js/main.js b/ras/frontend/static/js/main.js index 60fa102..48f4a95 100644 --- a/ras/frontend/static/js/main.js +++ b/ras/frontend/static/js/main.js @@ -1,2 +1,2 @@ /*! For license information please see main.js.LICENSE.txt */ -(()=>{"use strict";var __webpack_modules__={"./src/App.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ App)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n\nclass App extends react__WEBPACK_IMPORTED_MODULE_0__.Component {\n constructor(props) {\n super(props);\n }\n\n initChart(data, ratings, year) {\n /*\r\n ----------------------------------\r\n Books per month per genre\r\n ----------------------------------\r\n */\n var genres = [];\n var colors = [\'#696ffc\', \'#7596fa\', \'#92adfe\', \'#abc0ff\'];\n var dataSet = [];\n data.forEach(book => {\n if (!genres.includes(book.genre)) {\n genres.push(book.genre);\n }\n });\n\n if (genres && genres.length > 0) {\n genres.forEach((genre, index) => {\n var genreData = [];\n\n for (var i = 0; i < 12; i++) {\n genreData[i] = 0;\n\n if (i + 1 < 10) {\n var month = "0" + (i + 1);\n } else {\n month = i + 1;\n }\n\n for (var j = 0; j < data.length; j++) {\n if (data && data[j] && data[j].readed == month + \'-\' + year) {\n if (data[j].genre == genre) {\n genreData[i] = data[j].count;\n }\n }\n }\n }\n\n dataSet.push({\n label: genre,\n data: genreData,\n backgroundColor: colors[index],\n order: 2\n });\n });\n }\n /*\r\n ----------------------------------\r\n Avarage ratings per month\r\n ----------------------------------\r\n */\n\n\n var avgRatings = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n\n for (var j = 0; j < 12; j++) {\n if (j < 9) {\n var month = "0" + (j + 1);\n } else {\n month = j + 1;\n }\n\n for (var i = 0; i < ratings.length; i++) {\n if (ratings[i].date == month + \'-\' + year) {\n avgRatings[j] = ratings[i].rating;\n }\n }\n }\n\n dataSet.push({\n label: \'Gemiddelde beoordeling\',\n data: avgRatings,\n backgroundColor: \'#ffa500\',\n borderColor: \'#ffa500\',\n tension: 0.4,\n type: \'line\',\n order: 1\n });\n /*\r\n ----------------------------------\r\n Stacked bar chart\r\n ----------------------------------\r\n */\n\n new Chart(document.getElementById(\'chart\'), {\n type: \'bar\',\n data: {\n labels: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"],\n datasets: dataSet\n },\n options: {\n responsive: true,\n showTooltips: true,\n legend: {\n display: true\n },\n interaction: {\n mode: \'index\'\n },\n scales: {\n x: {\n ticks: {\n beginAtZero: true,\n color: "white"\n },\n stacked: true\n },\n y: {\n ticks: {\n beginAtZero: true,\n stepSize: 1,\n color: "white"\n },\n stacked: true\n }\n },\n plugins: {\n legend: {\n labels: {\n color: "white"\n }\n }\n }\n }\n });\n }\n\n componentDidMount() {\n var currentyear = new Date("2021-09-29").getFullYear();\n fetch(\'/api/books/genres\', {\n "method": "GET",\n "headers": {\n "year": currentyear\n }\n }).then(response => response.json()).then(books => {\n fetch(\'/api/ratings\', {\n "method": "GET",\n "headers": {\n "year": currentyear\n }\n }).then(response => response.json()).then(ratings => {\n console.log(ratings);\n this.initChart(books, ratings, currentyear);\n });\n });\n }\n\n render() {\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {\n className: "books-per-month"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {\n id: "chart"\n })));\n }\n\n}\n\n//# sourceURL=webpack://frontend/./src/App.js?')},"./src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{eval('__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ "./node_modules/react-dom/index.js");\n/* harmony import */ var _App__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./App */ "./src/App.js");\n\n\n\nreact_dom__WEBPACK_IMPORTED_MODULE_1__.render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_App__WEBPACK_IMPORTED_MODULE_2__["default"], null), document.getElementById(\'app\'));\n\n//# sourceURL=webpack://frontend/./src/index.js?')},"./node_modules/react-dom/cjs/react-dom.development.js":(__unused_webpack_module,exports,__webpack_require__)=>{eval("/**\n * @license React\n * react-dom.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\n\nif (true) {\n (function() {\n\n 'use strict';\n\n/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */\nif (\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart ===\n 'function'\n) {\n __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());\n}\n var React = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\nvar Scheduler = __webpack_require__(/*! scheduler */ \"./node_modules/scheduler/index.js\");\n\nvar ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n\nvar suppressWarning = false;\nfunction setSuppressWarning(newSuppressWarning) {\n {\n suppressWarning = newSuppressWarning;\n }\n} // In DEV, calls to console.warn and console.error get replaced\n// by calls to these methods by a Babel plugin.\n//\n// In PROD (or in packages without access to React internals),\n// they are left as they are instead.\n\nfunction warn(format) {\n {\n if (!suppressWarning) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n printWarning('warn', format, args);\n }\n }\n}\nfunction error(format) {\n {\n if (!suppressWarning) {\n for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n args[_key2 - 1] = arguments[_key2];\n }\n\n printWarning('error', format, args);\n }\n }\n}\n\nfunction printWarning(level, format, args) {\n // When changing this logic, you might want to also\n // update consoleWithStackDev.www.js as well.\n {\n var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n var stack = ReactDebugCurrentFrame.getStackAddendum();\n\n if (stack !== '') {\n format += '%s';\n args = args.concat([stack]);\n } // eslint-disable-next-line react-internal/safe-string-coercion\n\n\n var argsWithFormat = args.map(function (item) {\n return String(item);\n }); // Careful: RN currently depends on this prefix\n\n argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it\n // breaks IE9: https://github.com/facebook/react/issues/13610\n // eslint-disable-next-line react-internal/no-production-logging\n\n Function.prototype.apply.call(console[level], console, argsWithFormat);\n }\n}\n\nvar FunctionComponent = 0;\nvar ClassComponent = 1;\nvar IndeterminateComponent = 2; // Before we know whether it is function or class\n\nvar HostRoot = 3; // Root of a host tree. Could be nested inside another node.\n\nvar HostPortal = 4; // A subtree. Could be an entry point to a different renderer.\n\nvar HostComponent = 5;\nvar HostText = 6;\nvar Fragment = 7;\nvar Mode = 8;\nvar ContextConsumer = 9;\nvar ContextProvider = 10;\nvar ForwardRef = 11;\nvar Profiler = 12;\nvar SuspenseComponent = 13;\nvar MemoComponent = 14;\nvar SimpleMemoComponent = 15;\nvar LazyComponent = 16;\nvar IncompleteClassComponent = 17;\nvar DehydratedFragment = 18;\nvar SuspenseListComponent = 19;\nvar ScopeComponent = 21;\nvar OffscreenComponent = 22;\nvar LegacyHiddenComponent = 23;\nvar CacheComponent = 24;\nvar TracingMarkerComponent = 25;\n\n// -----------------------------------------------------------------------------\n\nvar enableClientRenderFallbackOnTextMismatch = true; // TODO: Need to review this code one more time before landing\n// the react-reconciler package.\n\nvar enableNewReconciler = false; // Support legacy Primer support on internal FB www\n\nvar enableLazyContextPropagation = false; // FB-only usage. The new API has different semantics.\n\nvar enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber\n\nvar enableSuspenseAvoidThisFallback = false; // Enables unstable_avoidThisFallback feature in Fizz\n// React DOM Chopping Block\n//\n// Similar to main Chopping Block but only flags related to React DOM. These are\n// grouped because we will likely batch all of them into a single major release.\n// -----------------------------------------------------------------------------\n// Disable support for comment nodes as React DOM containers. Already disabled\n// in open source, but www codebase still relies on it. Need to remove.\n\nvar disableCommentsAsDOMContainers = true; // Disable javascript: URL strings in href for XSS protection.\n// and client rendering, mostly to allow JSX attributes to apply to the custom\n// element's object properties instead of only HTML attributes.\n// https://github.com/facebook/react/issues/11347\n\nvar enableCustomElementPropertySupport = false; // Disables children for