Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into HK-180-no-duplicate-re…
Browse files Browse the repository at this point in the history
…sumes
  • Loading branch information
christianhelp committed Dec 17, 2024
2 parents ffcd85d + 5c6bcb8 commit fd3dd3d
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 21 deletions.
12 changes: 12 additions & 0 deletions apps/web/src/actions/admin/registration-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const defaultRegistrationToggleSchema = z.object({
enabled: z.boolean(),
});

const defaultRSVPLimitSchema = z.object({
rsvpLimit: z.number(),
});

export const toggleRegistrationEnabled = adminAction
.schema(defaultRegistrationToggleSchema)
.action(async ({ parsedInput: { enabled }, ctx: { user, userId } }) => {
Expand Down Expand Up @@ -40,3 +44,11 @@ export const toggleRSVPs = adminAction
revalidatePath("/admin/toggles/registration");
return { success: true, statusSet: enabled };
});

export const setRSVPLimit = adminAction
.schema(defaultRSVPLimitSchema)
.action(async ({ parsedInput: { rsvpLimit }, ctx: { user, userId } }) => {
await kv.set("config:registration:maxRSVPs", rsvpLimit);
revalidatePath("/admin/toggles/registration");
return { success: true, statusSet: rsvpLimit };
});
5 changes: 1 addition & 4 deletions apps/web/src/app/admin/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ export default async function AdminLayout({ children }: AdminLayoutProps) {
<ClientToast />
<div className="fixed z-20 grid h-16 w-full grid-cols-2 bg-nav px-5">
<div className="flex items-center gap-x-4">
<Link
href={"/"}
className="mr-5 flex items-center gap-x-2"
>
<Link href={"/"} className="mr-5 flex items-center gap-x-2">
<Image
src={c.icon.svg}
alt={c.hackathonName + " Logo"}
Expand Down
9 changes: 8 additions & 1 deletion apps/web/src/app/admin/toggles/registration/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RegistrationToggles } from "@/components/admin/toggles/RegistrationSettings";
import { kv } from "@vercel/kv";
import { parseRedisBoolean } from "@/lib/utils/server/redis";
import { parseRedisBoolean, parseRedisNumber } from "@/lib/utils/server/redis";
import c from "config";

