diff --git a/eslint.config.js b/eslint.config.js index 3f8cd75..4d7656d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -335,6 +335,10 @@ export default [ // disallow use of the Array constructor "@typescript-eslint/no-array-constructor": "warn", + // disallow if as the only statement in an else block + // https://eslint.org/docs/rules/no-lonely-if + "no-lonely-if": "warn", + // disallow un-paren'd mixes of different operators // https://eslint.org/docs/rules/no-mixed-operators "@stylistic/no-mixed-operators": [ diff --git a/src/lib/assets/icon.opt.svg b/src/lib/assets/icon.opt.svg deleted file mode 100644 index c31cd4e..0000000 --- a/src/lib/assets/icon.opt.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/lib/assets/icon.png b/src/lib/assets/icon.png deleted file mode 100644 index 33a689f..0000000 Binary files a/src/lib/assets/icon.png and /dev/null differ diff --git a/src/lib/assets/icon.svg b/src/lib/assets/icon.svg deleted file mode 100644 index 3311f23..0000000 --- a/src/lib/assets/icon.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/lib/components/filter/Autocomplete.svelte b/src/lib/components/filter/Autocomplete.svelte index bbcfd30..05badf5 100644 --- a/src/lib/components/filter/Autocomplete.svelte +++ b/src/lib/components/filter/Autocomplete.svelte @@ -13,7 +13,7 @@ import IconButton from "$lib/components/ui/IconButton.svelte"; import outclick from "$lib/actions/outclick"; - import type { BaseItem, OnSelectResult } from "./types"; + import type { BaseItem } from "./types"; /** * This is a simplified version of simple-svelte-autocomplete @@ -23,6 +23,7 @@ */ type T = $$Generic; + type OnSelectResult = { newValue: string; close: boolean }; /** List of items to choose from (or an async function fetching them) */ export let items: T[] | (() => Promise); @@ -57,7 +58,6 @@ export let filterFn: (item: T) => boolean = () => true; /** Selection callback. Returns the new input value after selection */ - export let onTextInput: (value: string) => OnSelectResult | void = () => {}; export let onSelect: (item: T, kb: boolean) => OnSelectResult | void = () => {}; export let onUnselect = (): void => {}; export let onClose = (kb: boolean): void => {}; @@ -267,13 +267,6 @@ function selectItem(): void { const listItem = filteredItems[highlightIndex]; selectListItem(listItem, true); - if (!listItem && inputElm && inputElm.value.length > 0) { - const res = onTextInput(inputElm.value); - if (res) { - setInputValue(res.newValue); - if (res.close) close(true); - } - } } const [floatingRef, floatingContent] = createFloatingActions({ diff --git a/src/lib/components/filter/FilterChip.svelte b/src/lib/components/filter/FilterChip.svelte index 50bac86..1f76870 100644 --- a/src/lib/components/filter/FilterChip.svelte +++ b/src/lib/components/filter/FilterChip.svelte @@ -33,14 +33,6 @@ else onRemove(); } - const onTextInput = filter.textToItem ? (text: string) => { - const res = filter.textToItem!(text); - if (res) { - fdata.selection = res; - return { close: true, newValue: "" }; - } - } : undefined; - $: if (fdata.editing && autocomplete) { autocomplete.open(); } @@ -99,7 +91,6 @@ } return { close: false, newValue: item.name ?? "" }; }} - {onTextInput} padding={false} partOfFilterbar selection={fdata.selection?.id diff --git a/src/lib/components/filter/filters.ts b/src/lib/components/filter/filters.ts index 50dac8a..905e389 100644 --- a/src/lib/components/filter/filters.ts +++ b/src/lib/components/filter/filters.ts @@ -28,7 +28,7 @@ export function weekFilterItems(): BaseItem[] { res.push({ id: r.toString(), name: r.format() }); }; - addRange(new DateRange(null, range.end)); + addRange(new DateRange(null, range.start)); for (let i = 0; i < WEEK_LIMIT; i++) { addRange(range); range.addDays(7); @@ -104,16 +104,10 @@ export const ENTRY_FILTERS: Record = { }, date: { id: "date", - name: "Datum", + name: "Woche", icon: mdiCalendar, inputType: InputType.FilterList, options: async () => weekFilterItems(), - textToItem: (s) => { - const parsed = DateRange.parseHuman(s); - if (parsed) { - return { id: parsed.toString(), name: parsed.format() }; - } - }, }, }; diff --git a/src/lib/components/filter/types.ts b/src/lib/components/filter/types.ts index cc3eb6b..a5128e3 100644 --- a/src/lib/components/filter/types.ts +++ b/src/lib/components/filter/types.ts @@ -28,7 +28,6 @@ export type FilterDef = { icon?: string; }; options?: () => Promise; - textToItem?: (s: string) => BaseItem | void; }; export type FilterData = { @@ -42,8 +41,6 @@ export type FilterQdata = Record< string | number | boolean | { id: string | number; name?: string }[] >; -export type OnSelectResult = { newValue: string; close: boolean }; - export function isFilterValueless(inputType: InputType): boolean { return inputType === InputType.None || inputType === InputType.Boolean; } diff --git a/src/lib/components/ui/EntryCard.svelte b/src/lib/components/ui/EntryCard.svelte index eff1442..409c5db 100644 --- a/src/lib/components/ui/EntryCard.svelte +++ b/src/lib/components/ui/EntryCard.svelte @@ -18,12 +18,6 @@ {#if entry.current_version.priority}
Priorität
{/if} - {#if entry.execution && !entry.execution.done} -
Notiz
- {/if} - {#if entry.patient.room} -
{entry.patient.room.name}
- {/if} {formatPatientName(entry.patient)} diff --git a/src/lib/components/ui/PaginationButtons.svelte b/src/lib/components/ui/PaginationButtons.svelte index f6133da..3e49d40 100644 --- a/src/lib/components/ui/PaginationButtons.svelte +++ b/src/lib/components/ui/PaginationButtons.svelte @@ -4,21 +4,14 @@ } from "@mdi/js"; import { PAGINATION_LIMIT } from "$lib/shared/constants"; - import type { PaginationRequest } from "$lib/shared/model"; + import type { Pagination, PaginationRequest } from "$lib/shared/model"; import { screenWidthSmall } from "$lib/stores"; import Icon from "./Icon.svelte"; - type PaginationX = { - items?: unknown[]; - nItems?: number; - total: number; - offset: number; - }; - export let paginationData: PaginationRequest | null | undefined; - export let data: PaginationX; + export let data: Pagination; export let onUpdate: (pagination: PaginationRequest) => void = () => {}; $: limit = paginationData?.limit ?? PAGINATION_LIMIT; @@ -59,7 +52,7 @@

- {data.offset + 1}-{data.offset + (data.items?.length ?? data.nItems ?? 0)} von {data.total} + {data.offset + 1}-{data.offset + data.items.length} von {data.total}

diff --git a/src/lib/components/ui/WeekSelector.svelte b/src/lib/components/ui/WeekSelector.svelte index 8bc29b7..ce4008d 100644 --- a/src/lib/components/ui/WeekSelector.svelte +++ b/src/lib/components/ui/WeekSelector.svelte @@ -1,13 +1,11 @@
- addDays(true, false)} /> - addDays(false, false)} /> - -
- {#if editing} - weekFilterItems()} - noAutoselect1 - onClose={stopEditing} - onSelect={(item) => { - if (typeof item.id === "string") { - const parsed = DateRange.parse(item.id); - if (parsed) dateRange = parsed; - onSelect(dateRange); - } - return { close: true, newValue: "" }; - }} - {onTextInput} - partOfFilterbar - selection={{ id: dateRange.toString(), name: dateRange.format() }} /> - {:else} - - {/if} -
- - addDays(false, true)} /> - addDays(true, true)} /> + + {#if editing} + weekFilterItems()} + onClose={stopEditing} + onSelect={(item) => { + if (typeof item.id === "string") { + const parsed = DateRange.parse(item.id); + if (parsed) dateRange = parsed; + onSelect(dateRange); + } + return { close: true, newValue: "" }; + }} + partOfFilterbar + selection={{ id: dateRange.toString(), name: dateRange.format() }} /> + {:else} + + {/if} +
diff --git a/src/lib/shared/model/validation.ts b/src/lib/shared/model/validation.ts index bde6428..95e9d47 100644 --- a/src/lib/shared/model/validation.ts +++ b/src/lib/shared/model/validation.ts @@ -153,9 +153,7 @@ export const ZEntriesFilter = returnDataInSameOrderAsPassed(z }) .partial()); -export const ZEntriesQuery = paginatedQuery(ZEntriesFilter).extend({ - group: z.string().optional(), -}); +export const ZEntriesQuery = paginatedQuery(ZEntriesFilter); export const ZPatientsFilter = returnDataInSameOrderAsPassed(z .object({ diff --git a/src/lib/shared/util/date.test.ts b/src/lib/shared/util/date.test.ts index 38c0401..eca9cc9 100644 --- a/src/lib/shared/util/date.test.ts +++ b/src/lib/shared/util/date.test.ts @@ -1,14 +1,7 @@ import { expect, it, vi } from "vitest"; import { - DateRange, - dateFromHuman, - dateFromYMD, - dateToYMD, - formatDate, - humanDate, - shiftDateRange, - utcDateToYMD, + DateRange, dateFromYMD, dateToYMD, formatDate, humanDate, utcDateToYMD, } from "./date"; const MINUTE = 60000; @@ -79,64 +72,3 @@ it.each([ expect(res.toString()).toBe(s); } }); - -it.each([ - // Open ranges - { - r: "..2024-04-14", week: true, fwd: true, exp: "2024-04-15..2024-04-21", - }, - { - r: "..2024-04-14", week: true, fwd: false, exp: "2024-04-08..2024-04-14", - }, - { - r: "2024-04-08..", week: true, fwd: true, exp: "2024-04-08..2024-04-14", - }, - { - r: "2024-04-08..", week: true, fwd: false, exp: "2024-04-01..2024-04-07", - }, - // Full week - { - r: "2024-04-08..2024-04-14", week: true, fwd: true, exp: "2024-04-15..2024-04-21", - }, - { - r: "2024-04-08..2024-04-14", week: true, fwd: false, exp: "2024-04-01..2024-04-07", - }, - // Partial week - { - r: "2024-04-13..2024-04-16", week: true, fwd: true, exp: "2024-04-15..2024-04-21", - }, - { - r: "2024-04-13..2024-04-16", week: true, fwd: false, exp: "2024-04-08..2024-04-14", - }, - - // Days - { - r: "2024-04-13..2024-04-13", week: false, fwd: true, exp: "2024-04-14..2024-04-14", - }, - { - r: "2024-04-13..2024-04-13", week: false, fwd: false, exp: "2024-04-12..2024-04-12", - }, - // Full range to day - { - r: "2024-04-08..2024-04-14", week: false, fwd: true, exp: "2024-04-14..2024-04-14", // TODO: inc date (15) - }, - { - r: "2024-04-08..2024-04-14", week: false, fwd: false, exp: "2024-04-08..2024-04-08", // TODO: dec date (7) - }, - // Open range to day - { - r: "..2024-04-14", week: false, fwd: true, exp: "2024-04-15..2024-04-15", - }, -])("shiftDateRange $r", ({ - r, week, fwd, exp, -}) => { - const range = DateRange.parse(r, true)!; - const expected = DateRange.parse(exp, true); - shiftDateRange(range, week, fwd); - expect(range).toStrictEqual(expected); -}); - -it("dateFromHuman", () => { - expect(dateFromHuman("04.12.2023")).toStrictEqual(new Date(2023, 11, 4)); - expect(dateFromHuman("04.12.")).toStrictEqual(new Date(new Date().getFullYear(), 11, 4)); -}); diff --git a/src/lib/shared/util/date.ts b/src/lib/shared/util/date.ts index 731ea29..1e21442 100644 --- a/src/lib/shared/util/date.ts +++ b/src/lib/shared/util/date.ts @@ -42,22 +42,6 @@ export function dateFromYMD(s: string): Date { return NaN; } -export function dateFromHuman(s: string): Date { - const parts = s.split(".").filter((x) => x.length > 0).map((x) => parseInt(x)); - if (parts.length > 0 && parts.length < 4) { - const [d, m, y] = parts; - const now = new Date(); - return new Date( - // eslint-disable-next-line no-nested-ternary - y ? y < 1000 ? y + 2000 : y : now.getFullYear(), - m ? m - 1 : now.getMonth(), - d, - ); - } - // @ts-expect-error emulate behavior of date constructor - return NaN; -} - /** Convert the given date to a string (using the internal UTC format) */ export function utcDateToYMD(date: Date): string { return date.toISOString().slice(0, 10); @@ -77,25 +61,19 @@ function dateDiffInDays(a: Date, b: Date): number { return Math.round((ts2 - ts1) / MS_PER_DAY); } -export function humanDate(date: Date | string, time = false, cap = false): string { +export function humanDate(date: Date | string, time = false): string { const now = new Date(); const dt = coerceDate(date); const threshold = 302400000; // 3.5 * 24 * 3_600_000 const diff = Number(dt) - Number(now); // pos: Future, neg: Past - if (Math.abs(diff) > threshold) { - const datestr = formatDate(date, time); - return cap ? datestr : "am" + datestr; - } + if (Math.abs(diff) > threshold) return `am ${formatDate(date, time)}`; const intl = new Intl.RelativeTimeFormat(LOCALE); - const outstr = cap ? (s: string) => { - return s.charAt(0).toUpperCase() + s.slice(1); - } : (s: string) => s; const diffDays = dateDiffInDays(now, dt); if (diffDays !== 0) { - if (diffDays === 1) return outstr("morgen"); - if (diffDays === -1) return outstr("gestern"); + if (diffDays === 1) return "morgen"; + if (diffDays === -1) return "gestern"; return intl.format(diffDays, "day"); } @@ -107,7 +85,7 @@ export function humanDate(date: Date | string, time = false, cap = false): strin if (diffMinutes !== 0) return intl.format(diffMinutes, "minute"); } - return outstr(time ? "jetzt gerade" : "heute"); + return time ? "jetzt gerade" : "heute"; } export class DateRange { @@ -128,19 +106,14 @@ export class DateRange { return new DateRange(start, end); } - /** Get a date range of the week containing the given date */ - static weekOf(day: Date, offset = 0): DateRange { - const thisDay = new Date(day); - const todayWd = thisDay.getDay(); - // Day starts at Sunday (0) - const daysMinus = (todayWd === 0 ? 6 : todayWd - 1) - offset * 7; - thisDay.setDate(thisDay.getDate() - daysMinus); - return DateRange.withLength(thisDay, 6); - } - /** Create a date range of the current calendar week */ static thisWeek(): DateRange { - return DateRange.weekOf(new Date()); + const dayStart = new Date(); + const todayWd = dayStart.getDay(); + // Day starts at Sunday (0) + const daysMinus = todayWd === 0 ? 6 : todayWd - 1; + dayStart.setDate(dayStart.getDate() - daysMinus); + return DateRange.withLength(dayStart, 6); } /** Parse a date range from a string @@ -151,23 +124,10 @@ export class DateRange { * - Range with 1 end: `2024-04-13..`; `..2024-04-20` */ static parse(s: string, utc = false): DateRange | null { - return DateRange.parseInternal(s, "..", (p) => utc ? new Date(p) : dateFromYMD(p)); - } - - /** Parse a date range from human input */ - static parseHuman(s: string): DateRange | null { - return DateRange.parseInternal(s, "-", dateFromHuman); - } - - private static parseInternal( - s: string, - split: string | RegExp, - dateParser: (s: string) => Date, - ): DateRange | null { - const parts = s.split(split, 2); + const parts = s.split("..", 2); const parsed = parts.map((p) => { if (p.length === 0) return null; - return dateParser(p); + return utc ? new Date(p) : dateFromYMD(p); }); if (parsed.length === 0 @@ -185,8 +145,8 @@ export class DateRange { /** Shift the range by the given number of days. This modifies the range in-place */ addDays(n: number): void { - this.start?.setUTCDate(this.start.getUTCDate() + n); - this.end?.setUTCDate(this.end.getUTCDate() + n); + this.start?.setDate(this.start.getDate() + n); + this.end?.setDate(this.end.getDate() + n); } /** Return a parsable string representation */ @@ -202,54 +162,6 @@ export class DateRange { format(): string { if (this.start === null) return "bis " + formatDate(this.end!); if (this.end === null) return "ab " + formatDate(this.start); - if (this.start.getFullYear() === this.end.getFullYear() - && this.start.getMonth() === this.end.getMonth() - && this.start.getDate() === this.end.getDate()) return formatDate(this.start); return formatDate(this.start) + " \u2013 " + formatDate(this.end); } - - eq(b: DateRange): boolean { - return dateEq(this.start, b.start) && dateEq(this.end, b.end); - } -} - -function dateEq(d1: Date | null, d2: Date | null): boolean { - if (!d1 || !d2) return d1 === d2; - return d1.getUTCFullYear() === d2.getUTCFullYear() - && d1.getUTCMonth() === d2.getUTCMonth() - && d1.getUTCDate() === d2.getUTCDate(); -} - -export function shiftDateRange(dateRange: DateRange, week: boolean, fwd: boolean) { - let modDir = null; - if (dateRange.start === null) { - dateRange.start = new Date(dateRange.end!); - modDir = true; - } - if (dateRange.end === null) { - dateRange.end = new Date(dateRange.start!); - modDir = false; - } - - const inc = fwd ? 1 : -1; - const leader = fwd ? dateRange.end : dateRange.start; - - if (week) { - // Align range with week - const lweek = DateRange.weekOf(leader); - if (dateRange.eq(lweek)) { - if (modDir === null || modDir === fwd) dateRange.addDays(inc * 7); - } else { - dateRange.start = lweek.start; - dateRange.end = lweek.end; - if (modDir === fwd) dateRange.addDays(inc * 7); - } - } else { - if (dateEq(dateRange.start, dateRange.end)) { - dateRange.addDays(inc); - } else { - dateRange.start = leader; - dateRange.end = leader; - } - } } diff --git a/src/lib/shared/util/util.test.ts b/src/lib/shared/util/util.test.ts index c1ea818..f94ce78 100644 --- a/src/lib/shared/util/util.test.ts +++ b/src/lib/shared/util/util.test.ts @@ -20,7 +20,7 @@ it("getQueryUrl", () => { }; const queryUrl = getQueryUrl(query, ""); - expect(queryUrl).toBe("?filter%5Bauthor%5D%5B0%5D%5Bid%5D=2&filter%5Bauthor%5D%5B0%5D%5Bname%5D=Max&filter%5Bcategory%5D%5B0%5D%5Bid%5D=1&filter%5Bcategory%5D%5B0%5D%5Bname%5D=Blutabnahme&filter%5Bcategory%5D%5B1%5D%5Bid%5D=2&filter%5Bcategory%5D%5B1%5D%5Bname%5D=Labortests&filter%5Bdone%5D=true&filter%5Bsearch%5D=Hello%20World&pagination%5Blimit%5D=10&pagination%5Boffset%5D=20&sort%5B0%5D=room"); + expect(queryUrl).toBe("?filter%5Bauthor%5D%5B0%5D%5Bid%5D=2&filter%5Bauthor%5D%5B0%5D%5Bname%5D=Max&filter%5Bcategory%5D%5B0%5D%5Bid%5D=1&filter%5Bcategory%5D%5B0%5D%5Bname%5D=Blutabnahme&filter%5Bcategory%5D%5B1%5D%5Bid%5D=2&filter%5Bcategory%5D%5B1%5D%5Bname%5D=Labortests&filter%5Bdone%5D=true&filter%5Bsearch%5D=Hello%20World&pagination%5Blimit%5D=10&pagination%5Boffset%5D=20&sort%5Bfield%5D=room&sort%5Basc%5D=true"); const decoded = ZEntriesQuery.parse(parseQueryUrl(queryUrl)); expect(decoded).toStrictEqual(query); diff --git a/src/lib/shared/util/util.ts b/src/lib/shared/util/util.ts index 33204f1..afe25b4 100644 --- a/src/lib/shared/util/util.ts +++ b/src/lib/shared/util/util.ts @@ -161,7 +161,7 @@ export function defaultVisitUrl(): string { export async function moveEntryTodoDate(id: number, nTodoDays: number, init?: TRPCClientInit) { if (nTodoDays > 0) { const entry = await trpc(init).entry.get.query(id); - const newDate = new Date(); + const newDate = new Date(entry.current_version.date); newDate.setDate(newDate.getDate() + nTodoDays); await trpc(init).entry.newVersion.mutate({ diff --git a/src/routes/(app)/about/+page.svelte b/src/routes/(app)/about/+page.svelte index 57482f6..0ef0423 100644 --- a/src/routes/(app)/about/+page.svelte +++ b/src/routes/(app)/about/+page.svelte @@ -1,6 +1,4 @@
-

Visitenbuch

Version: {version}

Letzte Änderung: {lastmod}

diff --git a/src/routes/(app)/entry/[id]/+page.server.ts b/src/routes/(app)/entry/[id]/+page.server.ts index 49aa997..bfd54cc 100644 --- a/src/routes/(app)/entry/[id]/+page.server.ts +++ b/src/routes/(app)/entry/[id]/+page.server.ts @@ -7,7 +7,7 @@ import { ZUrlEntityId } from "$lib/shared/model/validation"; import { trpc } from "$lib/shared/trpc"; import { loadWrap, moveEntryTodoDate } from "$lib/shared/util"; -import { SchemaNewExecution } from "./schema"; +import { SchemaNewExecution } from "./editExecution/schema"; export const actions: Actions = { default: async (event) => loadWrap(async () => { diff --git a/src/routes/(app)/entry/[id]/+page.svelte b/src/routes/(app)/entry/[id]/+page.svelte index 6828514..8da72e7 100644 --- a/src/routes/(app)/entry/[id]/+page.svelte +++ b/src/routes/(app)/entry/[id]/+page.svelte @@ -10,7 +10,7 @@ import EntryTodoButton from "$lib/components/ui/EntryTodoButton.svelte"; import MarkdownInput from "$lib/components/ui/markdown/MarkdownInput.svelte"; - import { SchemaNewExecution } from "./schema"; + import { SchemaNewExecution } from "./editExecution/schema"; export let data: PageData; diff --git a/src/routes/(app)/entry/[id]/+page.ts b/src/routes/(app)/entry/[id]/+page.ts index 98499b7..3e48be4 100644 --- a/src/routes/(app)/entry/[id]/+page.ts +++ b/src/routes/(app)/entry/[id]/+page.ts @@ -6,7 +6,7 @@ import { ZUrlEntityId } from "$lib/shared/model/validation"; import { trpc } from "$lib/shared/trpc"; import { loadWrap } from "$lib/shared/util"; -import { SchemaNewExecution } from "./schema"; +import { SchemaNewExecution } from "./editExecution/schema"; export const load: PageLoad = async (event) => { const entry = await loadWrap(async () => { diff --git a/src/routes/(app)/entry/[id]/editExecution/+page.server.ts b/src/routes/(app)/entry/[id]/editExecution/+page.server.ts index 92b9b6c..2fd0dbe 100644 --- a/src/routes/(app)/entry/[id]/editExecution/+page.server.ts +++ b/src/routes/(app)/entry/[id]/editExecution/+page.server.ts @@ -7,7 +7,7 @@ import { ZUrlEntityId } from "$lib/shared/model/validation"; import { trpc } from "$lib/shared/trpc"; import { loadWrap, moveEntryTodoDate } from "$lib/shared/util"; -import { SchemaNewExecution } from "../schema"; +import { SchemaNewExecution } from "./schema"; export const actions: Actions = { default: async (event) => loadWrap(async () => { diff --git a/src/routes/(app)/entry/[id]/editExecution/+page.svelte b/src/routes/(app)/entry/[id]/editExecution/+page.svelte index d67ec0f..6815372 100644 --- a/src/routes/(app)/entry/[id]/editExecution/+page.svelte +++ b/src/routes/(app)/entry/[id]/editExecution/+page.svelte @@ -10,7 +10,7 @@ import EntryTodoButton from "$lib/components/ui/EntryTodoButton.svelte"; import MarkdownInput from "$lib/components/ui/markdown/MarkdownInput.svelte"; - import { SchemaNewExecution } from "../schema"; + import { SchemaNewExecution } from "./schema"; export let data: PageData; diff --git a/src/routes/(app)/entry/[id]/editExecution/+page.ts b/src/routes/(app)/entry/[id]/editExecution/+page.ts index dcaced1..98499b7 100644 --- a/src/routes/(app)/entry/[id]/editExecution/+page.ts +++ b/src/routes/(app)/entry/[id]/editExecution/+page.ts @@ -6,7 +6,7 @@ import { ZUrlEntityId } from "$lib/shared/model/validation"; import { trpc } from "$lib/shared/trpc"; import { loadWrap } from "$lib/shared/util"; -import { SchemaNewExecution } from "../schema"; +import { SchemaNewExecution } from "./schema"; export const load: PageLoad = async (event) => { const entry = await loadWrap(async () => { diff --git a/src/routes/(app)/entry/[id]/editExecution/schema.ts b/src/routes/(app)/entry/[id]/editExecution/schema.ts new file mode 100644 index 0000000..dd65863 --- /dev/null +++ b/src/routes/(app)/entry/[id]/editExecution/schema.ts @@ -0,0 +1,9 @@ +import { zod } from "sveltekit-superforms/adapters"; + +import { ZEntryExecutionNew, fields } from "$lib/shared/model/validation"; + +export const SchemaNewExecution = zod( + ZEntryExecutionNew.extend({ + old_execution_id: fields.EntityId().optional(), + }), +); diff --git a/src/routes/(app)/entry/[id]/schema.ts b/src/routes/(app)/entry/[id]/schema.ts index dd65863..5613684 100644 --- a/src/routes/(app)/entry/[id]/schema.ts +++ b/src/routes/(app)/entry/[id]/schema.ts @@ -1,9 +1,10 @@ import { zod } from "sveltekit-superforms/adapters"; +import { z } from "zod"; -import { ZEntryExecutionNew, fields } from "$lib/shared/model/validation"; +import { fields } from "$lib/shared/model/validation"; -export const SchemaNewExecution = zod( - ZEntryExecutionNew.extend({ - old_execution_id: fields.EntityId().optional(), - }), -); +const ZEntryDone = z.object({ + text: fields.TextString(), +}); + +export const SchemaEntryExecution = zod(ZEntryDone); diff --git a/src/routes/(app)/visit/+page.svelte b/src/routes/(app)/visit/+page.svelte index 08aa4fe..ef23819 100644 --- a/src/routes/(app)/visit/+page.svelte +++ b/src/routes/(app)/visit/+page.svelte @@ -3,18 +3,13 @@ import { goto } from "$app/navigation"; import type { PageData } from "./$types"; - import { mdiCalendar, mdiDomain } from "@mdi/js"; - import { URL_VISIT } from "$lib/shared/constants"; import type { PaginationRequest, Station } from "$lib/shared/model"; import { trpc } from "$lib/shared/trpc"; - import { - DateRange, dateFromYMD, getQueryUrl, humanDate, - } from "$lib/shared/util"; + import { DateRange, getQueryUrl } from "$lib/shared/util"; import Autocomplete from "$lib/components/filter/Autocomplete.svelte"; import EntryCard from "$lib/components/ui/EntryCard.svelte"; - import IconButton from "$lib/components/ui/IconButton.svelte"; import PaginationButtons from "$lib/components/ui/PaginationButtons.svelte"; import WeekSelector from "$lib/components/ui/WeekSelector.svelte"; @@ -45,12 +40,9 @@ selection = null; } - $: groupByStation = data.query.group === "station"; - function paginationUpdate(pagination: PaginationRequest): void { updateQuery({ filter: data.query.filter, - group: data.query.group, pagination, }); } @@ -62,14 +54,6 @@ station: selection ? [selection] : undefined, date: dateRange ? [{ id: dateRange.toString() }] : undefined, }, - group: data.query.group, - }); - } - - function toggleGroup(): void { - updateQuery({ - ...data.query, - group: groupByStation ? undefined : "station", }); } @@ -90,53 +74,30 @@
- + Woche:
-
-
- Gruppierung: - -
-
- Station: - trpc().station.list.query()} - onSelect={filterUpdate} - onUnselect={filterUpdate} - bind:selection /> -
+
+ Station: + trpc().station.list.query()} + onSelect={filterUpdate} + onUnselect={filterUpdate} + bind:selection />
- {#each data.groups as group} - {@const first = group.items[0] ?? group.prio[0]} -
- {#if data.groupByStation} - {#if first.patient.room} - Station {first.patient.room?.station.name} - {:else} - Keine Station - {/if} - {:else} - {humanDate(dateFromYMD(first.current_version.date), false, true)} - {/if} -
- {#each group.prio as entry} - - {/each} - {#each group.items as entry} - - {/each} + {#each data.entries.items as entry} + {/each}
diff --git a/src/routes/(app)/visit/+page.ts b/src/routes/(app)/visit/+page.ts index b5baeec..b3c727a 100644 --- a/src/routes/(app)/visit/+page.ts +++ b/src/routes/(app)/visit/+page.ts @@ -4,16 +4,9 @@ import { redirect } from "@sveltejs/kit"; import { z } from "zod"; import { ZEntriesQuery } from "$lib/shared/model/validation"; -import { trpc, type RouterOutput } from "$lib/shared/trpc"; +import { trpc } from "$lib/shared/trpc"; import { defaultVisitUrl, loadWrap, parseQueryUrl } from "$lib/shared/util"; -type EntryItems = RouterOutput["entry"]["list"]["items"]; -type EntryItem = EntryItems[0]; -type EntryGroup = { - items: EntryItems, - prio: EntryItems, -}; - export const load: PageLoad = async (event) => { return loadWrap(async () => { let query: z.infer = {}; @@ -27,49 +20,20 @@ export const load: PageLoad = async (event) => { redirect(302, defaultVisitUrl()); } - const groupByStation = query.group === "station"; - // Sort entries by date - query.sort = ["date", "room"]; - if (groupByStation) query.sort.reverse(); + if (!query.sort) { + query.sort = ["priority:dsc", "date"]; + } const entries = await trpc(event).entry.list.query(query); - // Group items by date - const getGroupKey = groupByStation - ? (e: EntryItem) => e.patient.room?.station.id - : (e: EntryItem) => e.current_version.date; - - const groups: EntryGroup[] = []; - let dg = null; - let items: EntryItems = []; - let prio: EntryItems = []; - - for (const entry of entries.items) { - // New group - if (getGroupKey(entry) !== dg) { - dg = getGroupKey(entry); - if (items.length > 0 || prio.length > 0) { - groups.push({ items, prio }); - items = []; - prio = []; - } + // Move prioritized items to the front + entries.items.forEach((itm, i) => { + if (itm.current_version.priority) { + entries.items.unshift(entries.items.splice(i, 1)[0]); } - if (entry.current_version.priority) { - prio.push(entry); - } else { - items.push(entry); - } - } - if (items.length > 0 || prio.length > 0) { - groups.push({ items, prio }); - } + }); - return { - query, - groups, - pagination: { offset: entries.offset, total: entries.total, nItems: entries.items.length }, - groupByStation, - }; + return { query, entries }; }); }; diff --git a/static/favicon.png b/static/favicon.png index 33a689f..825b9e6 100644 Binary files a/static/favicon.png and b/static/favicon.png differ