lifetracker/packages/trpc/routers/hours.ts

161 lines
4.8 KiB
TypeScript

import { experimental_trpcMiddleware, TRPCError } from "@trpc/server";
import { and, desc, eq, inArray, notExists } from "drizzle-orm";
import { date, z } from "zod";
import { SqliteError } from "@lifetracker/db";
import { categories, days, hours, colors } from "@lifetracker/db/schema";
import {
zDaySchema, ZDay, ZHour, zHourSchema
} from "@lifetracker/shared/types/days";
import type { Context } from "../index";
import { authedProcedure, router } from "../index";
import { format } from "date-fns";
import { TZDate } from "@date-fns/tz";
import { dateFromInput } from "@lifetracker/shared/utils/days";
import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
export async function hourColors(hour: ZHour, ctx: Context) {
const categoryColor = await ctx.db.select()
.from(colors)
.leftJoin(categories, eq(categories.id, hour.categoryId))
.where(and(
eq(colors.id, categories.colorId),
eq(colors.userId, ctx.user!.id)
))
if (!categoryColor[0]) {
return {
background: "inherit",
foreground: "inherit"
}
}
else {
return {
background: categoryColor[0].color.hexcode,
foreground: categoryColor[0].color.inverse,
}
}
}
export async function hourJoinsQuery(
ctx: Context,
dayId: string,
time: number,
) {
const hourMatch = await ctx.db.select({
id: hours.id,
dayId: hours.dayId,
time: hours.time,
categoryId: hours.categoryId,
categoryCode: categories.code,
categoryName: categories.name,
categoryDesc: categories.description,
comment: hours.comment,
date: days.date,
}).from(hours)
.leftJoin(categories, eq(categories.id, hours.categoryId))
.leftJoin(days, eq(days.id, hours.dayId))
.where(and(
eq(hours.time, time),
eq(hours.dayId, dayId)
));
const dayHour = {
...hourMatch[0],
...(await hourColors(hourMatch[0], ctx)),
};
return dayHour;
};
export const hoursAppRouter = router({
get: authedProcedure
.input(z.object({
dateQuery: z.string(),
time: z.number()
}))
.output(zHourSchema)
.query(async ({ input, ctx }) => {
const date = dateFromInput({ dateQuery: input.dateQuery });
const hourRes = await getHourSelectQuery(ctx, date, input.time,
and(eq(hours.time, input.time), eq(days.date, date))
);
return {
date: format(date, "yyyy-MM-dd"),
...hourRes[0]
};
}),
update: authedProcedure
.input(
z.object({
date: z.string(),
hourTime: z.number(),
dayId: z.string(),
code: z.string().nullish(),
comment: z.string().nullable().optional(),
}),
)
.output(zHourSchema)
.mutation(async ({ input, ctx }) => {
const { code, ...updatedProps } = input;
let dateCondition;
if (input.dayId) {
dateCondition = eq(days.id, input.dayId)
}
else {
throw new TRPCError({ code: "BAD_REQUEST", message: "dayId is required" });
}
const category =
code == "" ? [{
id: null,
name: null
}]
: await ctx.db.select(
{
id: categories.id,
name: categories.name,
description: categories.description
}
)
.from(categories)
.where(
and(
eq(categories.code, code),
eq(categories.userId, ctx.user!.id),
)
);
const newProps = {
categoryId: category[0].id,
code: code,
...updatedProps
};
if (newProps.comment == "") { newProps.comment = null }
const hourRes = await ctx.db
.update(hours)
.set(newProps)
.where(
and(
eq(hours.time, input.hourTime),
eq(hours.dayId, input.dayId),
eq(hours.userId, ctx.user!.id)
)
).returning();
// return {
// date: input.date,
// ...hourRes[0]
// };
return hourJoinsQuery(ctx, input.dayId, input.hourTime);
}),
});