From ae726bbc1a037aa8a64e21019313fd0d94954941 Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Thu, 12 Dec 2024 11:29:08 +0300 Subject: [PATCH 01/10] Added stats query and stats API request --- src/api/queries/index.ts | 1 + src/api/queries/stats/get-page-stats-query.ts | 27 +++++++++++++ src/api/queries/stats/index.ts | 1 + src/app/api/sentry-example-api/route.ts | 9 ----- src/app/api/stats/route.ts | 40 +++++++++++++++++++ src/config/.gitignore | 2 +- src/config/config.template.ts | 6 +++ src/core/react-query/index.ts | 3 +- 8 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 src/api/queries/stats/get-page-stats-query.ts create mode 100644 src/api/queries/stats/index.ts delete mode 100644 src/app/api/sentry-example-api/route.ts create mode 100644 src/app/api/stats/route.ts diff --git a/src/api/queries/index.ts b/src/api/queries/index.ts index 438a41855..a3fd984e4 100644 --- a/src/api/queries/index.ts +++ b/src/api/queries/index.ts @@ -68,3 +68,4 @@ export * from "./get-chain-properties-query"; export * from "./get-gifs-query"; export * from "./spk"; export * from "./engine"; +export * from "./stats"; diff --git a/src/api/queries/stats/get-page-stats-query.ts b/src/api/queries/stats/get-page-stats-query.ts new file mode 100644 index 000000000..bc0c5c75f --- /dev/null +++ b/src/api/queries/stats/get-page-stats-query.ts @@ -0,0 +1,27 @@ +import { EcencyQueriesManager, QueryIdentifiers } from "@/core/react-query"; +import { appAxios } from "@/api/axios"; + +interface StatsResponse { + results: [ + { + metrics: [visitors: number, pageviews: number]; + } + ]; + query: { + site_id: string; + metrics: string[]; + date_range: string[]; + filters: unknown[]; + }; +} + +export function useGetStatsQuery(url: string) { + return EcencyQueriesManager.generateClientServerQuery({ + queryKey: [QueryIdentifiers.PAGE_STATS, url], + queryFn: async () => { + const response = await appAxios.get(`/stats?url=${encodeURIComponent(url)}`); + return response.data; + }, + enabled: !!url + }); +} diff --git a/src/api/queries/stats/index.ts b/src/api/queries/stats/index.ts new file mode 100644 index 000000000..67fbc9d63 --- /dev/null +++ b/src/api/queries/stats/index.ts @@ -0,0 +1 @@ +export * from "./get-page-stats-query"; diff --git a/src/app/api/sentry-example-api/route.ts b/src/app/api/sentry-example-api/route.ts deleted file mode 100644 index f486f3d1d..000000000 --- a/src/app/api/sentry-example-api/route.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NextResponse } from "next/server"; - -export const dynamic = "force-dynamic"; - -// A faulty API route to test Sentry's error monitoring -export function GET() { - throw new Error("Sentry Example API Route Error"); - return NextResponse.json({ data: "Testing Sentry Error..." }); -} diff --git a/src/app/api/stats/route.ts b/src/app/api/stats/route.ts new file mode 100644 index 000000000..7499e7528 --- /dev/null +++ b/src/app/api/stats/route.ts @@ -0,0 +1,40 @@ +import { NextRequest } from "next/server"; +import { EcencyConfigManager } from "@/config"; + +export async function GET(request: NextRequest) { + const isEnabled = EcencyConfigManager.getConfigValue( + ({ visionFeatures }) => visionFeatures.plausible.enabled + ); + if (!isEnabled) { + return Response.json({ status: 404 }); + } + + const url = request.nextUrl.searchParams.get("url"); + const dateRange = request.nextUrl.searchParams.get("dateRange") ?? "all"; + + if (!url) { + return Response.json({ status: 400 }); + } + + const statsHost = EcencyConfigManager.getConfigValue( + ({ visionFeatures }) => visionFeatures.plausible.host + ); + + return fetch(`${statsHost}/api/v2/query`, { + method: "POST", + headers: { + Authorization: `Bearer ${EcencyConfigManager.getConfigValue( + ({ visionFeatures }) => visionFeatures.plausible.apiKey + )}))}` + }, + body: JSON.stringify({ + site_id: EcencyConfigManager.getConfigValue( + ({ visionFeatures }) => visionFeatures.plausible.siteId + ), + metrics: ["visitors", "pageviews"], + filters: [["contains", "event:page", [url]]], + date_range: dateRange + }), + cache: "default" + }); +} diff --git a/src/config/.gitignore b/src/config/.gitignore index c3c165302..58ae5385d 100644 --- a/src/config/.gitignore +++ b/src/config/.gitignore @@ -1 +1 @@ -config.ts +./config.ts diff --git a/src/config/config.template.ts b/src/config/config.template.ts index 5a8b03dd4..21b8201e9 100644 --- a/src/config/config.template.ts +++ b/src/config/config.template.ts @@ -94,6 +94,12 @@ const CONFIG = { }, center: { enabled: true + }, + plausible: { + enabled: true, + host: "pl.ecency.com", + siteId: "ecency.com", + apiKey: process.env.PLAUSIBLE_API_KEY } }, service: { diff --git a/src/core/react-query/index.ts b/src/core/react-query/index.ts index 4d1fbf1bc..1188b3b7d 100644 --- a/src/core/react-query/index.ts +++ b/src/core/react-query/index.ts @@ -95,7 +95,8 @@ export enum QueryIdentifiers { HIVE_ENGINE_ALL_TOKENS = "hive-engine-all-tokens", GET_HIVE_ENGINE_MARKET_DATA = "get-hive-engine-market-data", HIVE_ENGINE_TOKEN_BALANCES = "hive-engine-token-balances", - HIVE_ENGINE_TOKEN_BALANCES_USD = "hive-engine-token-balances-usd" + HIVE_ENGINE_TOKEN_BALANCES_USD = "hive-engine-token-balances-usd", + PAGE_STATS = "page-stats" } export function makeQueryClient() { From 9abf0cb9b3c3e58c9d0c407bf17fd62e7034a74c Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Thu, 12 Dec 2024 11:59:56 +0300 Subject: [PATCH 02/10] Clean up entry header --- .../_components/entry-page-main-info.tsx | 68 +++++++------- .../[category]/[author]/[permlink]/entry.scss | 90 ------------------- src/features/i18n/locales/en-US.json | 2 +- src/features/shared/entry-menu/index.tsx | 40 +-------- src/features/shared/user-avatar/_index.scss | 4 + src/servers.json | 1 + 6 files changed, 43 insertions(+), 162 deletions(-) diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx index 7713e470c..9604be37f 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx @@ -19,56 +19,54 @@ export function EntryPageMainInfo({ entry }: Props) { const reputation = accountReputation(entry.author_reputation ?? 0); return ( -
- -
- -
-
- -
-
+
+
+ + + +
-
- - - + -
-
- - {published.fromNow()} - - -
- {i18next.t("entry.community-in")} +
+
{i18next.t("entry.published")}
-
- {entry.community ? entry.community_title : `#${entry.category}`} -
+ {entry.community ? entry.community_title : `#${entry.category}`}
+ +
+ {published.fromNow()} +
- - {!isComment && ( - visionFeatures.bookmarks.enabled} - > - - - )} - {!isComment && } +
+
+
+ {!isComment && ( + visionFeatures.bookmarks.enabled} + > + + + )} + {!isComment && } +
+
); } diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss index 4f06f4b7b..59b44fee5 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss @@ -197,16 +197,6 @@ .entry-header { margin-bottom: 15px; - @include themify(day) { - border-bottom: 1px solid; - @apply border-light-400; - } - - @include themify(night) { - border-bottom: 1px solid; - @apply border-dark-200; - } - h1.entry-title { font-size: 42px; margin: 16px 0 22px 0; @@ -262,86 +252,6 @@ gap: 0.5rem; } - .entry-info { - @include clearfix(); - @apply text-gray-steel; - align-items: center; - display: flex; - flex-grow: 1; - flex-shrink: 0; - - @media (min-width: $md-break) { - flex-direction: row; - } - - @include themify(day) { - @apply text-gray-steel; - } - - @include themify(night) { - @apply text-gray-pinkish; - } - - .separator { - &:first-of-type { - display: none; - - @media (min-width: $sm-break) { - display: block; - } - } - } - - .author { - align-items: center; - cursor: pointer; - display: none; - - @media (min-width: $sm-break) { - display: inline-flex; - } - - .author-name { - font-weight: 700; - margin-right: 2px; - } - - @include themify(day) { - @apply text-gray-charcoal; - } - - @include themify(night) { - @apply text-gray-pinkish; - } - - .author-reputation { - @apply text-gray-steel; - font-weight: 500; - - &::before { - content: "("; - } - - &::after { - content: ")"; - } - } - } - - .app { - font-weight: 700; - - a { - text-decoration: none; - @apply text-gray-steel; - } - - .app-name { - font-weight: 400; - } - } - } - .entry-controls { align-items: center; display: flex; diff --git a/src/features/i18n/locales/en-US.json b/src/features/i18n/locales/en-US.json index debd298b5..1ac0cf29f 100644 --- a/src/features/i18n/locales/en-US.json +++ b/src/features/i18n/locales/en-US.json @@ -731,7 +731,7 @@ "browse-original": "Open original post", "cross-post-by": "Cross post by", "cross-post-community": "community", - "community-in": "in", + "published": "Published in", "post-word-count": "Words:", "post-read-time": "Reading:", "post-read-minuites": "min", diff --git a/src/features/shared/entry-menu/index.tsx b/src/features/shared/entry-menu/index.tsx index 020ba3e38..cf212dc1f 100644 --- a/src/features/shared/entry-menu/index.tsx +++ b/src/features/shared/entry-menu/index.tsx @@ -9,13 +9,8 @@ import { getCommunityCache, useCommunityPin } from "@/core/caches"; import { useGlobalStore } from "@/core/global-store"; import { useDeleteComment, usePinToBlog } from "@/api/mutations"; import { useRouter } from "next/navigation"; -import { dotsHorizontal, shareVariantSvg } from "@ui/svg"; -import { - EntryShare, - shareFacebook, - shareReddit, - shareTwitter -} from "@/features/shared/entry-share"; +import { dotsHorizontal } from "@ui/svg"; +import { EntryShare } from "@/features/shared/entry-share"; import i18next from "i18next"; import { Dropdown, DropdownItemWithIcon, DropdownMenu, DropdownToggle } from "@ui/dropdown"; import { CrossPost } from "@/features/shared/entry-menu/cross-post"; @@ -23,7 +18,7 @@ import { EditHistory } from "@/features/shared/edit-history"; import { Button, ModalConfirm } from "@/features/ui"; import { MuteBtn } from "@/features/shared/mute-btn"; import { Promote } from "@/features/shared/promote"; -import { UilFacebook, UilRedditAlienAlt, UilTwitter } from "@tooni/iconscout-unicons-react"; +import { UilShareAlt } from "@tooni/iconscout-unicons-react"; interface Props { entry: Entry; @@ -74,34 +69,7 @@ export const EntryMenu = ({ return (
- {separatedSharing && ( -
-
setShare(false)}> - {shareVariantSvg} -
-
-
-
- )} + + setShowStats(false)}> + {i18next.t("entry.stats.stats-details")} + +
+ + {createdDate} – {i18next.t("g.today")} + + + {i18next.t("entry.stats.update-info")} +
+
+ + + +
+
+
+ ); } diff --git a/src/app/api/stats/route.ts b/src/app/api/stats/route.ts index 086e07c59..e8259147f 100644 --- a/src/app/api/stats/route.ts +++ b/src/app/api/stats/route.ts @@ -32,8 +32,9 @@ export async function GET(request: NextRequest) { site_id: EcencyConfigManager.getConfigValue( ({ visionFeatures }) => visionFeatures.plausible.siteId ), - metrics: ["visitors", "pageviews"], + metrics: ["visitors", "pageviews", "visit_duration"], filters: [["contains", "event:page", [decodeURIComponent(url)]]], + dimensions: ["visit:country_name", "visit:device"], date_range: dateRange }), cache: "default" diff --git a/src/features/i18n/locales/en-US.json b/src/features/i18n/locales/en-US.json index 1ac0cf29f..08098c30b 100644 --- a/src/features/i18n/locales/en-US.json +++ b/src/features/i18n/locales/en-US.json @@ -92,7 +92,8 @@ "success": "Success", "error": "Error", "reset-form": "Reset form", - "community": "Community" + "community": "Community", + "today": "Today" }, "confirm": { "title": "Are you sure?", @@ -736,7 +737,14 @@ "post-read-time": "Reading:", "post-read-minuites": "min", "raw": "View RAW format", - "post-top-curator": "Top Curator:" + "post-top-curator": "Top Curator:", + "stats": { + "stats-details": "Lifetime statistics", + "update-info": "Updating every minute", + "visitors": "Visitors", + "views": "Views", + "reads": "Read time" + } }, "edit-history": { "title": "Edit History", From c06829567610f97c47f816c1b6c19751697c6133 Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Fri, 13 Dec 2024 08:45:32 +0300 Subject: [PATCH 06/10] Added stats by countries --- src/api/queries/stats/get-page-stats-query.ts | 22 +++++--- .../entry-page-stats-by-countries.tsx | 55 +++++++++++++++++++ .../_components/entry-page-stats-item.tsx | 10 +++- .../_components/entry-page-stats.tsx | 22 +++----- src/app/api/stats/route.ts | 9 ++- src/features/i18n/locales/en-US.json | 3 +- 6 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx diff --git a/src/api/queries/stats/get-page-stats-query.ts b/src/api/queries/stats/get-page-stats-query.ts index 51763b0ca..c69879c3b 100644 --- a/src/api/queries/stats/get-page-stats-query.ts +++ b/src/api/queries/stats/get-page-stats-query.ts @@ -1,11 +1,11 @@ import { EcencyQueriesManager, QueryIdentifiers } from "@/core/react-query"; import { appAxios } from "@/api/axios"; -interface StatsResponse { +export interface StatsResponse { results: [ { - metrics: [visitors: number, pageviews: number, visit_duration: number]; - dimensions: [country: string, device: string]; + metrics: number[]; + dimensions: string[]; } ]; query: { @@ -16,13 +16,19 @@ interface StatsResponse { }; } -export function useGetStatsQuery(url: string) { +export function useGetStatsQuery( + url: string, + dimensions: string[] = [], + metrics = ["visitors", "pageviews", "visit_duration"] +) { return EcencyQueriesManager.generateClientServerQuery({ - queryKey: [QueryIdentifiers.PAGE_STATS, url], + queryKey: [QueryIdentifiers.PAGE_STATS, url, dimensions, metrics], queryFn: async () => { - const response = await appAxios.get( - `/api/stats?url=${encodeURIComponent(url)}` - ); + const response = await appAxios.post(`/api/stats`, { + metrics, + url: encodeURIComponent(url), + dimensions + }); return response.data; }, enabled: !!url diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx new file mode 100644 index 000000000..af597a61b --- /dev/null +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx @@ -0,0 +1,55 @@ +import i18next from "i18next"; +import { useMemo } from "react"; +import { useGetStatsQuery } from "@/api/queries"; +import { AnimatePresence, motion } from "framer-motion"; + +interface Props { + totalViews: number; + cleanedPathname: string; +} + +export function EntryPageStatsByCountries({ totalViews, cleanedPathname }: Props) { + const { data: stats } = useGetStatsQuery(cleanedPathname, [ + "visit:country_name" + ]).useClientQuery(); + + const countries = useMemo( + () => + stats?.results?.reduce>((acc, result) => { + const country = result.dimensions[0]; + const views = +result.metrics[1]; + return { ...acc, [country]: (acc[country] ?? 0) + views }; + }, {}) ?? {}, + [stats?.results] + ); + const countriesList = useMemo( + () => Object.entries(countries).sort((a, b) => b[1] - a[1]), + [countries] + ); + + return ( +
+
{i18next.t("entry.stats.countries")}
+ + {countriesList.map(([country, views]) => ( + + +
{country}
+
{views}
+
+ ))} +
+
+ ); +} diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item.tsx index 28040c47f..603fb1b12 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item.tsx @@ -1,3 +1,4 @@ +import { motion } from "framer-motion"; import { ReactNode } from "react"; interface Props { @@ -7,9 +8,14 @@ interface Props { export function EntryPageStatsItem({ count, label }: Props) { return ( -
+
{count}
{label}
-
+ ); } diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx index d5a3c4484..c446a85c8 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx @@ -10,6 +10,7 @@ import i18next from "i18next"; import { Entry } from "@/entities"; import { format, parseISO } from "date-fns"; import { EntryPageStatsItem } from "@/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item"; +import { EntryPageStatsByCountries } from "./entry-page-stats-by-countries"; interface Props { entry: Entry; @@ -38,19 +39,10 @@ export function EntryPageStats({ entry }: Props) { const { data: stats } = useGetStatsQuery(cleanedPathname).useClientQuery(); - const totalViews = useMemo( - () => stats?.results?.reduce((acc, result) => acc + result.metrics[1], 0) ?? 1, - [stats?.results] - ); - const totalVisitors = useMemo( - () => stats?.results?.reduce((acc, result) => acc + result.metrics[0], 0) ?? 0, - [stats?.results] - ); + const totalViews = useMemo(() => stats?.results?.[0].metrics[1] ?? 1, [stats?.results]); + const totalVisitors = useMemo(() => stats?.results?.[0].metrics[0] ?? 0, [stats?.results]); const averageReadTime = useMemo( - () => - ( - (stats?.results?.reduce((acc, result) => acc + result.metrics[2], 0) ?? 0 ?? 0) / totalViews - ).toFixed(1), + () => ((stats?.results?.[0].metrics[2] ?? 0) / totalViews).toFixed(1), [stats?.results, totalViews] ); @@ -65,7 +57,7 @@ export function EntryPageStats({ entry }: Props) { > {totalViews} - setShowStats(false)}> + setShowStats(false)}> {i18next.t("entry.stats.stats-details")}
@@ -83,6 +75,10 @@ export function EntryPageStats({ entry }: Props) { label={i18next.t("entry.stats.reads")} />
+ +
+ +
diff --git a/src/app/api/stats/route.ts b/src/app/api/stats/route.ts index e8259147f..3e349b986 100644 --- a/src/app/api/stats/route.ts +++ b/src/app/api/stats/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { EcencyConfigManager } from "@/config"; -export async function GET(request: NextRequest) { +export async function POST(request: NextRequest) { const isEnabled = EcencyConfigManager.getConfigValue( ({ visionFeatures }) => visionFeatures.plausible.enabled ); @@ -9,8 +9,7 @@ export async function GET(request: NextRequest) { return Response.json({ status: 404 }); } - const url = request.nextUrl.searchParams.get("url"); - const dateRange = request.nextUrl.searchParams.get("dateRange") ?? "all"; + const { url, dateRange = "all", metrics, dimensions } = await request.json(); if (!url) { return Response.json({ status: 400 }); @@ -32,9 +31,9 @@ export async function GET(request: NextRequest) { site_id: EcencyConfigManager.getConfigValue( ({ visionFeatures }) => visionFeatures.plausible.siteId ), - metrics: ["visitors", "pageviews", "visit_duration"], + metrics, filters: [["contains", "event:page", [decodeURIComponent(url)]]], - dimensions: ["visit:country_name", "visit:device"], + dimensions, date_range: dateRange }), cache: "default" diff --git a/src/features/i18n/locales/en-US.json b/src/features/i18n/locales/en-US.json index 08098c30b..852918881 100644 --- a/src/features/i18n/locales/en-US.json +++ b/src/features/i18n/locales/en-US.json @@ -743,7 +743,8 @@ "update-info": "Updating every minute", "visitors": "Visitors", "views": "Views", - "reads": "Read time" + "reads": "Read time", + "countries": "Countries" } }, "edit-history": { From 1cca629b7f32572e21bbe7389120e491d1829f02 Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Fri, 13 Dec 2024 08:50:29 +0300 Subject: [PATCH 07/10] Added stats by devices --- .../entry-page-stats-by-devices.tsx | 53 +++++++++++++++++++ .../_components/entry-page-stats.tsx | 2 + src/features/i18n/locales/en-US.json | 3 +- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx new file mode 100644 index 000000000..d37b29661 --- /dev/null +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx @@ -0,0 +1,53 @@ +import i18next from "i18next"; +import { useMemo } from "react"; +import { useGetStatsQuery } from "@/api/queries"; +import { AnimatePresence, motion } from "framer-motion"; + +interface Props { + totalViews: number; + cleanedPathname: string; +} + +export function EntryPageStatsByDevices({ totalViews, cleanedPathname }: Props) { + const { data: stats } = useGetStatsQuery(cleanedPathname, ["visit:device"]).useClientQuery(); + + const countries = useMemo( + () => + stats?.results?.reduce>((acc, result) => { + const country = result.dimensions[0]; + const views = +result.metrics[1]; + return { ...acc, [country]: (acc[country] ?? 0) + views }; + }, {}) ?? {}, + [stats?.results] + ); + const countriesList = useMemo( + () => Object.entries(countries).sort((a, b) => b[1] - a[1]), + [countries] + ); + + return ( +
+
{i18next.t("entry.stats.devices")}
+ + {countriesList.map(([country, views]) => ( + + +
{country}
+
{views}
+
+ ))} +
+
+ ); +} diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx index c446a85c8..e3b80b6ef 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx @@ -11,6 +11,7 @@ import { Entry } from "@/entities"; import { format, parseISO } from "date-fns"; import { EntryPageStatsItem } from "@/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item"; import { EntryPageStatsByCountries } from "./entry-page-stats-by-countries"; +import { EntryPageStatsByDevices } from "@/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices"; interface Props { entry: Entry; @@ -78,6 +79,7 @@ export function EntryPageStats({ entry }: Props) {
+
diff --git a/src/features/i18n/locales/en-US.json b/src/features/i18n/locales/en-US.json index 852918881..b9d8153af 100644 --- a/src/features/i18n/locales/en-US.json +++ b/src/features/i18n/locales/en-US.json @@ -744,7 +744,8 @@ "visitors": "Visitors", "views": "Views", "reads": "Read time", - "countries": "Countries" + "countries": "Countries", + "devices": "Devices" } }, "edit-history": { From c2ec4643511053ce77bea156517cac82a69e0d8d Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Fri, 13 Dec 2024 09:00:39 +0300 Subject: [PATCH 08/10] Added empty stats statement --- .../_components/entry-page-stats-by-countries.tsx | 4 +++- .../_components/entry-page-stats-by-devices.tsx | 13 ++++++------- .../[permlink]/_components/entry-page-stats.tsx | 8 +++++++- src/features/i18n/locales/en-US.json | 3 ++- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx index af597a61b..0fac0270a 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-countries.tsx @@ -27,7 +27,7 @@ export function EntryPageStatsByCountries({ totalViews, cleanedPathname }: Props [countries] ); - return ( + return countriesList.length > 0 ? (
{i18next.t("entry.stats.countries")}
@@ -51,5 +51,7 @@ export function EntryPageStatsByCountries({ totalViews, cleanedPathname }: Props ))}
+ ) : ( + <> ); } diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx index d37b29661..17fed0c13 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices.tsx @@ -11,7 +11,7 @@ interface Props { export function EntryPageStatsByDevices({ totalViews, cleanedPathname }: Props) { const { data: stats } = useGetStatsQuery(cleanedPathname, ["visit:device"]).useClientQuery(); - const countries = useMemo( + const devices = useMemo( () => stats?.results?.reduce>((acc, result) => { const country = result.dimensions[0]; @@ -20,16 +20,13 @@ export function EntryPageStatsByDevices({ totalViews, cleanedPathname }: Props) }, {}) ?? {}, [stats?.results] ); - const countriesList = useMemo( - () => Object.entries(countries).sort((a, b) => b[1] - a[1]), - [countries] - ); + const devicesList = useMemo(() => Object.entries(devices).sort((a, b) => b[1] - a[1]), [devices]); - return ( + return devicesList.length > 0 ? (
{i18next.t("entry.stats.devices")}
- {countriesList.map(([country, views]) => ( + {devicesList.map(([country, views]) => (
+ ) : ( + <> ); } diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx index e3b80b6ef..06124a466 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx @@ -2,7 +2,7 @@ import { usePathname } from "next/navigation"; import { useGetStatsQuery } from "@/api/queries"; -import { UilEye } from "@tooni/iconscout-unicons-react"; +import { UilEye, UilInfoCircle } from "@tooni/iconscout-unicons-react"; import { useMemo, useState } from "react"; import { Button } from "@ui/button"; import { Modal, ModalBody, ModalHeader } from "@ui/modal"; @@ -12,6 +12,7 @@ import { format, parseISO } from "date-fns"; import { EntryPageStatsItem } from "@/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-item"; import { EntryPageStatsByCountries } from "./entry-page-stats-by-countries"; import { EntryPageStatsByDevices } from "@/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats-by-devices"; +import { Alert } from "@ui/alert"; interface Props { entry: Entry; @@ -81,6 +82,11 @@ export function EntryPageStats({ entry }: Props) {
+ + + +
{i18next.t("entry.stats.warn")}
+
diff --git a/src/features/i18n/locales/en-US.json b/src/features/i18n/locales/en-US.json index b9d8153af..2559981ed 100644 --- a/src/features/i18n/locales/en-US.json +++ b/src/features/i18n/locales/en-US.json @@ -745,7 +745,8 @@ "views": "Views", "reads": "Read time", "countries": "Countries", - "devices": "Devices" + "devices": "Devices", + "warn": "Stats are collecting only in Ecency's applications" } }, "edit-history": { From 333039349bea3d3e42c6bbd36b1748fde81c43cb Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Fri, 13 Dec 2024 09:17:05 +0300 Subject: [PATCH 09/10] Fixed stats URL parameter --- .../[permlink]/_components/entry-page-main-info.tsx | 4 ++-- .../[author]/[permlink]/_components/entry-page-stats.tsx | 8 +++++--- .../[permlink]/_components/entry-read-time/index.tsx | 7 +++---- .../entry/[category]/[author]/[permlink]/entry.scss | 4 ---- src/config/config.ts | 6 ++++++ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx index ab1bc52aa..7475d422d 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-main-info.tsx @@ -49,10 +49,10 @@ export function EntryPageMainInfo({ entry }: Props) {
- -
+ +
diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx index 06124a466..be3dbfff6 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/_components/entry-page-stats.tsx @@ -28,11 +28,12 @@ export function EntryPageStats({ entry }: Props) { */ const cleanedPathname = useMemo(() => { const sections = pathname.split("/"); - if (sections.length === 3) { - return `${sections[1]}/${sections[2]}`; + console.log(sections); + if (sections.length === 4) { + return `${sections[2]}/${sections[3]}`; } - return `${sections[0]}/${sections[1]}`; + return `${sections[1]}/${sections[2]}`; }, [pathname]); const createdDate = useMemo( () => format(parseISO(entry.created), "dd MMM yyyy"), @@ -51,6 +52,7 @@ export function EntryPageStats({ entry }: Props) { return ( <>
) : ( diff --git a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss index 43405bb41..30c812426 100644 --- a/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss +++ b/src/app/(dynamicPages)/entry/[category]/[author]/[permlink]/entry.scss @@ -400,10 +400,6 @@ } } -.post-info { - margin-right: 10px; -} - .top-curator { display: flex; diff --git a/src/config/config.ts b/src/config/config.ts index 3621acb6f..0656df964 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -90,6 +90,12 @@ const CONFIG = { }, center: { enabled: true + }, + plausible: { + enabled: true, + host: "https://pl.ecency.com", + siteId: "ecency.com", + apiKey: process.env.PLAUSIBLE_API_KEY } }, service: { From 7e9228ea17deae66baa2595bc2dba1b9e03c4231 Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Fri, 13 Dec 2024 09:19:01 +0300 Subject: [PATCH 10/10] Added secrets to CDs --- .github/workflows/master.yml | 3 +++ .github/workflows/staging.yml | 1 + 2 files changed, 4 insertions(+) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 3f696df3d..851286f09 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -76,6 +76,7 @@ jobs: export HIVESIGNER_SECRET=$HIVESIGNER_SECRET export SEARCH_API_ADDR=$SEARCH_API_ADDR export SEARCH_API_SECRET=$SEARCH_API_SECRET + export PLAUSIBLE_API_KEY=$PLAUSIBLE_API_KEY cd ~/vision-next git pull origin main docker system prune -f @@ -110,6 +111,7 @@ jobs: export HIVESIGNER_SECRET=$HIVESIGNER_SECRET export SEARCH_API_ADDR=$SEARCH_API_ADDR export SEARCH_API_SECRET=$SEARCH_API_SECRET + export PLAUSIBLE_API_KEY=$PLAUSIBLE_API_KEY cd ~/vision-next git pull origin main docker system prune -f @@ -144,6 +146,7 @@ jobs: export HIVESIGNER_SECRET=$HIVESIGNER_SECRET export SEARCH_API_ADDR=$SEARCH_API_ADDR export SEARCH_API_SECRET=$SEARCH_API_SECRET + export PLAUSIBLE_API_KEY=$PLAUSIBLE_API_KEY cd ~/vision-next git pull origin main docker system prune -f diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index e1ce9d98e..61eb5e2e5 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -76,6 +76,7 @@ jobs: export HIVESIGNER_SECRET=$HIVESIGNER_SECRET export SEARCH_API_ADDR=$SEARCH_API_ADDR export SEARCH_API_SECRET=$SEARCH_API_SECRET + export PLAUSIBLE_API_KEY=$PLAUSIBLE_API_KEY cd ~/vision-next git pull origin develop docker pull ecency/vision-next:develop