- feat(rubgram): add webhook for submission
- fix(rubgram): return to register page after timer expire - fix(rubgram): hydration warning fix
This commit is contained in:
@@ -187,7 +187,7 @@ export function CharacterChooser({
|
||||
</span>
|
||||
</div>
|
||||
<center>ออกจากเกมเพื่อให้ข้อมูลอัพเดท แล้วกดรีโหลด</center>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogFooter suppressHydrationWarning>
|
||||
<AlertDialogCancel>ปิดหน้าต่าง</AlertDialogCancel>
|
||||
<Countdown
|
||||
time={cacheTtl}
|
||||
|
||||
+10
-3
@@ -216,7 +216,10 @@ export async function submitEndgame(formData: EndgameFormData) {
|
||||
})
|
||||
.returning({ queue: endgameSubmissions.queue, id: endgameSubmissions.id });
|
||||
revalidatePath("/rubgram/admin");
|
||||
ps.publish({}, { topic: "rubgram", event: "update" });
|
||||
ps.publish(
|
||||
{ type: "submit", sub: queue.id },
|
||||
{ topic: "rubgram", event: "update" },
|
||||
);
|
||||
return queue;
|
||||
}
|
||||
|
||||
@@ -286,7 +289,11 @@ export async function submitEndgamePayment(formData: EndgamePaymentFormData) {
|
||||
.where(eq(endgameSubmissions.id, sid));
|
||||
});
|
||||
revalidatePath("/rubgram/admin");
|
||||
ps.publish({}, { topic: "rubgram", event: "update" });
|
||||
if (Array.isArray(queue))
|
||||
ps.publish(
|
||||
{ type: "paid", sub: queue[0].id },
|
||||
{ topic: "rubgram", event: "update" },
|
||||
);
|
||||
return Array.isArray(queue) ? queue[0] : queue;
|
||||
}
|
||||
|
||||
@@ -401,7 +408,7 @@ export async function cancel(sid: string) {
|
||||
|
||||
await removeExpiredSubmissions();
|
||||
|
||||
ps.publish({}, { topic: "rubgram", event: "update" });
|
||||
ps.publish({ type: "cancel" }, { topic: "rubgram", event: "update" });
|
||||
|
||||
revalidatePath("/rubgram");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowRight, Check, Download, LogIn, ScrollText } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { type ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Blocker } from "@/components/blocker";
|
||||
@@ -185,11 +186,22 @@ export function DownloadButton() {
|
||||
export function Countdown({
|
||||
time,
|
||||
render = String,
|
||||
refreshWhenOver = false,
|
||||
}: {
|
||||
time: Date;
|
||||
render?: (time: string | null) => ReactNode;
|
||||
refreshWhenOver?: boolean;
|
||||
}) {
|
||||
const [now, setNow] = useState(new Date());
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!refreshWhenOver) return;
|
||||
const wait = time.getTime() - Date.now();
|
||||
if (wait < 0) return;
|
||||
const timeout = setTimeout(() => router.refresh(), wait);
|
||||
return () => clearTimeout(timeout);
|
||||
}, [time, router, refreshWhenOver]);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => setNow(new Date()), 1000);
|
||||
|
||||
@@ -175,8 +175,8 @@ export default async function EndgamePage() {
|
||||
<span className="font-bold text-lg">
|
||||
ยอดชำระ {q.price} บาท{" "}
|
||||
{q.expires && (
|
||||
<Kbd>
|
||||
<Countdown time={q.expires} />
|
||||
<Kbd suppressHydrationWarning>
|
||||
<Countdown time={q.expires} refreshWhenOver />
|
||||
</Kbd>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { env } from "node:process";
|
||||
import { redis } from "bun";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { and, asc, eq, isNull, lt, not, sql } from "drizzle-orm";
|
||||
import { removeExpiredSubmissions } from "@/app/(ui)/rubgram/api";
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
tierlistTiers,
|
||||
user,
|
||||
} from "@/lib/db/schema";
|
||||
import { rubgramWebhookTemplate } from "./webhook";
|
||||
|
||||
function logger(group: string) {
|
||||
const prefix = `[${group}]`;
|
||||
@@ -245,9 +247,53 @@ async function cacheCards() {
|
||||
} else schedule(120, cacheCards);
|
||||
}
|
||||
|
||||
const redisSubscribers: Record<
|
||||
string,
|
||||
(payload: { data: unknown; event?: string }) => void
|
||||
> = {
|
||||
"sse:rubgram": async ({ data, event }) => {
|
||||
type RubgramEvent = { type: "submit" | "paid" | "cancel"; sub: string };
|
||||
if (event !== "update") return;
|
||||
const { type, sub } = data as RubgramEvent;
|
||||
if (type === "cancel") return;
|
||||
if (!process.env.WEBHOOK_RUBGRAM_SUBMIT) return;
|
||||
const body = rubgramWebhookTemplate(
|
||||
type,
|
||||
await db
|
||||
.select()
|
||||
.from(endgameSubmissions)
|
||||
.where(eq(endgameSubmissions.id, sub))
|
||||
.limit(1)
|
||||
.then((s) => s[0]),
|
||||
await db.select().from(endgameTypes),
|
||||
);
|
||||
const res = await fetch(
|
||||
`${process.env.WEBHOOK_RUBGRAM_SUBMIT}?with_components=true`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok)
|
||||
console.error(
|
||||
"Webhook request wasn't ok.",
|
||||
await res.clone().json().catch(res.text.bind(res)),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
checkRubgramExpiration();
|
||||
seedDatabase();
|
||||
cacheCards();
|
||||
console.log("Tasks assigned");
|
||||
for (const [name, handler] of Object.entries(redisSubscribers))
|
||||
redis.subscribe(name, (p) => handler(JSON.parse(p)));
|
||||
|
||||
process
|
||||
.addListener("uncaughtException", console.error)
|
||||
.addListener("unhandledRejection", console.error);
|
||||
|
||||
process.on(15 as unknown as "SIGTERM", process.exit);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { endgameSubmissions, endgameTypes } from "@/lib/db/schema";
|
||||
|
||||
export function rubgramWebhookTemplate(
|
||||
type: "submit" | "paid",
|
||||
sub: typeof endgameSubmissions.$inferSelect,
|
||||
types: (typeof endgameTypes.$inferSelect)[],
|
||||
) {
|
||||
return {
|
||||
allowed_mentions: { parse: [] },
|
||||
flags: 1 << 15,
|
||||
components: [
|
||||
{
|
||||
type: 17,
|
||||
components: [
|
||||
{
|
||||
type: 9,
|
||||
components: [
|
||||
{
|
||||
type: 10,
|
||||
content:
|
||||
type === "submit"
|
||||
? "## :wave: New Submission"
|
||||
: "## :money_with_wings: Submission Paid",
|
||||
},
|
||||
],
|
||||
accessory: {
|
||||
type: 2,
|
||||
style: 5,
|
||||
label: "Admin",
|
||||
url: `${process.env.BASE_URL}/rubgram/admin/${sub.id}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 14,
|
||||
divider: true,
|
||||
spacing: 1,
|
||||
},
|
||||
{
|
||||
type: 10,
|
||||
content: `**Name**: ${sub.name}\n**Service**:\n${sub.service
|
||||
.map((s) => types.find((t) => t.id === s)?.display)
|
||||
.filter(Boolean)
|
||||
.map((s) => `- ${s}`)
|
||||
.join(
|
||||
"\n",
|
||||
)}\n**Server**: ${{ us: "America", eu: "Europe", as: "Asia", tw: "Taiwan" }[sub.server]}\n-# ${type === "submit" ? "**Not** p" : "P"}aid: **${sub.price} ฿** | <@${sub.user}>`,
|
||||
},
|
||||
],
|
||||
accent_color: type === "paid" ? 0x0ef06d : 15714574,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user