mirror of
https://github.com/BreizhHardware/Jellystat.git
synced 2026-01-18 16:27:20 +01:00
Changes for the daily & weekly playback duration charts
This commit is contained in:
@@ -5,7 +5,7 @@ exports.up = async function (knex) {
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.fs_watch_stats_over_time(
|
||||
days integer)
|
||||
RETURNS TABLE("Date" date, "Count" bigint, "TotalTime" bigint, "Library" text, "LibraryID" text)
|
||||
RETURNS TABLE("Date" date, "Count" bigint, "Duration" bigint, "Library" text, "LibraryID" text)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
@@ -17,7 +17,7 @@ AS $BODY$
|
||||
SELECT
|
||||
dates."Date",
|
||||
COALESCE(counts."Count", 0) AS "Count",
|
||||
COALESCE(counts."TotalTime", 0) AS "TotalTime",
|
||||
COALESCE(counts."Duration", 0) AS "Duration",
|
||||
l."Name" as "Library",
|
||||
l."Id" as "LibraryID"
|
||||
FROM
|
||||
@@ -32,7 +32,7 @@ AS $BODY$
|
||||
(SELECT
|
||||
DATE_TRUNC('day', a."ActivityDateInserted")::DATE AS "Date",
|
||||
COUNT(*) AS "Count",
|
||||
(SUM(a."PlaybackDuration") / 60)::bigint AS "TotalTime",
|
||||
(SUM(a."PlaybackDuration") / 60)::bigint AS "Duration",
|
||||
l."Name" as "Library"
|
||||
FROM
|
||||
jf_playback_activity a
|
||||
@@ -0,0 +1,141 @@
|
||||
exports.up = async function (knex) {
|
||||
try {
|
||||
await knex.schema.raw(`
|
||||
DROP FUNCTION IF EXISTS public.fs_watch_stats_popular_days_of_week(integer);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.fs_watch_stats_popular_days_of_week(
|
||||
days integer)
|
||||
RETURNS TABLE("Day" text, "Count" bigint, "Duration" bigint, "Library" text)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
WITH library_days AS (
|
||||
SELECT
|
||||
l."Name" AS "Library",
|
||||
d.day_of_week,
|
||||
d.day_name
|
||||
FROM
|
||||
jf_libraries l,
|
||||
(SELECT 0 AS "day_of_week", 'Sunday' AS "day_name" UNION ALL
|
||||
SELECT 1 AS "day_of_week", 'Monday' AS "day_name" UNION ALL
|
||||
SELECT 2 AS "day_of_week", 'Tuesday' AS "day_name" UNION ALL
|
||||
SELECT 3 AS "day_of_week", 'Wednesday' AS "day_name" UNION ALL
|
||||
SELECT 4 AS "day_of_week", 'Thursday' AS "day_name" UNION ALL
|
||||
SELECT 5 AS "day_of_week", 'Friday' AS "day_name" UNION ALL
|
||||
SELECT 6 AS "day_of_week", 'Saturday' AS "day_name"
|
||||
) d
|
||||
where l.archived=false
|
||||
)
|
||||
SELECT
|
||||
library_days.day_name AS "Day",
|
||||
COALESCE(SUM(counts."Count"), 0)::bigint AS "Count",
|
||||
COALESCE(SUM(counts."Duration"), 0)::bigint AS "Duration",
|
||||
library_days."Library" AS "Library"
|
||||
FROM
|
||||
library_days
|
||||
LEFT JOIN
|
||||
(SELECT
|
||||
DATE_TRUNC('day', a."ActivityDateInserted")::DATE AS "Date",
|
||||
COUNT(*) AS "Count",
|
||||
(SUM(a."PlaybackDuration") / 60)::bigint AS "Duration",
|
||||
EXTRACT(DOW FROM a."ActivityDateInserted") AS "DOW",
|
||||
l."Name" AS "Library"
|
||||
FROM
|
||||
jf_playback_activity a
|
||||
JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId"
|
||||
JOIN jf_libraries l ON i."ParentId" = l."Id" and l.archived=false
|
||||
WHERE
|
||||
a."ActivityDateInserted" BETWEEN NOW() - CAST(days || ' days' as INTERVAL) AND NOW()
|
||||
GROUP BY
|
||||
l."Name", EXTRACT(DOW FROM a."ActivityDateInserted"), DATE_TRUNC('day', a."ActivityDateInserted")
|
||||
) counts
|
||||
ON counts."DOW" = library_days.day_of_week AND counts."Library" = library_days."Library"
|
||||
GROUP BY
|
||||
library_days.day_name, library_days.day_of_week, library_days."Library"
|
||||
ORDER BY
|
||||
library_days.day_of_week, library_days."Library";
|
||||
END;
|
||||
|
||||
$BODY$;
|
||||
|
||||
ALTER FUNCTION public.fs_watch_stats_popular_days_of_week(integer)
|
||||
OWNER TO "${process.env.POSTGRES_ROLE}";
|
||||
`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
exports.down = async function (knex) {
|
||||
// try {
|
||||
// await knex.schema.raw(`
|
||||
// DROP FUNCTION IF EXISTS public.fs_watch_stats_popular_days_of_week(integer);
|
||||
|
||||
// CREATE OR REPLACE FUNCTION public.fs_watch_stats_popular_days_of_week(
|
||||
// days integer)
|
||||
// RETURNS TABLE("Day" text, "Count" bigint, "Library" text)
|
||||
// LANGUAGE 'plpgsql'
|
||||
// COST 100
|
||||
// VOLATILE PARALLEL UNSAFE
|
||||
// ROWS 1000
|
||||
|
||||
// AS $BODY$
|
||||
// BEGIN
|
||||
// RETURN QUERY
|
||||
// WITH library_days AS (
|
||||
// SELECT
|
||||
// l."Name" AS "Library",
|
||||
// d.day_of_week,
|
||||
// d.day_name
|
||||
// FROM
|
||||
// jf_libraries l,
|
||||
// (SELECT 0 AS "day_of_week", 'Sunday' AS "day_name" UNION ALL
|
||||
// SELECT 1 AS "day_of_week", 'Monday' AS "day_name" UNION ALL
|
||||
// SELECT 2 AS "day_of_week", 'Tuesday' AS "day_name" UNION ALL
|
||||
// SELECT 3 AS "day_of_week", 'Wednesday' AS "day_name" UNION ALL
|
||||
// SELECT 4 AS "day_of_week", 'Thursday' AS "day_name" UNION ALL
|
||||
// SELECT 5 AS "day_of_week", 'Friday' AS "day_name" UNION ALL
|
||||
// SELECT 6 AS "day_of_week", 'Saturday' AS "day_name"
|
||||
// ) d
|
||||
// )
|
||||
// SELECT
|
||||
// library_days.day_name AS "Day",
|
||||
// COALESCE(SUM(counts."Count"), 0)::bigint AS "Count",
|
||||
// library_days."Library" AS "Library"
|
||||
// FROM
|
||||
// library_days
|
||||
// LEFT JOIN
|
||||
// (SELECT
|
||||
// DATE_TRUNC('day', a."ActivityDateInserted")::DATE AS "Date",
|
||||
// COUNT(*) AS "Count",
|
||||
// EXTRACT(DOW FROM a."ActivityDateInserted") AS "DOW",
|
||||
// l."Name" AS "Library"
|
||||
// FROM
|
||||
// jf_playback_activity a
|
||||
// JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId"
|
||||
// JOIN jf_libraries l ON i."ParentId" = l."Id"
|
||||
// WHERE
|
||||
// a."ActivityDateInserted" BETWEEN NOW() - CAST(days || ' days' as INTERVAL) AND NOW()
|
||||
// GROUP BY
|
||||
// l."Name", EXTRACT(DOW FROM a."ActivityDateInserted"), DATE_TRUNC('day', a."ActivityDateInserted")
|
||||
// ) counts
|
||||
// ON counts."DOW" = library_days.day_of_week AND counts."Library" = library_days."Library"
|
||||
// GROUP BY
|
||||
// library_days.day_name, library_days.day_of_week, library_days."Library"
|
||||
// ORDER BY
|
||||
// library_days.day_of_week, library_days."Library";
|
||||
// END;
|
||||
|
||||
// $BODY$;
|
||||
|
||||
// ALTER FUNCTION fs_watch_stats_popular_days_of_week(integer)
|
||||
// OWNER TO "${process.env.POSTGRES_ROLE}";`);
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
exports.up = async function (knex) {
|
||||
try {
|
||||
await knex.schema.raw(`
|
||||
DROP FUNCTION IF EXISTS public.fs_watch_stats_popular_hour_of_day(integer);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.fs_watch_stats_popular_hour_of_day(
|
||||
days integer)
|
||||
RETURNS TABLE("Hour" integer, "Count" integer, "Duration" integer, "Library" text)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
h."Hour",
|
||||
COUNT(a."Id")::integer AS "Count",
|
||||
COALESCE(SUM(a."PlaybackDuration") / 60, 0)::integer AS "Duration",
|
||||
l."Name" AS "Library"
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
generate_series(0, 23) AS "Hour"
|
||||
) h
|
||||
CROSS JOIN jf_libraries l
|
||||
LEFT JOIN jf_library_items i ON i."ParentId" = l."Id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"NowPlayingItemId",
|
||||
DATE_PART('hour', "ActivityDateInserted") AS "Hour",
|
||||
"Id",
|
||||
"PlaybackDuration"
|
||||
FROM
|
||||
jf_playback_activity
|
||||
WHERE
|
||||
"ActivityDateInserted" BETWEEN NOW() - CAST(days || ' days' AS INTERVAL) AND NOW()
|
||||
) a ON a."NowPlayingItemId" = i."Id" AND a."Hour"::integer = h."Hour"
|
||||
WHERE
|
||||
l.archived=false
|
||||
and l."Id" IN (SELECT "Id" FROM jf_libraries)
|
||||
GROUP BY
|
||||
h."Hour",
|
||||
l."Name"
|
||||
ORDER BY
|
||||
l."Name",
|
||||
h."Hour";
|
||||
END;
|
||||
|
||||
$BODY$;
|
||||
|
||||
ALTER FUNCTION public.fs_watch_stats_popular_hour_of_day(integer)
|
||||
OWNER TO "${process.env.POSTGRES_ROLE}";
|
||||
`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
exports.down = async function (knex) {
|
||||
try {
|
||||
await knex.schema.raw(`
|
||||
DROP FUNCTION IF EXISTS public.fs_watch_stats_popular_hour_of_day(integer);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.fs_watch_stats_popular_hour_of_day(
|
||||
days integer)
|
||||
RETURNS TABLE("Hour" integer, "Count" integer, "Library" text)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
h."Hour",
|
||||
COUNT(a."Id")::integer AS "Count",
|
||||
l."Name" AS "Library"
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
generate_series(0, 23) AS "Hour"
|
||||
) h
|
||||
CROSS JOIN jf_libraries l
|
||||
LEFT JOIN jf_library_items i ON i."ParentId" = l."Id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"NowPlayingItemId",
|
||||
DATE_PART('hour', "ActivityDateInserted") AS "Hour",
|
||||
"Id"
|
||||
FROM
|
||||
jf_playback_activity
|
||||
WHERE
|
||||
"ActivityDateInserted" BETWEEN NOW() - CAST(days || ' days' AS INTERVAL) AND NOW()
|
||||
) a ON a."NowPlayingItemId" = i."Id" AND a."Hour"::integer = h."Hour"
|
||||
WHERE
|
||||
l."Id" IN (SELECT "Id" FROM jf_libraries)
|
||||
GROUP BY
|
||||
h."Hour",
|
||||
l."Name"
|
||||
ORDER BY
|
||||
l."Name",
|
||||
h."Hour";
|
||||
END;
|
||||
|
||||
$BODY$;
|
||||
|
||||
ALTER FUNCTION fs_watch_stats_popular_hour_of_day(integer)
|
||||
OWNER TO "${process.env.POSTGRES_ROLE}";`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
@@ -423,7 +423,7 @@ router.get("/getViewsOverTime", async (req, res) => {
|
||||
stats.forEach((item) => {
|
||||
const library = item.Library;
|
||||
const count = item.Count;
|
||||
const watchTime = item.TotalTime;
|
||||
const duration = item.Duration;
|
||||
const date = new Date(item.Date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
@@ -436,7 +436,7 @@ router.get("/getViewsOverTime", async (req, res) => {
|
||||
};
|
||||
}
|
||||
|
||||
reorganizedData[date] = { ...reorganizedData[date], [library]: { count, watchTime } };
|
||||
reorganizedData[date] = { ...reorganizedData[date], [library]: { count, duration } };
|
||||
});
|
||||
const finalData = { libraries: libraries, stats: Object.values(reorganizedData) };
|
||||
res.send(finalData);
|
||||
@@ -463,6 +463,7 @@ router.get("/getViewsByDays", async (req, res) => {
|
||||
stats.forEach((item) => {
|
||||
const library = item.Library;
|
||||
const count = item.Count;
|
||||
const duration = item.Duration;
|
||||
const day = item.Day;
|
||||
|
||||
if (!reorganizedData[day]) {
|
||||
@@ -471,7 +472,7 @@ router.get("/getViewsByDays", async (req, res) => {
|
||||
};
|
||||
}
|
||||
|
||||
reorganizedData[day] = { ...reorganizedData[day], [library]: count };
|
||||
reorganizedData[day] = { ...reorganizedData[day], [library]: { count, duration } };
|
||||
});
|
||||
const finalData = { libraries: libraries, stats: Object.values(reorganizedData) };
|
||||
res.send(finalData);
|
||||
@@ -498,6 +499,7 @@ router.get("/getViewsByHour", async (req, res) => {
|
||||
stats.forEach((item) => {
|
||||
const library = item.Library;
|
||||
const count = item.Count;
|
||||
const duration = item.Duration;
|
||||
const hour = item.Hour;
|
||||
|
||||
if (!reorganizedData[hour]) {
|
||||
@@ -506,7 +508,7 @@ router.get("/getViewsByHour", async (req, res) => {
|
||||
};
|
||||
}
|
||||
|
||||
reorganizedData[hour] = { ...reorganizedData[hour], [library]: count };
|
||||
reorganizedData[hour] = { ...reorganizedData[hour], [library]: { count, duration } };
|
||||
});
|
||||
const finalData = { libraries: libraries, stats: Object.values(reorganizedData) };
|
||||
res.send(finalData);
|
||||
|
||||
@@ -167,11 +167,11 @@
|
||||
"STAT_PAGE": {
|
||||
"STATISTICS": "Statistics",
|
||||
"DAILY_PLAY_PER_LIBRARY": "Daily Play Count Per Library",
|
||||
"DAILY_TIME_PER_LIBRARY": "Daily Watch Time Per Library",
|
||||
"DAILY_DURATION_PER_LIBRARY": "Daily Play Duration Per Library",
|
||||
"PLAY_COUNT_BY": "Play Count By",
|
||||
"PLAY_TIME_BY": "Play Time By",
|
||||
"COUNT_VIEW": "Total Count",
|
||||
"TIME_VIEW": "Total Time"
|
||||
"PLAY_DURATION_BY": "Play Duration By",
|
||||
"COUNT_VIEW": "Count",
|
||||
"DURATION_VIEW": "Duration"
|
||||
},
|
||||
"SETTINGS_PAGE": {
|
||||
"SETTINGS": "Settings",
|
||||
|
||||
@@ -10,7 +10,7 @@ function DailyPlayStats(props) {
|
||||
const [stats, setStats] = useState();
|
||||
const [libraries, setLibraries] = useState();
|
||||
const [days, setDays] = useState(20);
|
||||
const [viewName, setViewName] = useState("viewCount");
|
||||
const [viewName, setViewName] = useState("count");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
|
||||
@@ -52,14 +52,14 @@ function DailyPlayStats(props) {
|
||||
|
||||
const intervalId = setInterval(fetchLibraries, 60000 * 5);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [stats,libraries, days, props.days, token]);
|
||||
}, [stats,libraries, days, props.days, props.viewName, token]);
|
||||
|
||||
if (!stats) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const titleKey = viewName === "count" ? "STAT_PAGE.DAILY_PLAY_PER_LIBRARY" : "STAT_PAGE.DAILY_TIME_PER_LIBRARY";
|
||||
|
||||
const titleKey = viewName === "count" ? "STAT_PAGE.DAILY_PLAY_PER_LIBRARY" : "STAT_PAGE.DAILY_DURATION_PER_LIBRARY";
|
||||
|
||||
if (stats.length === 0) {
|
||||
return (
|
||||
<div className="main-widget">
|
||||
|
||||
@@ -9,6 +9,7 @@ function PlayStatsByDay(props) {
|
||||
const [stats, setStats] = useState();
|
||||
const [libraries, setLibraries] = useState();
|
||||
const [days, setDays] = useState(20);
|
||||
const [viewName, setViewName] = useState("count");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -41,19 +42,24 @@ function PlayStatsByDay(props) {
|
||||
setDays(props.days);
|
||||
fetchLibraries();
|
||||
}
|
||||
if (props.viewName !== viewName) {
|
||||
setViewName(props.viewName);
|
||||
}
|
||||
|
||||
const intervalId = setInterval(fetchLibraries, 60000 * 5);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [stats, libraries, days, props.days, token]);
|
||||
}, [stats, libraries, days, props.days, props.viewName, token]);
|
||||
|
||||
if (!stats) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const titleKey = viewName === "count" ? "STAT_PAGE.PLAY_COUNT_BY" : "STAT_PAGE.PLAY_DURATION_BY";
|
||||
|
||||
if (stats.length === 0) {
|
||||
return (
|
||||
<div className="statistics-widget small">
|
||||
<h1><Trans i18nKey={"STAT_PAGE.PLAY_COUNT_BY"}/> <Trans i18nKey={"UNITS.DAY"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h1>
|
||||
<h1><Trans i18nKey={titleKey}/> <Trans i18nKey={"UNITS.DAY"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h1>
|
||||
|
||||
<h5><Trans i18nKey={"ERROR_MESSAGES.NO_STATS"}/></h5>
|
||||
</div>
|
||||
@@ -62,9 +68,9 @@ function PlayStatsByDay(props) {
|
||||
|
||||
return (
|
||||
<div className="statistics-widget">
|
||||
<h2 className="text-start my-2"><Trans i18nKey={"STAT_PAGE.PLAY_COUNT_BY"}/> <Trans i18nKey={"UNITS.DAY"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h2>
|
||||
<h2 className="text-start my-2"><Trans i18nKey={titleKey}/> <Trans i18nKey={"UNITS.DAY"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h2>
|
||||
<div className="graph small">
|
||||
<Chart libraries={libraries} stats={stats} />
|
||||
<Chart libraries={libraries} stats={stats} viewName={viewName}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ function PlayStatsByHour(props) {
|
||||
const [stats, setStats] = useState();
|
||||
const [libraries, setLibraries] = useState();
|
||||
const [days, setDays] = useState(20);
|
||||
const [viewName, setViewName] = useState("count");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -40,19 +41,23 @@ function PlayStatsByHour(props) {
|
||||
setDays(props.days);
|
||||
fetchLibraries();
|
||||
}
|
||||
if (props.viewName !== viewName) {
|
||||
setViewName(props.viewName);
|
||||
}
|
||||
|
||||
const intervalId = setInterval(fetchLibraries, 60000 * 5);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [stats, libraries, days, props.days, token]);
|
||||
}, [stats, libraries, days, props.days, props.viewName, token]);
|
||||
|
||||
if (!stats) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const titleKey = viewName === "count" ? "STAT_PAGE.PLAY_COUNT_BY" : "STAT_PAGE.PLAY_DURATION_BY";
|
||||
if (stats.length === 0) {
|
||||
return (
|
||||
<div className="statistics-widget small">
|
||||
<h1><Trans i18nKey={"STAT_PAGE.PLAY_COUNT_BY"}/> <Trans i18nKey={"UNITS.HOUR"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h1>
|
||||
<h1><Trans i18nKey={titleKey}/> <Trans i18nKey={"UNITS.HOUR"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h1>
|
||||
|
||||
<h5><Trans i18nKey={"ERROR_MESSAGES.NO_STATS"}/></h5>
|
||||
</div>
|
||||
@@ -62,9 +67,9 @@ function PlayStatsByHour(props) {
|
||||
|
||||
return (
|
||||
<div className="statistics-widget">
|
||||
<h2 className="text-start my-2"><Trans i18nKey={"STAT_PAGE.PLAY_COUNT_BY"}/> <Trans i18nKey={"UNITS.HOUR"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h2>
|
||||
<h2 className="text-start my-2"><Trans i18nKey={titleKey}/> <Trans i18nKey={"UNITS.HOUR"}/> - <Trans i18nKey={"LAST"}/> {days} <Trans i18nKey={`UNITS.DAY${days>1 ? 'S':''}`}/></h2>
|
||||
<div className="graph small">
|
||||
<Chart libraries={libraries} stats={stats} />
|
||||
<Chart libraries={libraries} stats={stats} viewName={viewName}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -143,12 +143,3 @@ input[type="number"] {
|
||||
.item-name :hover {
|
||||
color: var(--secondary-color) !important;
|
||||
}
|
||||
|
||||
.pill-wrapper {
|
||||
color: white;
|
||||
display: flex;
|
||||
border-radius: 8px;
|
||||
font-size: 1.2em;
|
||||
align-self: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -47,6 +47,14 @@
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.stats-tab-nav {
|
||||
background-color: var(--secondary-background-color);
|
||||
display: flex;
|
||||
border-radius: 8px;
|
||||
align-self: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chart-canvas {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
|
||||
@@ -51,14 +51,22 @@ function Statistics() {
|
||||
<h1>
|
||||
<Trans i18nKey={"STAT_PAGE.STATISTICS"} />
|
||||
</h1>
|
||||
<div className="pill-wrapper">
|
||||
<div className="stats-tab-nav">
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={setTab}
|
||||
variant="pills"
|
||||
>
|
||||
<Tab eventKey="tabCount" title={<Trans i18nKey="STAT_PAGE.COUNT_VIEW" />} />
|
||||
<Tab eventKey="tabTime" title={<Trans i18nKey="STAT_PAGE.TIME_VIEW" />} />
|
||||
<Tab
|
||||
eventKey="tabCount"
|
||||
className="bg-transparent"
|
||||
title={<Trans i18nKey="STAT_PAGE.COUNT_VIEW" />}
|
||||
/>
|
||||
<Tab
|
||||
eventKey="tabDuration"
|
||||
className="bg-transparent"
|
||||
title={<Trans i18nKey="STAT_PAGE.DURATION_VIEW" />}
|
||||
/>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="date-range">
|
||||
@@ -75,23 +83,23 @@ function Statistics() {
|
||||
</div>
|
||||
|
||||
{activeTab === "tabCount" && (
|
||||
<>
|
||||
<div>
|
||||
<DailyPlayStats days={days} viewName="count" />
|
||||
<div className="statistics-graphs">
|
||||
<PlayStatsByDay days={days} viewName="count" />
|
||||
<PlayStatsByHour days={days} viewName="count" />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === "tabTime" && (
|
||||
<>
|
||||
<DailyPlayStats days={days} viewName="watchTime" />
|
||||
{activeTab === "tabDuration" && (
|
||||
<div>
|
||||
<DailyPlayStats days={days} viewName="duration" />
|
||||
<div className="statistics-graphs">
|
||||
<PlayStatsByDay days={days} viewName="watchTime" />
|
||||
<PlayStatsByHour days={days} viewName="watchTime" />
|
||||
<PlayStatsByDay days={days} viewName="duration" />
|
||||
<PlayStatsByHour days={days} viewName="duration" />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user