From 433f02fed37dc717ed856d831736d4b6edfd617d Mon Sep 17 00:00:00 2001 From: rebelchris Date: Mon, 2 Feb 2026 11:13:50 +0000 Subject: [PATCH 1/4] feat(analytics): add combined analytics page for user posts Add analytics dashboard that displays aggregated metrics across all posts authored by the current user. - Create /analytics page with ProtectedPage wrapper - Add summary tiles for impressions, upvotes, followers, reputation - Add impressions chart showing organic vs promoted (boosted) posts - Add paginated posts table with analytics per post - Add GraphQL queries and TypeScript types for user posts analytics - Add Analytics menu item in ProfileMenu dropdown Co-Authored-By: Claude Opus 4.5 --- .../ProfileMenu/sections/MainSection.tsx | 7 +- packages/shared/src/graphql/users.ts | 91 +++++ packages/shared/src/lib/query.ts | 3 + .../analytics/AnalyticsEmptyState.tsx | 51 +++ .../analytics/CombinedImpressionsChart.tsx | 105 ++++++ .../analytics/UserPostsAnalyticsTable.tsx | 181 +++++++++ packages/webapp/pages/analytics/index.tsx | 356 ++++++++++++++++++ 7 files changed, 793 insertions(+), 1 deletion(-) create mode 100644 packages/webapp/components/analytics/AnalyticsEmptyState.tsx create mode 100644 packages/webapp/components/analytics/CombinedImpressionsChart.tsx create mode 100644 packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx create mode 100644 packages/webapp/pages/analytics/index.tsx diff --git a/packages/shared/src/components/ProfileMenu/sections/MainSection.tsx b/packages/shared/src/components/ProfileMenu/sections/MainSection.tsx index f9dca357e7..183c870437 100644 --- a/packages/shared/src/components/ProfileMenu/sections/MainSection.tsx +++ b/packages/shared/src/components/ProfileMenu/sections/MainSection.tsx @@ -2,7 +2,7 @@ import React from 'react'; import type { ReactElement } from 'react'; import { ProfileSection } from '../ProfileSection'; -import { CoinIcon, DevCardIcon, UserIcon } from '../../icons'; +import { AnalyticsIcon, CoinIcon, DevCardIcon, UserIcon } from '../../icons'; import { settingsUrl, walletUrl, webappUrl } from '../../../lib/constants'; import { useAuthContext } from '../../../contexts/AuthContext'; import { useHasAccessToCores } from '../../../hooks/useCoresFeature'; @@ -29,6 +29,11 @@ export const MainSection = (): ReactElement => { href: `${settingsUrl}/customization/devcard`, icon: DevCardIcon, }, + { + title: 'Analytics', + href: `${webappUrl}analytics`, + icon: AnalyticsIcon, + }, ].filter(Boolean)} /> ); diff --git a/packages/shared/src/graphql/users.ts b/packages/shared/src/graphql/users.ts index a846ebabd2..5e4ae1dac6 100644 --- a/packages/shared/src/graphql/users.ts +++ b/packages/shared/src/graphql/users.ts @@ -593,6 +593,41 @@ export interface UserProfileAnalyticsHistory { updatedAt: Date; } +export interface UserPostsAnalytics { + id: string; + impressions: number; + reach: number; + upvotes: number; + comments: number; + bookmarks: number; + awards: number; + profileViews: number; + followers: number; + reputation: number; + coresEarned: number; + shares: number; + clicks: number; + upvotesRatio: number; +} + +export interface UserPostsAnalyticsHistoryNode { + date: string; + impressions: number; + impressionsAds: number; +} + +export interface UserPostWithAnalytics { + id: string; + title: string | null; + image: string | null; + createdAt: string; + impressions: number; + upvotes: number; + reputation: number; + isBoosted: boolean; + commentsPermalink: string; +} + export const getReadingStreak = async (): Promise => { const res = await gqlClient.request(USER_STREAK_QUERY); @@ -892,3 +927,59 @@ export const updateNotificationSettings = async ( notificationFlags, }); }; + +export const USER_POSTS_ANALYTICS_QUERY = gql` + query UserPostsAnalytics { + userPostsAnalytics { + id + impressions + reach + upvotes + comments + bookmarks + awards + profileViews + followers + reputation + coresEarned + shares + clicks + upvotesRatio + } + } +`; + +export const USER_POSTS_ANALYTICS_HISTORY_QUERY = gql` + query UserPostsAnalyticsHistory { + userPostsAnalyticsHistory { + date + impressions + impressionsAds + } + } +`; + +export const USER_POSTS_WITH_ANALYTICS_QUERY = gql` + query UserPostsWithAnalytics($after: String, $first: Int) { + userPostsWithAnalytics(after: $after, first: $first) { + edges { + cursor + node { + id + title + image + createdAt + impressions + upvotes + reputation + isBoosted + commentsPermalink + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +`; diff --git a/packages/shared/src/lib/query.ts b/packages/shared/src/lib/query.ts index 838d236596..833b2f41df 100644 --- a/packages/shared/src/lib/query.ts +++ b/packages/shared/src/lib/query.ts @@ -214,6 +214,9 @@ export enum RequestKey { PostAnalyticsHistory = 'post_analytics_history', ProfileAnalytics = 'profile_analytics', ProfileAnalyticsHistory = 'profile_analytics_history', + UserPostsAnalytics = 'user_posts_analytics', + UserPostsAnalyticsHistory = 'user_posts_analytics_history', + UserPostsWithAnalytics = 'user_posts_with_analytics', CheckLocation = 'check_location', GenerateBrief = 'generate_brief', Opportunity = 'opportunity', diff --git a/packages/webapp/components/analytics/AnalyticsEmptyState.tsx b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx new file mode 100644 index 0000000000..48e7e28263 --- /dev/null +++ b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import type { ReactElement } from 'react'; +import { + Typography, + TypographyColor, + TypographyType, +} from '@dailydotdev/shared/src/components/typography/Typography'; +import { Button, ButtonVariant } from '@dailydotdev/shared/src/components/buttons/Button'; +import { PlusIcon, EditIcon } from '@dailydotdev/shared/src/components/icons'; +import { useLazyModal } from '@dailydotdev/shared/src/hooks/useLazyModal'; +import { LazyModal } from '@dailydotdev/shared/src/components/modals/common/types'; + +export const AnalyticsEmptyState = (): ReactElement => { + const { openModal } = useLazyModal(); + + const handleNewPost = () => { + openModal({ + type: LazyModal.NewPost, + }); + }; + + return ( +
+ +
+ + It's never too late to start posting + + + Hardest part of being a developer? Where do we start... it's + everything. Go on, share with us your best rant. + +
+ +
+ ); +}; diff --git a/packages/webapp/components/analytics/CombinedImpressionsChart.tsx b/packages/webapp/components/analytics/CombinedImpressionsChart.tsx new file mode 100644 index 0000000000..b4137cc4ab --- /dev/null +++ b/packages/webapp/components/analytics/CombinedImpressionsChart.tsx @@ -0,0 +1,105 @@ +import React from 'react'; +import type { ReactElement } from 'react'; +import { + Bar, + BarChart, + CartesianGrid, + Cell, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import type { TickProp } from 'recharts/types/util/types'; +import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; + +type ImpressionNode = { + name: string; + value: number; + isBoosted: boolean; +}; + +export interface CombinedImpressionsChartProps { + data: ImpressionNode[] | undefined; +} + +const tickProp: TickProp = { + fill: 'var(--theme-text-tertiary)', + fontSize: '0.6875rem', +}; + +export const CombinedImpressionsChart = ({ + data, +}: CombinedImpressionsChartProps): ReactElement => { + return ( +
+ {!!data && ( + + + + + largeNumberFormat(value)} + tickLine={false} + tick={tickProp} + interval={1} + /> + ( +
+ {largeNumberFormat(payload?.[0]?.value || 0)}{' '} + impressions on {label} +
+ )} + /> + + {data.map((entry) => { + return ( + + ); + })} + +
+
+ )} +
+ ); +}; diff --git a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx new file mode 100644 index 0000000000..0438700607 --- /dev/null +++ b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx @@ -0,0 +1,181 @@ +import React from 'react'; +import type { ReactElement } from 'react'; +import Link from 'next/link'; +import { + Typography, + TypographyColor, + TypographyType, +} from '@dailydotdev/shared/src/components/typography/Typography'; +import { Button, ButtonVariant } from '@dailydotdev/shared/src/components/buttons/Button'; +import { BoostIcon } from '@dailydotdev/shared/src/components/icons/Boost'; +import { IconSize } from '@dailydotdev/shared/src/components/Icon'; +import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; +import { TimeFormatType, formatDate } from '@dailydotdev/shared/src/lib/dateFormat'; +import type { UserPostWithAnalytics } from '@dailydotdev/shared/src/graphql/users'; +import { webappUrl } from '@dailydotdev/shared/src/lib/constants'; +import { LazyImage } from '@dailydotdev/shared/src/components/LazyImage'; +import { fallbackImages } from '@dailydotdev/shared/src/lib/config'; + +export interface UserPostsAnalyticsTableProps { + posts: UserPostWithAnalytics[]; + isLoading: boolean; + hasNextPage: boolean | undefined; + isFetchingNextPage: boolean; + fetchNextPage: () => void; +} + +export const UserPostsAnalyticsTable = ({ + posts, + isLoading, + hasNextPage, + isFetchingNextPage, + fetchNextPage, +}: UserPostsAnalyticsTableProps): ReactElement => { + if (isLoading) { + return ( +
+ + Loading posts... + +
+ ); + } + + return ( +
+
+ + + + + + + + + + + + {posts.map((post) => ( + + + + + + + + ))} + +
+ + Post + + + + Date + + + + Reputation + + + + Impressions + + + + Upvotes + +
+ + +
+
+ + {post.title || 'Untitled'} + + {post.isBoosted && ( + + )} +
+
+ +
+ + {formatDate({ + value: post.createdAt, + type: TimeFormatType.Post, + })} + + + + {largeNumberFormat(post.reputation)} + + + + {largeNumberFormat(post.impressions)} + + + + {largeNumberFormat(post.upvotes)} + +
+
+ {hasNextPage && ( + + )} +
+ ); +}; diff --git a/packages/webapp/pages/analytics/index.tsx b/packages/webapp/pages/analytics/index.tsx new file mode 100644 index 0000000000..cb90615154 --- /dev/null +++ b/packages/webapp/pages/analytics/index.tsx @@ -0,0 +1,356 @@ +import type { ReactElement } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import type { NextSeoProps } from 'next-seo'; +import { useQuery, useInfiniteQuery } from '@tanstack/react-query'; +import { addDays, subDays } from 'date-fns'; +import { + ResponsivePageContainer, + Divider, +} from '@dailydotdev/shared/src/components/utilities'; +import { LayoutHeader } from '@dailydotdev/shared/src/components/layout/common'; +import classNames from 'classnames'; +import { pageBorders } from '@dailydotdev/shared/src/components/utilities'; +import { + Typography, + TypographyColor, + TypographyTag, + TypographyType, +} from '@dailydotdev/shared/src/components/typography/Typography'; +import { DataTile } from '@dailydotdev/shared/src/components/DataTile'; +import { + AddUserIcon, + ReputationIcon, + UpvoteIcon, + EyeIcon, +} from '@dailydotdev/shared/src/components/icons'; +import { IconSize } from '@dailydotdev/shared/src/components/Icon'; +import classed from '@dailydotdev/shared/src/lib/classed'; +import { useAuthContext } from '@dailydotdev/shared/src/contexts/AuthContext'; +import { + generateQueryKey, + RequestKey, + StaleTime, + getNextPageParam, +} from '@dailydotdev/shared/src/lib/query'; +import { gqlClient } from '@dailydotdev/shared/src/graphql/common'; +import { + USER_POSTS_ANALYTICS_QUERY, + USER_POSTS_ANALYTICS_HISTORY_QUERY, + USER_POSTS_WITH_ANALYTICS_QUERY, +} from '@dailydotdev/shared/src/graphql/users'; +import type { + UserPostsAnalytics, + UserPostsAnalyticsHistoryNode, + UserPostWithAnalytics, +} from '@dailydotdev/shared/src/graphql/users'; +import type { Connection } from '@dailydotdev/shared/src/graphql/common'; +import { + dateFormatInTimezone, + DEFAULT_TIMEZONE, +} from '@dailydotdev/shared/src/lib/timezones'; +import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; +import dynamic from 'next/dynamic'; +import ProtectedPage from '../../components/ProtectedPage'; +import { getLayout } from '../../components/layouts/MainLayout'; +import { UserPostsAnalyticsTable } from '../../components/analytics/UserPostsAnalyticsTable'; +import { AnalyticsEmptyState } from '../../components/analytics/AnalyticsEmptyState'; + +const CombinedImpressionsChart = dynamic( + () => + import('../../components/analytics/CombinedImpressionsChart').then( + (mod) => mod.CombinedImpressionsChart, + ), + { + loading: () =>
, + }, +); + +const dividerClassName = 'bg-border-subtlest-tertiary'; +const SectionContainer = classed('div', 'flex flex-col gap-4'); +const SectionHeader = ({ children }: { children: React.ReactNode }): ReactElement => { + return ( + + {children} + + ); +}; + +const POST_ANALYTICS_HISTORY_LIMIT = 45; + +type ImpressionNode = { + name: string; + value: number; + isBoosted: boolean; +}; + +const Analytics = (): ReactElement => { + const { user } = useAuthContext(); + const userTimezone = user?.timezone || DEFAULT_TIMEZONE; + + const analyticsQueryKey = generateQueryKey( + RequestKey.UserPostsAnalytics, + user, + ); + + const historyQueryKey = generateQueryKey( + RequestKey.UserPostsAnalyticsHistory, + user, + ); + + const postsQueryKey = generateQueryKey( + RequestKey.UserPostsWithAnalytics, + user, + ); + + const { data: analytics, isLoading: isLoadingAnalytics } = useQuery({ + queryKey: analyticsQueryKey, + queryFn: async () => { + const result = await gqlClient.request<{ + userPostsAnalytics: UserPostsAnalytics; + }>(USER_POSTS_ANALYTICS_QUERY); + return result.userPostsAnalytics; + }, + staleTime: StaleTime.Default, + enabled: !!user, + }); + + const { data: historyData } = useQuery({ + queryKey: historyQueryKey, + queryFn: async () => { + const result = await gqlClient.request<{ + userPostsAnalyticsHistory: UserPostsAnalyticsHistoryNode[]; + }>(USER_POSTS_ANALYTICS_HISTORY_QUERY); + return result.userPostsAnalyticsHistory; + }, + staleTime: StaleTime.Default, + enabled: !!user, + select: useCallback( + (data: UserPostsAnalyticsHistoryNode[]): ImpressionNode[] => { + if (!data) { + return []; + } + + const impressionsMap = data.reduce( + (acc, item) => { + const date = dateFormatInTimezone( + new Date(item.date), + 'yyyy-MM-dd', + userTimezone, + ); + + acc[date] = { + name: new Date(item.date).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + }), + value: item.impressions, + isBoosted: item.impressionsAds > 0, + }; + + return acc; + }, + {} as Record, + ); + + const historyCutOffDate = subDays( + new Date(), + POST_ANALYTICS_HISTORY_LIMIT - 1, + ); + + const impressionsData: ImpressionNode[] = []; + + for (let i = 0; i < POST_ANALYTICS_HISTORY_LIMIT; i += 1) { + const paddedDate = addDays(historyCutOffDate, i); + const date = dateFormatInTimezone( + paddedDate, + 'yyyy-MM-dd', + userTimezone, + ); + + if (impressionsMap[date]) { + impressionsData.push(impressionsMap[date]); + } else { + impressionsData.push({ + name: paddedDate.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + }), + value: 0, + isBoosted: false, + }); + } + } + + return impressionsData; + }, + [userTimezone], + ), + }); + + const { + data: postsData, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + isLoading: isLoadingPosts, + } = useInfiniteQuery({ + queryKey: postsQueryKey, + queryFn: async ({ pageParam }) => { + const result = await gqlClient.request<{ + userPostsWithAnalytics: Connection; + }>(USER_POSTS_WITH_ANALYTICS_QUERY, { + first: 20, + after: pageParam, + }); + return result.userPostsWithAnalytics; + }, + initialPageParam: null as string | null, + getNextPageParam: (lastPage) => getNextPageParam(lastPage?.pageInfo), + staleTime: StaleTime.Default, + enabled: !!user, + }); + + const posts = useMemo( + () => postsData?.pages.flatMap((page) => page.edges.map((e) => e.node)) ?? [], + [postsData], + ); + + const hasNoPosts = !isLoadingPosts && posts.length === 0; + + if (hasNoPosts) { + return ( + +
+ + + Analytics + + + + + +
+
+ ); + } + + return ( + +
+ + + Analytics + + + + + Overview +
+ + } + /> + + } + /> + + } + /> + + } + /> +
+
+ + +
+ + Impressions in the last 45 days + +
+
+
+ Organic +
+
+
+ Promoted +
+
+
+ + + + + Posts + + + +
+ + ); +}; + +const seo: NextSeoProps = { title: 'Analytics', nofollow: true, noindex: true }; + +Analytics.getLayout = getLayout; +Analytics.layoutProps = { seo }; + +export default Analytics; From 6e10ab81b8f87f4cafc7f475a23657f6c645b387 Mon Sep 17 00:00:00 2001 From: rebelchris Date: Mon, 2 Feb 2026 11:32:49 +0000 Subject: [PATCH 2/4] fix(analytics): resolve TypeScript and lint errors in analytics page - Fix AnalyticsEmptyState to use navigation link instead of non-existent LazyModal.NewPost - Add recharts dependency to webapp for CombinedImpressionsChart - Use cloudinaryPostImageCoverPlaceholder for post image fallbacks - Change Link import to use shared utilities Link component - Remove unused isLoadingAnalytics variable - Fix duplicate imports and formatting issues Co-Authored-By: Claude Opus 4.5 --- .../analytics/AnalyticsEmptyState.tsx | 29 +- .../analytics/UserPostsAnalyticsTable.tsx | 23 +- packages/webapp/package.json | 1 + packages/webapp/pages/analytics/index.tsx | 57 ++-- pnpm-lock.yaml | 293 ++++++++++++++++-- 5 files changed, 328 insertions(+), 75 deletions(-) diff --git a/packages/webapp/components/analytics/AnalyticsEmptyState.tsx b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx index 48e7e28263..9f4ebfac9f 100644 --- a/packages/webapp/components/analytics/AnalyticsEmptyState.tsx +++ b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx @@ -5,20 +5,15 @@ import { TypographyColor, TypographyType, } from '@dailydotdev/shared/src/components/typography/Typography'; -import { Button, ButtonVariant } from '@dailydotdev/shared/src/components/buttons/Button'; +import { + Button, + ButtonVariant, +} from '@dailydotdev/shared/src/components/buttons/Button'; import { PlusIcon, EditIcon } from '@dailydotdev/shared/src/components/icons'; -import { useLazyModal } from '@dailydotdev/shared/src/hooks/useLazyModal'; -import { LazyModal } from '@dailydotdev/shared/src/components/modals/common/types'; +import { link } from '@dailydotdev/shared/src/lib/links'; +import Link from '@dailydotdev/shared/src/components/utilities/Link'; export const AnalyticsEmptyState = (): ReactElement => { - const { openModal } = useLazyModal(); - - const handleNewPost = () => { - openModal({ - type: LazyModal.NewPost, - }); - }; - return (
@@ -39,13 +34,11 @@ export const AnalyticsEmptyState = (): ReactElement => { everything. Go on, share with us your best rant.
- + + +
); }; diff --git a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx index 0438700607..302c0b443a 100644 --- a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx +++ b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx @@ -1,20 +1,26 @@ import React from 'react'; import type { ReactElement } from 'react'; -import Link from 'next/link'; +import Link from '@dailydotdev/shared/src/components/utilities/Link'; import { Typography, TypographyColor, TypographyType, } from '@dailydotdev/shared/src/components/typography/Typography'; -import { Button, ButtonVariant } from '@dailydotdev/shared/src/components/buttons/Button'; +import { + Button, + ButtonVariant, +} from '@dailydotdev/shared/src/components/buttons/Button'; import { BoostIcon } from '@dailydotdev/shared/src/components/icons/Boost'; import { IconSize } from '@dailydotdev/shared/src/components/Icon'; import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; -import { TimeFormatType, formatDate } from '@dailydotdev/shared/src/lib/dateFormat'; +import { + TimeFormatType, + formatDate, +} from '@dailydotdev/shared/src/lib/dateFormat'; import type { UserPostWithAnalytics } from '@dailydotdev/shared/src/graphql/users'; import { webappUrl } from '@dailydotdev/shared/src/lib/constants'; import { LazyImage } from '@dailydotdev/shared/src/components/LazyImage'; -import { fallbackImages } from '@dailydotdev/shared/src/lib/config'; +import { cloudinaryPostImageCoverPlaceholder } from '@dailydotdev/shared/src/lib/image'; export interface UserPostsAnalyticsTableProps { posts: UserPostWithAnalytics[]; @@ -34,7 +40,10 @@ export const UserPostsAnalyticsTable = ({ if (isLoading) { return (
- + Loading posts...
@@ -101,11 +110,11 @@ export const UserPostsAnalyticsTable = ({ className="flex items-center gap-3 hover:underline" >
diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 3da7853cc7..d375928714 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -47,6 +47,7 @@ "react-modal": "^3.15.1", "react-parallax-tilt": "^1.7.248", "react-swipeable": "^7.0.1", + "recharts": "^3.1.2", "zod": "4.1.8" }, "devDependencies": { diff --git a/packages/webapp/pages/analytics/index.tsx b/packages/webapp/pages/analytics/index.tsx index cb90615154..a43a9fa209 100644 --- a/packages/webapp/pages/analytics/index.tsx +++ b/packages/webapp/pages/analytics/index.tsx @@ -6,10 +6,10 @@ import { addDays, subDays } from 'date-fns'; import { ResponsivePageContainer, Divider, + pageBorders, } from '@dailydotdev/shared/src/components/utilities'; import { LayoutHeader } from '@dailydotdev/shared/src/components/layout/common'; import classNames from 'classnames'; -import { pageBorders } from '@dailydotdev/shared/src/components/utilities'; import { Typography, TypographyColor, @@ -48,7 +48,6 @@ import { dateFormatInTimezone, DEFAULT_TIMEZONE, } from '@dailydotdev/shared/src/lib/timezones'; -import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; import dynamic from 'next/dynamic'; import ProtectedPage from '../../components/ProtectedPage'; import { getLayout } from '../../components/layouts/MainLayout'; @@ -67,7 +66,11 @@ const CombinedImpressionsChart = dynamic( const dividerClassName = 'bg-border-subtlest-tertiary'; const SectionContainer = classed('div', 'flex flex-col gap-4'); -const SectionHeader = ({ children }: { children: React.ReactNode }): ReactElement => { +const SectionHeader = ({ + children, +}: { + children: React.ReactNode; +}): ReactElement => { return ( { user, ); - const { data: analytics, isLoading: isLoadingAnalytics } = useQuery({ + const { data: analytics } = useQuery({ queryKey: analyticsQueryKey, queryFn: async () => { const result = await gqlClient.request<{ @@ -135,27 +138,24 @@ const Analytics = (): ReactElement => { return []; } - const impressionsMap = data.reduce( - (acc, item) => { - const date = dateFormatInTimezone( - new Date(item.date), - 'yyyy-MM-dd', - userTimezone, - ); + const impressionsMap = data.reduce((acc, item) => { + const date = dateFormatInTimezone( + new Date(item.date), + 'yyyy-MM-dd', + userTimezone, + ); - acc[date] = { - name: new Date(item.date).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - }), - value: item.impressions, - isBoosted: item.impressionsAds > 0, - }; + acc[date] = { + name: new Date(item.date).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + }), + value: item.impressions, + isBoosted: item.impressionsAds > 0, + }; - return acc; - }, - {} as Record, - ); + return acc; + }, {} as Record); const historyCutOffDate = subDays( new Date(), @@ -216,7 +216,8 @@ const Analytics = (): ReactElement => { }); const posts = useMemo( - () => postsData?.pages.flatMap((page) => page.edges.map((e) => e.node)) ?? [], + () => + postsData?.pages.flatMap((page) => page.edges.map((e) => e.node)) ?? [], [postsData], ); @@ -321,11 +322,15 @@ const Analytics = (): ReactElement => {
- Organic + + Organic +
- Promoted + + Promoted +
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f6ae2a760..3f4b6bfbb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: version: 3.9.4(eslint@7.32.0) eslint-plugin-testing-library: specifier: ^3.10.2 - version: 3.10.2(typescript@5.6.3) + version: 3.10.2(typescript@4.9.5) devDependencies: '@dailydotdev/eslint-plugin-daily-dev-eslint-rules': specifier: workspace:* @@ -34,19 +34,19 @@ importers: version: link:../prettier-config '@typescript-eslint/eslint-plugin': specifier: ^4.31.2 - version: 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3) + version: 4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5) '@typescript-eslint/parser': specifier: ^4.31.2 - version: 4.33.0(eslint@7.32.0)(typescript@5.6.3) + version: 4.33.0(typescript@4.9.5) eslint-config-airbnb-typescript: specifier: ^12.3.1 - version: 12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0)(typescript@5.6.3) + version: 12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2)(typescript@4.9.5) eslint-config-prettier: specifier: ^8.1.0 version: 8.10.0(eslint@7.32.0) eslint-plugin-import: specifier: ^2.24.0 - version: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0) + version: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) eslint-plugin-jsx-a11y: specifier: ^6.4.1 version: 6.10.2(eslint@7.32.0) @@ -64,10 +64,10 @@ importers: version: 3.17.5(tailwindcss@3.4.16) eslint-plugin-unused-imports: specifier: ^3.2.0 - version: 3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@5.6.3))(typescript@5.6.3)) + version: 3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)) typescript: specifier: 5.6.3 - version: 5.6.3 + version: 4.9.5 packages/eslint-rules: devDependencies: @@ -476,7 +476,7 @@ importers: version: 0.1.5 graphql-ws: specifier: ^5.5.5 - version: 5.16.0(graphql@16.9.0) + version: 5.16.0(graphql@15.10.1) jotai: specifier: ^2.12.2 version: 2.12.2(@types/react@18.3.12)(react@18.3.1) @@ -543,10 +543,10 @@ importers: version: 0.1.1(tailwindcss@3.4.16) '@tanstack/react-query': specifier: ^5.80.5 - version: 5.80.6(react@18.3.1) + version: 4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/react-query-devtools': specifier: ^5.80.5 - version: 5.80.6(@tanstack/react-query@5.80.6(react@18.3.1))(react@18.3.1) + version: 4.43.0(@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/jest-dom': specifier: ^5.17.0 version: 5.17.0 @@ -654,10 +654,10 @@ importers: version: 7.2.3 graphql: specifier: ^16.9.0 - version: 16.9.0 + version: 15.10.1 graphql-request: specifier: ^3.6.1 - version: 3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@16.9.0) + version: 3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@15.10.1) idb-keyval: specifier: ^5.1.5 version: 5.1.5 @@ -720,7 +720,7 @@ importers: version: 3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-swipeable: specifier: ^7.0.1 - version: 7.0.2(react@18.3.1) + version: 6.2.2(react@18.3.1) tailwindcss: specifier: ^3.4.14 version: 3.4.16 @@ -953,6 +953,9 @@ importers: react-swipeable: specifier: ^7.0.1 version: 7.0.2(react@18.3.1) + recharts: + specifier: ^3.1.2 + version: 3.1.2(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(redux@5.0.1) zod: specifier: 4.1.8 version: 4.1.8 @@ -3441,18 +3444,44 @@ packages: peerDependencies: tailwindcss: '>=3.2.0' + '@tanstack/match-sorter-utils@8.19.4': + resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} + engines: {node: '>=12'} + + '@tanstack/query-core@4.43.0': + resolution: {integrity: sha512-m1QeUUIpNXDYxmfuuWNFZLky0EwVmbE0hj8ulZ2nIGA1183raJgDCn0IKlxug80NotRqzodxAaoYTKHbE1/P/Q==} + '@tanstack/query-core@5.80.6': resolution: {integrity: sha512-nl7YxT/TAU+VTf+e2zTkObGTyY8YZBMnbgeA1ee66lIVqzKlYursAII6z5t0e6rXgwUMJSV4dshBTNacNpZHbQ==} '@tanstack/query-devtools@5.80.0': resolution: {integrity: sha512-D6gH4asyjaoXrCOt5vG5Og/YSj0D/TxwNQgtLJIgWbhbWCC/emu2E92EFoVHh4ppVWg1qT2gKHvKyQBEFZhCuA==} + '@tanstack/react-query-devtools@4.43.0': + resolution: {integrity: sha512-UwoY7qMysWMjuIE0lb+8NqTuovC1Uj1761lDybAMYsDPFQVAmahTeIzrclYKSK7CsW4mk9LvKAa1Z7E3141/VQ==} + peerDependencies: + '@tanstack/react-query': ^4.43.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-query-devtools@5.80.6': resolution: {integrity: sha512-y7Es0OJ4RYQxrPYsuuQP0jxjgJ40a03UbEPmJ6vwf/ERVMRoRIMkpjtvPxf1D+n9nwPfWmGdD0jW8Wxd+TxeEw==} peerDependencies: '@tanstack/react-query': ^5.80.6 react: ^18 || ^19 + '@tanstack/react-query@4.43.0': + resolution: {integrity: sha512-Lj8luFKHQL27oZbw5T8xdTbsfAPp2+bCtSCa2bAVvIwnvNfRP0hpB1GxfKFgCktat8lPcYBHAu8eMTXzz2sQtQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + '@tanstack/react-query@5.80.6': resolution: {integrity: sha512-izX+5CnkpON3NQGcEm3/d7LfFQNo9ZpFtX2QsINgCYK9LT2VCIdi8D3bMaMSNhrAJCznRoAkFic76uvLroALBw==} peerDependencies: @@ -4814,6 +4843,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -6034,6 +6067,10 @@ packages: peerDependencies: graphql: '>=0.11 <=16' + graphql@15.10.1: + resolution: {integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==} + engines: {node: '>= 10.x'} + graphql@16.9.0: resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -6505,6 +6542,10 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -8299,6 +8340,11 @@ packages: '@types/react': optional: true + react-swipeable@6.2.2: + resolution: {integrity: sha512-Oz7nSFrssvq2yvy05aNL3F+yBUqSvLsK6x1mu+rQFOpMdQVnt4izKt1vyjvvTb70q6GQOaSpaB6qniROW2MAzQ==} + peerDependencies: + react: ^16.8.3 || ^17 || ^18 + react-swipeable@7.0.2: resolution: {integrity: sha512-v1Qx1l+aC2fdxKa9aKJiaU/ZxmJ5o98RMoFwUqAAzVWUcxgfHFXDDruCKXhw6zIYXm6V64JiHgP9f6mlME5l8w==} peerDependencies: @@ -8440,6 +8486,9 @@ packages: rematrix@0.2.2: resolution: {integrity: sha512-agFFS3RzrLXJl5LY5xg/xYyXvUuVAnkhgKO7RaO9J1Ssth6yvbO+PIiV67V59MB5NCdAK2flvGvNT4mdKVniFA==} + remove-accents@0.5.0: + resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} + remove-trailing-separator@1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} @@ -8952,6 +9001,10 @@ packages: peerDependencies: postcss: ^8.3.3 + superjson@1.13.3: + resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==} + engines: {node: '>=10'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -9251,6 +9304,11 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -9400,6 +9458,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use@3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} engines: {node: '>=0.10.0'} @@ -12171,16 +12234,39 @@ snapshots: dependencies: tailwindcss: 3.4.16 + '@tanstack/match-sorter-utils@8.19.4': + dependencies: + remove-accents: 0.5.0 + + '@tanstack/query-core@4.43.0': {} + '@tanstack/query-core@5.80.6': {} '@tanstack/query-devtools@5.80.0': {} + '@tanstack/react-query-devtools@4.43.0(@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/match-sorter-utils': 8.19.4 + '@tanstack/react-query': 4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + superjson: 1.13.3 + use-sync-external-store: 1.5.0(react@18.3.1) + '@tanstack/react-query-devtools@5.80.6(@tanstack/react-query@5.80.6(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.80.0 '@tanstack/react-query': 5.80.6(react@18.3.1) react: 18.3.1 + '@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/query-core': 4.43.0 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + '@tanstack/react-query@5.80.6(react@18.3.1)': dependencies: '@tanstack/query-core': 5.80.6 @@ -12704,11 +12790,27 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/experimental-utils@3.10.1(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)': + dependencies: + '@typescript-eslint/experimental-utils': 4.33.0(typescript@4.9.5) + '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) + '@typescript-eslint/scope-manager': 4.33.0 + debug: 4.4.1 + functional-red-black-tree: 1.0.1 + ignore: 5.3.2 + regexpp: 3.2.0 + semver: 7.7.2 + tsutils: 3.21.0(typescript@4.9.5) + optionalDependencies: + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/experimental-utils@3.10.1(typescript@4.9.5)': dependencies: '@types/json-schema': 7.0.15 '@typescript-eslint/types': 3.10.1 - '@typescript-eslint/typescript-estree': 3.10.1(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 3.10.1(typescript@4.9.5) eslint-scope: 5.1.1 eslint-utils: 2.1.0 transitivePeerDependencies: @@ -12728,6 +12830,18 @@ snapshots: - supports-color - typescript + '@typescript-eslint/experimental-utils@4.33.0(typescript@4.9.5)': + dependencies: + '@types/json-schema': 7.0.15 + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@4.9.5) + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@7.32.0) + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 4.33.0 @@ -12740,6 +12854,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@4.33.0(typescript@4.9.5)': + dependencies: + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@4.9.5) + debug: 4.4.1 + optionalDependencies: + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@4.33.0': dependencies: '@typescript-eslint/types': 4.33.0 @@ -12756,7 +12881,7 @@ snapshots: '@typescript-eslint/types@8.17.0': {} - '@typescript-eslint/typescript-estree@3.10.1(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@3.10.1(typescript@4.9.5)': dependencies: '@typescript-eslint/types': 3.10.1 '@typescript-eslint/visitor-keys': 3.10.1 @@ -12765,9 +12890,23 @@ snapshots: is-glob: 4.0.3 lodash: 4.17.21 semver: 7.7.2 - tsutils: 3.21.0(typescript@5.6.3) + tsutils: 3.21.0(typescript@4.9.5) optionalDependencies: - typescript: 5.6.3 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@4.33.0(typescript@4.9.5)': + dependencies: + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/visitor-keys': 4.33.0 + debug: 4.4.1 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.7.2 + tsutils: 3.21.0(typescript@4.9.5) + optionalDependencies: + typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -13784,6 +13923,10 @@ snapshots: cookie@0.7.2: {} + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + copy-descriptor@0.1.1: {} copy-webpack-plugin@6.4.1(webpack@5.97.0): @@ -14527,6 +14670,13 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 + eslint-config-airbnb-base@14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))): + dependencies: + confusing-browser-globals: 1.0.11 + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) + object.assign: 4.1.5 + object.entries: 1.1.8 + eslint-config-airbnb-typescript@12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0)(typescript@5.6.3): dependencies: '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.6.3) @@ -14541,6 +14691,20 @@ snapshots: - supports-color - typescript + eslint-config-airbnb-typescript@12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2)(typescript@4.9.5): + dependencies: + '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) + eslint-config-airbnb: 18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2) + eslint-config-airbnb-base: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))) + transitivePeerDependencies: + - eslint + - eslint-plugin-import + - eslint-plugin-jsx-a11y + - eslint-plugin-react + - eslint-plugin-react-hooks + - supports-color + - typescript + eslint-config-airbnb@18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0): dependencies: eslint: 7.32.0 @@ -14552,6 +14716,16 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 + eslint-config-airbnb@18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2): + dependencies: + eslint-config-airbnb-base: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@7.32.0) + eslint-plugin-react: 7.37.2(eslint@7.32.0) + eslint-plugin-react-hooks: 4.6.2(eslint@7.32.0) + object.assign: 4.1.5 + object.entries: 1.1.8 + eslint-config-prettier@8.10.0(eslint@7.32.0): dependencies: eslint: 7.32.0 @@ -14574,6 +14748,15 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-module-utils@2.12.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(eslint-import-resolver-node@0.3.9): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0): dependencies: '@rtsao/scc': 1.1.0 @@ -14603,6 +14786,34 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(eslint-import-resolver-node@0.3.9) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-jest-dom@3.9.4(eslint@7.32.0): dependencies: '@babel/runtime': 7.28.4 @@ -14683,9 +14894,9 @@ snapshots: postcss: 8.4.49 tailwindcss: 3.4.16 - eslint-plugin-testing-library@3.10.2(typescript@5.6.3): + eslint-plugin-testing-library@3.10.2(typescript@4.9.5): dependencies: - '@typescript-eslint/experimental-utils': 3.10.1(typescript@5.6.3) + '@typescript-eslint/experimental-utils': 3.10.1(typescript@4.9.5) transitivePeerDependencies: - supports-color - typescript @@ -14698,11 +14909,11 @@ snapshots: - supports-color - typescript - eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@5.6.3))(typescript@5.6.3)): + eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)): dependencies: eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5) eslint-rule-composer@0.3.0: {} @@ -15239,6 +15450,15 @@ snapshots: graceful-fs@4.2.11: {} + graphql-request@3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@15.10.1): + dependencies: + cross-fetch: 3.1.8 + extract-files: 9.0.0 + form-data: 3.0.2 + graphql: 15.10.1 + transitivePeerDependencies: + - encoding + graphql-request@3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@16.9.0): dependencies: cross-fetch: 3.1.8 @@ -15248,9 +15468,11 @@ snapshots: transitivePeerDependencies: - encoding - graphql-ws@5.16.0(graphql@16.9.0): + graphql-ws@5.16.0(graphql@15.10.1): dependencies: - graphql: 16.9.0 + graphql: 15.10.1 + + graphql@15.10.1: {} graphql@16.9.0: {} @@ -15669,6 +15891,8 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-what@4.1.16: {} + is-windows@1.0.2: {} is-wsl@2.2.0: @@ -17876,6 +18100,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 + react-swipeable@6.2.2(react@18.3.1): + dependencies: + react: 18.3.1 + react-swipeable@7.0.2(react@18.3.1): dependencies: react: 18.3.1 @@ -18078,6 +18306,8 @@ snapshots: rematrix@0.2.2: {} + remove-accents@0.5.0: {} + remove-trailing-separator@1.1.0: {} renderkid@3.0.0: @@ -18698,6 +18928,10 @@ snapshots: dependencies: postcss: 8.4.49 + superjson@1.13.3: + dependencies: + copy-anything: 3.0.5 + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -18983,6 +19217,11 @@ snapshots: tslib@2.8.1: {} + tsutils@3.21.0(typescript@4.9.5): + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + tsutils@3.21.0(typescript@5.6.3): dependencies: tslib: 1.14.1 @@ -19049,6 +19288,8 @@ snapshots: typescript@3.9.3: {} + typescript@4.9.5: {} + typescript@5.6.3: {} typeson-registry@1.0.0-alpha.39: @@ -19211,6 +19452,10 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + use@3.1.1: {} useragent@2.3.0: From cff7a32c6d28489c01d1b31d5e883accc95adfca Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Mon, 2 Feb 2026 16:04:12 +0200 Subject: [PATCH 3/4] fix: cleanup --- .../analytics/CombinedImpressionsChart.tsx | 0 .../analytics/AnalyticsEmptyState.tsx | 5 +- .../analytics/UserPostsAnalyticsTable.tsx | 51 ++- packages/webapp/package.json | 1 - packages/webapp/pages/analytics/index.tsx | 93 +++--- pnpm-lock.yaml | 297 ++---------------- 6 files changed, 97 insertions(+), 350 deletions(-) rename packages/{webapp => shared/src}/components/analytics/CombinedImpressionsChart.tsx (100%) diff --git a/packages/webapp/components/analytics/CombinedImpressionsChart.tsx b/packages/shared/src/components/analytics/CombinedImpressionsChart.tsx similarity index 100% rename from packages/webapp/components/analytics/CombinedImpressionsChart.tsx rename to packages/shared/src/components/analytics/CombinedImpressionsChart.tsx diff --git a/packages/webapp/components/analytics/AnalyticsEmptyState.tsx b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx index 9f4ebfac9f..9549f88fc1 100644 --- a/packages/webapp/components/analytics/AnalyticsEmptyState.tsx +++ b/packages/webapp/components/analytics/AnalyticsEmptyState.tsx @@ -9,14 +9,13 @@ import { Button, ButtonVariant, } from '@dailydotdev/shared/src/components/buttons/Button'; -import { PlusIcon, EditIcon } from '@dailydotdev/shared/src/components/icons'; +import { PlusIcon } from '@dailydotdev/shared/src/components/icons'; import { link } from '@dailydotdev/shared/src/lib/links'; import Link from '@dailydotdev/shared/src/components/utilities/Link'; export const AnalyticsEmptyState = (): ReactElement => { return (
-
{ everything. Go on, share with us your best rant.
- + diff --git a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx index 302c0b443a..2c337bd29d 100644 --- a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx +++ b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx @@ -105,32 +105,31 @@ export const UserPostsAnalyticsTable = ({ className="border-b border-border-subtlest-tertiary last:border-b-0" > - - -
-
- - {post.title || 'Untitled'} - - {post.isBoosted && ( - - )} + +
+ +
+
+ + {post.title || 'Untitled'} + + {post.isBoosted && ( + + )} +
diff --git a/packages/webapp/package.json b/packages/webapp/package.json index d375928714..3da7853cc7 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -47,7 +47,6 @@ "react-modal": "^3.15.1", "react-parallax-tilt": "^1.7.248", "react-swipeable": "^7.0.1", - "recharts": "^3.1.2", "zod": "4.1.8" }, "devDependencies": { diff --git a/packages/webapp/pages/analytics/index.tsx b/packages/webapp/pages/analytics/index.tsx index a43a9fa209..b48b49fdde 100644 --- a/packages/webapp/pages/analytics/index.tsx +++ b/packages/webapp/pages/analytics/index.tsx @@ -56,9 +56,9 @@ import { AnalyticsEmptyState } from '../../components/analytics/AnalyticsEmptySt const CombinedImpressionsChart = dynamic( () => - import('../../components/analytics/CombinedImpressionsChart').then( - (mod) => mod.CombinedImpressionsChart, - ), + import( + '@dailydotdev/shared/src/components/analytics/CombinedImpressionsChart' + ).then((mod) => mod.CombinedImpressionsChart), { loading: () =>
, }, @@ -223,29 +223,10 @@ const Analytics = (): ReactElement => { const hasNoPosts = !isLoadingPosts && posts.length === 0; - if (hasNoPosts) { - return ( - -
- - - Analytics - - - - - -
-
- ); - } + const hasChartData = useMemo(() => { + if (!historyData || historyData.length === 0) return false; + return historyData.some((item) => item.value > 0); + }, [historyData]); return ( @@ -319,33 +300,51 @@ const Analytics = (): ReactElement => { Impressions in the last 45 days -
-
-
- - Organic - -
-
-
- - Promoted - + {hasChartData && ( +
+
+
+ + Organic + +
+
+
+ + Promoted + +
-
+ )}
- + {hasChartData ? ( + + ) : ( +
+ + No impression data yet. Check back after your posts get some + views. + +
+ )} Posts - + {hasNoPosts ? ( + + ) : ( + + )}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f4b6bfbb8..59d14e2491 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: version: 3.9.4(eslint@7.32.0) eslint-plugin-testing-library: specifier: ^3.10.2 - version: 3.10.2(typescript@4.9.5) + version: 3.10.2(typescript@5.6.3) devDependencies: '@dailydotdev/eslint-plugin-daily-dev-eslint-rules': specifier: workspace:* @@ -34,19 +34,19 @@ importers: version: link:../prettier-config '@typescript-eslint/eslint-plugin': specifier: ^4.31.2 - version: 4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5) + version: 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^4.31.2 - version: 4.33.0(typescript@4.9.5) + version: 4.33.0(eslint@7.32.0)(typescript@5.6.3) eslint-config-airbnb-typescript: specifier: ^12.3.1 - version: 12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2)(typescript@4.9.5) + version: 12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0)(typescript@5.6.3) eslint-config-prettier: specifier: ^8.1.0 version: 8.10.0(eslint@7.32.0) eslint-plugin-import: specifier: ^2.24.0 - version: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) + version: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0) eslint-plugin-jsx-a11y: specifier: ^6.4.1 version: 6.10.2(eslint@7.32.0) @@ -64,10 +64,10 @@ importers: version: 3.17.5(tailwindcss@3.4.16) eslint-plugin-unused-imports: specifier: ^3.2.0 - version: 3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)) + version: 3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@5.6.3))(typescript@5.6.3)) typescript: specifier: 5.6.3 - version: 4.9.5 + version: 5.6.3 packages/eslint-rules: devDependencies: @@ -476,7 +476,7 @@ importers: version: 0.1.5 graphql-ws: specifier: ^5.5.5 - version: 5.16.0(graphql@15.10.1) + version: 5.16.0(graphql@16.9.0) jotai: specifier: ^2.12.2 version: 2.12.2(@types/react@18.3.12)(react@18.3.1) @@ -543,10 +543,10 @@ importers: version: 0.1.1(tailwindcss@3.4.16) '@tanstack/react-query': specifier: ^5.80.5 - version: 4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 5.80.6(react@18.3.1) '@tanstack/react-query-devtools': specifier: ^5.80.5 - version: 4.43.0(@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 5.80.6(@tanstack/react-query@5.80.6(react@18.3.1))(react@18.3.1) '@testing-library/jest-dom': specifier: ^5.17.0 version: 5.17.0 @@ -654,10 +654,10 @@ importers: version: 7.2.3 graphql: specifier: ^16.9.0 - version: 15.10.1 + version: 16.9.0 graphql-request: specifier: ^3.6.1 - version: 3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@15.10.1) + version: 3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@16.9.0) idb-keyval: specifier: ^5.1.5 version: 5.1.5 @@ -720,7 +720,7 @@ importers: version: 3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-swipeable: specifier: ^7.0.1 - version: 6.2.2(react@18.3.1) + version: 7.0.2(react@18.3.1) tailwindcss: specifier: ^3.4.14 version: 3.4.16 @@ -953,9 +953,6 @@ importers: react-swipeable: specifier: ^7.0.1 version: 7.0.2(react@18.3.1) - recharts: - specifier: ^3.1.2 - version: 3.1.2(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(redux@5.0.1) zod: specifier: 4.1.8 version: 4.1.8 @@ -3444,44 +3441,18 @@ packages: peerDependencies: tailwindcss: '>=3.2.0' - '@tanstack/match-sorter-utils@8.19.4': - resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} - engines: {node: '>=12'} - - '@tanstack/query-core@4.43.0': - resolution: {integrity: sha512-m1QeUUIpNXDYxmfuuWNFZLky0EwVmbE0hj8ulZ2nIGA1183raJgDCn0IKlxug80NotRqzodxAaoYTKHbE1/P/Q==} - '@tanstack/query-core@5.80.6': resolution: {integrity: sha512-nl7YxT/TAU+VTf+e2zTkObGTyY8YZBMnbgeA1ee66lIVqzKlYursAII6z5t0e6rXgwUMJSV4dshBTNacNpZHbQ==} '@tanstack/query-devtools@5.80.0': resolution: {integrity: sha512-D6gH4asyjaoXrCOt5vG5Og/YSj0D/TxwNQgtLJIgWbhbWCC/emu2E92EFoVHh4ppVWg1qT2gKHvKyQBEFZhCuA==} - '@tanstack/react-query-devtools@4.43.0': - resolution: {integrity: sha512-UwoY7qMysWMjuIE0lb+8NqTuovC1Uj1761lDybAMYsDPFQVAmahTeIzrclYKSK7CsW4mk9LvKAa1Z7E3141/VQ==} - peerDependencies: - '@tanstack/react-query': ^4.43.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/react-query-devtools@5.80.6': resolution: {integrity: sha512-y7Es0OJ4RYQxrPYsuuQP0jxjgJ40a03UbEPmJ6vwf/ERVMRoRIMkpjtvPxf1D+n9nwPfWmGdD0jW8Wxd+TxeEw==} peerDependencies: '@tanstack/react-query': ^5.80.6 react: ^18 || ^19 - '@tanstack/react-query@4.43.0': - resolution: {integrity: sha512-Lj8luFKHQL27oZbw5T8xdTbsfAPp2+bCtSCa2bAVvIwnvNfRP0hpB1GxfKFgCktat8lPcYBHAu8eMTXzz2sQtQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - '@tanstack/react-query@5.80.6': resolution: {integrity: sha512-izX+5CnkpON3NQGcEm3/d7LfFQNo9ZpFtX2QsINgCYK9LT2VCIdi8D3bMaMSNhrAJCznRoAkFic76uvLroALBw==} peerDependencies: @@ -4843,10 +4814,6 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -6067,10 +6034,6 @@ packages: peerDependencies: graphql: '>=0.11 <=16' - graphql@15.10.1: - resolution: {integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==} - engines: {node: '>= 10.x'} - graphql@16.9.0: resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -6542,10 +6505,6 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -8340,11 +8299,6 @@ packages: '@types/react': optional: true - react-swipeable@6.2.2: - resolution: {integrity: sha512-Oz7nSFrssvq2yvy05aNL3F+yBUqSvLsK6x1mu+rQFOpMdQVnt4izKt1vyjvvTb70q6GQOaSpaB6qniROW2MAzQ==} - peerDependencies: - react: ^16.8.3 || ^17 || ^18 - react-swipeable@7.0.2: resolution: {integrity: sha512-v1Qx1l+aC2fdxKa9aKJiaU/ZxmJ5o98RMoFwUqAAzVWUcxgfHFXDDruCKXhw6zIYXm6V64JiHgP9f6mlME5l8w==} peerDependencies: @@ -8486,9 +8440,6 @@ packages: rematrix@0.2.2: resolution: {integrity: sha512-agFFS3RzrLXJl5LY5xg/xYyXvUuVAnkhgKO7RaO9J1Ssth6yvbO+PIiV67V59MB5NCdAK2flvGvNT4mdKVniFA==} - remove-accents@0.5.0: - resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} - remove-trailing-separator@1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} @@ -9001,10 +8952,6 @@ packages: peerDependencies: postcss: ^8.3.3 - superjson@1.13.3: - resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==} - engines: {node: '>=10'} - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -9304,11 +9251,6 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -9458,11 +9400,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - use@3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} engines: {node: '>=0.10.0'} @@ -12234,39 +12171,16 @@ snapshots: dependencies: tailwindcss: 3.4.16 - '@tanstack/match-sorter-utils@8.19.4': - dependencies: - remove-accents: 0.5.0 - - '@tanstack/query-core@4.43.0': {} - '@tanstack/query-core@5.80.6': {} '@tanstack/query-devtools@5.80.0': {} - '@tanstack/react-query-devtools@4.43.0(@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/match-sorter-utils': 8.19.4 - '@tanstack/react-query': 4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - superjson: 1.13.3 - use-sync-external-store: 1.5.0(react@18.3.1) - '@tanstack/react-query-devtools@5.80.6(@tanstack/react-query@5.80.6(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.80.0 '@tanstack/react-query': 5.80.6(react@18.3.1) react: 18.3.1 - '@tanstack/react-query@4.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/query-core': 4.43.0 - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - '@tanstack/react-query@5.80.6(react@18.3.1)': dependencies: '@tanstack/query-core': 5.80.6 @@ -12790,27 +12704,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)': - dependencies: - '@typescript-eslint/experimental-utils': 4.33.0(typescript@4.9.5) - '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) - '@typescript-eslint/scope-manager': 4.33.0 - debug: 4.4.1 - functional-red-black-tree: 1.0.1 - ignore: 5.3.2 - regexpp: 3.2.0 - semver: 7.7.2 - tsutils: 3.21.0(typescript@4.9.5) - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/experimental-utils@3.10.1(typescript@4.9.5)': + '@typescript-eslint/experimental-utils@3.10.1(typescript@5.6.3)': dependencies: '@types/json-schema': 7.0.15 '@typescript-eslint/types': 3.10.1 - '@typescript-eslint/typescript-estree': 3.10.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 3.10.1(typescript@5.6.3) eslint-scope: 5.1.1 eslint-utils: 2.1.0 transitivePeerDependencies: @@ -12830,18 +12728,6 @@ snapshots: - supports-color - typescript - '@typescript-eslint/experimental-utils@4.33.0(typescript@4.9.5)': - dependencies: - '@types/json-schema': 7.0.15 - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@4.9.5) - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@7.32.0) - transitivePeerDependencies: - - supports-color - - typescript - '@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 4.33.0 @@ -12854,17 +12740,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@4.33.0(typescript@4.9.5)': - dependencies: - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@4.9.5) - debug: 4.4.1 - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/scope-manager@4.33.0': dependencies: '@typescript-eslint/types': 4.33.0 @@ -12881,7 +12756,7 @@ snapshots: '@typescript-eslint/types@8.17.0': {} - '@typescript-eslint/typescript-estree@3.10.1(typescript@4.9.5)': + '@typescript-eslint/typescript-estree@3.10.1(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 3.10.1 '@typescript-eslint/visitor-keys': 3.10.1 @@ -12890,23 +12765,9 @@ snapshots: is-glob: 4.0.3 lodash: 4.17.21 semver: 7.7.2 - tsutils: 3.21.0(typescript@4.9.5) - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@4.33.0(typescript@4.9.5)': - dependencies: - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/visitor-keys': 4.33.0 - debug: 4.4.1 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.7.2 - tsutils: 3.21.0(typescript@4.9.5) + tsutils: 3.21.0(typescript@5.6.3) optionalDependencies: - typescript: 4.9.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -13923,10 +13784,6 @@ snapshots: cookie@0.7.2: {} - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - copy-descriptor@0.1.1: {} copy-webpack-plugin@6.4.1(webpack@5.97.0): @@ -14670,13 +14527,6 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 - eslint-config-airbnb-base@14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))): - dependencies: - confusing-browser-globals: 1.0.11 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) - object.assign: 4.1.5 - object.entries: 1.1.8 - eslint-config-airbnb-typescript@12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0)(typescript@5.6.3): dependencies: '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.6.3) @@ -14691,20 +14541,6 @@ snapshots: - supports-color - typescript - eslint-config-airbnb-typescript@12.3.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2)(typescript@4.9.5): - dependencies: - '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) - eslint-config-airbnb: 18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2) - eslint-config-airbnb-base: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))) - transitivePeerDependencies: - - eslint - - eslint-plugin-import - - eslint-plugin-jsx-a11y - - eslint-plugin-react - - eslint-plugin-react-hooks - - supports-color - - typescript - eslint-config-airbnb@18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.2(eslint@7.32.0))(eslint-plugin-react@7.37.2(eslint@7.32.0))(eslint@7.32.0): dependencies: eslint: 7.32.0 @@ -14716,16 +14552,6 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 - eslint-config-airbnb@18.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)))(eslint-plugin-jsx-a11y@6.10.2)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-react@7.37.2): - dependencies: - eslint-config-airbnb-base: 14.2.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@7.32.0) - eslint-plugin-react: 7.37.2(eslint@7.32.0) - eslint-plugin-react-hooks: 4.6.2(eslint@7.32.0) - object.assign: 4.1.5 - object.entries: 1.1.8 - eslint-config-prettier@8.10.0(eslint@7.32.0): dependencies: eslint: 7.32.0 @@ -14748,15 +14574,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(eslint-import-resolver-node@0.3.9): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0): dependencies: '@rtsao/scc': 1.1.0 @@ -14786,34 +14603,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5)): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(eslint-import-resolver-node@0.3.9) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - string.prototype.trimend: 1.0.8 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 4.33.0(typescript@4.9.5) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jest-dom@3.9.4(eslint@7.32.0): dependencies: '@babel/runtime': 7.28.4 @@ -14894,9 +14683,9 @@ snapshots: postcss: 8.4.49 tailwindcss: 3.4.16 - eslint-plugin-testing-library@3.10.2(typescript@4.9.5): + eslint-plugin-testing-library@3.10.2(typescript@5.6.3): dependencies: - '@typescript-eslint/experimental-utils': 3.10.1(typescript@4.9.5) + '@typescript-eslint/experimental-utils': 3.10.1(typescript@5.6.3) transitivePeerDependencies: - supports-color - typescript @@ -14909,11 +14698,11 @@ snapshots: - supports-color - typescript - eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5)): + eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(typescript@5.6.3))(typescript@5.6.3)): dependencies: eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0(typescript@4.9.5))(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.6.3))(eslint@7.32.0)(typescript@5.6.3) eslint-rule-composer@0.3.0: {} @@ -15450,15 +15239,6 @@ snapshots: graceful-fs@4.2.11: {} - graphql-request@3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@15.10.1): - dependencies: - cross-fetch: 3.1.8 - extract-files: 9.0.0 - form-data: 3.0.2 - graphql: 15.10.1 - transitivePeerDependencies: - - encoding - graphql-request@3.7.0(patch_hash=fxjjyfdyg6h6dchjekndlox4o4)(graphql@16.9.0): dependencies: cross-fetch: 3.1.8 @@ -15468,11 +15248,9 @@ snapshots: transitivePeerDependencies: - encoding - graphql-ws@5.16.0(graphql@15.10.1): + graphql-ws@5.16.0(graphql@16.9.0): dependencies: - graphql: 15.10.1 - - graphql@15.10.1: {} + graphql: 16.9.0 graphql@16.9.0: {} @@ -15891,8 +15669,6 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 - is-what@4.1.16: {} - is-windows@1.0.2: {} is-wsl@2.2.0: @@ -16109,11 +15885,7 @@ snapshots: pretty-format: 26.6.2 throat: 5.0.0 transitivePeerDependencies: - - bufferutil - - canvas - supports-color - - ts-node - - utf-8-validate jest-junit@12.3.0: dependencies: @@ -18100,10 +17872,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 - react-swipeable@6.2.2(react@18.3.1): - dependencies: - react: 18.3.1 - react-swipeable@7.0.2(react@18.3.1): dependencies: react: 18.3.1 @@ -18306,8 +18074,6 @@ snapshots: rematrix@0.2.2: {} - remove-accents@0.5.0: {} - remove-trailing-separator@1.1.0: {} renderkid@3.0.0: @@ -18928,10 +18694,6 @@ snapshots: dependencies: postcss: 8.4.49 - superjson@1.13.3: - dependencies: - copy-anything: 3.0.5 - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -19217,11 +18979,6 @@ snapshots: tslib@2.8.1: {} - tsutils@3.21.0(typescript@4.9.5): - dependencies: - tslib: 1.14.1 - typescript: 4.9.5 - tsutils@3.21.0(typescript@5.6.3): dependencies: tslib: 1.14.1 @@ -19288,8 +19045,6 @@ snapshots: typescript@3.9.3: {} - typescript@4.9.5: {} - typescript@5.6.3: {} typeson-registry@1.0.0-alpha.39: @@ -19452,10 +19207,6 @@ snapshots: dependencies: react: 18.3.1 - use-sync-external-store@1.6.0(react@18.3.1): - dependencies: - react: 18.3.1 - use@3.1.1: {} useragent@2.3.0: From fd9d3422d005192875df5532692ce714b2d6133f Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Mon, 2 Feb 2026 16:13:54 +0200 Subject: [PATCH 4/4] fix: lint --- .../src/components/analytics/CombinedImpressionsChart.tsx | 2 +- .../webapp/components/analytics/UserPostsAnalyticsTable.tsx | 4 +++- packages/webapp/pages/analytics/index.tsx | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/components/analytics/CombinedImpressionsChart.tsx b/packages/shared/src/components/analytics/CombinedImpressionsChart.tsx index b4137cc4ab..8ed1ee7279 100644 --- a/packages/shared/src/components/analytics/CombinedImpressionsChart.tsx +++ b/packages/shared/src/components/analytics/CombinedImpressionsChart.tsx @@ -11,7 +11,7 @@ import { YAxis, } from 'recharts'; import type { TickProp } from 'recharts/types/util/types'; -import { largeNumberFormat } from '@dailydotdev/shared/src/lib'; +import { largeNumberFormat } from '../../lib'; type ImpressionNode = { name: string; diff --git a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx index 2c337bd29d..2c2d7979d5 100644 --- a/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx +++ b/packages/webapp/components/analytics/UserPostsAnalyticsTable.tsx @@ -108,7 +108,9 @@ export const UserPostsAnalyticsTable = ({
{ const hasNoPosts = !isLoadingPosts && posts.length === 0; const hasChartData = useMemo(() => { - if (!historyData || historyData.length === 0) return false; + if (!historyData || historyData.length === 0) { + return false; + } return historyData.some((item) => item.value > 0); }, [historyData]);