Add proper download counting functionality

This commit is contained in:
Jared Schoeny
2025-10-24 14:05:18 -10:00
parent 9287ddbace
commit 32d5af3c8e
9 changed files with 270 additions and 11 deletions

View File

@@ -0,0 +1,37 @@
"use client";
import React from "react";
import { FaDownload } from "react-icons/fa6";
import { formatCompactNumber } from "@/utils/format";
import type { DownloadEvent } from "@/types/util";
export default function DownloadsBadge({ slug, initialCount }: { slug: string; initialCount: number }) {
const [count, setCount] = React.useState<number>(initialCount);
const [anim, setAnim] = React.useState<boolean>(false);
React.useEffect(() => {
function onApplied(e: Event) {
const detail = (e as DownloadEvent).detail;
if (detail.slug !== slug) return;
setCount((c) => c + 1);
setAnim(true);
const t = setTimeout(() => setAnim(false), 600);
return () => clearTimeout(t);
}
window.addEventListener("hack:patch-applied", onApplied);
return () => window.removeEventListener("hack:patch-applied", onApplied);
}, [slug]);
return (
<div
className={`inline-flex items-center gap-2 rounded-full ring-1 ring-[var(--border)] bg-[var(--surface-2)] px-3 py-1 text-sm text-foreground/85 transition-transform ${
anim ? "scale-110 shadow-md font-bold" : ""
}`}
>
<FaDownload size={16} className="text-foreground/85" />
<span>{formatCompactNumber(count)}</span>
</div>
);
}

View File

@@ -6,6 +6,7 @@ import { useBaseRoms } from "@/contexts/BaseRomContext";
import { baseRoms } from "@/data/baseRoms";
import BinFile from "rom-patcher-js/rom-patcher-js/modules/BinFile.js";
import BPS from "rom-patcher-js/rom-patcher-js/modules/RomPatcher.format.bps.js";
import type { DownloadEventDetail } from "@/types/util";
interface HackActionsProps {
title: string;
@@ -14,6 +15,8 @@ interface HackActionsProps {
baseRomId: string;
platform?: "GBA" | "GBC" | "GB" | "NDS";
patchUrl: string;
patchId?: number;
hackSlug: string;
}
const HackActions: React.FC<HackActionsProps> = ({
@@ -23,6 +26,8 @@ const HackActions: React.FC<HackActionsProps> = ({
baseRomId,
platform,
patchUrl,
patchId,
hackSlug,
}) => {
const { isLinked, hasPermission, hasCached, importUploadedBlob, ensurePermission, linkRom, getFileBlob, supported } = useBaseRoms();
const [file, setFile] = React.useState<File | null>(null);
@@ -160,6 +165,29 @@ const HackActions: React.FC<HackActionsProps> = ({
patchedRom.save();
setStatus("done");
// Best-effort log applied event for counting and animate badge
try {
if (patchId != null) {
const key = "deviceId";
let deviceId = localStorage.getItem(key);
if (!deviceId) {
deviceId = crypto.randomUUID();
localStorage.setItem(key, deviceId);
}
await fetch(`/api/patches/${patchId}/applied`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ deviceId }),
})
.then((res) => {
if (res.status === 201) {
window.dispatchEvent(new CustomEvent<DownloadEventDetail>("hack:patch-applied", { detail: { slug: hackSlug } }));
}
})
.catch(() => {});
}
} catch {}
} catch (e: any) {
setError(e?.message || "Failed to patch ROM");
setStatus("idle");