diff --git a/package.json b/package.json index 916f998..af1cd98 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@mdi/js": "^7.4.47", "@prisma/client": "^5.8.1", "svelte-floating-ui": "^1.5.8", + "svelte-markdown": "^0.4.1", "zod": "^3.22.4" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9af6efd..1ab8cad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ dependencies: svelte-floating-ui: specifier: ^1.5.8 version: 1.5.8 + svelte-markdown: + specifier: ^0.4.1 + version: 0.4.1(svelte@4.2.9) zod: specifier: ^3.22.4 version: 3.22.4 @@ -856,6 +859,10 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true + /@types/marked@5.0.2: + resolution: {integrity: sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==} + dev: false + /@types/node@20.11.7: resolution: {integrity: sha512-GPmeN1C3XAyV5uybAf4cMLWT9fDWcmQhZVtMFu7OR32WjrqGG+Wnk2V1d0bmtUyE/Zy1QJ9BxyiTih9z8Oks8A==} dependencies: @@ -2096,6 +2103,12 @@ packages: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + /marked@5.1.2: + resolution: {integrity: sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==} + engines: {node: '>= 16'} + hasBin: true + dev: false + /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} @@ -2872,6 +2885,16 @@ packages: dependencies: svelte: 4.2.9 + /svelte-markdown@0.4.1(svelte@4.2.9): + resolution: {integrity: sha512-pOlLY6EruKJaWI9my/2bKX8PdTeP5CM0s4VMmwmC2prlOkjAf+AOmTM4wW/l19Y6WZ87YmP8+ZCJCCwBChWjYw==} + peerDependencies: + svelte: ^4.0.0 + dependencies: + '@types/marked': 5.0.2 + marked: 5.1.2 + svelte: 4.2.9 + dev: false + /svelte-preprocess@5.1.3(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3): resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} engines: {node: '>= 16.0.0', pnpm: ^8.0.0} diff --git a/prisma/migrations/20240113185049_init/migration.sql b/prisma/migrations/20240113185049_init/migration.sql index ff8c396..e9f7a31 100644 --- a/prisma/migrations/20240113185049_init/migration.sql +++ b/prisma/migrations/20240113185049_init/migration.sql @@ -78,7 +78,7 @@ CREATE TABLE "entry_versions" ( "id" SERIAL NOT NULL, "entry_id" INTEGER NOT NULL, "text" TEXT NOT NULL, - "date" TIMESTAMP(3) NOT NULL, + "date" DATE NOT NULL, "category_id" INTEGER, "priority" BOOLEAN NOT NULL, "author_id" INTEGER NOT NULL, diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aebefd9..915ca43 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -116,7 +116,7 @@ model EntryVersion { entry_id Int text String - date DateTime + date DateTime @db.Date category Category? @relation(fields: [category_id], references: [id], onDelete: SetNull) category_id Int? diff --git a/src/app.pcss b/src/app.pcss index 2d53edd..4abb4ca 100644 --- a/src/app.pcss +++ b/src/app.pcss @@ -7,6 +7,10 @@ button { text-align: initial; } +.heading { + @apply text-2xl font-bold; +} + .ellipsis { overflow: hidden; white-space: nowrap; diff --git a/src/hooks.client.ts b/src/hooks.client.ts new file mode 100644 index 0000000..5c7d379 --- /dev/null +++ b/src/hooks.client.ts @@ -0,0 +1,28 @@ +import type { HandleClientError } from "@sveltejs/kit"; +import { TRPCClientError } from "@trpc/client"; + +const CHECK_CONNECTION = + "Die Seite konnte nicht geladen werden, prüfen sie ihre Verbindung"; + +export const handleError: HandleClientError = async ({ error, message, status }) => { + // If there are client-side errors, SvelteKit always returns the nondescript + // "Internal error" message. The most common errors should be mapped to a more + // detailed description + if (status === 500) { + // eslint-disable-next-line no-console + console.error("Client error:", error); + + if ( + error instanceof TypeError && + error.message.includes("dynamically imported module") + ) { + // Could not load JS module + message = CHECK_CONNECTION; + } else if (error instanceof TRPCClientError && !error.data) { + // Could not load fetched data + message = CHECK_CONNECTION; + } + } + + return { message }; +}; diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 2b69631..065efc2 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -65,6 +65,7 @@ export const handle = sequence( return opt.session; }, }, + trustHost: true, }), authorization, createTRPCHandle({ router, createContext }) diff --git a/src/lib/components/filter/Autocomplete.svelte b/src/lib/components/filter/Autocomplete.svelte index 7b55b89..2f34a43 100644 --- a/src/lib/components/filter/Autocomplete.svelte +++ b/src/lib/components/filter/Autocomplete.svelte @@ -22,6 +22,7 @@ export let cacheKey: string | undefined = undefined; export let placeholder: string | undefined = undefined; export let padding = true; + export let cls = ""; /** Selection callback. Returns the new input value after selection */ export let onSelect: (item: SelectionOrText, kb: boolean) => OnSelectResult = ( @@ -195,7 +196,7 @@ }); -
+
{#each activeFilters as fdata, i} + diff --git a/src/lib/components/table/PatientTable.svelte b/src/lib/components/table/PatientTable.svelte new file mode 100644 index 0000000..042e008 --- /dev/null +++ b/src/lib/components/table/PatientTable.svelte @@ -0,0 +1,64 @@ + + +
+ + + + + + + + + + + + {#each patients.items as patient} + + + + + + + + + {/each} + +
+
{patient.id}{patient.first_name} {patient.last_name}{patient.age} + {#if patient.room} + + {/if} + {formatDate(patient.created_at, true)} + +
+
+ + diff --git a/src/lib/components/table/UserField.svelte b/src/lib/components/table/UserField.svelte index 6525cba..0d2eefb 100644 --- a/src/lib/components/table/UserField.svelte +++ b/src/lib/components/table/UserField.svelte @@ -14,4 +14,4 @@ } - + diff --git a/src/lib/components/ui/ErrorMessage.svelte b/src/lib/components/ui/ErrorMessage.svelte new file mode 100644 index 0000000..7821f94 --- /dev/null +++ b/src/lib/components/ui/ErrorMessage.svelte @@ -0,0 +1,34 @@ + + +{#if statusCode === 404} +
+
+

Fehler 404:

+

Die Seite wurde nicht gefunden

+ {#if withBtn} + Zur Startseite + {/if} +
+
+{:else} +
+
+

Fehler {statusCode}:

+

{error.message}

+ {#if withBtn} + {#if statusCode && statusCode < 500} + Zur Startseite + {:else} + Neu laden{/if} + {/if} +
+
+{/if} diff --git a/src/lib/components/ui/LoadingBar.svelte b/src/lib/components/ui/LoadingBar.svelte new file mode 100644 index 0000000..e8a4c9e --- /dev/null +++ b/src/lib/components/ui/LoadingBar.svelte @@ -0,0 +1,60 @@ + + +
+ + diff --git a/src/lib/server/handleError.ts b/src/lib/server/handleError.ts deleted file mode 100644 index 4c9be4c..0000000 --- a/src/lib/server/handleError.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -import { ErrorConflict, ErrorNotFound } from "$lib/shared/util/error"; -import { ZodError } from "zod"; -import { - Ok, - BadRequest, - NotFound, - Conflict, - InternalServerError, -} from "sveltekit-zero-api/http"; -import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; -import { userId } from "./util"; -import type { RequestEvent } from "@sveltejs/kit"; - -function handleError(error: unknown) { - if (error instanceof ZodError) { - // return { status: 400, msg: "Invalid input", data: error.flatten() }; - return BadRequest({ - body: { status: 400, msg: "Invalid input", data: error.flatten() }, - }); - } else if (error instanceof PrismaClientKnownRequestError) { - if (error.code === "P2025") { - return NotFound({ - body: { status: 404, msg: error.message }, - }); - } else { - return InternalServerError({ - body: { status: 500, msg: error.message, prismaCode: error.code }, - }); - } - } else if (error instanceof ErrorNotFound) { - return NotFound({ - body: { status: 404, msg: error.message }, - }); - } else if (error instanceof ErrorConflict) { - return Conflict({ - body: { status: 409, msg: error.message }, - }); - } else if (error instanceof Error) { - return InternalServerError({ - body: { status: 500, msg: error.message }, - }); - } else { - return InternalServerError({ - body: { status: 500, msg: "unknown error" }, - }); - } -} - -export async function apiWrap(f: () => Promise) { - try { - const body = await f(); - return Ok({ body }); - } catch (error) { - return handleError(error); - } -} - -export async function apiWrapUser( - event: RequestEvent, - f: (uId: number) => Promise -) { - try { - const uId = await userId(event); - const body = await f(uId); - return Ok({ body }); - } catch (error) { - return handleError(error); - } -} -*/ diff --git a/src/lib/server/trpc/handleError.ts b/src/lib/server/trpc/handleError.ts new file mode 100644 index 0000000..bb9aafb --- /dev/null +++ b/src/lib/server/trpc/handleError.ts @@ -0,0 +1,42 @@ +import { ErrorConflict, ErrorNotFound } from "$lib/shared/util/error"; +import { ZodError } from "zod"; +import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; +import { TRPCError } from "@trpc/server"; + +function handleError(error: unknown): void { + if (error instanceof ZodError) { + // return { status: 400, msg: "Invalid input", data: error.flatten() }; + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Invalid input", + cause: error.flatten(), + }); + } else if (error instanceof PrismaClientKnownRequestError) { + if (error.code === "P2025") { + throw new TRPCError({ code: "NOT_FOUND", message: error.message }); + } else { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: error.message, + cause: "Prisma error " + error.code, + }); + } + } else if (error instanceof ErrorNotFound) { + throw new TRPCError({ code: "NOT_FOUND", message: error.message }); + } else if (error instanceof ErrorConflict) { + throw new TRPCError({ code: "CONFLICT", message: error.message }); + } else if (error instanceof Error) { + throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: error.message }); + } else { + throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "unknown error" }); + } +} + +/** Wrap a TRPC query to handle occuring errors */ +export async function trpcWrap(f: () => Promise) { + try { + return await f(); + } catch (error) { + return handleError(error); + } +} diff --git a/src/lib/server/trpc/index.ts b/src/lib/server/trpc/index.ts index d4d7ae3..877310d 100644 --- a/src/lib/server/trpc/index.ts +++ b/src/lib/server/trpc/index.ts @@ -1,4 +1,6 @@ import { initTRPC } from "@trpc/server"; import type { Context } from "./context"; +export { trpcWrap } from "$lib/server/trpc/handleError"; + export const t = initTRPC.context().create(); diff --git a/src/lib/shared/constants.ts b/src/lib/shared/constants.ts index a7659dc..f90c1a6 100644 --- a/src/lib/shared/constants.ts +++ b/src/lib/shared/constants.ts @@ -1 +1,4 @@ +import type { Renderers } from "svelte-markdown"; + export const PAGINATION_LIMIT = 20; +export const MARKDOWN_RENDERERS: Partial = { image: undefined }; diff --git a/src/lib/shared/model/requests.ts b/src/lib/shared/model/requests.ts index c788854..4daf9a6 100644 --- a/src/lib/shared/model/requests.ts +++ b/src/lib/shared/model/requests.ts @@ -34,3 +34,13 @@ export type PatientsFilter = Partial<{ room: FilterList; hidden: boolean; }>; + +export type TRPCErrorResponse = { + message: string; + data?: { + code: string; + httpStatus: number; + stack?: string; + path?: string; + }; +}; diff --git a/src/lib/shared/model/validation.ts b/src/lib/shared/model/validation.ts index f9dcae7..75d17af 100644 --- a/src/lib/shared/model/validation.ts +++ b/src/lib/shared/model/validation.ts @@ -15,6 +15,7 @@ import type { } from "."; export const ZEntityId = z.number().int().nonnegative(); +export const ZUrlEntityId = z.coerce.number().int().nonnegative(); const ZNameString = z.string().min(1).max(200).trim(); const ZTextString = z.string().trim(); diff --git a/src/lib/shared/util/index.ts b/src/lib/shared/util/index.ts index cd5453d..76543f7 100644 --- a/src/lib/shared/util/index.ts +++ b/src/lib/shared/util/index.ts @@ -1,5 +1,7 @@ import { goto } from "$app/navigation"; import type { EntityQuery } from "$lib/shared/model"; +import { TRPCClientError } from "@trpc/client"; +import { error } from "@sveltejs/kit"; export function formatDate(date: Date | string, time = false): string { let dt = date; @@ -23,14 +25,13 @@ export function formatDate(date: Date | string, time = false): string { } } -export function getQueryUrl(q: EntityQuery, basePath: string = ""): string { - return basePath + "?q=" + JSON.stringify(q); +export function getQueryUrl(q: EntityQuery, basePath: string): string { + return basePath + "/" + JSON.stringify(q); } export function gotoEntityQuery(q: EntityQuery, basePath: string) { - if (window && basePath === window.location.pathname) { - const ws = new URLSearchParams(window.location.search); - const qstr = ws.get("q"); + if (window && window.location.pathname.startsWith(basePath + "/")) { + const qstr = decodeURI(window.location.pathname.substring(basePath.length + 1)); if (qstr) { const oldq: EntityQuery = JSON.parse(qstr); const nq: EntityQuery = { @@ -43,3 +44,21 @@ export function gotoEntityQuery(q: EntityQuery, basePath: string) { } goto(getQueryUrl(q, basePath)); } + +/** Wrap a page load query to handle occuring errors + * + * Converts TRPC errors to SvelteKit ones + */ +export async function loadWrap(f: () => Promise) { + try { + return await f(); + } catch (e) { + if (e instanceof TRPCClientError) { + error(e.data?.httpStatus ?? 500, e.message); + } else if (e instanceof Error) { + error(500, e.message); + } else { + error(500, "unknown error"); + } + } +} diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 3d542a0..6755954 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -19,8 +19,9 @@ cls={$page.route.id === "/(app)" ? "text-primary" : ""} /> - Planung + Planung Visite + Patienten
{#if $page.data.session?.user} @@ -34,6 +35,9 @@ tabindex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52" > +
  • Zimmer
  • +
  • Kategorien
  • +
  • Benutzer
  • + + Throw error
    diff --git a/src/routes/(app)/entry/[id]/+page.svelte b/src/routes/(app)/entry/[id]/+page.svelte new file mode 100644 index 0000000..38f223b --- /dev/null +++ b/src/routes/(app)/entry/[id]/+page.svelte @@ -0,0 +1,69 @@ + + + + Eintrag #{data.entry.id} + + +

    + Eintrag #{data.entry.id} + {#if data.entry.current_version.category} + + {/if} +

    + +
    +

    + {#if data.entry.patient.room} + + {/if} + {data.entry.patient.first_name} + {data.entry.patient.last_name} + ({data.entry.patient.age}) +

    +
    + +
    +

    + +

    +
    + +{#if data.entry.execution} +
    +

    + Erledigt am {formatDate(data.entry.execution.created_at, true)} von + : +

    + +

    + +

    +
    +{/if} + + diff --git a/src/routes/(app)/entry/[id]/+page.ts b/src/routes/(app)/entry/[id]/+page.ts new file mode 100644 index 0000000..204d7cf --- /dev/null +++ b/src/routes/(app)/entry/[id]/+page.ts @@ -0,0 +1,11 @@ +import { ZUrlEntityId } from "$lib/shared/model/validation"; +import { trpc } from "$lib/shared/trpc"; +import { loadWrap } from "$lib/shared/util"; +import type { PageLoad } from "./$types"; + +export const load: PageLoad = async (event) => { + const id = ZUrlEntityId.parse(event.params.id); + const entry = await loadWrap(async () => trpc(event).entry.get.query(id)); + + return { entry }; +}; diff --git a/src/routes/(app)/plan/+page.svelte b/src/routes/(app)/patients/[[query]]/+page.svelte similarity index 77% rename from src/routes/(app)/plan/+page.svelte rename to src/routes/(app)/patients/[[query]]/+page.svelte index d2bab98..1effd52 100644 --- a/src/routes/(app)/plan/+page.svelte +++ b/src/routes/(app)/patients/[[query]]/+page.svelte @@ -2,14 +2,14 @@ import { browser } from "$app/environment"; import type { PageData } from "./$types"; - import EntryTable from "$lib/components/table/EntryTable.svelte"; import PaginationButtons from "$lib/components/ui/PaginationButtons.svelte"; import FilterBar from "$lib/components/filter/FilterBar.svelte"; import type { PaginationRequest, SortRequest } from "$lib/shared/model"; import type { FilterQdata } from "$lib/components/filter/types"; import { trpc } from "$lib/shared/trpc"; - import { ENTRY_FILTERS } from "$lib/components/filter/filters"; + import { ENTRY_FILTERS, PATIENT_FILTER } from "$lib/components/filter/filters"; import { getQueryUrl } from "$lib/shared/util"; + import PatientTable from "$lib/components/table/PatientTable.svelte"; export let data: PageData; @@ -39,14 +39,14 @@ if (browser) { // Update page URL (not using the Svelte Router here because // we do not need to reload the page) - const url = getQueryUrl(query); + const url = getQueryUrl(query, "/patients"); window.history.replaceState(null, "", url); loading = true; trpc() - .entry.list.query(query) - .then((entries) => { - data.entries = entries; + .patient.list.query(query) + .then((patients) => { + data.patients = patients; data.query = query; loading = false; }); @@ -55,11 +55,11 @@ - Visitenbuch - Planung + Patienten @@ -68,10 +68,10 @@

    Loading...

    {/if} - + diff --git a/src/routes/(app)/patients/[[query]]/+page.ts b/src/routes/(app)/patients/[[query]]/+page.ts new file mode 100644 index 0000000..af436ff --- /dev/null +++ b/src/routes/(app)/patients/[[query]]/+page.ts @@ -0,0 +1,18 @@ +import { z } from "zod"; + +import { ZPatientsQuery } from "$lib/shared/model/validation"; +import { trpc } from "$lib/shared/trpc"; +import type { PageLoad } from "./$types"; +import { loadWrap } from "$lib/shared/util"; + +export const load: PageLoad = async (event) => { + let query: z.infer = {}; + + if (event.params.query) { + query = ZPatientsQuery.parse(JSON.parse(event.params.query)); + } + + const patients = await loadWrap(async () => trpc(event).patient.list.query(query)); + + return { query, patients }; +}; diff --git a/src/routes/(app)/plan/+page.ts b/src/routes/(app)/plan/+page.ts deleted file mode 100644 index a3028c4..0000000 --- a/src/routes/(app)/plan/+page.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from "zod"; - -import { ZEntriesQuery } from "$lib/shared/model/validation"; -import { trpc } from "$lib/shared/trpc"; -import type { PageLoad } from "./$types"; - -export const load: PageLoad = async (event) => { - const q = event.url.searchParams.get("q"); - let query: z.infer = {}; - - if (q) { - query = ZEntriesQuery.parse(JSON.parse(q)); - } - - const entries = await trpc(event).entry.list.query(query); - - return { query, entries }; -}; diff --git a/src/routes/(app)/plan/[[query]]/+page.svelte b/src/routes/(app)/plan/[[query]]/+page.svelte new file mode 100644 index 0000000..c9fa6bc --- /dev/null +++ b/src/routes/(app)/plan/[[query]]/+page.svelte @@ -0,0 +1,90 @@ + + + + Planung + + + + + + +{#if error} + +{:else} + + + +{/if} diff --git a/src/routes/(app)/plan/[[query]]/+page.ts b/src/routes/(app)/plan/[[query]]/+page.ts new file mode 100644 index 0000000..7476822 --- /dev/null +++ b/src/routes/(app)/plan/[[query]]/+page.ts @@ -0,0 +1,15 @@ +import { trpc } from "$lib/shared/trpc"; +import { loadWrap } from "$lib/shared/util"; +import type { PageLoad } from "./$types"; + +export const load: PageLoad = async (event) => { + let query = {}; + + if (event.params.query) { + query = JSON.parse(event.params.query); + } + + const entries = await loadWrap(() => trpc(event).entry.list.query(query)); + + return { query, entries }; +}; diff --git a/src/routes/(app)/visit/+page.svelte b/src/routes/(app)/visit/+page.svelte index 8c9961a..67f9a0f 100644 --- a/src/routes/(app)/visit/+page.svelte +++ b/src/routes/(app)/visit/+page.svelte @@ -2,7 +2,7 @@ - Visitenbuch - Visite + Visite

    Visite

    diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte new file mode 100644 index 0000000..ac78805 --- /dev/null +++ b/src/routes/+error.svelte @@ -0,0 +1,15 @@ + + + + Visitenbuch: Fehler {$page.status} + + +{#if $page.error} + +{/if} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e680e4a..71aeada 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,7 +1,23 @@ + +
    diff --git a/tests/helpers/generate-mockdata.ts b/tests/helpers/generate-mockdata.ts index 53b7356..2cc2b4c 100644 --- a/tests/helpers/generate-mockdata.ts +++ b/tests/helpers/generate-mockdata.ts @@ -15,7 +15,7 @@ const CATEGORY_IDS: { [id: string]: number } = { Entlassung: 5, Sonstiges: 6, }; -const refDate = new Date(2023, 11, 1); +const refDate = new Date(Date.UTC(2023, 11, 1)); const N_USERS = 10; const N_ROOMS = 20; diff --git a/tests/integration/query/entry.ts b/tests/integration/query/entry.ts index 03815e0..f7303fc 100644 --- a/tests/integration/query/entry.ts +++ b/tests/integration/query/entry.ts @@ -12,7 +12,7 @@ import { expect, test } from "vitest"; const TEST_VERSION = { category_id: 1, text: "10ml Blut abnehmen", - date: new Date(2024, 1, 1), + date: new Date(Date.UTC(2024, 1, 1)), priority: false, }; @@ -40,7 +40,7 @@ test("create entry version", async () => { version: TEST_VERSION, }); const text = "10ml Blut abnehmen\n\nPS: Nadel nicht vergessen"; - const date = new Date(2024, 1, 2); + const date = new Date(Date.UTC(2024, 1, 2)); await newEntryVersion(1, eId, { date, @@ -155,7 +155,7 @@ async function insertTestEntries() { patient_id: 2, version: { text: "Carrot cake jelly-o bonbon toffee chocolate.", - date: new Date(2024, 1, 5), + date: new Date(Date.UTC(2024, 1, 5)), priority: false, category_id: null, }, @@ -164,7 +164,7 @@ async function insertTestEntries() { patient_id: 1, version: { text: "Cheesecake danish donut oat cake caramels.", - date: new Date(2024, 1, 6), + date: new Date(Date.UTC(2024, 1, 6)), priority: false, category_id: null, }, @@ -174,7 +174,7 @@ async function insertTestEntries() { await newEntryVersion(2, eId1, { category_id: 3, text: TEST_VERSION.text + "\n\n> Hello World", - date: new Date(2024, 1, 1), + date: new Date(Date.UTC(2024, 1, 1)), priority: true, });