Skip to content

Commit 0123ef9

Browse files
authored
Add timer for students on cooldown (#142)
1 parent 03e148b commit 0123ef9

File tree

5 files changed

+64
-6
lines changed

5 files changed

+64
-6
lines changed

src/components/admin/CooldownTimer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const CoolDownTimer = () => {
5555
max={180}
5656
width="100%"
5757
onChange={(val) => setCooldownTime(parseInt(val))}
58+
mr={1}
5859
>
5960
<NumberInputField />
6061
<NumberInputStepper>

src/components/queue/CreateTicket.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
} from "@prisma/client";
77
import { useRef } from "react";
88
import { MutableRefObject } from "react";
9+
import { trpc } from "../../utils/trpc";
10+
import Countdown from "../ticket-page/Countdown";
911
import CreateTicketForm from "./CreateTicketForm";
1012

1113
interface CreateTicketProps {
@@ -20,9 +22,11 @@ const CreateTicket = (props: CreateTicketProps) => {
2022
const { siteSettings, personalQueue } = props;
2123
const endOfForm = useRef() as MutableRefObject<HTMLSpanElement>;
2224

25+
const { data: userCooldown } = trpc.ticket.getUserCooldownTime.useQuery();
26+
2327
return (
2428
<Flex width="full" align="left" flexDir="column" p={4}>
25-
<Text fontSize="2xl" mb={5}>
29+
<Text fontSize="2xl">
2630
Welcome back. Create a ticket to get started or{" "}
2731
<span
2832
style={{ cursor: "pointer", textDecoration: "underline" }}
@@ -32,6 +36,14 @@ const CreateTicket = (props: CreateTicketProps) => {
3236
view the queue
3337
</span>
3438
</Text>
39+
{userCooldown && (
40+
<Flex>
41+
<Text mt="0.5" fontSize="lg">
42+
Cooldown until you can make another ticket:&nbsp;
43+
</Text>
44+
<Countdown initialTimeInMs={userCooldown} />
45+
</Flex>
46+
)}
3547
<CreateTicketForm
3648
personalQueue={personalQueue}
3749
arePublicTicketsEnabled={

src/components/queue/CreateTicketForm.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,12 @@ const CreateTicketForm = (props: CreateTicketFormProps) => {
151151
},
152152
});
153153

154-
const cooldownPeriod = trpc.admin.getCoolDownTime.useQuery(undefined, {
155-
refetchOnWindowFocus: false,
156-
}).data;
154+
const { data: cooldownPeriod } = trpc.admin.getCoolDownTime.useQuery(
155+
undefined,
156+
{
157+
refetchOnWindowFocus: false,
158+
},
159+
);
157160

158161
const handleTicketTypeChange = (newVal: TicketType) => {
159162
setTicketType(newVal);
@@ -266,6 +269,7 @@ const CreateTicketForm = (props: CreateTicketFormProps) => {
266269
borderWidth={1}
267270
borderRadius={8}
268271
boxShadow="lg"
272+
mt={5}
269273
>
270274
<Box my={4} textAlign="left">
271275
<form onSubmit={onSubmit}>

src/components/queue/QueueLayout.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ const QueueLayout = (props: QueueLayoutProps) => {
3838

3939
const [isQueueOpen, setIsQueueOpen] = useState<boolean>();
4040
const [isPendingStageEnabled, setIsPendingStageEnabled] = useState<boolean>();
41-
const [arePublicTicketsEnabled, setArePublicTicketsEnabled] = useState<boolean>();
41+
const [arePublicTicketsEnabled, setArePublicTicketsEnabled] =
42+
useState<boolean>();
4243
const changeUserRoleMutation = trpc.user.updateUserRole.useMutation();
4344
const { siteSettings } = useSiteSettings();
4445

@@ -95,7 +96,11 @@ const QueueLayout = (props: QueueLayoutProps) => {
9596
}
9697
});
9798

98-
if (isQueueOpen === undefined || isPendingStageEnabled === undefined || arePublicTicketsEnabled === undefined) {
99+
if (
100+
isQueueOpen === undefined ||
101+
isPendingStageEnabled === undefined ||
102+
arePublicTicketsEnabled === undefined
103+
) {
99104
return <Spinner />;
100105
}
101106

src/server/trpc/router/ticket.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,42 @@ export const ticketRouter = router({
736736
return ticketsWithNames[0];
737737
}),
738738

739+
getUserCooldownTime: protectedProcedure.query(async ({ ctx }) => {
740+
// If there is a cooldown timer and the user is a student, return how long the student
741+
// has to wait before making another ticket. The wait time is returned in milliseconds and is
742+
// calculated by (lastTicketResolvedAt + cooldownTime) - Date.now()
743+
if (ctx.session.user.role !== UserRole.STUDENT) {
744+
return null;
745+
}
746+
747+
const cooldownTimeResult = await ctx.prisma.variableSettings.findUnique({
748+
where: { setting: VariableSiteSettings.COOLDOWN_TIME },
749+
});
750+
751+
const cooldownTime = parseInt(cooldownTimeResult?.value ?? "0");
752+
753+
if (!cooldownTime) {
754+
return null;
755+
}
756+
757+
const lastTicket = await ctx.prisma.ticket.findFirst({
758+
where: {
759+
createdByUserId: ctx.session.user.id,
760+
resolvedAt: {
761+
gte: new Date(Date.now() - cooldownTime * 60 * 1000),
762+
},
763+
},
764+
});
765+
766+
if (!lastTicket || !lastTicket.resolvedAt) {
767+
return null;
768+
}
769+
770+
return (
771+
lastTicket.resolvedAt.getTime() + cooldownTime * 60 * 1000 - Date.now()
772+
);
773+
}),
774+
739775
getTicketsWithStatus: protectedProcedure
740776
.input(
741777
z.object({

0 commit comments

Comments
 (0)