export default async function Page() {
const pipe = kv.pipeline();
Expand All @@ -12,10 +13,12 @@ export default async function Page() {
defaultRegistrationEnabled,
defaultSecretRegistrationEnabled,
defaultRSVPsEnabled,
defaultRSVPLimit,
]: (string | null)[] = await kv.mget(
"config:registration:registrationEnabled",
"config:registration:secretRegistrationEnabled",
"config:registration:allowRSVPs",
"config:registration:maxRSVPs",
);

return (
Expand All @@ -38,6 +41,10 @@ export default async function Page() {
defaultRSVPsEnabled,
true,
)}
defaultRSVPLimit={parseRedisNumber(
defaultRSVPLimit,
c.rsvpDefaultLimit,
)}
/>
</div>
);
Expand Down
8 changes: 7 additions & 1 deletion apps/web/src/app/admin/users/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Image from "next/image";
import { Button } from "@/components/shadcn/ui/button";
import { Badge } from "@/components/shadcn/ui/badge";
import { Info } from "lucide-react";
import { Info, CalendarCheck } from "lucide-react";
import Link from "next/link";
import UpdateRoleDialog from "@/components/admin/users/UpdateRoleDialog";
import {
Expand Down Expand Up @@ -88,6 +88,12 @@ export default async function Page({ params }: { params: { slug: string } }) {
.slice(1)
.join(" ")}
</Badge>
{user.isRSVPed && (
<Badge className="no-select bg-gradient-to-r from-teal-400 to-blue-500 bg-clip-padding text-center hover:from-teal-500 hover:to-blue-600">
<CalendarCheck className="mr-1 h-3 w-3" />
RSVP
</Badge>
)}
</div>
</div>
<div className="col-span-2 overflow-x-hidden">
Expand Down
40 changes: 29 additions & 11 deletions apps/web/src/app/rsvp/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import ConfirmDialogue from "@/components/rsvp/ConfirmDialogue";
import c from "config";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { db } from "db";
import { count, db } from "db";
import { eq } from "db/drizzle";
import { userCommonData } from "db/schema";
import ClientToast from "@/components/shared/ClientToast";
import { SignedOut, RedirectToSignIn } from "@clerk/nextjs";
import { kv } from "@vercel/kv";
import { parseRedisBoolean } from "@/lib/utils/server/redis";
import { parseRedisBoolean, parseRedisNumber } from "@/lib/utils/server/redis";
import Link from "next/link";
import { Button } from "@/components/shadcn/ui/button";
import { getUser } from "db/functions";
Expand Down Expand Up @@ -40,16 +40,34 @@ export default async function RsvpPage({
return redirect("/i/approval");
}

const rsvpEnabled = await kv.get("config:registration:allowRSVPs");
const rsvpEnabled = parseRedisBoolean(
(await kv.get("config:registration:allowRSVPs")) as
| string
| boolean
| null
| undefined,
true,
);

// TODO: fix type jank here
if (
parseRedisBoolean(
rsvpEnabled as string | boolean | null | undefined,
true,
) === true ||
user.isRSVPed === true
) {
let isRsvpPossible = false;

if (rsvpEnabled === true) {
const rsvpLimit = parseRedisNumber(
await kv.get("config:registration:maxRSVPs"),
c.rsvpDefaultLimit,
);

const rsvpUserCount = await db
.select({ count: count() })
.from(userCommonData)
.where(eq(userCommonData.isRSVPed, true))
.limit(rsvpLimit)
.then((result) => result[0].count);

isRsvpPossible = rsvpUserCount < rsvpLimit;
}

if (isRsvpPossible || user.isRSVPed === true) {
return (
<>
<ClientToast />
Expand Down
28 changes: 28 additions & 0 deletions apps/web/src/components/admin/toggles/RegistrationSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@ import {
toggleRegistrationMessageEnabled,
toggleSecretRegistrationEnabled,
toggleRSVPs,
setRSVPLimit,
} from "@/actions/admin/registration-actions";
import { UpdateItemWithConfirmation } from "./UpdateItemWithConfirmation";

interface RegistrationTogglesProps {
defaultRegistrationEnabled: boolean;
defaultSecretRegistrationEnabled: boolean;
defaultRSVPsEnabled: boolean;
defaultRSVPLimit: number;
}

export function RegistrationToggles({
defaultSecretRegistrationEnabled,
defaultRegistrationEnabled,
defaultRSVPsEnabled,
defaultRSVPLimit,
}: RegistrationTogglesProps) {
const {
execute: executeToggleSecretRegistrationEnabled,
Expand Down Expand Up @@ -57,6 +61,16 @@ export function RegistrationToggles({
},
});

const {
execute: executeSetRSVPLimit,
optimisticState: SetRSVPLimitOptimisticData,
} = useOptimisticAction(setRSVPLimit, {
currentState: { success: true, statusSet: defaultRSVPLimit },
updateFn: (state, { rsvpLimit }) => {
return { statusSet: rsvpLimit, success: true };
},
});

return (
<>
<div className="rounded-lg border-2 border-muted px-5 py-10">
Expand Down Expand Up @@ -116,6 +130,20 @@ export function RegistrationToggles({
}}
/>
</div>
<div className="flex items-center border-b border-t border-t-muted py-4">
<p className="mr-auto text-sm font-bold">RSVP Limit</p>
<UpdateItemWithConfirmation
defaultValue={SetRSVPLimitOptimisticData.statusSet}
enabled={toggleRSVPsOptimisticData.statusSet}
type="number"
onSubmit={(newLimit) => {
toast.success(
`Hacker RSVP limit successfully changed to ${newLimit}!`,
);
executeSetRSVPLimit({ rsvpLimit: newLimit });
}}
/>
</div>
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useState } from "react";
import { Input } from "@/components/shadcn/ui/input";
import { Button } from "@/components/shadcn/ui/button";

interface UpdateItemWithConfirmationBaseProps<T extends number | string> {
defaultValue: T;
enabled: boolean;
onSubmit: (value: T) => void;
}

type UpdateItemWithConfirmationProps =
| ({ type: "string" } & UpdateItemWithConfirmationBaseProps<string>)
| ({ type: "number" } & UpdateItemWithConfirmationBaseProps<number>);

export function UpdateItemWithConfirmation({
type,
defaultValue,
onSubmit,
enabled,
}: UpdateItemWithConfirmationProps) {
const [valueUpdated, setValueUpdated] = useState(false);
const [value, setValue] = useState(defaultValue.toString());

return (
<div className="flex max-h-8 items-center gap-2">
<Input
className="text-md w-24 text-center font-bold sm:w-40"
value={value}
disabled={!enabled}
onChange={({ target: { value: updated } }) => {
// Ignore the change if the value is a non numeric character.
if (type === "number" && /[^0-9]/.test(updated)) {
setValue(value);
return;
}

setValue(updated);

/* Avoid allowing the user to update the default value to itself.
* Also disallow the user from sending a zero length input. */
setValueUpdated(
updated !== defaultValue.toString() &&
updated.length !== 0,
);
}}
/>
<Button
className="text-sm font-bold"
type="button"
variant="default"
title="Apply Changes"
disabled={!valueUpdated || !enabled}
onClick={() => {
if (type === "number") {
onSubmit(parseInt(value));
} else {
onSubmit(value);
}

setValueUpdated(false);
}}
>
Apply
</Button>
</div>
);
}
8 changes: 4 additions & 4 deletions apps/web/src/lib/utils/client/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { redirect } from "next/navigation";
export function getClientTimeZone(vercelIPTimeZone: string | null) {
return vercelIPTimeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
}
export async function clientLogOut(){
"use server";
redirect("/");
};
export async function clientLogOut() {
"use server";
redirect("/");
}
8 changes: 8 additions & 0 deletions apps/web/src/lib/utils/server/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ export function parseRedisBoolean(
if (typeof value === "boolean") return value;
return defaultValue !== undefined ? defaultValue : false;
}

export function parseRedisNumber(value: string | null, defaultValue: number) {
if (value && !isNaN(parseInt(value))) {
return parseInt(value);
} else {
return defaultValue;
}
}
1 change: 1 addition & 0 deletions packages/config/hackkit.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ const c = {
itteration: "I",
siteUrl: "https://rowdyhacks.org", // Do not have a trailing slash
defaultMetaDataDescription: "Your Metadata Description Here",
rsvpDefaultLimit: 500,
botName: "HackKit",
botParticipantRole: "Participant",
hackathonTimezone: "America/Chicago",
Expand Down

0 comments on commit fd3dd3d

Please sign in to comment.