@@ -60,6 +71,7 @@ export default function Dash() {
{user.name} |
{user.rfid} |
{
+ if (lastRfid.data === "") return;
setUserRfid.mutateAsync({
username: user.username,
rfid: lastRfid.data || ""
diff --git a/src/pages/dash/index.tsx b/src/pages/dash/index.tsx
index 2e643c3..80db379 100644
--- a/src/pages/dash/index.tsx
+++ b/src/pages/dash/index.tsx
@@ -7,12 +7,17 @@ import { api } from "~/utils/api";
export default function Dash() {
const { push } = useRouter();
const isLoggedIn = api.admin.isLoggedIn.useQuery();
-
+ const periods = api.admin.getPeriods.useQuery();
+ const timePeriods = api.admin.getTimePeriods.useQuery();
+ const mySelectedPeriods = api.timeSel.getMySelectedPeriods.useQuery();
+ const toggleAttendance = api.timeSel.toggleAttendance.useMutation();
+ const attendTime = api.timeSel.attendTime.useQuery();
+ let periodCnt = 0;
useEffect(() => {
if (isLoggedIn.failureCount > 0) {
push("/");
- }
+ }
}, [isLoggedIn.failureCount])
if (isLoggedIn.isLoading) return <>>
@@ -25,6 +30,67 @@ export default function Dash() {
+
+ = 30 ? "bg-emerald-500" : "bg-red-300"
+ ].join(" ")}>
+ Hours
+
+
+ Click cells below to toggle
+
+
+
+ Date |
+ {
+ timePeriods.data?.map((timePeriods) => {
+ return ({timePeriods.name} ({timePeriods.start} ~ {timePeriods.end}) | )
+ })
+ }
+
+
+
+ {
+ Object.keys(periods.data || {}).map((date) => {
+ periodCnt = 0;
+ return (
+
+ {date} |
+ {
+ timePeriods.data?.map((timePeriod) => {
+ const thisPeriodId = periods.data![date]![periodCnt]?.id!;
+ if (periods.data![date]![periodCnt]?.timePeriodId == timePeriod.id) {
+ periodCnt++;
+ if (mySelectedPeriods.data?.findIndex((period) => period == thisPeriodId) != -1) {
+ return toggleAttendance.mutateAsync({
+ periodId: thisPeriodId || -1,
+ attendance: false
+ }).then(() => mySelectedPeriods.refetch()).then(() => attendTime.refetch())}>
+ Will Attend
+ |
+ } else {
+ return toggleAttendance.mutateAsync({
+ periodId: thisPeriodId || -1,
+ attendance: true
+ }).then(() => mySelectedPeriods.refetch()).then(() => attendTime.refetch())}> |
+ }
+ } else {
+ return N/A |
+ }
+ })
+ }
+
+ )
+ })
+ }
+
+
+
>)
}
\ No newline at end of file
diff --git a/src/server/api/root.ts b/src/server/api/root.ts
index 434dd54..db689d6 100644
--- a/src/server/api/root.ts
+++ b/src/server/api/root.ts
@@ -1,4 +1,4 @@
-import { postRouter } from "~/server/api/routers/post";
+import { timeSelRouter } from "~/server/api/routers/time-sel";
import { createTRPCRouter } from "~/server/api/trpc";
import { adminRouter } from "./routers/admin";
@@ -8,7 +8,7 @@ import { adminRouter } from "./routers/admin";
* All routers added in /api/routers should be manually added here.
*/
export const appRouter = createTRPCRouter({
- // post: postRouter,
+ timeSel: timeSelRouter,
admin: adminRouter,
});
diff --git a/src/server/api/routers/admin.ts b/src/server/api/routers/admin.ts
index e9d0af7..6ac0d8b 100644
--- a/src/server/api/routers/admin.ts
+++ b/src/server/api/routers/admin.ts
@@ -6,7 +6,7 @@ import { AddPeriods, AddTimePeriodSchema, AddUserSchema, ChgPasswordSchema, Logi
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { Period } from "@prisma/client";
-import { lastGotRfid } from "~/utils/rfid";
+import { lastGotRfid, rfidAttendance, setRfidAttendance } from "~/utils/rfid";
export const adminRouter = createTRPCRouter({
isLoggedIn: loggedInProcedure.query(() => true),
@@ -220,7 +220,18 @@ export const adminRouter = createTRPCRouter({
addPeriods: adminProcedure
.input(AddPeriods)
.mutation(async ({ input, ctx }) => {
- await ctx.db.timePeriod.findMany().then(
+ const period = await ctx.db.period.findFirst({
+ where: {
+ date: new Date(input.date),
+ },
+ });
+ if (period !== null) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Periods with date already exist.",
+ })
+ }
+ return await ctx.db.timePeriod.findMany().then(
async (timePeriods) => {
timePeriods.forEach(async (timePeriod) => {
await ctx.db.period.create({
@@ -249,6 +260,16 @@ export const adminRouter = createTRPCRouter({
timePeriodId: z.number().int(),
}))
.mutation(async ({ input, ctx }) => {
+ // if data exists, do nothing
+ const period = await ctx.db.period.findFirst({
+ where: {
+ date: new Date(input.date),
+ timePeriodId: input.timePeriodId,
+ },
+ });
+ if (period !== null) {
+ return period;
+ }
return await ctx.db.period.create({
data: {
date: new Date(input.date),
@@ -257,11 +278,15 @@ export const adminRouter = createTRPCRouter({
})
}),
disablePeriod: adminProcedure
- .input(z.number().int())
+ .input(z.object({
+ date: z.string(),
+ timePeriodId: z.number().int(),
+ }))
.mutation(async ({ input, ctx }) => {
- return await ctx.db.period.delete({
+ return await ctx.db.period.deleteMany({
where: {
- id: input,
+ date: new Date(input.date),
+ timePeriodId: input.timePeriodId,
},
})
}),
@@ -284,4 +309,19 @@ export const adminRouter = createTRPCRouter({
},
})
}),
+ rfidAttendance: adminProcedure
+ .query(() => {
+ return {
+ status: "success",
+ rfidAttendance: rfidAttendance,
+ }
+ }),
+ toggleRfidAttendance: adminProcedure
+ .mutation(() => {
+ setRfidAttendance(!rfidAttendance);
+ return {
+ status: "success",
+ message: "RFID attendance toggled.",
+ };
+ }),
});
diff --git a/src/server/api/routers/post.ts b/src/server/api/routers/post.ts
deleted file mode 100644
index 68367a3..0000000
--- a/src/server/api/routers/post.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { z } from "zod";
-
-import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
-
-export const postRouter = createTRPCRouter({
- hello: publicProcedure
- .input(z.object({ text: z.string() }))
- .query(({ input }) => {
- return {
- greeting: `Hello ${input.text}`,
- };
- }),
-
- create: publicProcedure
- .input(z.object({ name: z.string().min(1) }))
- .mutation(async ({ ctx, input }) => {
- // simulate a slow db call
- await new Promise((resolve) => setTimeout(resolve, 1000));
-
- return ctx.db.post.create({
- data: {
- name: input.name,
- },
- });
- }),
-
- getLatest: publicProcedure.query(({ ctx }) => {
- return ctx.db.post.findFirst({
- orderBy: { createdAt: "desc" },
- });
- }),
-});
diff --git a/src/server/api/routers/time-sel.ts b/src/server/api/routers/time-sel.ts
new file mode 100644
index 0000000..97e8896
--- /dev/null
+++ b/src/server/api/routers/time-sel.ts
@@ -0,0 +1,89 @@
+import { TRPCError } from "@trpc/server";
+import { z } from "zod";
+
+import { createTRPCRouter, loggedInProcedure, publicProcedure } from "~/server/api/trpc";
+
+export const timeSelRouter = createTRPCRouter({
+ getMySelectedPeriods: loggedInProcedure
+ .query(async ({ ctx }) => {
+ const user = await ctx.db.user.findUnique({
+ where: { username: ctx.session?.username },
+ select: {
+ periods: {
+ select: {
+ id: true,
+ }
+ }
+ }
+ });
+ if (!user) throw new TRPCError({ code: "UNAUTHORIZED", message: "User not found" });
+ return user.periods.map(period => period.id);
+ }),
+ toggleAttendance: loggedInProcedure
+ .input(z.object({
+ periodId: z.number().int(),
+ attendance: z.boolean(),
+ }))
+ .mutation(async ({ ctx, input }) => {
+ try {
+ if (input.attendance) {
+ await ctx.db.period.update({
+ where: { id: input.periodId },
+ data: {
+ users: {
+ connect: {
+ username: ctx.session?.username,
+ }
+ }
+ }
+ });
+ } else {
+ await ctx.db.period.update({
+ where: { id: input.periodId },
+ data: {
+ users: {
+ disconnect: {
+ username: ctx.session?.username,
+ }
+ }
+ }
+ });
+ }
+ } catch (e) {
+ throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "An error occurred." });
+ }
+ return true;
+ }),
+ attendTime: loggedInProcedure
+ .query(async ({ ctx }) => {
+ const user = await ctx.db.user.findUnique({
+ where: { username: ctx.session?.username },
+ select: {
+ periods: {
+ select: {
+ timePeriod: {
+ select: {
+ start: true,
+ end: true,
+ }
+ }
+ }
+ }
+ }
+ });
+ if (!user) throw new TRPCError({ code: "UNAUTHORIZED", message: "User not found" });
+ let total = 0;
+ user.periods.forEach(period => {
+ const start = new Date();
+ const end = new Date();
+ const [startHour, startMinute] = period.timePeriod.start.split(":");
+ const [endHour, endMinute] = period.timePeriod.end.split(":");
+ start.setHours(parseInt(startHour!));
+ start.setMinutes(parseInt(startMinute!));
+ end.setHours(parseInt(endHour!));
+ end.setMinutes(parseInt(endMinute!));
+ total += (end.getTime() - start.getTime()) / 1000 / 60 / 60; // convert to hours
+ })
+ return total;
+ }),
+});
diff --git a/src/utils/rfid.ts b/src/utils/rfid.ts
index 5cf6ebb..53637ad 100644
--- a/src/utils/rfid.ts
+++ b/src/utils/rfid.ts
@@ -1,4 +1,8 @@
export let lastGotRfid = "";
export const setLastRfid = (uid: string) => {
lastGotRfid = uid;
+};
+export let rfidAttendance = true;
+export const setRfidAttendance = (value: boolean) => {
+ rfidAttendance = value;
};
\ No newline at end of file
|