Checkpoint: Can actually log time (track life, if you will) using CLI and Web.

This commit is contained in:
Ryan Pandya 2024-11-30 23:36:01 -05:00
parent a85e8f294a
commit d0c07fd8b8
18 changed files with 348 additions and 112 deletions

View File

@ -66,9 +66,9 @@ export const daysCmd = new Command()
const day = (await api.days.get.query({ dateQuery: dateQuery, timezone: timezone })); const day = (await api.days.get.query({ dateQuery: dateQuery, timezone: timezone }));
console.log(`Snagged day with id '${day.id}'`); console.log(`Snagged day with id '${day.id}'`);
if (getGlobalOptions().json) { // if (getGlobalOptions().json) {
printObject(day); // printObject(day);
} else { // } else {
const moodStr = moodToStars(day.mood); const moodStr = moodToStars(day.mood);
const dateStr = format(day.date, "EEEE, MMMM do", { in: utc }); const dateStr = format(day.date, "EEEE, MMMM do", { in: utc });
@ -76,6 +76,8 @@ export const daysCmd = new Command()
[`Time (${timezones[timezone]})`, "Category", "Comment"] [`Time (${timezones[timezone]})`, "Category", "Comment"]
]; ];
console.log(day.hours.map((h) => h.date));
day.hours.forEach((h, i) => { day.hours.forEach((h, i) => {
data.push([ data.push([
getHourFromTime(i, 'twelves', `(${timezones[timezone]})`), getHourFromTime(i, 'twelves', `(${timezones[timezone]})`),
@ -85,7 +87,7 @@ export const daysCmd = new Command()
}) })
if (flags?.hour) { if (flags?.hour) {
doHour(day.hours, day, flags.hour, timezone); doHour(day, flags.hour, timezone);
} }
else { else {
@ -100,7 +102,7 @@ export const daysCmd = new Command()
return (lineIndex < 1 || lineIndex === 2 || lineIndex === 3 || lineIndex === rowCount); return (lineIndex < 1 || lineIndex === 2 || lineIndex === 3 || lineIndex === rowCount);
}, },
})); }));
} // }
} }
} catch (error) { } catch (error) {
printErrorMessageWithReason("Failed", error as object); printErrorMessageWithReason("Failed", error as object);

View File

@ -26,11 +26,12 @@ export const hoursCmd = new Command()
return "Hello"; return "Hello";
}); });
export async function doHour(hours: ZHour[], day: ZDay, hourFlags: string[], timezone = "UTC") { export async function doHour(day: ZDay, hourFlags: string[], timezone = "UTC") {
const hourNum = getTimeFromHour(hourFlags.shift()!); const hourNum = getTimeFromHour(hourFlags.shift()!);
const hour = hours[hourNum]; const hour = day.hours[hourNum];
if (hourFlags.length == 0) { if (hourFlags.length == 0) {
console.log("No new values to set; printing hour.")
printHour(hour, hourNum, day, timezone); printHour(hour, hourNum, day, timezone);
} }
else { else {
@ -48,6 +49,7 @@ export async function doHour(hours: ZHour[], day: ZDay, hourFlags: string[], tim
} }
} }
const props = { dateQuery: hour.date!, time: hour.time, code: hourFlags[0], comment: hourFlags[1] || null }; const props = { dateQuery: hour.date!, time: hour.time, code: hourFlags[0], comment: hourFlags[1] || null };
// console.log(props);
res = await api.hours.update.mutate({ ...props }); res = await api.hours.update.mutate({ ...props });
printHour(res as ZHour, hourNum, day, timezone); printHour(res as ZHour, hourNum, day, timezone);

View File

@ -2,6 +2,8 @@ import { notFound } from "next/navigation";
import { api } from "@/server/api/client"; import { api } from "@/server/api/client";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import DayView from "@/components/dashboard/days/DayView"; import DayView from "@/components/dashboard/days/DayView";
import spacetime from "spacetime";
import { useTimezone } from "@lifetracker/shared-react/hooks/timezones";
export default async function DayPage({ export default async function DayPage({
params, params,
@ -9,9 +11,12 @@ export default async function DayPage({
params: { dateQuery: string }; params: { dateQuery: string };
}) { }) {
let day; let day;
const tzName = await api.users.getTimezone();
console.log(`Displaying ${spacetime.now(tzName).format()} in ${tzName}.`);
try { try {
day = await api.days.get({ day = await api.days.get({
dateQuery: params.dateQuery, dateQuery: spacetime(params.dateQuery, tzName).format(),
timezone: tzName,
}); });
} catch (e) { } catch (e) {
if (e instanceof TRPCError) { if (e instanceof TRPCError) {
@ -23,8 +28,10 @@ export default async function DayPage({
} }
return ( return (
<>
<DayView <DayView
day={day} day={day}
/> />
</>
); );
} }

View File

@ -1,7 +1,7 @@
export default function DemoModeBanner() { export default function DemoModeBanner() {
return ( return (
<div className="h-min w-full rounded bg-yellow-100 px-4 py-2 text-center text-black"> <div className="h-min w-full rounded bg-yellow-100 px-4 py-2 text-center text-black">
Demo mode is on. All modifications are disabled. YO
</div> </div>
); );
} }

View File

@ -12,6 +12,9 @@ import Link from "next/link";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { ArrowLeftSquare, ArrowRightSquare } from "lucide-react"; import { ArrowLeftSquare, ArrowRightSquare } from "lucide-react";
import { UTCDate, utc } from "@date-fns/utc"; import { UTCDate, utc } from "@date-fns/utc";
import spacetime from "spacetime";
import EditableHour from "@/components/hours/EditableHour";
export default async function DayView({ export default async function DayView({
day, day,
}: { }: {
@ -22,8 +25,8 @@ export default async function DayView({
redirect("/"); redirect("/");
} }
const prevDay = format(addDays(day.date, -1), "yyyy-MM-dd"); const prevDay = spacetime(day.date).subtract(1, "day").format("iso-short");
const nextDay = format(addDays(day.date, 1), "yyyy-MM-dd"); const nextDay = spacetime(day.date).add(1, "day").format("iso-short");
return ( return (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
@ -41,7 +44,7 @@ export default async function DayView({
</div> </div>
</Link> </Link>
<span className="text-2xl flex-1"> <span className="text-2xl flex-1">
{format(day.date, "EEEE, MMMM do", { in: utc })} {spacetime(day.date).format("{day}, {month} {date}, {year}")}
</span> </span>
<Link <Link
href={`/dashboard/day/${nextDay}`} href={`/dashboard/day/${nextDay}`}
@ -70,9 +73,29 @@ export default async function DayView({
<Separator /> <Separator />
<ul> <ul>
<li>
<div className={cn(
"p-4 grid justify-between",
)}
style={{
fontFamily: "inherit",
gridTemplateColumns: "100px 1fr 200px"
}}
>
<span className="text-right">
Time
</span>
<span className="text-center">
Category
</span>
<div className="text-right">
Actions
</div>
</div>
</li>
{day.hours.map((hour) => ( {day.hours.map((hour) => (
<li key={hour.time}> <li key={hour.time} id={"hour-" + hour.time.toString()}>
{hour.time}: {hour.categoryName} {hour.comment} <EditableHour hour={hour} />
</li> </li>
))} ))}
</ul> </ul>

View File

@ -8,50 +8,73 @@ import { useTimezone } from "@lifetracker/shared-react/hooks/timezones";
import LoadingSpinner from "@/components/ui/spinner"; import LoadingSpinner from "@/components/ui/spinner";
import { db } from "@lifetracker/db"; import { db } from "@lifetracker/db";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import spacetime from "spacetime";
export default function TimezoneDisplay() { export default function TimezoneDisplay() {
const clientTime = spacetime.now();
const dbTimezone = useTimezone();
const [timezone, setTimezone] = useState(dbTimezone);
// Update timezone state when dbTimezone changes
useEffect(() => {
if (dbTimezone !== undefined) {
setTimezone(dbTimezone);
}
}, [dbTimezone]);
useEffect(() => {
const handleTzChange = (event) => {
setTimezone(event.detail.timezone);
};
window.addEventListener('timezoneUpdated', handleTzChange);
return () => {
window.removeEventListener('timezoneUpdated', handleTzChange);
};
}, []);
if (timezone === undefined) {
return (
<div className="flex flex-col items-center w-full">
<LoadingSpinner />
</div>
);
}
return ( return (
<div className="text-center w-full"> <div className="text-center w-full">
<Link href="/settings/app"> <Link href="/settings/app">
<b className="whitespace-nowrap">{format(TZDate.tz(timezone), 'MMM dd, hh:mm aa')}</b> <b className="whitespace-nowrap">
{clientTime.format('nice')}
</b>
<br /> <br />
<span>in&nbsp;</span> <span>in&nbsp;</span>
<span className="whitespace-nowrap"> <span className="whitespace-nowrap">
<b>{timezones[timezone]}</b> <b>
{timezones[clientTime.timezone().name] || clientTime.timezone().name}
</b>
</span> </span>
</Link> </Link>
</div> </div>
); );
} }
// export default function TimezoneDisplay() {
// const dbTimezone = useTimezone();
// const [timezone, setTimezone] = useState(dbTimezone);
// // Update timezone state when dbTimezone changes
// useEffect(() => {
// if (dbTimezone !== undefined) {
// setTimezone(dbTimezone);
// }
// }, [dbTimezone]);
// useEffect(() => {
// const handleTzChange = (event) => {
// setTimezone(event.detail.timezone);
// };
// window.addEventListener('timezoneUpdated', handleTzChange);
// return () => {
// window.removeEventListener('timezoneUpdated', handleTzChange);
// };
// }, []);
// if (timezone === undefined) {
// return (
// <div className="flex flex-col items-center w-full">
// <LoadingSpinner />
// </div>
// );
// }
// return (
// <div className="text-center w-full">
// <Link href="/settings/app">
// <b className="whitespace-nowrap">{format(TZDate.tz(timezone), 'MMM dd, hh:mm aa')}</b>
// <br />
// <span>in&nbsp;</span>
// <span className="whitespace-nowrap">
// <b>{timezones[timezone]}</b>
// </span>
// </Link>
// </div>
// );
// }

View File

@ -0,0 +1,137 @@
"use client";
import { usePathname, useRouter } from "next/navigation";
import { toast } from "@/components/ui/use-toast";
import { cn } from "@/lib/utils";
import { useUpdateHour } from "@lifetracker/shared-react/hooks/days";
import { EditableText } from "../dashboard/EditableText";
import { format } from "date-fns";
import { TZDate } from "@date-fns/tz";
import { ZHour } from "@lifetracker/shared/types/days";
import { useEffect, useRef } from "react";
function EditMode({
originalText,
hour,
onSubmit
}) {
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
if (ref.current) {
ref.current.value = originalText;
}
}, [ref]);
const submit = () => {
let newCode: string | null = ref.current?.value ?? null;
if (originalText == newCode) {
// Nothing to do here
return;
}
if (newCode == "") {
newCode = null;
}
// console.log(hour);
onSubmit({
dateQuery: hour.date,
time: hour.time,
code: newCode,
})
document.getElementById("hour-" + (hour.time + 1).toString())?.getElementsByClassName("edit-hour-code")[0].focus();
};
return (
<input
className="w-8 border-b-2 text-center edit-hour-code"
ref={ref}
value={originalText}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
submit();
}
}}
onClick={(e) => {
const range = document.createRange();
range.selectNodeContents(ref.current);
const selection = window.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}
}}
/>
// <input type="text"
// className="w-10 bg-inherit border-b-2 text-center"
// style={{ color: "inherit", borderColor: "inherit" }}
// onKeyDown={(e) => {
// if (e.key === "Enter") {
// e.preventDefault();
// onSave();
// }
// }}
// value={originalText.originalText ?? ""}
// />
);
}
export default function EditableHour({
hour,
className,
}: {
hour: ZHour,
className?: string;
}) {
const router = useRouter();
const currentPath = usePathname();
const { mutate: updateHour, isPending } = useUpdateHour({
onSuccess: () => {
toast({
description: "Hour updated!",
});
if (currentPath.includes("dashboard")) {
router.refresh();
}
},
});
function isActiveHour(hour: ZHour) {
const now = new TZDate();
return (hour.date == format(now, "yyyy-MM-dd")) && (((now.getHours()) + (now.getTimezoneOffset() / 60) - (parseInt(hour.time))) == 0)
}
return (
<div className={cn(
"p-4 grid justify-between",
)}
style={{
background: hour.background, color: hour.foreground, fontFamily: "inherit",
gridTemplateColumns: "100px 100px 1fr 200px"
}}
>
<span className="text-right">
{isActiveHour(hour) && "--> "}
{hour.datetime}
</span>
<div className="flex justify-center">
<EditMode
originalText={hour.categoryCode}
hour={hour}
onSubmit={updateHour}
/>
</div>
<span>
{hour.categoryDesc || " "}
</span>
<div className="text-right">
<EditableText
originalText={hour.comment || " "}
viewClassName="text-right"
/>
</div>
</div>
);
}

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { timezones } from '@/lib/timezones'; import { timezones } from "@lifetracker/shared/utils/timezones";
import TimezoneSelect, { type ITimezone } from 'react-timezone-select' import TimezoneSelect, { type ITimezone } from 'react-timezone-select'
import { useUpdateUserTimezone } from "@lifetracker/shared-react/hooks/timezones"; import { useUpdateUserTimezone } from "@lifetracker/shared-react/hooks/timezones";

View File

@ -77,6 +77,7 @@
"remark-gfm": "^4.0.0", "remark-gfm": "^4.0.0",
"request-ip": "^3.3.0", "request-ip": "^3.3.0",
"sharp": "^0.33.3", "sharp": "^0.33.3",
"spacetime": "^7.6.2",
"superjson": "^2.2.1", "superjson": "^2.2.1",
"tailwind-merge": "^2.2.1", "tailwind-merge": "^2.2.1",
"title-case": "^4.3.2", "title-case": "^4.3.2",

View File

@ -10,7 +10,7 @@ import dbConfig from "./drizzle.config";
const sqlite = new Database(dbConfig.dbCredentials.url); const sqlite = new Database(dbConfig.dbCredentials.url);
export const db = drizzle(sqlite, { export const db = drizzle(sqlite, {
schema, schema,
logger: false logger: false,
}); });
export function getInMemoryDB(runMigrations: boolean) { export function getInMemoryDB(runMigrations: boolean) {

View File

@ -4,6 +4,7 @@ export function useUpdateDay(
...opts: Parameters<typeof api.days.update.useMutation> ...opts: Parameters<typeof api.days.update.useMutation>
) { ) {
const apiUtils = api.useUtils(); const apiUtils = api.useUtils();
// console.log("UPDATING DAY");
return api.days.update.useMutation({ return api.days.update.useMutation({
...opts[0], ...opts[0],
onSuccess: (res, req, meta) => { onSuccess: (res, req, meta) => {
@ -13,30 +14,15 @@ export function useUpdateDay(
}); });
} }
export function useDeleteLabel( export function useUpdateHour(
...opts: Parameters<typeof api.labels.delete.useMutation> ...opts: Parameters<typeof api.hours.update.useMutation>
) { ) {
const apiUtils = api.useUtils(); const apiUtils = api.useUtils();
// console.log(opts[0]);
return api.labels.delete.useMutation({ return api.hours.update.useMutation({
...opts[0], ...opts[0],
onSuccess: (res, req, meta) => { onSuccess: (res, req, meta) => {
apiUtils.labels.list.invalidate(); apiUtils.days.get.invalidate({ dateQuery: req.dateQuery });
// apiUtils.bookmarks.getBookmark.invalidate();
return opts[0]?.onSuccess?.(res, req, meta);
},
});
}
export function useDeleteUnusedTags(
...opts: Parameters<typeof api.tags.deleteUnused.useMutation>
) {
const apiUtils = api.useUtils();
return api.tags.deleteUnused.useMutation({
...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.tags.list.invalidate();
return opts[0]?.onSuccess?.(res, req, meta); return opts[0]?.onSuccess?.(res, req, meta);
}, },
}); });

View File

@ -12,6 +12,7 @@ export function useUpdateUserTimezone(
} }
export function useTimezone() { export function useTimezone() {
const res = api.users.getTimezone.useQuery().data; const res = api.users.getTimezone.useQuery();
console.log("react hook useTimezone", res);
return res; return res;
} }

View File

@ -12,6 +12,8 @@ export const zHourSchema = z.object({
categoryName: z.string().nullish(), categoryName: z.string().nullish(),
categoryDesc: z.string().nullish(), categoryDesc: z.string().nullish(),
comment: z.string().nullish(), comment: z.string().nullish(),
background: z.string().nullish(),
foreground: z.string().nullish(),
}); });
export type ZHour = z.infer<typeof zHourSchema>; export type ZHour = z.infer<typeof zHourSchema>;

View File

@ -18,6 +18,7 @@
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"drizzle-orm": "^0.33.0", "drizzle-orm": "^0.33.0",
"spacetime": "^7.6.2",
"superjson": "^2.2.1", "superjson": "^2.2.1",
"tiny-invariant": "^1.3.3", "tiny-invariant": "^1.3.3",
"title-case": "^4.3.2", "title-case": "^4.3.2",

View File

@ -13,6 +13,9 @@ import { dateFromInput, hoursListInUTC } from "@lifetracker/shared/utils/days";
import { closestIndexTo, format } from "date-fns"; import { closestIndexTo, format } from "date-fns";
import { TZDate } from "@date-fns/tz"; import { TZDate } from "@date-fns/tz";
import { hoursAppRouter } from "./hours"; import { hoursAppRouter } from "./hours";
import spacetime from "spacetime";
import { getHourFromTime, getTimeFromHour } from "@lifetracker/shared/utils/hours";
import { hourColors } from "./hours";
async function createDay(date: string, ctx: Context) { async function createDay(date: string, ctx: Context) {
return await ctx.db.transaction(async (trx) => { return await ctx.db.transaction(async (trx) => {
@ -87,7 +90,9 @@ async function getDay(input: { dateQuery: string }, ctx: Context, date: string)
dayId: hours.dayId, dayId: hours.dayId,
time: hours.time, time: hours.time,
userId: hours.userId, userId: hours.userId,
date: days.date
}).from(hours) }).from(hours)
.leftJoin(days, eq(days.id, hours.dayId)) // Ensure days table is joined first
.where(and( .where(and(
eq(hours.userId, ctx.user!.id), eq(hours.userId, ctx.user!.id),
eq(hours.dayId, day.id), eq(hours.dayId, day.id),
@ -132,7 +137,7 @@ export const daysAppRouter = router({
} }
})); }));
const dayHours = await Promise.all(allHours.map(async function (map: { date, time }) { const dayHours = await Promise.all(allHours.map(async function (map: { date, time }, i) {
const dayId = allDayIds.find((dayIds: { id, date }) => map.date == dayIds.date)!.id; const dayId = allDayIds.find((dayIds: { id, date }) => map.date == dayIds.date)!.id;
const hourMatch = await ctx.db.select({ const hourMatch = await ctx.db.select({
@ -144,8 +149,10 @@ export const daysAppRouter = router({
categoryName: categories.name, categoryName: categories.name,
categoryDesc: categories.description, categoryDesc: categories.description,
comment: hours.comment, comment: hours.comment,
date: days.date
}).from(hours) }).from(hours)
.leftJoin(categories, eq(categories.id, hours.categoryId)) .leftJoin(categories, eq(categories.id, hours.categoryId))
.leftJoin(days, eq(days.id, hours.dayId))
.where(and( .where(and(
eq(hours.time, map.time), eq(hours.time, map.time),
eq(hours.dayId, dayId))); eq(hours.dayId, dayId)));
@ -155,15 +162,20 @@ export const daysAppRouter = router({
// }); // });
// console.log("Search values:: ", `allDayIds: ${allDayIds}, d: ${date}, t: ${time}, dayId: ${dayId}`) // console.log("Search values:: ", `allDayIds: ${allDayIds}, d: ${date}, t: ${time}, dayId: ${dayId}`)
// console.log("hourMatch", hourMatch[0]); // console.log("hourMatch", hourMatch[0]);
// console.log(hourMatch[0].categoryDesc);
const dayHour = { const dayHour = {
...hourMatch[0], ...hourMatch[0],
...(await hourColors(hourMatch[0], ctx)),
}; };
const localDateTime = spacetime(date, timezone).add(i, "hour");
return { return {
...dayHour, ...dayHour,
date: map.date, datetime: `${localDateTime.format('{hour} {ampm}')}`,
// datetime: `${localDateTime.format('{nice}')} ${timezone} (${localDateTime.goto("UTC").format('{nice}')} UTC)`,
}; };
})); }));

View File

@ -3,7 +3,7 @@ import { and, desc, eq, inArray, notExists } from "drizzle-orm";
import { date, z } from "zod"; import { date, z } from "zod";
import { SqliteError } from "@lifetracker/db"; import { SqliteError } from "@lifetracker/db";
import { categories, days, hours, } from "@lifetracker/db/schema"; import { categories, days, hours, colors } from "@lifetracker/db/schema";
import { import {
zDaySchema, ZDay, ZHour, zHourSchema zDaySchema, ZDay, ZHour, zHourSchema
} from "@lifetracker/shared/types/days"; } from "@lifetracker/shared/types/days";
@ -13,6 +13,32 @@ import { format } from "date-fns";
import { TZDate } from "@date-fns/tz"; import { TZDate } from "@date-fns/tz";
import { dateFromInput } from "@lifetracker/shared/utils/days"; import { dateFromInput } from "@lifetracker/shared/utils/days";
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)
))
// console.log(categoryColor);
if (!categoryColor[0]) {
return {
background: "inherit",
foreground: "inherit"
}
}
else {
return {
background: categoryColor[0].color.hexcode,
foreground: categoryColor[0].color.inverse,
}
}
}
export const hoursAppRouter = router({ export const hoursAppRouter = router({
get: authedProcedure get: authedProcedure
.input(z.object({ .input(z.object({
@ -30,6 +56,7 @@ export const hoursAppRouter = router({
categoryId: hours.categoryId, categoryId: hours.categoryId,
categoryCode: categories.code, categoryCode: categories.code,
categoryName: categories.name, categoryName: categories.name,
categoryDesc: categories.description,
comment: hours.comment, comment: hours.comment,
}) })
.from(hours) .from(hours)
@ -44,6 +71,8 @@ export const hoursAppRouter = router({
update: authedProcedure update: authedProcedure
.input( .input(
z.object({ z.object({
hourId: z.string().optional(),
dayId: z.string().optional(),
dateQuery: z.string(), dateQuery: z.string(),
time: z.number(), time: z.number(),
code: z.string().optional(), code: z.string().optional(),
@ -53,7 +82,13 @@ export const hoursAppRouter = router({
.output(zHourSchema) .output(zHourSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { dateQuery, time, code, ...updatedProps } = input; const { dateQuery, time, code, ...updatedProps } = input;
var date = dateFromInput({ dateQuery: dateQuery }); let dateCondition;
if (input.dayId) {
dateCondition = eq(days.id, input.dayId)
}
else {
dateCondition = eq(days.date, dateFromInput({ dateQuery: dateQuery }));
}
const category = const category =
code == "" ? [{ code == "" ? [{
@ -64,6 +99,7 @@ export const hoursAppRouter = router({
{ {
id: categories.id, id: categories.id,
name: categories.name, name: categories.name,
description: categories.description
} }
) )
.from(categories) .from(categories)
@ -74,14 +110,11 @@ export const hoursAppRouter = router({
) )
); );
const day = await ctx.db.select()
const day = await ctx.db.select(
{ id: days.id }
)
.from(days) .from(days)
.where( .where(
and( and(
eq(days.date, date), dateCondition,
eq(days.userId, ctx.user!.id), eq(days.userId, ctx.user!.id),
) )
); );
@ -107,8 +140,9 @@ export const hoursAppRouter = router({
.returning(); .returning();
return { return {
date: format(date, "yyyy-MM-dd"), date: format(day[0].date, "yyyy-MM-dd"),
categoryName: category[0].name, categoryName: category[0].name,
categoryDesc: category[0].description,
...hourRes[0] ...hourRes[0]
} }
}), }),

View File

@ -180,7 +180,6 @@ export const usersAppRouter = router({
) )
.query(async ({ ctx }) => { .query(async ({ ctx }) => {
const res = await ctx.db.select({ timezone: users.timezone }).from(users).where(eq(users.id, ctx.user.id)); const res = await ctx.db.select({ timezone: users.timezone }).from(users).where(eq(users.id, ctx.user.id));
return res[0].timezone; return res[0].timezone;
}), }),
changeTimezone: authedProcedure changeTimezone: authedProcedure

6
pnpm-lock.yaml generated
View File

@ -337,6 +337,9 @@ importers:
sharp: sharp:
specifier: ^0.33.3 specifier: ^0.33.3
version: 0.33.5 version: 0.33.5
spacetime:
specifier: ^7.6.2
version: 7.6.2
superjson: superjson:
specifier: ^2.2.1 specifier: ^2.2.1
version: 2.2.1 version: 2.2.1
@ -616,6 +619,9 @@ importers:
drizzle-orm: drizzle-orm:
specifier: ^0.33.0 specifier: ^0.33.0
version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7) version: 0.33.0(@types/better-sqlite3@7.6.11)(@types/react@18.2.61)(better-sqlite3@11.5.0)(expo-sqlite@14.0.6(expo@51.0.36(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)))(react@18.3.1)(sqlite3@5.1.7)
spacetime:
specifier: ^7.6.2
version: 7.6.2
superjson: superjson:
specifier: ^2.2.1 specifier: ^2.2.1
version: 2.2.1 version: 2.2.1