feat(don): add goal reset function
Build and Push Image / build-backend (push) Successful in 6m23s
Build and Push Image / build-frontend (push) Successful in 3m36s
Build and Push Image / push (push) Successful in 1m38s

This commit is contained in:
2026-06-16 06:52:07 +07:00 Unverified
parent 414f407d08
commit e483360b5b
6 changed files with 42 additions and 6 deletions
@@ -14,6 +14,8 @@ import { db } from "@/lib/db";
import { settings } from "@/lib/db/schema";
import { formParse } from "@/components/form-submit";
import { sse } from "@/lib/db/sse-endpoints";
import { ActionButton } from "@/components/action-button";
import { resetGoal } from "../../api";
const Schema = z.object({
goal: z.coerce.number().nonnegative().nullable().optional().default(null),
@@ -61,6 +63,9 @@ export default async function RgManualCreateModal() {
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<ActionButton action={resetGoal} type="button" variant="destructive">
Reset Goal
</ActionButton>
<Button asChild>
<FormAction
type="submit"
+20 -1
View File
@@ -2,12 +2,31 @@
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import { donations } from "@/lib/db/schema";
import { donations, settings } from "@/lib/db/schema";
import { sse } from "@/lib/db/sse-endpoints";
import { fileToDataUrl } from "@/lib/utils";
import { eq } from "drizzle-orm";
import { getPostHogClient } from "@/lib/posthog-server";
export async function resetGoal() {
if (!(await adminCheck())) throw new Error("Unauthorized");
getPostHogClient().capture({
distinctId: "admin",
event: "donation_admin_goal_reset",
});
await db
.insert(settings)
.values({ donateGoalStarting: new Date() })
.onConflictDoUpdate({
target: settings.id,
set: { donateGoalStarting: new Date() },
});
sse.donate.pub("update", null);
}
export async function testPopup() {
if (!(await adminCheck())) throw new Error("Unauthorized");
+5 -2
View File
@@ -1,15 +1,18 @@
"use server";
import { getArtifactConfig } from "@/lib/api";
import { db } from "@/lib/db";
import { donations, settings } from "@/lib/db/schema";
import { sum } from "drizzle-orm";
import { gt, sum } from "drizzle-orm";
export async function getDonateBar() {
const { donateGoalStarting } = await getArtifactConfig();
const [{ amount }] = await db
.select({
amount: sum(donations.amount),
})
.from(donations);
.from(donations)
.where(gt(donations.created, donateGoalStarting ?? new Date(0)));
const [{ goal }] = await db
.select({ goal: settings.donateGoal })
.from(settings)
+7 -3
View File
@@ -4,6 +4,7 @@ import { sse } from "@/lib/db/sse-endpoints";
import { useEffect, useRef, useState } from "react";
import { getDonateBar } from "./api";
import { motion } from "motion/react";
import { pausePass } from "@/lib/utils";
type Data = Awaited<ReturnType<typeof getDonateBar>>;
@@ -15,7 +16,9 @@ export default function TopDonateWidget() {
useEffect(() => {
async function update() {
void getDonateBar().then(setBar);
if (textRef.current)
void getDonateBar().then(pausePass(10000)).then(setBar);
else void getDonateBar().then(setBar);
}
queueMicrotask(update);
const { clean } = sse.donate.subMany({
@@ -74,13 +77,14 @@ export default function TopDonateWidget() {
return () => window.removeEventListener("resize", onResize);
}, [bar]);
return bar && bar.amount !== null && bar.goal ? (
return bar ? (
<div className="relative h-full max-h-[20svw] w-full rounded-full bg-[#252525]">
<div className="absolute inset-2 rounded-full bg-black" />
<motion.div
className="absolute inset-1.5 rounded-full bg-linear-to-b from-[#FD0000] to-[#830000]"
animate={{
width: `calc(6px + ${Math.min(1, Number(bar.amount) / bar.goal)} * (100% - 12px))`,
width: `calc(${Math.min(1, Number(bar.amount ?? "0") / (bar.goal ?? 1)) * 100}% - ${Math.min(1, Number(bar.amount ?? "0") / (bar.goal ?? 1)) * 12}px)`,
// width: `calc(6px + ${Math.min(1, Number(bar.amount) / bar.goal)} * (100% - 12px))`,
}}
initial={{
width: 0,
+1
View File
@@ -76,6 +76,7 @@ export const settings = pgTable("settings", {
id: boolean().primaryKey().default(true),
enka: boolean().notNull().default(false), // Turn this off when Enka is on maintenance
donateGoal: numeric({ mode: "number" }),
donateGoalStarting: timestamp(),
});
//#endregion
+4
View File
@@ -68,3 +68,7 @@ export function parseSearchString(
if (Array.isArray(param)) return parseSearchString(param[0], def);
return param ?? def;
}
export function pausePass<R>(time: number): (res: R) => Promise<R> {
return (res) => new Promise((r) => setTimeout(() => r(res), time));
}