Skip to content

Commit 7657861

Browse files
authored
Merge pull request #10 from LooseWireDev/feat/popular-apps-section
Add popular apps section to home page
2 parents b028bc7 + 2c8bd12 commit 7657861

3 files changed

Lines changed: 70 additions & 4 deletions

File tree

db/queries.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,35 @@ export async function getRecentApps(db: DrizzleDB) {
407407
return withSlimRelations(db, rows);
408408
}
409409

410+
export async function getPopularApps(db: DrizzleDB, limit = 6) {
411+
const popular = await db
412+
.select({ appId: appDownloads.appId, count: sql<number>`count(*)` })
413+
.from(appDownloads)
414+
.groupBy(appDownloads.appId)
415+
.orderBy(sql`count(*) desc`)
416+
.limit(limit);
417+
418+
if (popular.length === 0) return [];
419+
420+
const rows = await db
421+
.select(appCardColumns)
422+
.from(apps)
423+
.where(
424+
inArray(
425+
apps.id,
426+
popular.map((p) => p.appId),
427+
),
428+
);
429+
430+
const hydrated = await withSlimRelations(db, rows);
431+
432+
// Preserve download count ordering
433+
const orderMap = new Map(popular.map((p, i) => [p.appId, i]));
434+
return hydrated.sort(
435+
(a, b) => (orderMap.get(a.id) ?? 0) - (orderMap.get(b.id) ?? 0),
436+
);
437+
}
438+
410439
// ─── Desktop App Queries ────────────────────────────────────────────
411440

412441
export async function listDesktopApps(

src/lib/server-fns.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
getAppAlternatives,
88
getAppBySlug,
99
getComparisonBySlug,
10+
getPopularApps,
1011
getProprietaryAppAlternatives,
1112
getProprietaryAppBySlug,
1213
getRecentApps,
@@ -232,6 +233,15 @@ export const fetchRecentApps = createServerFn({ method: "GET" })
232233
});
233234
});
234235

236+
export const fetchPopularApps = createServerFn({ method: "GET" })
237+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
238+
.handler(async (): Promise<any> => {
239+
return kvCached(cacheKey("getPopularApps"), () => {
240+
const db = getDb();
241+
return getPopularApps(db);
242+
});
243+
});
244+
235245
export const fetchComparisonBySlug = createServerFn({ method: "GET" })
236246
.inputValidator((input: { slug: string }) => input)
237247
// eslint-disable-next-line @typescript-eslint/no-explicit-any

src/routes/index.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { JsonLd } from "~/components/json-ld";
44
import { PageLayout } from "~/components/layout/page-layout";
55
import { SearchBar } from "~/components/search-bar";
66
import { SITE_URL } from "~/lib/constants";
7-
import { fetchCategoriesWithApps, fetchRecentApps } from "~/lib/server-fns";
7+
import {
8+
fetchCategoriesWithApps,
9+
fetchPopularApps,
10+
fetchRecentApps,
11+
} from "~/lib/server-fns";
812

913
const popularAlternatives = [
1014
{ name: "WhatsApp", slug: "whatsapp" },
@@ -21,11 +25,12 @@ const popularAlternatives = [
2125

2226
export const Route = createFileRoute("/")({
2327
loader: async () => {
24-
const [recentApps, categories] = await Promise.all([
28+
const [recentApps, popularApps, categories] = await Promise.all([
2529
fetchRecentApps(),
30+
fetchPopularApps(),
2631
fetchCategoriesWithApps(),
2732
]);
28-
return { recentApps, categories };
33+
return { recentApps, popularApps, categories };
2934
},
3035
head: () => ({
3136
meta: [
@@ -53,7 +58,7 @@ export const Route = createFileRoute("/")({
5358
});
5459

5560
function HomePage() {
56-
const { recentApps, categories } = Route.useLoaderData();
61+
const { recentApps, popularApps, categories } = Route.useLoaderData();
5762

5863
const jsonLd = {
5964
"@context": "https://schema.org",
@@ -104,6 +109,28 @@ function HomePage() {
104109
</div>
105110
</section>
106111

112+
{/* Popular Apps */}
113+
{popularApps.length > 0 && (
114+
<section>
115+
<h2 className="mb-3 font-sans text-base font-bold text-foreground">
116+
Popular Apps
117+
</h2>
118+
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
119+
{popularApps.map((app: any) => (
120+
<AppCard
121+
key={app.slug}
122+
name={app.name}
123+
slug={app.slug}
124+
description={app.description}
125+
iconUrl={app.iconUrl}
126+
sources={app.sources}
127+
tags={app.tags}
128+
/>
129+
))}
130+
</div>
131+
</section>
132+
)}
133+
107134
{/* Recently Added */}
108135
{recentApps.length > 0 && (
109136
<section>

0 commit comments

Comments
 (0)