UI design + Ratings block
This commit is contained in:
parent
e7551b0599
commit
c0e78bee2d
Binary file not shown.
|
@ -19,6 +19,7 @@ urlpatterns = [
|
|||
path('books/genres', books_per_genre_per_month),
|
||||
path('books/genres/count', countGenres),
|
||||
path('books/ratings', avg_ratings_per_month),
|
||||
path('books/ratings/count', countRatings),
|
||||
path('books/authors', books_per_author),
|
||||
path('books/countries', books_per_country),
|
||||
|
||||
|
|
|
@ -296,6 +296,30 @@ def avg_ratings_per_month(request):
|
|||
"rating": int(row['rating'])
|
||||
})
|
||||
|
||||
return Response(data)
|
||||
else:
|
||||
return Response("No year header included")
|
||||
|
||||
@api_view(['GET'])
|
||||
def countRatings(request):
|
||||
datayear = request.META.get('HTTP_YEAR')
|
||||
|
||||
if datayear:
|
||||
data = []
|
||||
|
||||
# Get CSV file with book data
|
||||
df = filterData(getBooksData(), request.META.get('HTTP_YEAR'))
|
||||
|
||||
countratings = df.groupby('rating')['rating'].count().reset_index(name="count")
|
||||
countratings = countratings.sort_values(by='rating', ascending=False)
|
||||
|
||||
for index, row in countratings.iterrows():
|
||||
|
||||
data.append({
|
||||
"rating": int(row['rating']),
|
||||
"count": int(row['count'])
|
||||
})
|
||||
|
||||
return Response(data)
|
||||
else:
|
||||
return Response("No year header included")
|
Binary file not shown.
Binary file not shown.
|
@ -107,4 +107,17 @@ export const getAvgRatings = (year) => {
|
|||
.then(data => {
|
||||
return data;
|
||||
})
|
||||
}
|
||||
|
||||
export const getRatingsCount = (year) => {
|
||||
return fetch('/api/books/ratings/count', {
|
||||
"method": "GET",
|
||||
"headers": {
|
||||
"year": year
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
return data;
|
||||
})
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
import React, { Component } from 'react';
|
||||
import { getGenresCount, getRatingsCount } from "./Data.js";
|
||||
import { initDoughnut } from "./Charts.js";
|
||||
|
||||
export default class Ratings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
ratings: [],
|
||||
totalRatings: 0
|
||||
}
|
||||
}
|
||||
|
||||
getComponentData() {
|
||||
getRatingsCount(this.props.year).then(ratings => {
|
||||
|
||||
var total = 0;
|
||||
|
||||
ratings.forEach(rating => {
|
||||
total += rating.count;
|
||||
})
|
||||
|
||||
var ratingsArray = {
|
||||
5: 0,
|
||||
4: 0,
|
||||
3: 0,
|
||||
2: 0,
|
||||
1: 0
|
||||
}
|
||||
|
||||
for(var i = 5; i > 0; i--){
|
||||
ratings.forEach(rating => {
|
||||
if(rating.rating === i){
|
||||
ratingsArray[i] = rating.count
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log(Object.entries(ratingsArray));
|
||||
|
||||
this.setState({
|
||||
ratings: Object.entries(ratingsArray),
|
||||
totalRatings: total
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getComponentData();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.year !== this.props.year) {
|
||||
this.getComponentData();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="ratings">
|
||||
<span className="block_name">Waarderingen ({this.state.totalRatings})</span>
|
||||
<table id="DataTable" className="table responsive nowrap" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>percentage</th>
|
||||
<th>aantal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{this.state.ratings.map((rating) => {
|
||||
var ratingstars = '';
|
||||
var rating_percentage = rating[1] / this.state.totalRatings * 100;
|
||||
|
||||
console.log(rating[1], this.state.totalRatings);
|
||||
|
||||
if (rating[0]) {
|
||||
for (var i = 0; i < rating[0]; i++) {
|
||||
ratingstars += "<i class='fas fa-star'></i>";
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<tr>
|
||||
<td style={{width: '120px'}} className='book_rating' dangerouslySetInnerHTML={{__html: ratingstars}}></td>
|
||||
<td style={{width: '257px'}}>
|
||||
<div className="progress">
|
||||
<div className="progress-bar progress-bar-striped" role="progressbar" style={{ width: rating_percentage + '%' }} aria-valuenow={rating_percentage} aria-valuemin="0" aria-valuemax="100">
|
||||
{/* <div className="progress-bar-number">{rating_percentage}%</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{rating[1]}</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ function Sidebar(){
|
|||
<li><NavLink to="/"><i className="fa fa-chart-bar"></i> Dashboard</NavLink></li>
|
||||
<li><NavLink to="/booklist"><i className="fas fa-book"></i> Boekenlijst</NavLink></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
|
|
@ -6,8 +6,9 @@ import Countries from "../components/Countries";
|
|||
import Pages from "../components/Pages";
|
||||
import Genres from "../components/Genres";
|
||||
import Books from "../components/Books";
|
||||
import { getReadingYears } from "../components/Data.js";
|
||||
import { getRatingsCount, getReadingYears } from "../components/Data.js";
|
||||
import Sidebar from "../components/Sidebar";
|
||||
import Ratings from "../components/Ratings";
|
||||
|
||||
export default class Dashboard extends Component {
|
||||
|
||||
|
@ -31,6 +32,10 @@ export default class Dashboard extends Component {
|
|||
readingYears: data
|
||||
})
|
||||
})
|
||||
|
||||
getRatingsCount(this.state.year).then(data => {
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -65,14 +70,15 @@ export default class Dashboard extends Component {
|
|||
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-9">
|
||||
<div className="col-md-8">
|
||||
<Books year={this.state.year} />
|
||||
<Pages year={this.state.year} />
|
||||
</div>
|
||||
|
||||
<div className="col-md-3">
|
||||
<div className="col-md-4">
|
||||
<Countries year={this.state.year} />
|
||||
<Genres year={this.state.year} />
|
||||
<Ratings year={this.state.year} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Binary file not shown.
|
@ -47,7 +47,7 @@ html, body{
|
|||
height:600px !important;
|
||||
}
|
||||
|
||||
.books-per-month, .genresPercent, .books-per-country, .book{
|
||||
.books-per-month, .genresPercent, .books-per-country, .book, .ratings{
|
||||
background: #ffffff;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 0px 1px rgb(0 0 0 / 3%);
|
||||
|
@ -85,7 +85,7 @@ html, body{
|
|||
.sidebar{
|
||||
background: #363a53;
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.sidebar .menu-item{
|
||||
|
@ -108,6 +108,7 @@ html, body{
|
|||
|
||||
.sidebar ul {
|
||||
padding: 0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
|
@ -120,21 +121,19 @@ html, body{
|
|||
.sidebar ul li a {
|
||||
color: #a9b7d0;
|
||||
text-decoration: none;
|
||||
padding: 15px 0;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding: 12px 15px;
|
||||
display:block;
|
||||
width:100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.sidebar ul li:has(> a.active) {
|
||||
background: #333f54 !important;
|
||||
border-bottom: solid 3px #8066ee;
|
||||
}
|
||||
|
||||
.sidebar ul li a.active {
|
||||
color: #ffffff;
|
||||
background: rgba(0,0,0,0.2) !important;
|
||||
background: rgba(0,0,0,0.3) !important;
|
||||
}
|
||||
|
||||
.sidebar ul li a.active i {
|
||||
|
@ -148,7 +147,7 @@ html, body{
|
|||
display: inline-block;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
margin-right: 1.125rem;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.books-stats{
|
||||
|
@ -268,7 +267,7 @@ html, body{
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.progress{
|
||||
.stat-block .progress{
|
||||
background: #f8f8fa;
|
||||
height: 50px;
|
||||
border: solid 2px #efefef;
|
||||
|
@ -279,14 +278,20 @@ html, body{
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
.progress-bar{
|
||||
.stat-block .progress-bar{
|
||||
background-color: #8066ee;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
border-right: solid 2px #333;
|
||||
}
|
||||
|
||||
.progress-bar-number{
|
||||
.progress-bar{
|
||||
background-color: #8066ee;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.stat-block .progress-bar-number{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
background: #333;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
/*! For license information please see src_components_Data_js.js.LICENSE.txt */
|
||||
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([["src_components_Data_js"],{"./src/components/Data.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 */ "getAllBooks": () => (/* binding */ getAllBooks),\n/* harmony export */ "getAvgRatings": () => (/* binding */ getAvgRatings),\n/* harmony export */ "getBooksPerYearPerGenres": () => (/* binding */ getBooksPerYearPerGenres),\n/* harmony export */ "getChallenge": () => (/* binding */ getChallenge),\n/* harmony export */ "getCountries": () => (/* binding */ getCountries),\n/* harmony export */ "getGenresCount": () => (/* binding */ getGenresCount),\n/* harmony export */ "getReadingYears": () => (/* binding */ getReadingYears),\n/* harmony export */ "getShortestLongestBook": () => (/* binding */ getShortestLongestBook),\n/* harmony export */ "getStats": () => (/* binding */ getStats)\n/* harmony export */ });\nconst getAllBooks = () => {\n return fetch(\'/api/books\', {\n "method": "GET"\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getStats = year => {\n return fetch(\'/api/books/stats\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getChallenge = year => {\n return fetch(\'/api/books/challenge\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getReadingYears = () => {\n return fetch(\'/api/books/years\', {\n "method": "GET"\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getCountries = year => {\n return fetch(\'/api/books/countries\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getShortestLongestBook = year => {\n return fetch(\'/api/books/pages/stats\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getBooksPerYearPerGenres = year => {\n return fetch(\'/api/books/genres\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getGenresCount = year => {\n return fetch(\'/api/books/genres/count\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getAvgRatings = year => {\n return fetch(\'/api/books/ratings\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\n\n//# sourceURL=webpack://frontend/./src/components/Data.js?')}}]);
|
||||
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([["src_components_Data_js"],{"./src/components/Data.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 */ "getAllBooks": () => (/* binding */ getAllBooks),\n/* harmony export */ "getAvgRatings": () => (/* binding */ getAvgRatings),\n/* harmony export */ "getBooksPerYearPerGenres": () => (/* binding */ getBooksPerYearPerGenres),\n/* harmony export */ "getChallenge": () => (/* binding */ getChallenge),\n/* harmony export */ "getCountries": () => (/* binding */ getCountries),\n/* harmony export */ "getGenresCount": () => (/* binding */ getGenresCount),\n/* harmony export */ "getRatingsCount": () => (/* binding */ getRatingsCount),\n/* harmony export */ "getReadingYears": () => (/* binding */ getReadingYears),\n/* harmony export */ "getShortestLongestBook": () => (/* binding */ getShortestLongestBook),\n/* harmony export */ "getStats": () => (/* binding */ getStats)\n/* harmony export */ });\nconst getAllBooks = () => {\n return fetch(\'/api/books\', {\n "method": "GET"\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getStats = year => {\n return fetch(\'/api/books/stats\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getChallenge = year => {\n return fetch(\'/api/books/challenge\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getReadingYears = () => {\n return fetch(\'/api/books/years\', {\n "method": "GET"\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getCountries = year => {\n return fetch(\'/api/books/countries\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getShortestLongestBook = year => {\n return fetch(\'/api/books/pages/stats\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getBooksPerYearPerGenres = year => {\n return fetch(\'/api/books/genres\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getGenresCount = year => {\n return fetch(\'/api/books/genres/count\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getAvgRatings = year => {\n return fetch(\'/api/books/ratings\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\nconst getRatingsCount = year => {\n return fetch(\'/api/books/ratings/count\', {\n "method": "GET",\n "headers": {\n "year": year\n }\n }).then(response => response.json()).then(data => {\n return data;\n });\n};\n\n//# sourceURL=webpack://frontend/./src/components/Data.js?')}}]);
|
File diff suppressed because one or more lines are too long
|
@ -26,6 +26,10 @@
|
|||
!*** ./src/components/Genres.js ***!
|
||||
\**********************************/
|
||||
|
||||
/*!***********************************!*\
|
||||
!*** ./src/components/Ratings.js ***!
|
||||
\***********************************/
|
||||
|
||||
/*!***********************************!*\
|
||||
!*** ./src/components/Sidebar.js ***!
|
||||
\***********************************/
|
||||
|
|
Loading…
Reference in New Issue