+
+
+
+ {translate('menu.userRatings')}
+
+
+
+ {userName}
+
+
+ {typeLabel} ·{' '}
+ }
+ emptyIcon={}
+ />
+
+
+
+
+ {loading && }
+ {error && {error}}
+ {items && items.length === 0 && (
+ {translate('userRatings.noItemsFound')}
+ )}
+ {items && items.length > 0 && (
+
+ {items.map((item) => {
+ const albumId = type === 'album' ? item.id : item.albumId
+ return (
+
+
+
+
+
+
+ )
+ })}
+
+ )}
+
+
+
+ )
+}
+
+export default UserRatingItems
diff --git a/ui/src/userRatings/UserRatings.jsx b/ui/src/userRatings/UserRatings.jsx
new file mode 100644
index 000000000..4402387bc
--- /dev/null
+++ b/ui/src/userRatings/UserRatings.jsx
@@ -0,0 +1,255 @@
+import React, { useEffect, useState } from 'react'
+import {
+ Card,
+ CardContent,
+ CircularProgress,
+ Divider,
+ Tab,
+ Tabs,
+ Typography,
+ makeStyles,
+} from '@material-ui/core'
+import Rating from '@material-ui/lab/Rating'
+import StarIcon from '@material-ui/icons/Star'
+import StarBorderIcon from '@material-ui/icons/StarBorder'
+import PeopleIcon from '@material-ui/icons/People'
+import { useHistory } from 'react-router-dom'
+import { Title, useTranslate } from 'react-admin'
+import httpClient from '../dataProvider/httpClient'
+import { REST_URL } from '../consts'
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ padding: theme.spacing(2),
+ },
+ userCard: {
+ marginBottom: theme.spacing(3),
+ },
+ userName: {
+ marginBottom: theme.spacing(1),
+ },
+ totalLabel: {
+ color: theme.palette.primary.main,
+ fontWeight: 'bold',
+ },
+ table: {
+ width: '100%',
+ borderCollapse: 'collapse',
+ },
+ row: {
+ '&:nth-child(even)': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ },
+ ratingCell: {
+ width: 60,
+ textAlign: 'right',
+ paddingRight: theme.spacing(1),
+ color: theme.palette.primary.main,
+ fontWeight: 'bold',
+ whiteSpace: 'nowrap',
+ },
+ countCell: {
+ width: 50,
+ textAlign: 'right',
+ paddingRight: theme.spacing(1),
+ fontWeight: 'bold',
+ whiteSpace: 'nowrap',
+ },
+ barCell: {
+ padding: `${theme.spacing(0.5)}px ${theme.spacing(1)}px`,
+ },
+ barOuter: {
+ height: 20,
+ borderRadius: 3,
+ overflow: 'hidden',
+ backgroundColor: theme.palette.action.selected,
+ minWidth: 4,
+ },
+ barInner: {
+ height: '100%',
+ borderRadius: 3,
+ minWidth: 4,
+ transition: 'width 0.4s ease',
+ },
+ starsCell: {
+ width: 110,
+ paddingLeft: theme.spacing(1),
+ },
+ emptyMsg: {
+ color: theme.palette.text.secondary,
+ fontStyle: 'italic',
+ marginTop: theme.spacing(1),
+ },
+}))
+
+const ratingColor = (rating) => {
+ if (rating >= 4) return '#69c76f'
+ if (rating >= 3) return '#b8c750'
+ if (rating >= 2) return '#d4a843'
+ return '#c75050'
+}
+
+const ALL_RATINGS = [5, 4, 3, 2, 1]
+
+const RatingTable = ({ stats, label, userId, userName, type }) => {
+ const classes = useStyles()
+ const history = useHistory()
+ const translate = useTranslate()
+
+ const countMap = {}
+ let total = 0
+ ;(stats || []).forEach(({ rating, count }) => {
+ countMap[rating] = count
+ total += count
+ })
+
+ const maxCount = Math.max(...Object.values(countMap), 1)
+
+ return (
+