Skip to content

Commit 2fe485b

Browse files
authored
Merge pull request #125 from techulus/develop
Include page views in usage
2 parents d40b0b6 + a2326b6 commit 2fe485b

File tree

2 files changed

+53
-29
lines changed

2 files changed

+53
-29
lines changed

apps/web/pages/account/billing.tsx

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { supabaseAdmin } from "@changespage/supabase/admin";
22
import { SpinnerWithSpacing } from "@changespage/ui";
33
import { DateTime } from "@changespage/utils";
4-
import { CurrencyDollarIcon, DatabaseIcon } from "@heroicons/react/outline";
4+
import {
5+
CurrencyDollarIcon,
6+
DatabaseIcon,
7+
EyeIcon,
8+
} from "@heroicons/react/outline";
59
import { CalendarIcon } from "@heroicons/react/solid";
610
import classNames from "classnames";
711
import { InferGetServerSidePropsType } from "next";
@@ -15,11 +19,12 @@ import { httpPost } from "../../utils/http";
1519
import { withSupabase } from "../../utils/supabase/withSupabase";
1620
import { useUserData } from "../../utils/useUser";
1721

18-
interface PageStorageUsage {
22+
interface PageUsageStats {
1923
page_id: string;
2024
page_title: string;
2125
total_bytes: number;
2226
total_pretty: string;
27+
page_views_30d: number;
2328
}
2429

2530
function formatBytes(bytes: number): string {
@@ -39,22 +44,31 @@ export const getServerSideProps = withSupabase(async (_, { user }) => {
3944
if (!pages || pages.length === 0) {
4045
return {
4146
props: {
42-
storageUsage: [],
47+
usageStats: [],
4348
},
4449
};
4550
}
4651

47-
const storageUsage: PageStorageUsage[] = await Promise.all(
52+
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
53+
54+
const usageStats: PageUsageStats[] = await Promise.all(
4855
pages.map(async (page) => {
49-
const { data: objects } = await supabaseAdmin
50-
// @ts-expect-error - storage schema not in Database types
51-
.schema("storage")
52-
.from("objects")
53-
.select("metadata")
54-
.eq("bucket_id", "images")
55-
.like("name", `${user.id}/${page.id}/%`);
56+
const [storageResult, viewsResult] = await Promise.all([
57+
supabaseAdmin
58+
// @ts-expect-error - storage schema not in Database types
59+
.schema("storage")
60+
.from("objects")
61+
.select("metadata")
62+
.eq("bucket_id", "images")
63+
.like("name", `${user.id}/${page.id}/%`),
64+
supabaseAdmin
65+
.from("page_views")
66+
.select("id", { count: "exact", head: true })
67+
.eq("page_id", page.id)
68+
.gte("created_at", thirtyDaysAgo.toISOString()),
69+
]);
5670

57-
const totalBytes = (objects || []).reduce((sum, obj) => {
71+
const totalBytes = (storageResult.data || []).reduce((sum, obj) => {
5872
const size = (obj.metadata as { size?: number })?.size || 0;
5973
return sum + size;
6074
}, 0);
@@ -64,19 +78,20 @@ export const getServerSideProps = withSupabase(async (_, { user }) => {
6478
page_title: page.title,
6579
total_bytes: totalBytes,
6680
total_pretty: formatBytes(totalBytes),
81+
page_views_30d: viewsResult.count || 0,
6782
};
6883
})
6984
);
7085

7186
return {
7287
props: {
73-
storageUsage,
88+
usageStats,
7489
},
7590
};
7691
});
7792

7893
export default function Billing({
79-
storageUsage,
94+
usageStats,
8095
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
8196
const { billingDetails, fetchBilling } = useUserData();
8297

@@ -250,15 +265,15 @@ export default function Billing({
250265
<div className="md:col-span-1">
251266
<div className="px-4 sm:px-0">
252267
<h3 className="text-lg font-medium leading-6 text-gray-900 dark:text-gray-50">
253-
Storage Usage
268+
Usage
254269
</h3>
255270
<p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
256-
Storage used by each page for images and uploads.
271+
Storage and page views (last 30 days) for each page.
257272
</p>
258273
</div>
259274
</div>
260275
<div className="mt-5 md:mt-0 md:col-span-2">
261-
{storageUsage.length === 0 ? (
276+
{usageStats.length === 0 ? (
262277
<div className="shadow overflow-hidden sm:rounded-md">
263278
<div className="px-4 py-3 bg-white dark:bg-black sm:p-3">
264279
<p className="text-sm text-gray-500 dark:text-gray-400">
@@ -270,18 +285,20 @@ export default function Billing({
270285
<div className="shadow overflow-hidden sm:rounded-md">
271286
<div className="bg-white dark:bg-black">
272287
<ul className="divide-y divide-gray-200 dark:divide-gray-800">
273-
{storageUsage.map((page) => (
288+
{usageStats.map((page) => (
274289
<li key={page.page_id} className="px-4 py-4">
275-
<div className="flex items-center justify-between">
290+
<p className="text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">
291+
{page.page_title}
292+
</p>
293+
<div className="flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
276294
<div className="flex items-center">
277-
<DatabaseIcon className="h-5 w-5 text-gray-400 mr-3" />
278-
<p className="text-sm font-medium text-gray-900 dark:text-gray-100">
279-
{page.page_title}
280-
</p>
281-
</div>
282-
<p className="text-sm text-gray-500 dark:text-gray-400">
295+
<DatabaseIcon className="h-4 w-4 mr-1.5" />
283296
{page.total_pretty}
284-
</p>
297+
</div>
298+
<div className="flex items-center">
299+
<EyeIcon className="h-4 w-4 mr-1.5" />
300+
{page.page_views_30d.toLocaleString()} views
301+
</div>
285302
</div>
286303
</li>
287304
))}

apps/web/pages/changelog.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import HeaderComponent from "../components/layout/header.component";
1010
import { Spinner } from "@changespage/ui";
1111

1212
const POSTS_PER_PAGE = 10;
13+
const UNDERLINE_COLORS = [
14+
"decoration-blue-500",
15+
"decoration-yellow-500",
16+
"decoration-red-500",
17+
"decoration-indigo-500",
18+
"decoration-green-500",
19+
];
1320

1421
const client = createChangesPageClient({
1522
baseUrl: "https://hey.changes.page",
@@ -38,14 +45,14 @@ export default function Changelog({
3845
</p>
3946

4047
<div className="space-y-12">
41-
{posts.map((post) => (
48+
{posts.map((post, index) => (
4249
<ChangelogPost key={post.id} post={post}>
4350
{({ title, content, tags, formattedDate }) => (
44-
<article className="border-l-2 border-gray-200 dark:border-gray-700 pl-6">
51+
<article className="md:border-l-2 md:border-gray-200 md:dark:border-gray-700 md:pl-6">
4552
<time className="text-sm text-gray-500 dark:text-gray-400">
4653
{formattedDate}
4754
</time>
48-
<h2 className="text-2xl font-semibold text-gray-900 dark:text-white mt-1 mb-3">
55+
<h2 className={`text-2xl font-semibold text-gray-900 dark:text-white mt-1 mb-3 underline ${UNDERLINE_COLORS[index % UNDERLINE_COLORS.length]}`}>
4956
{title}
5057
</h2>
5158
<div className="flex gap-2 mb-4">

0 commit comments

Comments
 (0)