diff --git a/package.json b/package.json index 916f998..800f518 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,8 @@ "dependencies": { "@auth/core": "^0.18.6", "@auth/sveltekit": "^0.5.3", - "@floating-ui/core": "^1.6.0", "@mdi/js": "^7.4.47", "@prisma/client": "^5.8.1", - "svelte-floating-ui": "^1.5.8", "zod": "^3.22.4" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9af6efd..23d163d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,18 +11,12 @@ dependencies: '@auth/sveltekit': specifier: ^0.5.3 version: 0.5.3(@sveltejs/kit@2.5.0)(svelte@4.2.9) - '@floating-ui/core': - specifier: ^1.6.0 - version: 1.6.0 '@mdi/js': specifier: ^7.4.47 version: 7.4.47 '@prisma/client': specifier: ^5.8.1 version: 5.8.1(prisma@5.8.1) - svelte-floating-ui: - specifier: ^1.5.8 - version: 1.5.8 zod: specifier: ^3.22.4 version: 3.22.4 @@ -423,23 +417,6 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} dev: true - /@floating-ui/core@1.6.0: - resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} - dependencies: - '@floating-ui/utils': 0.2.1 - dev: false - - /@floating-ui/dom@1.6.0: - resolution: {integrity: sha512-SZ0BEXzsaaS6THZfZJUcAobbZTD+MvfGM42bxgeg0Tnkp4/an/avqwAXiVLsFtIBZtfsx3Ymvwx0+KnnhdA/9g==} - dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/utils': 0.2.1 - dev: false - - /@floating-ui/utils@0.2.1: - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: false - /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -2857,13 +2834,6 @@ packages: svelte: 4.2.9 dev: true - /svelte-floating-ui@1.5.8: - resolution: {integrity: sha512-dVvJhZ2bT+kQDHlE4Lep8t+sgEc0XD96fXLzAi2DDI2bsaegBbClxXVNMma0C2WsG+n9GJSYx292dTvA8CYRtw==} - dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/dom': 1.6.0 - dev: false - /svelte-hmr@0.15.3(svelte@4.2.9): resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} engines: {node: ^12.20 || ^14.13.1 || >= 16} diff --git a/prisma/migrations/20240128145410_entry_id_index/migration.sql b/prisma/migrations/20240128145410_entry_id_index/migration.sql deleted file mode 100644 index 9d4a176..0000000 --- a/prisma/migrations/20240128145410_entry_id_index/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- CreateIndex -CREATE INDEX "entry_executions_entry_id_idx" ON "entry_executions"("entry_id"); - --- CreateIndex -CREATE INDEX "entry_versions_entry_id_idx" ON "entry_versions"("entry_id"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aebefd9..fa81260 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -80,8 +80,8 @@ model Patient { full_name String? @default(dbgenerated("((first_name || ' '::text) || last_name)")) @ignore - @@map("patients") @@index([full_name(ops: raw("gin_trgm_ops"))], map: "patients_full_name", type: Gin) + @@map("patients") } // Entry category (e.g. Blood test, Exams, ...) @@ -128,7 +128,6 @@ model EntryVersion { created_at DateTime @default(now()) @@map("entry_versions") - @@index([entry_id]) } model EntryExecution { @@ -144,5 +143,4 @@ model EntryExecution { created_at DateTime @default(now()) @@map("entry_executions") - @@index([entry_id]) } diff --git a/src/app.d.ts b/src/app.d.ts index 9741a58..899c7e8 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -7,13 +7,6 @@ declare global { // interface PageData {} // interface Platform {} } - - declare namespace svelteHTML { - // Custom events (https://stackoverflow.com/a/75279911) - interface HTMLAttributes { - "on:outclick"?: CompositionEventHandler; - } - } } export {}; diff --git a/src/app.pcss b/src/app.pcss index d7adec1..1a7b7cf 100644 --- a/src/app.pcss +++ b/src/app.pcss @@ -2,9 +2,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -.ellipsis { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 2b69631..e0e58d1 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -17,11 +17,9 @@ import { router } from "$lib/server/trpc/router"; /** * Protect the application against unauthorized access. * If the user is not logged in, all requests get redirected to the login page - * with the exception of the login page and the TRPC API (which has its own - * auth mechanism) */ const authorization: Handle = async ({ event, resolve }) => { - if (!/^\/(login|trpc)/.test(event.url.pathname)) { + if (event.url.pathname !== "/login") { const session = await event.locals.getSession(); if (!session) { const params = new URLSearchParams({ returnURL: event.url.pathname }); @@ -46,25 +44,6 @@ export const handle = sequence( session: { strategy: "jwt", }, - callbacks: { - // Add user ID to session token - jwt({ token, account, user }) { - if (account) { - token.accessToken = account.access_token; - token.id = user?.id; - } - return token; - }, - session(opt) { - // @ts-expect-error because of union type - if (opt.session.user && opt.token.id) { - // @ts-expect-error because of union type - opt.session.user.id = opt.token.id; - } - - return opt.session; - }, - }, }), authorization, createTRPCHandle({ router, createContext }) diff --git a/src/lib/actions/outclick.ts b/src/lib/actions/outclick.ts deleted file mode 100644 index 8811649..0000000 --- a/src/lib/actions/outclick.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default function clickOutside(node: Element) { - const handleClick = (event: MouseEvent) => { - const tnode = event.target as Element; - - if (!node.contains(tnode)) { - node.dispatchEvent(new CustomEvent("outclick")); - } - }; - - document.addEventListener("click", handleClick, true); - - return { - destroy() { - document.removeEventListener("click", handleClick, true); - }, - }; -} diff --git a/src/lib/components/filter/Autocomplete.svelte b/src/lib/components/filter/Autocomplete.svelte deleted file mode 100644 index 7b55b89..0000000 --- a/src/lib/components/filter/Autocomplete.svelte +++ /dev/null @@ -1,262 +0,0 @@ - - -
- - - {#if opened && filteredItems.length > 0} -
- {#each filteredItems as item, i} -
selectListItem(item, false)} - on:keypress={(e) => { - e.key == "Enter" && selectListItem(item, true); - }} - on:pointerenter={() => { - highlightIndex = i; - }} - > - {#if item.icon} - - {/if} - {item.name} -
- {/each} -
- {/if} -
- - diff --git a/src/lib/components/filter/FilterBar.svelte b/src/lib/components/filter/FilterBar.svelte deleted file mode 100644 index feeb41d..0000000 --- a/src/lib/components/filter/FilterBar.svelte +++ /dev/null @@ -1,198 +0,0 @@ - - -
-
- {#each activeFilters as fdata, i} - getHiddenIds(fdata.id, i)} - {cache} - onRemove={() => removeFilter(i)} - onSelection={(sel, kb) => { - updateFilter(); - if (kb) focusInput(); - }} - /> - {/each} - { - const close = addFilter(item); - return { newValue: "", close }; - }} - onBackspace={() => { - activeFilters.pop(); - activeFilters = activeFilters; - updateFilter(); - }} - /> - -
-
diff --git a/src/lib/components/filter/FilterChip.svelte b/src/lib/components/filter/FilterChip.svelte deleted file mode 100644 index cdb002d..0000000 --- a/src/lib/components/filter/FilterChip.svelte +++ /dev/null @@ -1,127 +0,0 @@ - - -
- - - {#if hasInputField} - {#if fdata.editing} - {#if filter.inputType === 2} - {@const hids = hiddenIds()} - { - // Accept the selection if this is a free text field or the user selected a variant - if (filter.inputType !== 2 || item.id) { - fdata.selection = item; - return { close: true, newValue: "" }; - } else { - return { close: false, newValue: item.name || "" }; - } - }} - {onClose} - onBackspace={onRemove} - /> - {:else} - - { - if (e.key === "Escape") onClose(true); - }} - on:keypress={(e) => { - if (e.key === "Enter") { - // @ts-expect-error Input value is checked - if (e.target?.value) { - // @ts-expect-error Input value is checked - fdata.selection = { id: null, name: e.target.value }; - } - stopEditing(true); - } - }} - /> - {/if} - {:else} - - {/if} - {/if} - -
diff --git a/src/lib/components/filter/filters.ts b/src/lib/components/filter/filters.ts deleted file mode 100644 index aeecefd..0000000 --- a/src/lib/components/filter/filters.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { trpc } from "$lib/shared/trpc"; -import { - mdiAccount, - mdiAccountInjury, - mdiBedKingOutline, - mdiCheckboxBlankOutline, - mdiCheckboxOutline, - mdiDoctor, - mdiDomain, - mdiExclamation, - mdiMagnify, - mdiTag, -} from "@mdi/js"; -import type { FilterDef } from "./types"; - -export const ENTRY_FILTERS: { [key: string]: FilterDef } = { - category: { - id: "category", - name: "Kategorie", - icon: mdiTag, - inputType: 2, - options: async () => { - return await trpc().category.list.query(); - }, - }, - author: { - id: "author", - name: "Autor", - icon: mdiAccount, - inputType: 2, - options: async () => { - return await trpc().user.getNames.query(); - }, - }, - executor: { - id: "executor", - name: "Erledigt von", - icon: mdiDoctor, - inputType: 2, - options: async () => { - return await trpc().user.getNames.query(); - }, - }, - patient: { - id: "patient", - name: "Patient", - icon: mdiAccountInjury, - inputType: 2, - options: async () => { - return await trpc().patient.getNames.query(); - }, - }, - station: { - id: "station", - name: "Station", - icon: mdiDomain, - inputType: 2, - options: async () => { - return await trpc().station.list.query(); - }, - }, - room: { - id: "room", - name: "Zimmer", - icon: mdiBedKingOutline, - inputType: 2, - options: async () => { - return await trpc().room.list.query(); - }, - }, - done: { - id: "done", - name: "Erledigt", - icon: mdiCheckboxOutline, - inputType: 3, - toggleOff: { - name: "Zu erledigen", - icon: mdiCheckboxBlankOutline, - }, - }, - priority: { - id: "priority", - name: "Priorität", - icon: mdiExclamation, - inputType: 0, - }, - search: { - id: "search", - name: "Beschreibung", - icon: mdiMagnify, - inputType: 1, - }, -}; diff --git a/src/lib/components/filter/types.ts b/src/lib/components/filter/types.ts deleted file mode 100644 index ee41b66..0000000 --- a/src/lib/components/filter/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -export type BaseItem = { - id: string | number; - name: string; - icon?: string; - toggle?: boolean; -}; - -export type SelectionOrText = { - id?: string | number; - name?: string; - toggle?: boolean; -}; - -export type FilterDef = { - id: string; - name: string; - icon?: string; - // 0: No input (value: true); 1: Free text input; 2: Filter list; 3: Boolean switch - inputType: 0 | 1 | 2 | 3; - toggleOff?: { - name: string; - icon?: string; - }; - options?: () => Promise; -}; - -export type FilterData = { - id: string; - selection: SelectionOrText | null; - editing: boolean; -}; - -export type FilterQdata = { - [key: string]: string | number | boolean | { id: string | number; name?: string }[]; -}; - -export function isFilterValueless(inputType: 0 | 1 | 2 | 3): boolean { - return inputType === 0 || inputType === 3; -} diff --git a/src/lib/components/table/EntryTable.svelte b/src/lib/components/table/EntryTable.svelte deleted file mode 100644 index c3cf44e..0000000 --- a/src/lib/components/table/EntryTable.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - -
- - - - - - - - - - - - - - - {#each entries.items as entry} - - - - - - - - - - - {/each} - -
PatientZimmerKategorieErstellt amZu erledigen amAutorBeschreibungErledigt
{#if entry.patient.room}{/if}{entry.current_version.category?.name}{formatDate(entry.current_version.created_at, true)}{formatDate(entry.current_version.date)}{entry.current_version.author.name}{entry.current_version.text} - {#if entry.execution} - {formatDate(entry.execution.created_at, true)} - {entry.execution.author.name} - {/if} -
-
diff --git a/src/lib/components/table/PatientField.svelte b/src/lib/components/table/PatientField.svelte deleted file mode 100644 index 6a6b01b..0000000 --- a/src/lib/components/table/PatientField.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -{`${patient.first_name} ${patient.last_name} (${patient.age})`} diff --git a/src/lib/components/table/RoomField.svelte b/src/lib/components/table/RoomField.svelte deleted file mode 100644 index f28e124..0000000 --- a/src/lib/components/table/RoomField.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -{`${room.name} (${room.station.name})`} diff --git a/src/lib/components/ui/NavLink.svelte b/src/lib/components/ui/NavLink.svelte index 1141da7..d678d75 100644 --- a/src/lib/components/ui/NavLink.svelte +++ b/src/lib/components/ui/NavLink.svelte @@ -7,7 +7,7 @@
diff --git a/src/lib/components/ui/PaginationButtons.svelte b/src/lib/components/ui/PaginationButtons.svelte deleted file mode 100644 index fab6e4f..0000000 --- a/src/lib/components/ui/PaginationButtons.svelte +++ /dev/null @@ -1,73 +0,0 @@ - - -
-

- {data.offset + 1}-{data.offset + data.items.length} von {data.total} -

- -
- - - {#each { length: windowTop + 1 - windowBottom } as _, i} - {@const n = windowBottom + i} - - {/each} - - -
-
diff --git a/src/lib/server/authAdapter.ts b/src/lib/server/authAdapter.ts index c33fff9..a0b255f 100644 --- a/src/lib/server/authAdapter.ts +++ b/src/lib/server/authAdapter.ts @@ -43,7 +43,7 @@ export function PrismaAdapter(p: PrismaClient): Adapter { }) ), getUser: async (id) => - mapUserOpt(await p.user.findUnique({ where: { id: Number(id) } })), + mapUserOpt(await p.user.findUnique({ where: { id: parseInt(id) } })), getUserByEmail: async (email) => mapUserOpt(await p.user.findUnique({ where: { email } })), async getUserByAccount(provider_providerAccountId) { @@ -54,14 +54,14 @@ export function PrismaAdapter(p: PrismaClient): Adapter { return mapUserOpt(account?.user) ?? null; }, updateUser: async ({ id, ...data }) => - mapUser(await p.user.update({ where: { id: Number(id) }, data })), + mapUser(await p.user.update({ where: { id: parseInt(id) }, data })), deleteUser: async (id) => - mapUser(await p.user.delete({ where: { id: Number(id) } })), + mapUser(await p.user.delete({ where: { id: parseInt(id) } })), linkAccount: async (data) => mapAccount( await p.account.create({ data: { - user_id: Number(data.userId), + user_id: parseInt(data.userId), type: data.type, provider: data.provider, providerAccountId: data.providerAccountId, diff --git a/src/lib/server/query/entry.ts b/src/lib/server/query/entry.ts index 97f9e5c..a2a3917 100644 --- a/src/lib/server/query/entry.ts +++ b/src/lib/server/query/entry.ts @@ -12,7 +12,7 @@ import type { } from "$lib/shared/model"; import { ErrorConflict } from "$lib/shared/util/error"; import { mapEntry, mapVersion, mapExecution } from "./mapping"; -import { QueryBuilder, filterListToArray, parseSearchQuery } from "./util"; +import { QueryBuilder, parseSearchQuery } from "./util"; const USER_SELECT = { select: { id: true, name: true } }; @@ -236,9 +236,12 @@ join stations s on s.id = r.station_id` qb.addFilter("ev.priority", filter?.priority); if (filter?.author) { - const author = filterListToArray(filter?.author); + let author = filter?.author; + if (!Array.isArray(author)) { + author = [author]; + } qb.addFilterClause( - `(${qb.pvar()})::integer[] && (select array_agg(ev2.author_id) from entry_versions ev2 where ev2.entry_id=e.id)`, + `${qb.pvar()}::integer[] && (select array_agg(ev2.author_id) from entry_versions ev2 where ev2.entry_id=e.id)`, author ); } diff --git a/src/lib/server/query/mapping.ts b/src/lib/server/query/mapping.ts index 4b4a963..45f5bf2 100644 --- a/src/lib/server/query/mapping.ts +++ b/src/lib/server/query/mapping.ts @@ -6,7 +6,6 @@ import type { Room, EntryVersion, EntryExecution, - UserTagNameNonnull, } from "$lib/shared/model"; import { ErrorNotFound } from "$lib/shared/util/error"; import type { @@ -55,14 +54,10 @@ export function mapUser(user: DbUser): User { return { id: user.id, name: user.name, email: user.email }; } -export function mapUserTag(user: Omit): UserTag { +export function mapUserTag(user: DbUser): UserTag { return { id: user.id, name: user.name }; } -export function mapUserTagNameNonnull(user: Omit): UserTagNameNonnull { - return { id: user.id, name: user.name || "" }; -} - export function mapRoom(room: DbRoomLn): Room { return { id: room.id, name: room.name, station: room.station }; } diff --git a/src/lib/server/query/patient.ts b/src/lib/server/query/patient.ts index b338f27..d1b9ace 100644 --- a/src/lib/server/query/patient.ts +++ b/src/lib/server/query/patient.ts @@ -4,7 +4,6 @@ import type { Pagination, PaginationRequest, PatientsFilter, - PatientTag, } from "$lib/shared/model"; import { prisma } from "$lib/server/prisma"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; @@ -52,17 +51,6 @@ export async function getPatient(id: number): Promise { return mapPatient(patient); } -export async function getPatientNames(): Promise { - const patients = await prisma.patient.findMany({ - select: { id: true, first_name: true, last_name: true }, - where: { hidden: false }, - orderBy: { last_name: "asc" }, - }); - return patients.map((p) => { - return { id: p.id, name: p.last_name + ", " + p.first_name }; - }); -} - export async function getPatients( filter: PatientsFilter, pagination: PaginationRequest diff --git a/src/lib/server/query/room.ts b/src/lib/server/query/room.ts index b3f13a4..0a2d5ab 100644 --- a/src/lib/server/query/room.ts +++ b/src/lib/server/query/room.ts @@ -51,7 +51,7 @@ export async function getRoom(id: number): Promise { export async function getRooms(): Promise { const rooms = await prisma.room.findMany({ include: { station: true }, - orderBy: [{ station: { name: "asc" } }, { name: "asc" }], + orderBy: { name: "asc" }, }); return rooms.map(mapRoom); } diff --git a/src/lib/server/query/user.ts b/src/lib/server/query/user.ts index b873db2..da7ce65 100644 --- a/src/lib/server/query/user.ts +++ b/src/lib/server/query/user.ts @@ -1,11 +1,6 @@ -import type { - Pagination, - PaginationRequest, - User, - UserTagNameNonnull, -} from "$lib/shared/model"; +import type { Pagination, PaginationRequest, User, UserTag } from "$lib/shared/model"; import { prisma } from "$lib/server/prisma"; -import { mapUser, mapUserTagNameNonnull } from "./mapping"; +import { mapUser, mapUserTag } from "./mapping"; import { PAGINATION_LIMIT } from "$lib/shared/constants"; export async function getUser(id: number): Promise { @@ -15,7 +10,7 @@ export async function getUser(id: number): Promise { export async function getUsers( pagination: PaginationRequest -): Promise> { +): Promise> { const offset = pagination.offset || 0; const [users, total] = await Promise.all([ prisma.user.findMany({ @@ -26,17 +21,8 @@ export async function getUsers( prisma.user.count(), ]); return { - items: users.map(mapUser), + items: users.map(mapUserTag), offset, total, }; } - -export async function getUserNames(): Promise { - const users = await prisma.user.findMany({ - select: { id: true, name: true }, - where: { name: { not: null } }, - orderBy: { id: "asc" }, - }); - return users.map(mapUserTagNameNonnull); -} diff --git a/src/lib/server/query/util.test.ts b/src/lib/server/query/util.test.ts index f657562..03489e2 100644 --- a/src/lib/server/query/util.test.ts +++ b/src/lib/server/query/util.test.ts @@ -9,7 +9,7 @@ test("query builder", () => { const query = qb.getQuery(); expect(query).toBe( - "select e.id, e.text, e.category from entries e where category = any ($1) and text = $2 limit $3 offset $4" + "select e.id, e.text, e.category from entries e where category in $1 and text = $2 limit $3 offset $4" ); const params = qb.getParams(); diff --git a/src/lib/server/query/util.ts b/src/lib/server/query/util.ts index c7dda1d..4c841fb 100644 --- a/src/lib/server/query/util.ts +++ b/src/lib/server/query/util.ts @@ -1,27 +1,24 @@ import { PAGINATION_LIMIT } from "$lib/shared/constants"; import type { FilterList, PaginationRequest } from "$lib/shared/model"; +export function convertFilterList( + fl: FilterList | undefined +): { in: T[] } | T | undefined { + if (!fl) { + return undefined; + } else if (Array.isArray(fl)) { + return { in: fl }; + } else { + return fl; + } +} + enum QueryComponentType { Normal = 1, Exact, Trailing, } -export function filterListToArray(fl: FilterList): T[] { - if (Array.isArray(fl)) { - // @ts-expect-error checked if id is present - if (fl[0].id) { - // @ts-expect-error checked if id is present - return fl.map((itm) => itm.id); - } else { - // @ts-expect-error output type checked - return fl; - } - } else { - return [fl]; - } -} - class SearchQueryComponent { word: string; typ: QueryComponentType; @@ -152,8 +149,12 @@ export class QueryBuilder { addFilterList(fname: string, fl: FilterList | undefined) { if (fl === undefined) return; - this.filterClauses.push(`${fname} = any (${this.pvar()})`); - this.params.push(filterListToArray(fl)); + this.params.push(fl); + if (Array.isArray(fl)) { + this.filterClauses.push(`${fname} in ${this.pvar()}`); + } else { + this.filterClauses.push(`${fname} = ${this.pvar()}`); + } } getQuery(): string { diff --git a/src/lib/server/trpc/context.ts b/src/lib/server/trpc/context.ts index 9219979..09e1a63 100644 --- a/src/lib/server/trpc/context.ts +++ b/src/lib/server/trpc/context.ts @@ -9,7 +9,7 @@ export async function createContext(event: RequestEvent) { const session = await event.locals.getSession(); if (!session?.user) { - throw new TRPCError({ code: "UNAUTHORIZED", message: "not logged in" }); + throw new TRPCError({ code: "UNAUTHORIZED", message: "no session" }); } const user = ZUser.parse(session?.user); diff --git a/src/lib/server/trpc/router.ts b/src/lib/server/trpc/router.ts index ec3ffe5..a8ea9e2 100644 --- a/src/lib/server/trpc/router.ts +++ b/src/lib/server/trpc/router.ts @@ -2,21 +2,13 @@ import { t } from "."; import { categoryRouter } from "./routes/category"; import { entryRouter } from "./routes/entry"; -import { stationRouter } from "./routes/station"; -import { roomRouter } from "./routes/room"; -import { patientRouter } from "./routes/patient"; -import { userRouter } from "./routes/user"; export const router = t.router({ greeting: t.procedure.query(async () => { - return `Hello tRPC @ ${new Date().toLocaleTimeString()}`; + return `Hello tRPC v10 @ ${new Date().toLocaleTimeString()}`; }), category: categoryRouter, entry: entryRouter, - station: stationRouter, - room: roomRouter, - patient: patientRouter, - user: userRouter, }); export type Router = typeof router; diff --git a/src/lib/server/trpc/routes/patient.ts b/src/lib/server/trpc/routes/patient.ts deleted file mode 100644 index a148076..0000000 --- a/src/lib/server/trpc/routes/patient.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getPatientNames, getPatients } from "$lib/server/query"; -import { ZPagination, ZPatientsFilter } from "$lib/shared/model/validation"; -import { t } from ".."; -import { z } from "zod"; - -export const patientRouter = t.router({ - getNames: t.procedure.query(getPatientNames), - list: t.procedure - .input(z.object({ filter: ZPatientsFilter, pagination: ZPagination }).partial()) - .query(async (opts) => { - return getPatients(opts.input.filter || {}, opts.input.pagination || {}); - }), -}); diff --git a/src/lib/server/trpc/routes/room.ts b/src/lib/server/trpc/routes/room.ts deleted file mode 100644 index 145cb43..0000000 --- a/src/lib/server/trpc/routes/room.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getRooms } from "$lib/server/query"; -import { t } from ".."; -// import { z } from "zod"; - -export const roomRouter = t.router({ - list: t.procedure.query(getRooms), -}); diff --git a/src/lib/server/trpc/routes/station.ts b/src/lib/server/trpc/routes/station.ts deleted file mode 100644 index b4cbc9f..0000000 --- a/src/lib/server/trpc/routes/station.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getStations } from "$lib/server/query"; -import { t } from ".."; -// import { z } from "zod"; - -export const stationRouter = t.router({ - list: t.procedure.query(getStations), -}); diff --git a/src/lib/server/trpc/routes/user.ts b/src/lib/server/trpc/routes/user.ts deleted file mode 100644 index fae8b89..0000000 --- a/src/lib/server/trpc/routes/user.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getUserNames, getUsers } from "$lib/server/query"; -import { ZPagination } from "$lib/shared/model/validation"; -import { t } from ".."; -import { z } from "zod"; - -export const userRouter = t.router({ - list: t.procedure - .input(z.object({ pagination: ZPagination }).partial()) - .query(async (opts) => { - return getUsers(opts.input.pagination || {}); - }), - getNames: t.procedure.query(getUserNames), -}); diff --git a/src/lib/shared/model/model.ts b/src/lib/shared/model/model.ts index b9b7726..9761060 100644 --- a/src/lib/shared/model/model.ts +++ b/src/lib/shared/model/model.ts @@ -30,11 +30,6 @@ export type UserTag = { name: Option; }; -export type UserTagNameNonnull = { - id: number; - name: string; -}; - export type Station = { id: number; name: string; @@ -72,11 +67,6 @@ export type Patient = { created_at: Date; }; -export type PatientTag = { - id: number; - name: string; -}; - export type PatientNew = { first_name: string; last_name: string; diff --git a/src/lib/shared/model/requests.ts b/src/lib/shared/model/requests.ts index 7f909d9..96c2e5f 100644 --- a/src/lib/shared/model/requests.ts +++ b/src/lib/shared/model/requests.ts @@ -1,9 +1,9 @@ export type PaginationRequest = Partial<{ - limit: number | undefined; - offset: number | undefined; + limit: number; + offset: number; }>; -export type FilterList = T | T[] | { id: T }[]; +export type FilterList = T | T[]; export type EntriesFilter = Partial<{ search: string; diff --git a/src/lib/shared/model/validation.ts b/src/lib/shared/model/validation.ts index 1cdd726..bada4c8 100644 --- a/src/lib/shared/model/validation.ts +++ b/src/lib/shared/model/validation.ts @@ -18,7 +18,7 @@ const ZNameString = z.string().min(1).max(200).trim(); const ZTextString = z.string().trim(); export const ZUser = implement().with({ - id: z.coerce.number().int().nonnegative(), + id: ZEntityId, name: z.string().nullable(), email: z.string().nullable(), }); @@ -73,10 +73,12 @@ export const ZPagination = implement().with({ offset: ZEntityId.optional(), }); -const ZFilterListEntry = z.object({ id: ZEntityId, name: ZNameString.optional() }); -const ZFilterList = z.array(ZFilterListEntry); -const paginatedQuery = (f: z.ZodTypeAny) => - z.object({ filter: f, pagination: ZPagination }).partial(); +// const ZFilterList = z +// .string() +// .regex(/^\d+(;\d+)*$/) +// .transform((s) => s.split(";").map(Number)) +// .optional(); +const ZFilterList = z.array(ZEntityId).or(ZEntityId); export const ZEntriesFilter = z .object({ @@ -92,9 +94,7 @@ export const ZEntriesFilter = z }) .partial(); -export const ZEntriesQuery = paginatedQuery(ZEntriesFilter); - -export const ZPatientsFilter = z +export const ZPatientsFilterUrl = z .object({ search: z.string(), room: ZFilterList, @@ -102,5 +102,3 @@ export const ZPatientsFilter = z hidden: z.boolean(), }) .partial(); - -export const ZPatientsQuery = paginatedQuery(ZPatientsFilter); diff --git a/src/lib/shared/trpc.ts b/src/lib/shared/trpc.ts index b331cf9..cde6393 100644 --- a/src/lib/shared/trpc.ts +++ b/src/lib/shared/trpc.ts @@ -1,10 +1,6 @@ -import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server"; import type { Router } from "$lib/server/trpc/router"; import { createTRPCClient, type TRPCClientInit } from "trpc-sveltekit"; -export type RouterInput = inferRouterInputs; -export type RouterOutput = inferRouterOutputs; - let browserClient: ReturnType>; /** Get a new tRPC client diff --git a/src/lib/shared/util/index.ts b/src/lib/shared/util/index.ts deleted file mode 100644 index 731bf14..0000000 --- a/src/lib/shared/util/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -export function formatDate(date: Date | string, time = false): string { - let dt = date; - if (!(dt instanceof Date)) { - dt = new Date(dt); - } - if (time) { - return dt.toLocaleString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - }); - } else { - return dt.toLocaleDateString("de-DE", { - day: "2-digit", - month: "2-digit", - year: "numeric", - }); - } -} diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 3d542a0..b10ceca 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -8,10 +8,10 @@
-
-
+
diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte index e81153d..a8bd2a5 100644 --- a/src/routes/(app)/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -2,37 +2,30 @@ import { page } from "$app/stores"; - - Visitenbuch - - -{#if $page.data.session?.user} -

Hallo, {$page.data.session.user.name}

-{:else} -

Sie sind nicht angemeldet

-{/if} - -
-
-
-

Planung

-

Hier können sie neue Visitenbucheinträge erstellen.

-
- Planung -
-
-
- -
-
-

Visite

-

Hier können sie Visitenbucheinträge abarbeiten.

-

Heute müssen (n) Einträge erledigt werden.

-
- Visite -
-
-
+
+

SvelteKit Auth Example

+ +

+ {#if $page.data.session} + {#if $page.data.session.user?.image} + + {/if} + + Signed in as
+ {$page.data.session.user?.name ?? "User"} +
+ {:else} + You are not signed in + {/if} +

+ +

+ + {JSON.stringify($page.data.session)} + +

+

{new Date().toUTCString()}

diff --git a/src/routes/(app)/plan/+page.svelte b/src/routes/(app)/plan/+page.svelte index db97e38..05a9630 100644 --- a/src/routes/(app)/plan/+page.svelte +++ b/src/routes/(app)/plan/+page.svelte @@ -1,67 +1,10 @@ - - Visitenbuch - Planung - +

Planung

- - -{#if loading} -

Loading...

-{/if} - - - - +

{data.greeting}

+

{JSON.stringify(data.categories)}

diff --git a/src/routes/(app)/plan/+page.ts b/src/routes/(app)/plan/+page.ts index a3028c4..d2ee5a6 100644 --- a/src/routes/(app)/plan/+page.ts +++ b/src/routes/(app)/plan/+page.ts @@ -1,18 +1,11 @@ -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 = {}; + const [greeting, categories] = await Promise.all([ + trpc(event).greeting.query(), + trpc(event).category.list.query(), + ]); - if (q) { - query = ZEntriesQuery.parse(JSON.parse(q)); - } - - const entries = await trpc(event).entry.list.query(query); - - return { query, entries }; + return { greeting, categories }; }; diff --git a/src/routes/(app)/visit/+page.svelte b/src/routes/(app)/visit/+page.svelte index 8c9961a..a91baca 100644 --- a/src/routes/(app)/visit/+page.svelte +++ b/src/routes/(app)/visit/+page.svelte @@ -1,8 +1,4 @@ - - Visitenbuch - Visite - -

Visite

diff --git a/tests/integration/query/entry.ts b/tests/integration/query/entry.ts index 03815e0..d6cca4b 100644 --- a/tests/integration/query/entry.ts +++ b/tests/integration/query/entry.ts @@ -204,11 +204,9 @@ test("get entries", async () => { // Filter by category const entriesCategory = await getEntries({ category: 3 }, {}); - const entriesCategory2 = await getEntries({ category: [3] }, {}); expect(entriesCategory.items).length(1); expect(entriesCategory.total).toBe(1); expect(entriesCategory.items[0].id).toBe(eId1); - expect(entriesCategory2).toStrictEqual(entriesCategory); // Filter by author const entriesAuthor = await getEntries({ author: 2 }, {}); diff --git a/tests/integration/query/user.ts b/tests/integration/query/user.ts index 01458b0..300def0 100644 --- a/tests/integration/query/user.ts +++ b/tests/integration/query/user.ts @@ -17,12 +17,10 @@ test("get users", async () => { { id: 1, name: "Sven Schulz", - email: "sven.schulz@example.com", }, { id: 2, name: "Sabrina Loewe", - email: "sabrina.loewe@example.com", }, ], offset: 0, diff --git a/tsconfig.json b/tsconfig.json index 9fea023..794b95b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,8 @@ "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, - "strict": true, - }, + "strict": true + } // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes