132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
import { experimental_trpcMiddleware, TRPCError } from "@trpc/server";
|
|
import { and, desc, eq, inArray, notExists } from "drizzle-orm";
|
|
import { z } from "zod";
|
|
|
|
import { SqliteError } from "@lifetracker/db";
|
|
import { categories, days, hours, } from "@lifetracker/db/schema";
|
|
import {
|
|
zDaySchema, ZDay
|
|
} from "@lifetracker/shared/types/days";
|
|
import type { Context } from "../index";
|
|
import { authedProcedure, router } from "../index";
|
|
import { dateFromInput } from "@lifetracker/shared/utils/days";
|
|
|
|
async function createDay(date: string, ctx: Context) {
|
|
return await ctx.db.transaction(async (trx) => {
|
|
try {
|
|
// Create the Day object
|
|
const dayRes = await trx
|
|
.insert(days)
|
|
.values({
|
|
userId: ctx.user!.id,
|
|
date: date,
|
|
})
|
|
.returning({
|
|
id: days.id,
|
|
date: days.date,
|
|
mood: days.mood,
|
|
comment: days.comment,
|
|
});
|
|
|
|
const dayId = dayRes[0].id;
|
|
|
|
// Generate 24 "hour" objects
|
|
const hoursData = Array.from({ length: 24 }, (_, hour) => ({
|
|
userId: ctx.user!.id,
|
|
dayId: dayId,
|
|
time: hour
|
|
}));
|
|
|
|
// Insert the "hour" objects
|
|
await trx.insert(hours).values(hoursData);
|
|
|
|
return dayRes;
|
|
} catch (e) {
|
|
console.log(e);
|
|
if (e instanceof SqliteError) {
|
|
if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "This day already exists",
|
|
});
|
|
}
|
|
}
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Something went wrong",
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
export const daysAppRouter = router({
|
|
get: authedProcedure
|
|
.input(z.object({
|
|
dateQuery: z.string(),
|
|
}))
|
|
.output(zDaySchema)
|
|
.query(async ({ input, ctx }) => {
|
|
const date = dateFromInput(input);
|
|
|
|
// Fetch the day data
|
|
let dayRes;
|
|
dayRes = await ctx.db
|
|
.select({
|
|
id: days.id,
|
|
date: days.date,
|
|
mood: days.mood,
|
|
comment: days.comment,
|
|
})
|
|
.from(days)
|
|
.where(eq(days.date, date));
|
|
|
|
if (dayRes.length === 0) {
|
|
dayRes = await createDay(date, ctx);
|
|
}
|
|
|
|
const day = dayRes[0];
|
|
|
|
// Fetch the hours data for the corresponding dayId
|
|
const hoursRes = await ctx.db
|
|
.select({
|
|
id: hours.id,
|
|
dayId: hours.dayId,
|
|
time: hours.time,
|
|
categoryId: hours.categoryId,
|
|
categoryCode: categories.code,
|
|
comment: hours.comment,
|
|
})
|
|
.from(hours)
|
|
.where(eq(hours.dayId, day.id))
|
|
.leftJoin(categories, eq(categories.id, hours.categoryId))
|
|
|
|
// Combine the day and hours data
|
|
const result = {
|
|
...day,
|
|
hours: hoursRes,
|
|
};
|
|
return result;
|
|
}),
|
|
update: authedProcedure
|
|
.input(
|
|
z.object({
|
|
mood: z.string().optional().or(z.number()),
|
|
comment: z.string().optional(),
|
|
dateQuery: z.string(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const { dateQuery, ...updatedProps } = input;
|
|
|
|
// Convert mood to number, if it exists
|
|
if (updatedProps.mood) {
|
|
updatedProps.mood = parseInt(updatedProps.mood);
|
|
}
|
|
console.log(dateQuery, "::", dateFromInput({ dateQuery: dateQuery }));
|
|
await ctx.db
|
|
.update(days)
|
|
.set(updatedProps)
|
|
.where(eq(days.date, dateFromInput({ dateQuery: dateQuery })));
|
|
}),
|
|
});
|