feat(don): add goal reset function
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user