Stats Changes

Added more stuff to statistics page

Playback per hour page has a bug
This commit is contained in:
Thegan Govender
2023-04-02 22:15:28 +02:00
parent efe894f78a
commit 3a85fcdea3
17 changed files with 660 additions and 192 deletions

View File

@@ -16,11 +16,11 @@ if([_POSTGRES_USER,_POSTGRES_PASSWORD,_POSTGRES_IP,_POSTGRES_PORT].includes(unde
}
const development=true;
const _DEV_USER='jfstat';
const development=false;
const _DEV_USER='postgress';
const _DEV_PASSWORD = '123456';
const _DEV_IP='10.0.0.99';
const _DEV_PORT = 32778;
const _DEV_IP='localhost';
const _DEV_PORT = 5432;
const pool = new Pool({
user: (development ? _DEV_USER: _POSTGRES_USER),

View File

@@ -5,7 +5,7 @@
-- Dumped from database version 15.2 (Debian 15.2-1.pgdg110+1)
-- Dumped by pg_dump version 15.1
-- Started on 2023-04-01 09:50:04 UTC
-- Started on 2023-04-02 20:11:41 UTC
SET statement_timeout = 0;
SET lock_timeout = 0;
@@ -19,7 +19,7 @@ SET client_min_messages = warning;
SET row_security = off;
--
-- TOC entry 252 (class 1255 OID 49412)
-- TOC entry 254 (class 1255 OID 49412)
-- Name: fs_last_library_activity(text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -57,7 +57,7 @@ $$;
ALTER FUNCTION public.fs_last_library_activity(libraryid text) OWNER TO postgres;
--
-- TOC entry 248 (class 1255 OID 49383)
-- TOC entry 250 (class 1255 OID 49383)
-- Name: fs_last_user_activity(text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -93,7 +93,7 @@ $$;
ALTER FUNCTION public.fs_last_user_activity(userid text) OWNER TO postgres;
--
-- TOC entry 246 (class 1255 OID 49411)
-- TOC entry 248 (class 1255 OID 49411)
-- Name: fs_library_stats(integer, text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -145,7 +145,7 @@ $$;
ALTER FUNCTION public.fs_most_active_user(days integer) OWNER TO postgres;
--
-- TOC entry 250 (class 1255 OID 49386)
-- TOC entry 252 (class 1255 OID 49386)
-- Name: fs_most_played_items(integer, text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -186,7 +186,7 @@ $$;
ALTER FUNCTION public.fs_most_played_items(days integer, itemtype text) OWNER TO postgres;
--
-- TOC entry 251 (class 1255 OID 49394)
-- TOC entry 253 (class 1255 OID 49394)
-- Name: fs_most_popular_items(integer, text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -256,7 +256,7 @@ $$;
ALTER FUNCTION public.fs_most_used_clients(days integer) OWNER TO postgres;
--
-- TOC entry 249 (class 1255 OID 49385)
-- TOC entry 251 (class 1255 OID 49385)
-- Name: fs_most_viewed_libraries(integer); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -300,7 +300,7 @@ $$;
ALTER FUNCTION public.fs_most_viewed_libraries(days integer) OWNER TO postgres;
--
-- TOC entry 247 (class 1255 OID 49364)
-- TOC entry 249 (class 1255 OID 49364)
-- Name: fs_user_stats(integer, text); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -325,7 +325,7 @@ $$;
ALTER FUNCTION public.fs_user_stats(hours integer, userid text) OWNER TO postgres;
--
-- TOC entry 245 (class 1255 OID 49418)
-- TOC entry 246 (class 1255 OID 49418)
-- Name: fs_watch_stats_over_time(integer); Type: FUNCTION; Schema: public; Owner: postgres
--
@@ -350,6 +350,77 @@ $$;
ALTER FUNCTION public.fs_watch_stats_over_time(days integer) OWNER TO postgres;
--
-- TOC entry 247 (class 1255 OID 57644)
-- Name: fs_watch_stats_popular_days_of_week(integer); Type: FUNCTION; Schema: public; Owner: postgres
--
CREATE FUNCTION public.fs_watch_stats_popular_days_of_week(days integer) RETURNS TABLE("Day" text, "Count" bigint, "Library" text)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
TO_CHAR(d."Day", 'Day') AS "Day",
COUNT(a."NowPlayingItemId") AS "Count",
COALESCE(l."Name", 'Unknown') AS "Library"
FROM (
SELECT
DATE_TRUNC('week', NOW()) + n * INTERVAL '1 day' AS "Day"
FROM generate_series(0, 6) n
) d
CROSS JOIN jf_libraries l
LEFT JOIN (
SELECT
DATE_TRUNC('day', "ActivityDateInserted") AS "Day",
"NowPlayingItemId",
i."ParentId"
FROM jf_playback_activity a
JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId"
WHERE a."ActivityDateInserted" BETWEEN NOW() - CAST(days || ' days' as INTERVAL) AND NOW()
) a ON d."Day" = a."Day" AND l."Id" = a."ParentId"
GROUP BY d."Day", l."Name"
ORDER BY d."Day";
END;
$$;
ALTER FUNCTION public.fs_watch_stats_popular_days_of_week(days integer) OWNER TO postgres;
--
-- TOC entry 245 (class 1255 OID 57646)
-- Name: fs_watch_stats_popular_hour_of_day(integer); Type: FUNCTION; Schema: public; Owner: postgres
--
CREATE FUNCTION public.fs_watch_stats_popular_hour_of_day(days integer) RETURNS TABLE("Hour" integer, "Count" integer, "Library" text)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
DATE_PART('hour', hl."Hour")::INTEGER AS "Hour",
COALESCE(CAST(COUNT(a."NowPlayingItemId") AS INTEGER), 0) AS "Count",
COALESCE(l."Name", hl."Name") AS "Library"
FROM (
SELECT
DATE_TRUNC('week', NOW()) + INTERVAL '1 hour' * n AS "Hour",
l."Name"
FROM generate_series(0, 167) n
CROSS JOIN jf_libraries l
) hl
LEFT JOIN jf_playback_activity a ON DATE_TRUNC('hour', a."ActivityDateInserted") = hl."Hour"
LEFT JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId"
LEFT JOIN jf_libraries l ON i."ParentId" = l."Id"
WHERE hl."Hour" BETWEEN NOW() - CAST(days || ' days' as INTERVAL) AND NOW()
GROUP BY DATE_PART('hour', hl."Hour"), COALESCE(l."Name", hl."Name")
ORDER BY DATE_PART('hour', hl."Hour"), COALESCE(l."Name", hl."Name");
END;
$$;
ALTER FUNCTION public.fs_watch_stats_popular_hour_of_day(days integer) OWNER TO postgres;
SET default_tablespace = '';
SET default_table_access_method = heap;
@@ -688,7 +759,7 @@ CREATE VIEW public.js_library_stats_overview AS
ALTER TABLE public.js_library_stats_overview OWNER TO postgres;
--
-- TOC entry 3237 (class 2606 OID 16401)
-- TOC entry 3239 (class 2606 OID 16401)
-- Name: app_config app_config_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -697,7 +768,7 @@ ALTER TABLE ONLY public.app_config
--
-- TOC entry 3239 (class 2606 OID 16419)
-- TOC entry 3241 (class 2606 OID 16419)
-- Name: jf_libraries jf_libraries_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -706,7 +777,7 @@ ALTER TABLE ONLY public.jf_libraries
--
-- TOC entry 3245 (class 2606 OID 24912)
-- TOC entry 3247 (class 2606 OID 24912)
-- Name: jf_library_episodes jf_library_episodes_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -715,7 +786,7 @@ ALTER TABLE ONLY public.jf_library_episodes
--
-- TOC entry 3241 (class 2606 OID 24605)
-- TOC entry 3243 (class 2606 OID 24605)
-- Name: jf_library_items jf_library_items_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -724,7 +795,7 @@ ALTER TABLE ONLY public.jf_library_items
--
-- TOC entry 3243 (class 2606 OID 24737)
-- TOC entry 3245 (class 2606 OID 24737)
-- Name: jf_library_seasons jf_library_seasons_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -733,7 +804,7 @@ ALTER TABLE ONLY public.jf_library_seasons
--
-- TOC entry 3247 (class 2606 OID 41737)
-- TOC entry 3249 (class 2606 OID 41737)
-- Name: jf_users jf_users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
@@ -742,7 +813,7 @@ ALTER TABLE ONLY public.jf_users
--
-- TOC entry 3391 (class 2618 OID 25163)
-- TOC entry 3393 (class 2618 OID 25163)
-- Name: jf_library_count_view _RETURN; Type: RULE; Schema: public; Owner: postgres
--
@@ -762,7 +833,7 @@ CREATE OR REPLACE VIEW public.jf_library_count_view AS
--
-- TOC entry 3248 (class 2606 OID 24617)
-- TOC entry 3250 (class 2606 OID 24617)
-- Name: jf_library_items jf_library_items_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
@@ -771,15 +842,15 @@ ALTER TABLE ONLY public.jf_library_items
--
-- TOC entry 3399 (class 0 OID 0)
-- Dependencies: 3248
-- TOC entry 3401 (class 0 OID 0)
-- Dependencies: 3250
-- Name: CONSTRAINT jf_library_items_fkey ON jf_library_items; Type: COMMENT; Schema: public; Owner: postgres
--
COMMENT ON CONSTRAINT jf_library_items_fkey ON public.jf_library_items IS 'jf_library';
-- Completed on 2023-04-01 09:50:05 UTC
-- Completed on 2023-04-02 20:11:41 UTC
--
-- PostgreSQL database dump complete

View File

@@ -12,7 +12,7 @@ const db = require('./db');
const app = express();
const PORT = process.env.PORT || 3003;
const LISTEN_IP = '127.0.0.1';
const JWT_SECRET = process.env.JWT_SECRET ||'my-secret-jwt-key';
const JWT_SECRET = process.env.JWT_SECRET;
if (JWT_SECRET === undefined) {
console.log('JWT Secret cannot be undefined');

View File

@@ -320,6 +320,80 @@ const finalData = Object.values(reorganizedData);
}
});
router.post("/getViewsByDays", async (req, res) => {
try {
const { days } = req.body;
let _days = days;
if (days=== undefined) {
_days = 30;
}
const { rows } = await db.query(
`select * from fs_watch_stats_popular_days_of_week('${_days}')`
);
const reorganizedData = {};
rows.forEach((item) => {
const id = item.Library;
const count = item.Count;
const day = item.Day;
if (!reorganizedData[id]) {
reorganizedData[id] = {
id,
data: []
};
}
reorganizedData[id].data.push({ x: day, y: count });
});
const finalData = Object.values(reorganizedData);
res.send(finalData);
} catch (error) {
console.log(error);
res.send(error);
}
});
router.post("/getViewsByHour", async (req, res) => {
try {
const { days } = req.body;
let _days = days;
if (days=== undefined) {
_days = 30;
}
const { rows } = await db.query(
`select * from fs_watch_stats_popular_hour_of_day('${_days}')`
);
const reorganizedData = {};
rows.forEach((item) => {
const id = item.Library;
const count = item.Count;
const hour = item.Hour;
if (!reorganizedData[id]) {
reorganizedData[id] = {
id,
data: []
};
}
reorganizedData[id].data.push({ x: hour, y: count });
});
const finalData = Object.values(reorganizedData);
res.send(finalData);
} catch (error) {
console.log(error);
res.send(error);
}
});

View File

@@ -12,6 +12,7 @@ services:
POSTGRES_PASSWORD: mypassword
POSTGRES_IP: jellystat-db
POSTGRES_PORT: 5432
JWT_SECRET: 'my-secret-jwt-key'
ports:
- "3000:3000"
depends_on:

View File

@@ -13,6 +13,7 @@ export default function Navbar() {
return (
<div className={"navbar"}>
<h1 style={{marginRight:"20px"}}>Jellystat</h1>
{navData.map((item) => {
return (
<NavLink key={item.id} className={"navitem"} to={item.link}>

View File

@@ -1,41 +1,37 @@
import React,{useState,useEffect} from 'react';
import axios from 'axios';
import { ResponsiveLine } from '@nivo/line';
import React, { useState, useEffect } from "react";
import axios from "axios";
import { ResponsiveLine } from "@nivo/line";
import '../../css/stats.css';
import "../../css/stats.css";
function DailyPlayStats(props) {
const [data, setData] = useState();
const [data, setData] = useState();
const [days, setDays] = useState(60);
const token = localStorage.getItem('token');
const token = localStorage.getItem("token");
useEffect(() => {
const fetchLibraries = () => {
const url = `/stats/getViewsOverTime`;
const url = `/stats/getViewsOverTime`;
axios
.post(url, {days:props.days}, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
axios
.post(
url,
{ days: props.days },
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
)
.then((data) => {
setData(data.data);
})
.then((data) => {
setData(data.data);
})
.catch((error) => {
console.log(error);
});
.catch((error) => {
console.log(error);
});
};
if (!data) {
fetchLibraries();
}
@@ -44,130 +40,120 @@ function DailyPlayStats(props) {
fetchLibraries();
}
const intervalId = setInterval(fetchLibraries, 60000 * 5);
return () => clearInterval(intervalId);
}, [data, days,props.days ,token]);
}, [data, days, props.days, token]);
if (!data) {
return <></>;
return <></>;
}
if (data.length === 0) {
return (<div className="statistics-widget">
return (
<div className="statistics-widget">
<h1>Daily Play Count Per Library - {days} Days</h1>
<h1>Daily Play Count Per Library - {days} Days</h1>
<h1>No Stats to display</h1>
</div>
<h1>No Stats to display</h1>
</div>
);
}
return (
<div className="statistics-widget">
<h1>Daily Play Count Per Library - {days} Days</h1>
return (
<div className="statistics-widget" >
<h1>Daily Play Count Per Library - {days} Days</h1>
<div className="graph">
<ResponsiveLine
data={data}
margin={{ top: 50, right: 100, bottom: 200, left: 50 }}
xScale={{ type: 'point' }}
yScale={{
type: 'linear',
min: 'auto',
max: 'auto',
data={data}
margin={{ top: 50, right: 100, bottom: 200, left: 50 }}
xScale={{ type: "point" }}
yScale={{
type: "linear",
min: "auto",
max: "auto",
stacked: false,
reverse: false
}}
enableGridX={false}
enableSlices={"x"}
yFormat=" >-.0f"
curve="natural"
theme={{
axis: {
ticks: {
line: {
stroke: "white"
},
text: {
fill: "white"
}
}
},
grid: {
line: {
stroke: "rgba(255,255,255,0.2)",
strokeWidth: 2,
strokeDasharray: "1 40"
}
}
reverse: false,
}}
axisBottom={{
orient: 'bottom',
enableGridX={false}
enableSlices={"x"}
yFormat=" >-.0f"
curve="natural"
theme={{
axis: {
ticks: {
line: {
stroke: "white",
},
text: {
fill: "white",
},
},
},
grid: {
line: {
stroke: "rgba(255,255,255,0.2)",
strokeWidth: 2,
strokeDasharray: "1 40",
},
},
}}
axisBottom={{
orient: "bottom",
tickSize: 5,
tickPadding: 10,
tickRotation: -45,
legend: 'Days',
legend: "Days",
legendOffset: 36,
legendPosition: 'middle'
}}
axisLeft={{
orient: 'left',
legendPosition: "middle",
}}
axisLeft={{
orient: "left",
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'Plays',
legend: "Plays",
legendOffset: -40,
legendPosition: 'middle',
itemTextColor: '#fff',
theme:"white"
}}
colors={{ scheme: 'category10' }}
pointSize={10}
pointColor={{ theme: 'background' }}
pointBorderWidth={2}
pointBorderColor={{ from: 'serieColor' }}
pointLabelYOffset={-12}
legends={[
legendPosition: "middle",
itemTextColor: "#fff",
theme: "white",
}}
colors={{ scheme: "category10" }}
pointSize={10}
pointColor={{ theme: "background" }}
pointBorderWidth={2}
pointBorderColor={{ from: "serieColor" }}
pointLabelYOffset={-12}
legends={[
{
itemTextColor: '#fff',
anchor: 'bottom',
direction: 'row',
justify: false,
translateX: 0,
translateY: 100,
itemsSpacing: 0,
itemDirection: 'left-to-right',
itemWidth: 80,
itemHeight: 20,
itemOpacity: 0.75,
symbolSize: 12,
symbolShape: 'circle',
symbolBorderColor: 'rgba(0, 0, 0, .5)',
effects: [
{
on: 'hover',
style: {
itemBackground: 'rgba(0, 0, 0, .03)',
itemOpacity: 1
}
}
]
}
]}
/>
</div>
);
itemTextColor: "#fff",
anchor: "bottom",
direction: "row",
justify: false,
translateX: 0,
translateY: 100,
itemsSpacing: 0,
itemDirection: "left-to-right",
itemWidth: 100,
itemHeight: 20,
itemOpacity: 0.75,
symbolSize: 12,
symbolShape: "circle",
symbolBorderColor: "rgba(0, 0, 0, .5)",
effects: [
{
on: "hover",
style: {
itemBackground: "rgba(0, 0, 0, .03)",
itemOpacity: 1,
},
},
],
},
]}
/>
</div>
</div>
);
}
export default DailyPlayStats;

View File

@@ -0,0 +1,159 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { ResponsiveLine } from "@nivo/line";
import "../../css/stats.css";
function PlayStatsByDay(props) {
const [data, setData] = useState();
const [days, setDays] = useState(60);
const token = localStorage.getItem("token");
useEffect(() => {
const fetchLibraries = () => {
const url = `/stats/getViewsByDays`;
axios
.post(
url,
{ days: props.days },
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
)
.then((data) => {
setData(data.data);
})
.catch((error) => {
console.log(error);
});
};
if (!data) {
fetchLibraries();
}
if (days !== props.days) {
setDays(props.days);
fetchLibraries();
}
const intervalId = setInterval(fetchLibraries, 60000 * 5);
return () => clearInterval(intervalId);
}, [data, days, props.days, token]);
if (!data) {
return <></>;
}
if (data.length === 0) {
return (
<div className="statistics-widget small">
<h1>Play Count By Day - {days} Days</h1>
<h1>No Stats to display</h1>
</div>
);
}
return (
<div className="statistics-widget">
<h1>Play Count By Day - {days} Days</h1>
<div className="graph small">
<ResponsiveLine
data={data}
margin={{ top: 50, right: 100, bottom: 200, left: 50 }}
xScale={{ type: "point" }}
yScale={{
type: "linear",
min: "auto",
max: "auto",
stacked: false,
reverse: false,
}}
enableGridX={false}
enableSlices={"x"}
yFormat=" >-.0f"
curve="natural"
enableArea={true}
theme={{
axis: {
ticks: {
line: {
stroke: "white",
},
text: {
fill: "white",
},
},
},
grid: {
line: {
stroke: "rgba(255,255,255,0.2)",
strokeWidth: 2,
strokeDasharray: "1 40",
},
},
}}
axisBottom={{
orient: "bottom",
tickSize: 5,
tickPadding: 10,
tickRotation: -45,
legend: "Days",
legendOffset: 36,
legendPosition: "middle",
}}
axisLeft={{
orient: "left",
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: "Plays",
legendOffset: -40,
legendPosition: "middle",
itemTextColor: "#fff",
theme: "white",
}}
colors={{ scheme: "category10" }}
pointSize={10}
pointColor={{ theme: "background" }}
pointBorderWidth={2}
pointBorderColor={{ from: "serieColor" }}
pointLabelYOffset={-12}
legends={[
{
itemTextColor: "#fff",
anchor: "bottom",
direction: "row",
justify: false,
translateX: 0,
translateY: 100,
itemsSpacing: 0,
itemDirection: "left-to-right",
itemWidth: 100,
itemHeight: 20,
itemOpacity: 0.75,
symbolSize: 12,
symbolShape: "circle",
symbolBorderColor: "rgba(0, 0, 0, .5)",
effects: [
{
on: "hover",
style: {
itemBackground: "rgba(0, 0, 0, .03)",
itemOpacity: 1,
},
},
],
},
]}
/>
</div>
</div>
);
}
export default PlayStatsByDay;

View File

@@ -0,0 +1,161 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { ResponsiveLine } from "@nivo/line";
import "../../css/stats.css";
function PlayStatsByHour(props) {
const [data, setData] = useState();
const [days, setDays] = useState(60);
const token = localStorage.getItem("token");
useEffect(() => {
const fetchLibraries = () => {
const url = `/stats/getViewsByHour`;
axios
.post(
url,
{ days: props.days },
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
)
.then((data) => {
setData(data.data);
})
.catch((error) => {
console.log(error);
});
};
if (!data) {
fetchLibraries();
}
if (days !== props.days) {
setDays(props.days);
fetchLibraries();
}
const intervalId = setInterval(fetchLibraries, 60000 * 5);
return () => clearInterval(intervalId);
}, [data, days, props.days, token]);
if (!data) {
return <></>;
}
if (data.length === 0) {
return (
<div className="statistics-widget small">
<h1>Play Count By Hour - {days} Days</h1>
<h1>No Stats to display</h1>
</div>
);
}
console.log(data);
return (
<div className="statistics-widget">
<h1>Play Count By Hour - {days} Days</h1>
<div className="graph small">
<ResponsiveLine
data={data}
margin={{ top: 50, right: 100, bottom: 200, left: 50 }}
xScale={{ type: "point" }}
yScale={{
type: "linear",
min: "auto",
max: "auto",
stacked: false,
reverse: false,
}}
enableGridX={false}
enableSlices={"x"}
yFormat=" >-.0f"
curve="linear"
enableArea={true}
theme={{
axis: {
ticks: {
line: {
stroke: "white",
},
text: {
fill: "white",
},
},
},
grid: {
line: {
stroke: "rgba(255,255,255,0.2)",
strokeWidth: 2,
strokeDasharray: "1 40",
},
},
}}
axisBottom={{
orient: "bottom",
tickSize: 5,
tickPadding: 10,
tickRotation: -45,
legend: "Days",
legendOffset: 36,
legendPosition: "middle",
}}
axisLeft={{
orient: "left",
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: "Plays",
legendOffset: -40,
legendPosition: "middle",
itemTextColor: "#fff",
theme: "white",
}}
colors={{ scheme: "category10" }}
pointSize={10}
pointColor={{ theme: "background" }}
pointBorderWidth={2}
pointBorderColor={{ from: "serieColor" }}
pointLabelYOffset={-12}
legends={[
{
itemTextColor: "#fff",
anchor: "bottom",
direction: "row",
justify: false,
translateX: 0,
translateY: 100,
itemsSpacing: 0,
itemDirection: "left-to-right",
itemWidth: 100,
itemHeight: 20,
itemOpacity: 0.75,
symbolSize: 12,
symbolShape: "circle",
symbolBorderColor: "rgba(0, 0, 0, .5)",
effects: [
{
on: "hover",
style: {
itemBackground: "rgba(0, 0, 0, .03)",
itemOpacity: 1,
},
},
],
},
]}
/>
</div>
</div>
);
}
export default PlayStatsByHour;

View File

@@ -16,7 +16,7 @@ div a
.activity-table
{
background-color: rgba(0, 0, 0, 0.2);
background-color: rgba(100,100, 100, 0.2);
}

View File

@@ -1,12 +1,32 @@
.statistics-widget
.graph
{
height: 700px;
color:black !important;
background-color:rgba(0,0,0,0.2);
background-color:rgba(100,100,100,0.2);
padding:20px;
border-radius:4px;
/* text-align: center; */
}
.small
{
height: 500px;
}
.statistics-graphs
{
display: flex;
justify-content: space-between;
}
.statistics-widget
{
flex: 1;
/* margin-right: 20px; */
}

View File

@@ -23,7 +23,7 @@
height: 100px;
border-radius: 50%;
object-fit: cover;
box-shadow: 0 0 10px 5px rgba(0,0,0,0.2);
box-shadow: 0 0 10px 5px rgba(100,100,100,0.2);
}
.user-image-container

View File

@@ -13,7 +13,7 @@
font-family: sans-serif;
min-width: 400px;
/* box-shadow: 0 0 20px rgba(255, 255, 255, 0.15); */
background-color: rgba(0, 0, 0, 0.2);
background-color: rgba(100,100, 100, 0.2);
color: white;
width: 100%;

View File

@@ -1,12 +1,13 @@
import React,{useState} from 'react';
import React, { useState } from "react";
// import './css/library/libraries.css';
import "./css/statCard.css";
import "./css/stats.css";
import DailyPlayStats from './components/statistics/daily-play-count';
import DailyPlayStats from "./components/statistics/daily-play-count";
import PlayStatsByDay from "./components/statistics/play-stats-by-day";
import PlayStatsByHour from "./components/statistics/play-stats-by-hour";
function Statistics() {
const [days, setDays] = useState(60);
const [input, setInput] = useState(60);
@@ -23,40 +24,34 @@ function Statistics() {
}
};
return (
<div className="watch-stats">
<div className="Heading">
<h1>Statistics</h1>
<div className="date-range">
<div className="header">Last</div>
<div className="days">
<input
type="number"
min={1}
value={input}
onChange={(event) => setInput(event.target.value)}
onKeyDown={handleKeyDown}
/>
</div>
<div className="trailer">Days</div>
return (
<div className="watch-stats">
<div className="Heading">
<h1>Statistics</h1>
<div className="date-range">
<div className="header">Last</div>
<div className="days">
<input
type="number"
min={1}
value={input}
onChange={(event) => setInput(event.target.value)}
onKeyDown={handleKeyDown}
/>
</div>
</div>
<div >
<DailyPlayStats days={days}/>
<div className="trailer">Days</div>
</div>
</div>
);
<div>
<DailyPlayStats days={days} />
<div className="statistics-graphs">
<PlayStatsByDay days={days} />
<PlayStatsByHour days={days} />
</div>
</div>
</div>
);
}
export default Statistics;