Basic Day functionality works in CLI and Web (getOrCreate, update Mood, Comment)
This commit is contained in:
parent
d440eb155d
commit
4af1f35687
@ -16,11 +16,13 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@date-fns/tz": "^1.2.0",
|
||||||
"@lifetracker/db": "workspace:*",
|
"@lifetracker/db": "workspace:*",
|
||||||
"@lifetracker/trpc": "workspace:^",
|
"@lifetracker/trpc": "workspace:^",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"dotenv": "^16.4.1",
|
||||||
"table": "^6.8.2",
|
"table": "^6.8.2",
|
||||||
"vite-tsconfig-paths": "^5.1.0",
|
"vite-tsconfig-paths": "^5.1.0"
|
||||||
"dotenv": "^16.4.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commander-js/extra-typings": "^12.1.0",
|
"@commander-js/extra-typings": "^12.1.0",
|
||||||
|
|||||||
61
apps/cli/src/commands/days.ts
Normal file
61
apps/cli/src/commands/days.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { getGlobalOptions } from "@/lib/globals";
|
||||||
|
import {
|
||||||
|
printError,
|
||||||
|
printErrorMessageWithReason,
|
||||||
|
printObject,
|
||||||
|
printSuccess,
|
||||||
|
} from "@/lib/output";
|
||||||
|
import { getAPIClient } from "@/lib/trpc";
|
||||||
|
import { Command } from "@commander-js/extra-typings";
|
||||||
|
import { getBorderCharacters, table } from "table";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
import { TZDate } from "@date-fns/tz";
|
||||||
|
|
||||||
|
function moodToStars(mood: number) {
|
||||||
|
// const full_stars = Math.floor(mood / 2);
|
||||||
|
// const half_star = mood % 2;
|
||||||
|
// return "★".repeat(full_stars) + (half_star ? "⯨" : "");
|
||||||
|
return "★".repeat(mood) + "☆".repeat(10 - mood);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const daysCmd = new Command()
|
||||||
|
.name("day")
|
||||||
|
.description("Get data for a specific day")
|
||||||
|
.argument('<date>', 'A date in ISO-8601 format, or "yesterday", "today", "tomorrow", etc.')
|
||||||
|
.option('-c, --comment <comment>', "edit this day's comment")
|
||||||
|
.option('-m, --mood <number>', "edit this day's mood")
|
||||||
|
.action(async (dateQuery: string, flags?) => {
|
||||||
|
const api = getAPIClient();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (flags?.comment || flags?.mood) {
|
||||||
|
const updateProps = { dateQuery: dateQuery, ...flags };
|
||||||
|
await api.days.update.mutate(updateProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
const day = (await api.days.get.query({ dateQuery: dateQuery }));
|
||||||
|
|
||||||
|
if (getGlobalOptions().json) {
|
||||||
|
printObject(day);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const moodStr = moodToStars(day.mood);
|
||||||
|
const dateStr = format(`${day.date}T00:00:00`, "EEEE, MMMM do");
|
||||||
|
const data: string[][] = [[dateStr, moodStr], [day.comment ?? "No comment", '',]];
|
||||||
|
|
||||||
|
console.log(table(data, {
|
||||||
|
// border: getBorderCharacters("ramac"),
|
||||||
|
// singleLine: true,
|
||||||
|
spanningCells: [{ col: 0, row: 1, colSpan: 2 }],
|
||||||
|
drawVerticalLine: (lineIndex, columnCount) => {
|
||||||
|
return lineIndex === 0 || lineIndex === columnCount || (lineIndex === 0 && columnCount === 2);
|
||||||
|
},
|
||||||
|
drawHorizontalLine: (lineIndex, rowCount) => {
|
||||||
|
return (lineIndex < 2 || lineIndex === rowCount);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
printErrorMessageWithReason("Failed to get day", error as object);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -4,6 +4,7 @@ import { Command, Option } from "@commander-js/extra-typings";
|
|||||||
import { whoamiCmd } from "@/commands/whoami";
|
import { whoamiCmd } from "@/commands/whoami";
|
||||||
import { colorsCmd } from "@/commands/colors";
|
import { colorsCmd } from "@/commands/colors";
|
||||||
import { categoriesCmd } from "@/commands/categories";
|
import { categoriesCmd } from "@/commands/categories";
|
||||||
|
import { daysCmd } from "@/commands/days";
|
||||||
|
|
||||||
import { config } from "dotenv";
|
import { config } from "dotenv";
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ const program = new Command()
|
|||||||
);
|
);
|
||||||
|
|
||||||
program.addCommand(whoamiCmd);
|
program.addCommand(whoamiCmd);
|
||||||
|
program.addCommand(daysCmd);
|
||||||
program.addCommand(colorsCmd);
|
program.addCommand(colorsCmd);
|
||||||
program.addCommand(categoriesCmd);
|
program.addCommand(categoriesCmd);
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import Bookmarks from "@/components/dashboard/bookmarks/Bookmarks";
|
|
||||||
|
|
||||||
export default async function BookmarksPage() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Bookmarks query={{ archived: false }} showEditorCard={true} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
32
apps/web/app/dashboard/day/[dateQuery]/page.tsx
Normal file
32
apps/web/app/dashboard/day/[dateQuery]/page.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import { api } from "@/server/api/client";
|
||||||
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import DayView from "@/components/dashboard/days/DayView";
|
||||||
|
import LoadingSpinner from "@/components/ui/spinner";
|
||||||
|
|
||||||
|
export default async function DayPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { dateQuery: string };
|
||||||
|
}) {
|
||||||
|
let day;
|
||||||
|
try {
|
||||||
|
day = await api.days.get({ dateQuery: params.dateQuery });
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof TRPCError) {
|
||||||
|
if (e.code == "NOT_FOUND") {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
params.dateQuery === undefined ?
|
||||||
|
<LoadingSpinner />
|
||||||
|
:
|
||||||
|
<DayView
|
||||||
|
day={day}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export default async function TodayPage() {
|
export default async function MainDayPage() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Hello from a logged in page!
|
Hello from a logged in page!
|
||||||
@ -4,7 +4,7 @@ import { getServerAuthSession } from "@/server/auth";
|
|||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const session = await getServerAuthSession();
|
const session = await getServerAuthSession();
|
||||||
if (session) {
|
if (session) {
|
||||||
redirect("/dashboard/today");
|
redirect("/dashboard/day/today");
|
||||||
} else {
|
} else {
|
||||||
redirect("/signin");
|
redirect("/signin");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,16 +98,14 @@ function ViewMode({
|
|||||||
return (
|
return (
|
||||||
<Tooltip delayDuration={500}>
|
<Tooltip delayDuration={500}>
|
||||||
<div className="flex max-w-full items-center gap-3">
|
<div className="flex max-w-full items-center gap-3">
|
||||||
<TooltipTrigger asChild>
|
|
||||||
{originalText ? (
|
{originalText ? (
|
||||||
<p className={viewClassName}>{originalText}</p>
|
<p className={viewClassName}>{originalText}</p>
|
||||||
) : (
|
) : (
|
||||||
<p className={untitledClassName}>Untitled</p>
|
<p className={untitledClassName}>Untitled</p>
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
delayDuration={500}
|
delayDuration={500}
|
||||||
tooltip="Edit title"
|
tooltip="Edit"
|
||||||
size="none"
|
size="none"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="align-middle text-gray-400"
|
className="align-middle text-gray-400"
|
||||||
|
|||||||
@ -1,146 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React, { useCallback, useState } from "react";
|
|
||||||
import useUpload from "@/lib/hooks/upload-file";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { TRPCClientError } from "@trpc/client";
|
|
||||||
import DropZone from "react-dropzone";
|
|
||||||
|
|
||||||
import { useCreateBookmarkWithPostHook } from "@hoarder/shared-react/hooks/bookmarks";
|
|
||||||
import { BookmarkTypes } from "@hoarder/shared/types/bookmarks";
|
|
||||||
|
|
||||||
import LoadingSpinner from "../ui/spinner";
|
|
||||||
import { toast } from "../ui/use-toast";
|
|
||||||
import BookmarkAlreadyExistsToast from "../utils/BookmarkAlreadyExistsToast";
|
|
||||||
|
|
||||||
export function useUploadAsset() {
|
|
||||||
const { mutateAsync: createBookmark } = useCreateBookmarkWithPostHook({
|
|
||||||
onSuccess: (resp) => {
|
|
||||||
if (resp.alreadyExists) {
|
|
||||||
toast({
|
|
||||||
description: <BookmarkAlreadyExistsToast bookmarkId={resp.id} />,
|
|
||||||
variant: "default",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toast({ description: "Bookmark uploaded" });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
toast({ description: "Something went wrong", variant: "destructive" });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { mutateAsync: runUploadAsset } = useUpload({
|
|
||||||
onSuccess: async (resp) => {
|
|
||||||
const assetType =
|
|
||||||
resp.contentType === "application/pdf" ? "pdf" : "image";
|
|
||||||
await createBookmark({ ...resp, type: BookmarkTypes.ASSET, assetType });
|
|
||||||
},
|
|
||||||
onError: (err, req) => {
|
|
||||||
toast({
|
|
||||||
description: `${req.name}: ${err.error}`,
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return useCallback(
|
|
||||||
(file: File) => {
|
|
||||||
return runUploadAsset(file);
|
|
||||||
},
|
|
||||||
[runUploadAsset],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function useUploadAssets({
|
|
||||||
onFileUpload,
|
|
||||||
onFileError,
|
|
||||||
onAllUploaded,
|
|
||||||
}: {
|
|
||||||
onFileUpload: () => void;
|
|
||||||
onFileError: (name: string, e: Error) => void;
|
|
||||||
onAllUploaded: () => void;
|
|
||||||
}) {
|
|
||||||
const runUpload = useUploadAsset();
|
|
||||||
|
|
||||||
return async (files: File[]) => {
|
|
||||||
if (files.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const file of files) {
|
|
||||||
try {
|
|
||||||
await runUpload(file);
|
|
||||||
onFileUpload();
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof TRPCClientError || e instanceof Error) {
|
|
||||||
onFileError(file.name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onAllUploaded();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UploadDropzone({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
const [numUploading, setNumUploading] = useState(0);
|
|
||||||
const [numUploaded, setNumUploaded] = useState(0);
|
|
||||||
const uploadAssets = useUploadAssets({
|
|
||||||
onFileUpload: () => {
|
|
||||||
setNumUploaded((c) => c + 1);
|
|
||||||
},
|
|
||||||
onFileError: () => {
|
|
||||||
setNumUploaded((c) => c + 1);
|
|
||||||
},
|
|
||||||
onAllUploaded: () => {
|
|
||||||
setNumUploading(0);
|
|
||||||
setNumUploaded(0);
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const [isDragging, setDragging] = useState(false);
|
|
||||||
const onDrop = (acceptedFiles: File[]) => {
|
|
||||||
uploadAssets(acceptedFiles);
|
|
||||||
setNumUploading(acceptedFiles.length);
|
|
||||||
setDragging(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropZone
|
|
||||||
noClick
|
|
||||||
onDrop={onDrop}
|
|
||||||
onDragEnter={() => setDragging(true)}
|
|
||||||
onDragLeave={() => setDragging(false)}
|
|
||||||
>
|
|
||||||
{({ getRootProps, getInputProps }) => (
|
|
||||||
<div {...getRootProps()}>
|
|
||||||
<input {...getInputProps()} hidden />
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"fixed inset-0 z-50 flex h-full w-full items-center justify-center bg-gray-200 opacity-90",
|
|
||||||
isDragging || numUploading > 0 ? undefined : "hidden",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{numUploading > 0 ? (
|
|
||||||
<div className="flex items-center justify-center gap-2">
|
|
||||||
<p className="text-2xl font-bold text-gray-700">
|
|
||||||
Uploading {numUploaded} / {numUploading}
|
|
||||||
</p>
|
|
||||||
<LoadingSpinner />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<p className="text-2xl font-bold text-gray-700">
|
|
||||||
Drop Your Image / Bookmark file
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</DropZone>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import UploadDropzone from "@/components/dashboard/UploadDropzone";
|
|
||||||
import { api } from "@/lib/trpc";
|
|
||||||
|
|
||||||
import type {
|
|
||||||
ZGetBookmarksRequest,
|
|
||||||
ZGetBookmarksResponse,
|
|
||||||
} from "@hoarder/shared/types/bookmarks";
|
|
||||||
import { BookmarkGridContextProvider } from "@hoarder/shared-react/hooks/bookmark-grid-context";
|
|
||||||
|
|
||||||
import BookmarksGrid from "./BookmarksGrid";
|
|
||||||
|
|
||||||
export default function UpdatableBookmarksGrid({
|
|
||||||
query,
|
|
||||||
bookmarks: initialBookmarks,
|
|
||||||
showEditorCard = false,
|
|
||||||
}: {
|
|
||||||
query: ZGetBookmarksRequest;
|
|
||||||
bookmarks: ZGetBookmarksResponse;
|
|
||||||
showEditorCard?: boolean;
|
|
||||||
itemsPerPage?: number;
|
|
||||||
}) {
|
|
||||||
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
|
||||||
api.bookmarks.getBookmarks.useInfiniteQuery(
|
|
||||||
{ ...query, useCursorV2: true },
|
|
||||||
{
|
|
||||||
initialData: () => ({
|
|
||||||
pages: [initialBookmarks],
|
|
||||||
pageParams: [query.cursor],
|
|
||||||
}),
|
|
||||||
initialCursor: null,
|
|
||||||
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const grid = (
|
|
||||||
<BookmarksGrid
|
|
||||||
bookmarks={data!.pages.flatMap((b) => b.bookmarks)}
|
|
||||||
hasNextPage={hasNextPage}
|
|
||||||
fetchNextPage={() => fetchNextPage()}
|
|
||||||
isFetchingNextPage={isFetchingNextPage}
|
|
||||||
showEditorCard={showEditorCard}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BookmarkGridContextProvider query={query}>
|
|
||||||
{showEditorCard ? <UploadDropzone>{grid}</UploadDropzone> : grid}
|
|
||||||
</BookmarkGridContextProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
45
apps/web/components/dashboard/days/DayView.tsx
Normal file
45
apps/web/components/dashboard/days/DayView.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { api } from "@/server/api/client";
|
||||||
|
import { getServerAuthSession } from "@/server/auth";
|
||||||
|
import { ZDay } from "@lifetracker/shared/types/days";
|
||||||
|
import EditableDayComment from "./EditableDayComment";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
|
||||||
|
export default async function DayView({
|
||||||
|
day,
|
||||||
|
header,
|
||||||
|
showDivider,
|
||||||
|
showEditorCard = false,
|
||||||
|
}: {
|
||||||
|
day: ZDay;
|
||||||
|
header?: React.ReactNode;
|
||||||
|
showDivider?: boolean;
|
||||||
|
showEditorCard?: boolean;
|
||||||
|
}) {
|
||||||
|
const session = await getServerAuthSession();
|
||||||
|
if (!session) {
|
||||||
|
redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
// const entries = await api.entries.get({ day: day });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-2xl">
|
||||||
|
{format(`${day.date}T00:00:00`, "EEEE, MMMM do")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
<div>Rating: {day.mood?.toString() ?? "-"}</div>
|
||||||
|
|
||||||
|
<EditableDayComment day={day}
|
||||||
|
className="text-xl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
56
apps/web/components/dashboard/days/EditableDayComment.tsx
Normal file
56
apps/web/components/dashboard/days/EditableDayComment.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
|
import { toast } from "@/components/ui/use-toast";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
import { useUpdateDay } from "@lifetracker/shared-react/hooks/days";
|
||||||
|
import { EditableText } from "../EditableText";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
|
||||||
|
export default function EditableDayComment({
|
||||||
|
day,
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
day: { id: string; date: string, comment: string };
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const currentPath = usePathname();
|
||||||
|
const { mutate: updateDay, isPending } = useUpdateDay({
|
||||||
|
onSuccess: () => {
|
||||||
|
toast({
|
||||||
|
description: "Day updated!",
|
||||||
|
});
|
||||||
|
if (currentPath.includes("dashboard")) {
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<EditableText
|
||||||
|
viewClassName={className}
|
||||||
|
editClassName={cn("p-2", className)}
|
||||||
|
originalText={day.comment ?? "No Comment"}
|
||||||
|
onSave={(newComment) => {
|
||||||
|
if (!newComment) { return }
|
||||||
|
updateDay(
|
||||||
|
{
|
||||||
|
dateQuery: format(`${day.date}T00:00:00`, "yyyy-MM-dd"),
|
||||||
|
comment: newComment,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onError: (e) => {
|
||||||
|
console.log(e);
|
||||||
|
toast({
|
||||||
|
description: e.message,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
isSaving={isPending}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -49,6 +49,7 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"color-2-name": "^1.4.4",
|
"color-2-name": "^1.4.4",
|
||||||
"csv-parse": "^5.5.6",
|
"csv-parse": "^5.5.6",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"drizzle-orm": "^0.33.0",
|
"drizzle-orm": "^0.33.0",
|
||||||
"fastest-levenshtein": "^1.0.16",
|
"fastest-levenshtein": "^1.0.16",
|
||||||
|
|||||||
@ -7,12 +7,10 @@ import path from "path";
|
|||||||
|
|
||||||
import dbConfig from "./drizzle.config";
|
import dbConfig from "./drizzle.config";
|
||||||
|
|
||||||
console.log("dbURL: ", dbConfig.dbCredentials.url);
|
|
||||||
|
|
||||||
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: true
|
logger: false
|
||||||
});
|
});
|
||||||
|
|
||||||
export function getInMemoryDB(runMigrations: boolean) {
|
export function getInMemoryDB(runMigrations: boolean) {
|
||||||
|
|||||||
@ -54,10 +54,23 @@ CREATE TABLE `config` (
|
|||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE `day` (
|
CREATE TABLE `day` (
|
||||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
`mood` integer,
|
|
||||||
`date` text NOT NULL,
|
`date` text NOT NULL,
|
||||||
`comment` text NOT NULL
|
`mood` integer,
|
||||||
|
`comment` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `entry` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`createdAt` integer NOT NULL,
|
||||||
|
`userId` text NOT NULL,
|
||||||
|
`comment` text,
|
||||||
|
`dayId` integer,
|
||||||
|
`startedAt` integer NOT NULL,
|
||||||
|
`endedAt` integer NOT NULL,
|
||||||
|
`categoryId` text NOT NULL,
|
||||||
|
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||||
|
FOREIGN KEY (`categoryId`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE `session` (
|
CREATE TABLE `session` (
|
||||||
@ -89,4 +102,5 @@ CREATE UNIQUE INDEX `apiKey_name_userId_unique` ON `apiKey` (`name`,`userId`);--
|
|||||||
CREATE UNIQUE INDEX `category_userId_code_unique` ON `category` (`userId`,`code`);--> statement-breakpoint
|
CREATE UNIQUE INDEX `category_userId_code_unique` ON `category` (`userId`,`code`);--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX `color_userId_name_unique` ON `color` (`userId`,`name`);--> statement-breakpoint
|
CREATE UNIQUE INDEX `color_userId_name_unique` ON `color` (`userId`,`name`);--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX `day_date_unique` ON `day` (`date`);--> statement-breakpoint
|
CREATE UNIQUE INDEX `day_date_unique` ON `day` (`date`);--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `entry_userId_startedAt_endedAt_unique` ON `entry` (`userId`,`startedAt`,`endedAt`);--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);
|
CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "7f1d6157-2405-4b96-be6a-a4bfb35f9aaf",
|
"id": "ceed45ad-37d0-4e59-92bd-3be02d271535",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"tables": {
|
"tables": {
|
||||||
"account": {
|
"account": {
|
||||||
@ -409,16 +409,9 @@
|
|||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "integer",
|
"type": "text",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": true
|
|
||||||
},
|
|
||||||
"mood": {
|
|
||||||
"name": "mood",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
@ -428,11 +421,18 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"mood": {
|
||||||
|
"name": "mood",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"name": "comment",
|
"name": "comment",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": false,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -449,6 +449,108 @@
|
|||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
|
"entry": {
|
||||||
|
"name": "entry",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"name": "userId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"name": "comment",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"dayId": {
|
||||||
|
"name": "dayId",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"startedAt": {
|
||||||
|
"name": "startedAt",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"endedAt": {
|
||||||
|
"name": "endedAt",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"categoryId": {
|
||||||
|
"name": "categoryId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"entry_userId_startedAt_endedAt_unique": {
|
||||||
|
"name": "entry_userId_startedAt_endedAt_unique",
|
||||||
|
"columns": [
|
||||||
|
"userId",
|
||||||
|
"startedAt",
|
||||||
|
"endedAt"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"entry_userId_user_id_fk": {
|
||||||
|
"name": "entry_userId_user_id_fk",
|
||||||
|
"tableFrom": "entry",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"entry_categoryId_category_id_fk": {
|
||||||
|
"name": "entry_categoryId_category_id_fk",
|
||||||
|
"tableFrom": "entry",
|
||||||
|
"tableTo": "category",
|
||||||
|
"columnsFrom": [
|
||||||
|
"categoryId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
"session": {
|
"session": {
|
||||||
"name": "session",
|
"name": "session",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1732441653703,
|
"when": 1732544381615,
|
||||||
"tag": "0000_awesome_stepford_cuckoos",
|
"tag": "0000_powerful_zodiak",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { AdapterAccount } from "@auth/core/adapters";
|
import type { AdapterAccount } from "@auth/core/adapters";
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
import { relations, SQL, sql } from "drizzle-orm";
|
import { relations, SQL, sql } from "drizzle-orm";
|
||||||
|
import { date } from "drizzle-orm/mysql-core";
|
||||||
import {
|
import {
|
||||||
AnySQLiteColumn,
|
AnySQLiteColumn,
|
||||||
index,
|
index,
|
||||||
@ -122,10 +123,13 @@ export const verificationTokens = sqliteTable(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const days = sqliteTable("day", {
|
export const days = sqliteTable("day", {
|
||||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
id: text("id")
|
||||||
mood: integer("mood"),
|
.notNull()
|
||||||
|
.primaryKey()
|
||||||
|
.$defaultFn(() => createId()),
|
||||||
date: text("date").notNull().unique(),
|
date: text("date").notNull().unique(),
|
||||||
comment: text("comment").notNull(),
|
mood: integer("mood"),
|
||||||
|
comment: text("comment"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const colors = sqliteTable(
|
export const colors = sqliteTable(
|
||||||
@ -175,6 +179,28 @@ export const categories = sqliteTable(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const entries = sqliteTable(
|
||||||
|
"entry",
|
||||||
|
{
|
||||||
|
id: text("id")
|
||||||
|
.notNull()
|
||||||
|
.primaryKey()
|
||||||
|
.$defaultFn(() => createId()),
|
||||||
|
createdAt: createdAtField(),
|
||||||
|
userId: text("userId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
|
comment: text("comment"),
|
||||||
|
dayId: integer("dayId"),
|
||||||
|
startedAt: integer("startedAt", { mode: "timestamp" }).notNull(),
|
||||||
|
endedAt: integer("endedAt", { mode: "timestamp" }).notNull(),
|
||||||
|
categoryId: text("categoryId").notNull().references(() => categories.id),
|
||||||
|
},
|
||||||
|
(e) => ({
|
||||||
|
uniq: unique().on(e.userId, e.startedAt, e.endedAt)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|
||||||
export const apiKeyRelations = relations(apiKeys, ({ one }) => ({
|
export const apiKeyRelations = relations(apiKeys, ({ one }) => ({
|
||||||
@ -186,9 +212,21 @@ export const apiKeyRelations = relations(apiKeys, ({ one }) => ({
|
|||||||
export const userRelations = relations(users, ({ many }) => ({
|
export const userRelations = relations(users, ({ many }) => ({
|
||||||
categories: many(categories),
|
categories: many(categories),
|
||||||
colors: many(colors),
|
colors: many(colors),
|
||||||
|
entries: many(entries),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
export const colorsRelations = relations(
|
||||||
|
colors,
|
||||||
|
({ many, one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [colors.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
categories: many(categories),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const categoriesRelations = relations(
|
export const categoriesRelations = relations(
|
||||||
categories,
|
categories,
|
||||||
({ many, one }) => ({
|
({ many, one }) => ({
|
||||||
@ -204,16 +242,32 @@ export const categoriesRelations = relations(
|
|||||||
fields: [categories.parentId],
|
fields: [categories.parentId],
|
||||||
references: [categories.id],
|
references: [categories.id],
|
||||||
}),
|
}),
|
||||||
|
entries: many(entries),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const colorsRelations = relations(
|
export const daysRelations = relations(
|
||||||
colors,
|
days,
|
||||||
({ many, one }) => ({
|
({ many }) => ({
|
||||||
user: one(users, {
|
entries: many(entries),
|
||||||
fields: [colors.userId],
|
}),
|
||||||
references: [users.id],
|
);
|
||||||
}),
|
|
||||||
categories: many(categories),
|
export const entriesRelations = relations(
|
||||||
|
entries,
|
||||||
|
({ many, one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [entries.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
categories: one(categories, {
|
||||||
|
fields: [entries.categoryId],
|
||||||
|
references: [categories.id],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
day: one(days, {
|
||||||
|
fields: [entries.dayId],
|
||||||
|
references: [days.id],
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
43
packages/shared-react/hooks/days.ts
Normal file
43
packages/shared-react/hooks/days.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { api } from "../trpc";
|
||||||
|
|
||||||
|
export function useUpdateDay(
|
||||||
|
...opts: Parameters<typeof api.days.update.useMutation>
|
||||||
|
) {
|
||||||
|
const apiUtils = api.useUtils();
|
||||||
|
return api.days.update.useMutation({
|
||||||
|
...opts[0],
|
||||||
|
onSuccess: (res, req, meta) => {
|
||||||
|
apiUtils.days.get.invalidate({ dateQuery: req.dateQuery });
|
||||||
|
return opts[0]?.onSuccess?.(res, req, meta);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDeleteLabel(
|
||||||
|
...opts: Parameters<typeof api.labels.delete.useMutation>
|
||||||
|
) {
|
||||||
|
const apiUtils = api.useUtils();
|
||||||
|
|
||||||
|
return api.labels.delete.useMutation({
|
||||||
|
...opts[0],
|
||||||
|
onSuccess: (res, req, meta) => {
|
||||||
|
apiUtils.labels.list.invalidate();
|
||||||
|
// 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);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
"@lifetracker/trpc": "workspace:^",
|
"@lifetracker/trpc": "workspace:^",
|
||||||
"@tanstack/react-query": "^5.24.8",
|
"@tanstack/react-query": "^5.24.8",
|
||||||
"@trpc/client": "11.0.0-next-beta.308",
|
"@trpc/client": "11.0.0-next-beta.308",
|
||||||
|
"@trpc/react-query": "11.0.0-next-beta.308",
|
||||||
"superjson": "^2.2.1"
|
"superjson": "^2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
9
packages/shared/types/days.ts
Normal file
9
packages/shared/types/days.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const zDaySchema = z.object({
|
||||||
|
id: z.string().optional(),
|
||||||
|
date: z.string(),
|
||||||
|
mood: z.number().nullable(),
|
||||||
|
comment: z.string().nullable(),
|
||||||
|
});
|
||||||
|
export type ZDay = z.infer<typeof zDaySchema>;
|
||||||
@ -56,19 +56,6 @@ function parseApiKey(plain: string) {
|
|||||||
export async function authenticateApiKey(key: string) {
|
export async function authenticateApiKey(key: string) {
|
||||||
|
|
||||||
const { keyId, keySecret } = parseApiKey(key);
|
const { keyId, keySecret } = parseApiKey(key);
|
||||||
|
|
||||||
console.log("\n\nWELCOME TO HELL\n\n");
|
|
||||||
console.log(parseApiKey(key));
|
|
||||||
// Console.log all rows in the apiKeys table
|
|
||||||
console.log(await db.query.apiKeys.findMany());
|
|
||||||
console.log(await db.query.apiKeys.findFirst({
|
|
||||||
where: (k, { eq }) => eq(k.keyId, keyId),
|
|
||||||
with: {
|
|
||||||
user: true,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
console.log("\n\n\n\n");
|
|
||||||
|
|
||||||
const apiKey = await db.query.apiKeys.findFirst({
|
const apiKey = await db.query.apiKeys.findFirst({
|
||||||
where: (k, { eq }) => eq(k.keyId, keyId),
|
where: (k, { eq }) => eq(k.keyId, keyId),
|
||||||
with: {
|
with: {
|
||||||
|
|||||||
@ -10,11 +10,13 @@
|
|||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@date-fns/tz": "^1.2.0",
|
||||||
"@lifetracker/db": "workspace:*",
|
"@lifetracker/db": "workspace:*",
|
||||||
"@lifetracker/shared": "workspace:^",
|
"@lifetracker/shared": "workspace:^",
|
||||||
"@lifetracker/ui": "workspace:*",
|
"@lifetracker/ui": "workspace:*",
|
||||||
"@trpc/server": "^11.0.0-next-beta.308",
|
"@trpc/server": "^11.0.0-next-beta.308",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"drizzle-orm": "^0.33.0",
|
"drizzle-orm": "^0.33.0",
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
"tiny-invariant": "^1.3.3",
|
"tiny-invariant": "^1.3.3",
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import { apiKeysAppRouter } from "./apiKeys";
|
|||||||
import { adminAppRouter } from "./admin";
|
import { adminAppRouter } from "./admin";
|
||||||
import { categoriesAppRouter } from "./categories";
|
import { categoriesAppRouter } from "./categories";
|
||||||
import { colorsAppRouter } from "./colors";
|
import { colorsAppRouter } from "./colors";
|
||||||
|
import { daysAppRouter } from "./days";
|
||||||
|
|
||||||
export const appRouter = router({
|
export const appRouter = router({
|
||||||
users: usersAppRouter,
|
users: usersAppRouter,
|
||||||
apiKeys: apiKeysAppRouter,
|
apiKeys: apiKeysAppRouter,
|
||||||
admin: adminAppRouter,
|
admin: adminAppRouter,
|
||||||
|
days: daysAppRouter,
|
||||||
colors: colorsAppRouter,
|
colors: colorsAppRouter,
|
||||||
categories: categoriesAppRouter,
|
categories: categoriesAppRouter,
|
||||||
});
|
});
|
||||||
|
|||||||
105
packages/trpc/routers/days.ts
Normal file
105
packages/trpc/routers/days.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
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 { days, } from "@lifetracker/db/schema";
|
||||||
|
import {
|
||||||
|
zDaySchema, ZDay
|
||||||
|
} 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";
|
||||||
|
|
||||||
|
function dateFromInput(input: { dateQuery: string }) {
|
||||||
|
let t: string;
|
||||||
|
console.log(input.dateQuery);
|
||||||
|
if (input.dateQuery == "today") {
|
||||||
|
t = TZDate.tz("America/Los_Angeles");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t = new TZDate(input.dateQuery, "Etc/UTC");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(format(t, "yyyy-MM-dd"));
|
||||||
|
return format(t, "yyyy-MM-dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createDay(date: string, ctx: Context) {
|
||||||
|
return await ctx.db.transaction(async (trx) => {
|
||||||
|
try {
|
||||||
|
const result = await trx
|
||||||
|
.insert(days)
|
||||||
|
.values({
|
||||||
|
date: date,
|
||||||
|
})
|
||||||
|
.returning({
|
||||||
|
id: days.id,
|
||||||
|
date: days.date,
|
||||||
|
mood: days.mood,
|
||||||
|
comment: days.comment,
|
||||||
|
});
|
||||||
|
return result[0];
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
const res = await ctx.db
|
||||||
|
.select({
|
||||||
|
id: days.id,
|
||||||
|
date: days.date,
|
||||||
|
mood: days.mood,
|
||||||
|
comment: days.comment,
|
||||||
|
})
|
||||||
|
.from(days)
|
||||||
|
.where(eq(days.date, date));
|
||||||
|
|
||||||
|
const day = res.length == 0 ? createDay(date, ctx) : res[0];
|
||||||
|
return day;
|
||||||
|
}),
|
||||||
|
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 })));
|
||||||
|
}),
|
||||||
|
});
|
||||||
28
pnpm-lock.yaml
generated
28
pnpm-lock.yaml
generated
@ -20,12 +20,18 @@ importers:
|
|||||||
|
|
||||||
apps/cli:
|
apps/cli:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@date-fns/tz':
|
||||||
|
specifier: ^1.2.0
|
||||||
|
version: 1.2.0
|
||||||
'@lifetracker/db':
|
'@lifetracker/db':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/db
|
version: link:../../packages/db
|
||||||
'@lifetracker/trpc':
|
'@lifetracker/trpc':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../../packages/trpc
|
version: link:../../packages/trpc
|
||||||
|
date-fns:
|
||||||
|
specifier: ^4.1.0
|
||||||
|
version: 4.1.0
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.1
|
specifier: ^16.4.1
|
||||||
version: 16.4.5
|
version: 16.4.5
|
||||||
@ -235,6 +241,9 @@ importers:
|
|||||||
csv-parse:
|
csv-parse:
|
||||||
specifier: ^5.5.6
|
specifier: ^5.5.6
|
||||||
version: 5.5.6
|
version: 5.5.6
|
||||||
|
date-fns:
|
||||||
|
specifier: ^4.1.0
|
||||||
|
version: 4.1.0
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.10
|
specifier: ^1.11.10
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
@ -482,6 +491,9 @@ importers:
|
|||||||
'@trpc/client':
|
'@trpc/client':
|
||||||
specifier: 11.0.0-next-beta.308
|
specifier: 11.0.0-next-beta.308
|
||||||
version: 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308)
|
version: 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308)
|
||||||
|
'@trpc/react-query':
|
||||||
|
specifier: 11.0.0-next-beta.308
|
||||||
|
version: 11.0.0-next-beta.308(@tanstack/react-query@5.60.2(react@18.3.1))(@trpc/client@11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308))(@trpc/server@11.0.0-next-beta.308)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
react:
|
react:
|
||||||
specifier: '*'
|
specifier: '*'
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@ -544,6 +556,9 @@ importers:
|
|||||||
|
|
||||||
packages/trpc:
|
packages/trpc:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@date-fns/tz':
|
||||||
|
specifier: ^1.2.0
|
||||||
|
version: 1.2.0
|
||||||
'@lifetracker/db':
|
'@lifetracker/db':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../db
|
version: link:../db
|
||||||
@ -559,6 +574,9 @@ importers:
|
|||||||
bcryptjs:
|
bcryptjs:
|
||||||
specifier: ^2.4.3
|
specifier: ^2.4.3
|
||||||
version: 2.4.3
|
version: 2.4.3
|
||||||
|
date-fns:
|
||||||
|
specifier: ^4.1.0
|
||||||
|
version: 4.1.0
|
||||||
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))))(react@18.3.1)
|
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))))(react@18.3.1)
|
||||||
@ -1896,6 +1914,9 @@ packages:
|
|||||||
'@dabh/diagnostics@2.0.3':
|
'@dabh/diagnostics@2.0.3':
|
||||||
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||||
|
|
||||||
|
'@date-fns/tz@1.2.0':
|
||||||
|
resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==}
|
||||||
|
|
||||||
'@discoveryjs/json-ext@0.5.7':
|
'@discoveryjs/json-ext@0.5.7':
|
||||||
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@ -5683,6 +5704,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
|
resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
date-fns@4.1.0:
|
||||||
|
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||||
|
|
||||||
dayjs@1.11.13:
|
dayjs@1.11.13:
|
||||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
|
||||||
@ -14179,6 +14203,8 @@ snapshots:
|
|||||||
enabled: 2.0.0
|
enabled: 2.0.0
|
||||||
kuler: 2.0.0
|
kuler: 2.0.0
|
||||||
|
|
||||||
|
'@date-fns/tz@1.2.0': {}
|
||||||
|
|
||||||
'@discoveryjs/json-ext@0.5.7': {}
|
'@discoveryjs/json-ext@0.5.7': {}
|
||||||
|
|
||||||
'@docsearch/css@3.6.2': {}
|
'@docsearch/css@3.6.2': {}
|
||||||
@ -19106,6 +19132,8 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-data-view: 1.0.1
|
is-data-view: 1.0.1
|
||||||
|
|
||||||
|
date-fns@4.1.0: {}
|
||||||
|
|
||||||
dayjs@1.11.13: {}
|
dayjs@1.11.13: {}
|
||||||
|
|
||||||
debounce@1.2.1: {}
|
debounce@1.2.1: {}
|
||||||
|
|||||||
10
scripts/apiKey.json
Normal file
10
scripts/apiKey.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"createdAt": 1731634820,
|
||||||
|
"id": "wxl62dg2n721tgzlz3spnjbu",
|
||||||
|
"keyHash": "$2a$10$NhOG42FjMbDycWHcJI4LH.Jp.aCV.op7llIP0zw/CBUmB3lO0HHQu",
|
||||||
|
"keyId": "b9b17eb909ce0ecdbf33",
|
||||||
|
"name": "CLI App",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
}
|
||||||
|
]
|
||||||
792
scripts/category.json
Normal file
792
scripts/category.json
Normal file
@ -0,0 +1,792 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"code": 0.0,
|
||||||
|
"colorId": "ej29qv1e7l1dnfxajl0561dt",
|
||||||
|
"createdAt": 1732442037,
|
||||||
|
"description": "Time spent sleeping.",
|
||||||
|
"id": "pjb9vypaflgdcl3w9cn59bfy",
|
||||||
|
"name": "Sleep",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 0.4,
|
||||||
|
"colorId": "ej29qv1e7l1dnfxajl0561dt",
|
||||||
|
"createdAt": 1732442768,
|
||||||
|
"description": "Typically shitty half-sleep on a plane or in a car.",
|
||||||
|
"id": "iazlvs3xxaml3viytgcisvbl",
|
||||||
|
"name": "Travel sleep",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 0.5,
|
||||||
|
"colorId": "ej29qv1e7l1dnfxajl0561dt",
|
||||||
|
"createdAt": 1732443778,
|
||||||
|
"description": "Sleep other than at night.",
|
||||||
|
"id": "orqt6lk4jyy0578e9vt3jn37",
|
||||||
|
"name": "Nap",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 0.9,
|
||||||
|
"colorId": "ej29qv1e7l1dnfxajl0561dt",
|
||||||
|
"createdAt": 1732443779,
|
||||||
|
"description": "Resting while sick or injured.",
|
||||||
|
"id": "qtfjtrpbbz7adlyd2ynn4tq6",
|
||||||
|
"name": "Sick",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 1.0,
|
||||||
|
"colorId": "ahapbp9ujym8lgf4ny02i26h",
|
||||||
|
"createdAt": 1732444271,
|
||||||
|
"description": "Time spent with family.",
|
||||||
|
"id": "iwja5v39r48weawdp5rmomb1",
|
||||||
|
"name": "Family",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 13.0,
|
||||||
|
"colorId": "ahapbp9ujym8lgf4ny02i26h",
|
||||||
|
"createdAt": 1732444273,
|
||||||
|
"description": "Wedding and related stuff.",
|
||||||
|
"id": "vwihwohm09c1zsoh6rnddw0m",
|
||||||
|
"name": "Wedding, etc.",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 15.0,
|
||||||
|
"colorId": "ahapbp9ujym8lgf4ny02i26h",
|
||||||
|
"createdAt": 1732444274,
|
||||||
|
"description": "Local family, if you will.",
|
||||||
|
"id": "ontipjpabhqx5wlocjab0xpd",
|
||||||
|
"name": "Neighborhood / Community",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 16.0,
|
||||||
|
"colorId": "ahapbp9ujym8lgf4ny02i26h",
|
||||||
|
"createdAt": 1732444275,
|
||||||
|
"description": "TV, movies, or the like, watched with family.",
|
||||||
|
"id": "e4hbzc6f3t43gfrbfj25m7ve",
|
||||||
|
"name": "Watching something",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 2.0,
|
||||||
|
"colorId": "wseq6pmjce562ds089pduv24",
|
||||||
|
"createdAt": 1732444277,
|
||||||
|
"description": "Time spent with friends.",
|
||||||
|
"id": "gozno3fockquztot23l7u62w",
|
||||||
|
"name": "Friends",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 22.0,
|
||||||
|
"colorId": "wseq6pmjce562ds089pduv24",
|
||||||
|
"createdAt": 1732444278,
|
||||||
|
"description": "Party with friends.",
|
||||||
|
"id": "on371jnjjof728m72hvmvvq5",
|
||||||
|
"name": "Party",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 26.0,
|
||||||
|
"colorId": "wseq6pmjce562ds089pduv24",
|
||||||
|
"createdAt": 1732444280,
|
||||||
|
"description": "Playing active games or sports with friends.",
|
||||||
|
"id": "uy1mexnou9phcm9usxujqcu6",
|
||||||
|
"name": "Active / Sports",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 28.0,
|
||||||
|
"colorId": "wseq6pmjce562ds089pduv24",
|
||||||
|
"createdAt": 1732444281,
|
||||||
|
"description": "Preparing or eating a meal with friends.",
|
||||||
|
"id": "mqamdgvll8fhpeh04iaahgt1",
|
||||||
|
"name": "Meal",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 29.0,
|
||||||
|
"colorId": "wseq6pmjce562ds089pduv24",
|
||||||
|
"createdAt": 1732444283,
|
||||||
|
"description": "Drugs with friends.",
|
||||||
|
"id": "jn5uzh2j2n4yj8faf1hq1m1h",
|
||||||
|
"name": "Drugs",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 3.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444284,
|
||||||
|
"description": "Time spent on dates or primarily with/for Jen.",
|
||||||
|
"id": "na3g6sz33dxgxd2p27pep4d8",
|
||||||
|
"name": "Jen",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 31.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444286,
|
||||||
|
"description": "Time spent with Jen's family.",
|
||||||
|
"id": "pw0ev83xwb7egvkjkwatjy0k",
|
||||||
|
"name": "Jen's family",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 32.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444287,
|
||||||
|
"description": "Time with primarily Jen's friends.",
|
||||||
|
"id": "aybqbkj4oigocfhtgf9xiziu",
|
||||||
|
"name": "Jen's friends",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 33.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444289,
|
||||||
|
"description": "Sex or sex-related activities.",
|
||||||
|
"id": "ocicgnndcpb2brdhi9hzj3jk",
|
||||||
|
"name": "Sex",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 34.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444290,
|
||||||
|
"description": "Exploring and adventuring, with a more urban (non-nature) focus.",
|
||||||
|
"id": "z07iadfzm0gdnuexeybl78tj",
|
||||||
|
"name": "Exploring",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 35.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444291,
|
||||||
|
"description": "When shit needs to get done, for me and Jen.",
|
||||||
|
"id": "ufdq763hkkv1a6fjjstsmkpg",
|
||||||
|
"name": "Errands & Logistics",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 36.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444293,
|
||||||
|
"description": "Watching a movie, TV show, or Internet stuff with Jen.",
|
||||||
|
"id": "pnqrj2ksxd86g2kv3pwfokjj",
|
||||||
|
"name": "Watching something",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 37.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444295,
|
||||||
|
"description": "Hiking, camping, and backcountry adventures with an active focus.",
|
||||||
|
"id": "pravf1muoqxvpg7pr590t882",
|
||||||
|
"name": "Hiking / Adventuring",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 38.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444296,
|
||||||
|
"description": "Cooking, eating out, or just having a meal with my love.",
|
||||||
|
"id": "uoaghsua2r5qtp6ef0nwil01",
|
||||||
|
"name": "Meal with Jen",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 39.0,
|
||||||
|
"colorId": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"createdAt": 1732444297,
|
||||||
|
"description": "Rest and cuddles, other than primarily for sleep or sex.",
|
||||||
|
"id": "nb70nsg3e3ch27t1o3ke24av",
|
||||||
|
"name": "Relaxing / Napping",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 4.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444299,
|
||||||
|
"description": "Anything related to private flying.",
|
||||||
|
"id": "k5pxee2j5qr80fa844x28xyk",
|
||||||
|
"name": "Flying",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 41.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444300,
|
||||||
|
"description": "Dealing with FBOs, getting in or out of the plane, etc.",
|
||||||
|
"id": "qcg39xfln3r1a2ae9d1h6iyu",
|
||||||
|
"name": "Airports, etc.",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 42.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444302,
|
||||||
|
"description": "Tour or flight for fun with friends.",
|
||||||
|
"id": "gendguvt1pbmc9ybgrhrr8sa",
|
||||||
|
"name": "Flying with friends",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 43.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444303,
|
||||||
|
"description": "A flying trip primarily for me and Jen.",
|
||||||
|
"id": "lo5fsd43de6rkf3fia3xsjmu",
|
||||||
|
"name": "Flying with Jen",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 44.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444305,
|
||||||
|
"description": "Checking weather, planning, filing flight plan, etc.",
|
||||||
|
"id": "jepjh7y5y49c8f8araawnyzr",
|
||||||
|
"name": "Flight planning",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 45.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444306,
|
||||||
|
"description": "A primarily business-oriented flying trip.",
|
||||||
|
"id": "wm210bl3mdfxzwimxk0hrxj3",
|
||||||
|
"name": "Flying for work",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 46.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444307,
|
||||||
|
"description": "A primarily maintenance-related flying trip.",
|
||||||
|
"id": "dhjwzwur71t7y4nvil2f97l6",
|
||||||
|
"name": "Maintenance",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 47.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444309,
|
||||||
|
"description": "A primarily training-related flying trip.",
|
||||||
|
"id": "gmdiu72n8q9u5nc8273ej76c",
|
||||||
|
"name": "Training",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 49.0,
|
||||||
|
"colorId": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"createdAt": 1732444310,
|
||||||
|
"description": "e.g., Phone calls, research, buying/selling",
|
||||||
|
"id": "lm2xe9ouzo07ewlfpiu3xl74",
|
||||||
|
"name": "Other Flying Related",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 5.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444312,
|
||||||
|
"description": "Time spent working for money.",
|
||||||
|
"id": "bwnzw4g3dm1qns7cw0h1gwt1",
|
||||||
|
"name": "Work",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 51.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444313,
|
||||||
|
"description": "Pitching, diligence, calls, or somehow convincing investors to pony up.",
|
||||||
|
"id": "k3eofqjexruoklmqys5pndq9",
|
||||||
|
"name": "Investors",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 52.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444315,
|
||||||
|
"description": "Meeting with one or more of Perumal, Bonney, TM.",
|
||||||
|
"id": "veb5xubue47hqhebyzt3jlaa",
|
||||||
|
"name": "Cofounders",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 53.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444316,
|
||||||
|
"description": "This was set up because I was working so hard on the wedding in 2023 I thought I was going to die, but it really doesn't have much use being in the 5s.",
|
||||||
|
"id": "saun6t9fo6js9vfg0jta6mcd",
|
||||||
|
"name": "[REMAP ME] Wedding prep",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 55.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444318,
|
||||||
|
"description": "Dealing with Board members or Board matters.",
|
||||||
|
"id": "lyad7iipkvwefn9xdd2mn48e",
|
||||||
|
"name": "Board",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 56.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444319,
|
||||||
|
"description": "Getting the inbox under control.",
|
||||||
|
"id": "zm2zwf7h29qz6py1i2fo225z",
|
||||||
|
"name": "Emails",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 57.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444321,
|
||||||
|
"description": "Thinking, ruminating, or journaling about work.",
|
||||||
|
"id": "gfxtjd5sae6d8i0y7rsmv3gv",
|
||||||
|
"name": "Work meditation",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 58.0,
|
||||||
|
"colorId": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"createdAt": 1732444322,
|
||||||
|
"description": "Out building work-related relationships.",
|
||||||
|
"id": "gsbbgkm2um4vg30rs4dsmhlb",
|
||||||
|
"name": "Socializing",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444323,
|
||||||
|
"description": "Time spent active (working out), fulfilling obligations, running errands, doing work without pay, or otherwise in a useful and productive way.",
|
||||||
|
"id": "gjfckt52lo0j5ucagp6r5ykp",
|
||||||
|
"name": "Productive",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 61.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444325,
|
||||||
|
"description": "Tidying, organizing, or cleaning a space.",
|
||||||
|
"id": "cdk4v2mcer9cvtmsd51pwfc6",
|
||||||
|
"name": "Cleaning",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 62.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444327,
|
||||||
|
"description": "Having important conversations or working on the big stuff.",
|
||||||
|
"id": "sn705vdodh4uy4lwxtua656o",
|
||||||
|
"name": "Relationship work",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 63.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444329,
|
||||||
|
"description": "Productivity related to the home or household.",
|
||||||
|
"id": "zgxrgvqzy27kjdm3eoq2842b",
|
||||||
|
"name": "Home maintenance",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 65.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444330,
|
||||||
|
"description": "Chores related to life administration and personal finances.",
|
||||||
|
"id": "l22sh0he7xj2rdlgb55l2iag",
|
||||||
|
"name": "Personal finances / Life admin",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 66.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444332,
|
||||||
|
"description": "Walking, running, biking, or hiking outdoors.",
|
||||||
|
"id": "em9t97vltn1sdikap2okjiw6",
|
||||||
|
"name": "Outdoor exercise",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 67.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444333,
|
||||||
|
"description": "Working on my fitness in a gym.",
|
||||||
|
"id": "vvs26xkohcnt8sroal5l0edc",
|
||||||
|
"name": "Gym",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 68.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444335,
|
||||||
|
"description": "Working on myself.",
|
||||||
|
"id": "w2666f0qdo0fk0q9fjiglwbi",
|
||||||
|
"name": "Meditation / Therapy",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 69.0,
|
||||||
|
"colorId": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"createdAt": 1732444336,
|
||||||
|
"description": "Working on a needed but Kafkaesque nightmare chore.",
|
||||||
|
"id": "t9sxvt97kgkkfehxcuin1t4a",
|
||||||
|
"name": "Bureaucracy / Bullshit",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 7.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444338,
|
||||||
|
"description": "Time used for personal development, improving skills, or what I consider to be productive hobbies.",
|
||||||
|
"id": "w42zyrh33ll3g3is563unhqx",
|
||||||
|
"name": "Hobbies & Skills",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 71.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444339,
|
||||||
|
"description": "Learning, studying, reading, or practicing a foreign language.",
|
||||||
|
"id": "d03wwnvt9nnkeoz18ouxpdgo",
|
||||||
|
"name": "Language learning",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 72.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444341,
|
||||||
|
"description": "Preparing food.",
|
||||||
|
"id": "grgvf8su5ms01tstj3jmcu2z",
|
||||||
|
"name": "Cooking",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 73.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444342,
|
||||||
|
"description": "Fun or useful stuff for the house, including gardening, automation, or other projecs that are basically hobbies.",
|
||||||
|
"id": "adwj4mh49cqsj56muc1dhdal",
|
||||||
|
"name": "Home improvement",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 75.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444344,
|
||||||
|
"description": "Reading an article, book, or something else edifying.",
|
||||||
|
"id": "csvjptm37vafhlp9vumc0vi0",
|
||||||
|
"name": "Reading",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 76.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444345,
|
||||||
|
"description": "Working on a hobby or skill, but doing the boring / annoying bits.",
|
||||||
|
"id": "hzir2qmsy1fpww2fmi4ilxwf",
|
||||||
|
"name": "Organizing / Workflow",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 78.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444347,
|
||||||
|
"description": "Nerding out and building something with computers.",
|
||||||
|
"id": "v4b02ymp61afkf6sxbi75a69",
|
||||||
|
"name": "Programming / Computers",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 79.0,
|
||||||
|
"colorId": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"createdAt": 1732444349,
|
||||||
|
"description": "Shopping that isn't a waste of time.",
|
||||||
|
"id": "gxel0vj9vdf9lxl4oz5k8bt6",
|
||||||
|
"name": "Shopping",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 8.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444350,
|
||||||
|
"description": "Time spent gaming, relaxing, consuming entertainment, or participating in passive activities.",
|
||||||
|
"id": "c5qffeg64wcsu4b2ow35pb5z",
|
||||||
|
"name": "Relaxation & Leisure",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 81.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444352,
|
||||||
|
"description": "Watching something produced for the screen (TV / Movies / Tiktok / YouTube)",
|
||||||
|
"id": "j7a54hdrm59e7h0kx4wjcu09",
|
||||||
|
"name": "Watching something",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 82.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444353,
|
||||||
|
"description": "Sweating or swimming in a relaxing way, other than to get clean.",
|
||||||
|
"id": "cauh6fv06sqj054idsc7os9e",
|
||||||
|
"name": "Hot tub / Sauna / Pool",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 83.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444355,
|
||||||
|
"description": "Self sex.",
|
||||||
|
"id": "cr1ddtrq7ut0wo8fgafcis1u",
|
||||||
|
"name": "Masturbation",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 87.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444356,
|
||||||
|
"description": "Exploring the inner cosmos.",
|
||||||
|
"id": "nal715gx0vw2jzrbi66keqpd",
|
||||||
|
"name": "Drugs",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 88.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444358,
|
||||||
|
"description": "High-octane relaxation.",
|
||||||
|
"id": "ool44khvisy404vzmkjo4bse",
|
||||||
|
"name": "Video games",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 89.0,
|
||||||
|
"colorId": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"createdAt": 1732444359,
|
||||||
|
"description": "Scrolling.",
|
||||||
|
"id": "rz1a12cxs7oe097vdajtp462",
|
||||||
|
"name": "Social media",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 9.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444361,
|
||||||
|
"description": "Time better spent doing something else.",
|
||||||
|
"id": "hsibd24jewb7rkyc68hvq2bo",
|
||||||
|
"name": "Waste",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 91.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444362,
|
||||||
|
"description": "Literally staring at a clock with nothing else to do.",
|
||||||
|
"id": "zdxm0t6h86uw22mhecotcw1a",
|
||||||
|
"name": "Waiting / Killing time",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 93.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444364,
|
||||||
|
"description": "Not understanding or communicating well.",
|
||||||
|
"id": "j5vt0dmzaomk859puypttx6f",
|
||||||
|
"name": "Fight",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 96.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444365,
|
||||||
|
"description": "Something has gone horribly wrong, and everything else is canceled.",
|
||||||
|
"id": "i9q43q6ek9js8o5hok2b7ws1",
|
||||||
|
"name": "Disaster",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 97.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444366,
|
||||||
|
"description": "Ah, mindless consumerism!",
|
||||||
|
"id": "nr9gqgr0seh6y8bvzm6zva1y",
|
||||||
|
"name": "Shopping",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 98.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444368,
|
||||||
|
"description": "Lying in bed wishing I was asleep.",
|
||||||
|
"id": "jquru1u59f00gdapixmol2v6",
|
||||||
|
"name": "Can't sleep",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 99.0,
|
||||||
|
"colorId": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"createdAt": 1732444369,
|
||||||
|
"description": "Shoveling empty calories or toxins, knowing it's a mistake.",
|
||||||
|
"id": "z3gt25btq1ejib3ygv1aoq28",
|
||||||
|
"name": "Stress eating / drinking / smoking",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 10.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444371,
|
||||||
|
"description": "Time spent for personal hygiene, getting around, or similar.",
|
||||||
|
"id": "z37g5owwy3jqlxv7ebvrl4qt",
|
||||||
|
"name": "Health & Travel",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 101.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444372,
|
||||||
|
"description": "A regular ol' meal.",
|
||||||
|
"id": "h8xi5wefhl7gklh31j34d21l",
|
||||||
|
"name": "Food",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 103.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444373,
|
||||||
|
"description": "Taking a bath.",
|
||||||
|
"id": "udix1ejz8zg7axmn56lh7tum",
|
||||||
|
"name": "Bath",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 104.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444375,
|
||||||
|
"description": "Getting from a place to another place.",
|
||||||
|
"id": "bx9klccq3dxngm1ofq8lqggd",
|
||||||
|
"name": "Travel",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 105.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444376,
|
||||||
|
"description": "Getting clean to go somewhere or do something -- or, flossing, brushing, and getting ready for bed..",
|
||||||
|
"id": "yjwfwupm3bzriffhumy3zdvt",
|
||||||
|
"name": "Bathroom",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 106.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444378,
|
||||||
|
"description": "Packing for a trip and cleaning before or after a trip.",
|
||||||
|
"id": "r6288qk2icwl40anm9614dkx",
|
||||||
|
"name": "Packing & Cleaning",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 107.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444379,
|
||||||
|
"description": "A doctor, dentist, hospital visit, or appointment of some kind.",
|
||||||
|
"id": "vn1xlghxpah2029ab1w15eua",
|
||||||
|
"name": "Medical / Health",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 108.0,
|
||||||
|
"colorId": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"createdAt": 1732444380,
|
||||||
|
"description": "Taking care of myself in a more aesthetic or relaxing way.",
|
||||||
|
"id": "sk9z8c8uxw28lkqllx3n1e5h",
|
||||||
|
"name": "Grooming / Massage",
|
||||||
|
"parentId": null,
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
}
|
||||||
|
]
|
||||||
90
scripts/color.json
Normal file
90
scripts/color.json
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"createdAt": 1732441996,
|
||||||
|
"hexcode": "#273036",
|
||||||
|
"id": "ej29qv1e7l1dnfxajl0561dt",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Black",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732441997,
|
||||||
|
"hexcode": "#00A9B3",
|
||||||
|
"id": "wtlivlqr3ehecyo9h76asydc",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Blue",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732441999,
|
||||||
|
"hexcode": "#BFFF55",
|
||||||
|
"id": "rk6d9osfs7hvjjofwh7a3tl9",
|
||||||
|
"inverse": "#000000",
|
||||||
|
"name": "Lime",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442000,
|
||||||
|
"hexcode": "#189749",
|
||||||
|
"id": "nnpn5rrn3wx47i1553tvx8tb",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Green",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442002,
|
||||||
|
"hexcode": "#FF65AE",
|
||||||
|
"id": "v86zsclb9cayijf8djilk5lv",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Pink",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442003,
|
||||||
|
"hexcode": "#5B3AB1",
|
||||||
|
"id": "bmt6w43t0jd2s9x6igevhnmt",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Purple",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442004,
|
||||||
|
"hexcode": "#FF6D01",
|
||||||
|
"id": "y6hn5dkk8jfixg2nf11k5rvd",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Orange",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442006,
|
||||||
|
"hexcode": "#FFF336",
|
||||||
|
"id": "v0tzvsbxs1wq66123qy71r3o",
|
||||||
|
"inverse": "#000000",
|
||||||
|
"name": "Yellow",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442007,
|
||||||
|
"hexcode": "#005744",
|
||||||
|
"id": "wseq6pmjce562ds089pduv24",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Teal",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442008,
|
||||||
|
"hexcode": "#C71634",
|
||||||
|
"id": "ahapbp9ujym8lgf4ny02i26h",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Crimson",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"createdAt": 1732442010,
|
||||||
|
"hexcode": "#FF2816",
|
||||||
|
"id": "lx36kwpg92wwtjfouxk5ha69",
|
||||||
|
"inverse": "#ffffff",
|
||||||
|
"name": "Red",
|
||||||
|
"userId": "n7yns1s5b122y5e8v0p6uyt8"
|
||||||
|
}
|
||||||
|
]
|
||||||
11
scripts/user.json
Normal file
11
scripts/user.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"email": "ryan@ryanpandya.com",
|
||||||
|
"emailVerified": null,
|
||||||
|
"id": "n7yns1s5b122y5e8v0p6uyt8",
|
||||||
|
"image": null,
|
||||||
|
"name": "Ryan Pandya",
|
||||||
|
"password": "$2a$10$ngv9752uxDT11hSPfdZmAe2D8VXLB9mcXkN7TRPI5GZQCuriIu1gC",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user