refactor(frontend): utility dedup, component splits, dead code removal (#193–#200) #241

Merged
marcel merged 19 commits from refactor/issues-193-200 into main 2026-04-15 15:23:16 +02:00

19 Commits

Author SHA1 Message Date
Marcel
ed2c0231db test(drag-drop): add reorder logic tests for useBlockDragDrop
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m32s
CI / Backend Unit Tests (push) Failing after 2m34s
CI / Unit & Component Tests (pull_request) Failing after 2m29s
CI / Backend Unit Tests (pull_request) Failing after 2m38s
Adds simulateDragDrop helper and three tests covering the splice/insertAt
index arithmetic in handlePointerUp:
- move-to-end (insertAt path where target > fromIdx)
- move-to-start (insertAt path where target <= fromIdx)
- move-down-by-one (verifies the off-by-one dropTargetIdx - 1 branch)

Fixes @saraholt: "reorder calculation in handlePointerUp is untested"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:20:43 +02:00
Marcel
45490ebaac fix(a11y): increase nav label font size from 9px to 11px in EntityNavSection
text-[9px] is below WCAG practical minimum and unreadable for senior users.
Changed all three occurrences (tablet button count, desktop link label,
flyout link label) to text-[11px].

Fixes @leonievoss: "text-[9px] is below 12px minimum"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:16:37 +02:00
Marcel
7fb6ec04ab fix(i18n): replace hardcoded German edit hint in CommentMessage with Paraglide key
Adds comment_edit_hint key to de/en/es message files and replaces the
hardcoded "Enter speichern · Esc abbrechen" string in CommentMessage.svelte.

Fixes @felixbrandt + @leonievoss: "hardcoded German bypasses Paraglide"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:14:14 +02:00
Marcel
8739511058 test(notifications): add SSE event handling tests for useNotificationStream
Adds MockEventSource.simulate() helper and two tests covering:
- unread notification via SSE prepends to list and increments unreadCount
- read notification via SSE adds to list but does not increment unreadCount

Fixes @saraholt: "SSE event handling not tested"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:09:26 +02:00
Marcel
2b93ccf92d refactor(notifications): import relativeTime from canonical time.ts
NotificationDropdown was importing relativeTime through notifications.ts,
creating an accidental coupling to a module unrelated to timestamp formatting.
Now imports directly from the canonical \$lib/utils/time module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:06:26 +02:00
Marcel
ff9ae198c4 refactor(notifications): extract useNotificationStream and NotificationDropdown from NotificationBell (#200)
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m38s
CI / Backend Unit Tests (push) Failing after 2m50s
CI / Unit & Component Tests (pull_request) Failing after 2m30s
CI / Backend Unit Tests (pull_request) Failing after 2m48s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 14:54:55 +02:00
Marcel
8898863a48 refactor(transcription): extract useBlockAutoSave and useBlockDragDrop from TranscriptionEditView (#199)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 14:45:03 +02:00
Marcel
eb8aa92cf0 refactor(pdf): extract usePdfRenderer and PdfControls from PdfViewer (#196)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 14:34:26 +02:00
Marcel
bc3fec11a9 refactor(comments): extract CommentMessage component from CommentThread (#198)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 14:23:25 +02:00
Marcel
fe6c247882 refactor(admin): extract EntityNavSection to eliminate nav markup repetition (#197)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:54:42 +02:00
Marcel
accfa5373e refactor(unsaved): extract createUnsavedWarning hook and UnsavedWarningBanner
Move the identical isDirty / beforeNavigate / discard pattern out of the
three admin detail pages (groups, tags, users) into a reusable
createUnsavedWarning() hook and a UnsavedWarningBanner presentational
component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:31:17 +02:00
Marcel
34e7436fdc refactor(fileloader): extract createFileLoader hook from document/enrich pages
Move blob URL lifecycle management into a reusable createFileLoader()
hook that owns revoke-before-create and revoke-on-destroy. Replace
identical inline logic in documents/[id] and enrich/[id] with the hook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:20:32 +02:00
Marcel
dbf7f0bc16 fix(fileloader): revoke blob URLs before re-assignment and on destroy
Calling loadFile a second time previously leaked the previous object URL.
Add URL.revokeObjectURL(fileUrl) before creating a new one and in
onDestroy so all URLs are freed. Revoke behavior will be covered by the
useFileLoader hook tests in the next commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:13:21 +02:00
Marcel
8be876492c refactor(date): consolidate formatDate in date.ts with optional format param
Add format?: 'short'|'long' (default 'long') to date.ts formatDate and
remove the duplicate from personFormat.ts. Update DocumentTopBar to
import from date.ts directly. Move the formatDate tests from
personFormat.spec to date.spec.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:10:44 +02:00
Marcel
76d6f234b4 refactor(personFormat): replace getInitials(Person) with getInitials(name: string)
Unify the initials-extraction logic: the new string-based getInitials()
splits on whitespace, takes the first char of the first and last word
uppercased — matching the pattern that was already inlined in
CommentThread. Update PersonChip, DocumentMetadataDrawer, and
CommentThread to use the shared function.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:07:23 +02:00
Marcel
655a2003cb refactor(time): extract relativeTime into shared time.ts utility
Move relativeTime from notifications.ts (Intl.RelativeTimeFormat) to a
new time.ts that uses the Paraglide comment_time_* message keys — the
same logic that was already in CommentThread's timeAgo(). Remove the
duplicate timeAgo() from CommentThread and re-export relativeTime from
notifications.ts for backwards compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:02:49 +02:00
Marcel
c50845bcfc refactor(bell): migrate attachClickOutside to use:clickOutside action (#195)
Replace the inline attachClickOutside attachment in NotificationBell with
the shared use:clickOutside action from $lib/actions/clickOutside. The
inline implementation was functionally identical to the existing action.

Guard the onclickoutside handler so it only calls closeDropdown() when
the notification panel is already open, preventing the bell button from
stealing focus from other interactive elements (e.g. the user avatar menu).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 12:55:29 +02:00
Marcel
4446e80875 test(actions): add defaultPrevented coverage for clickOutside (#195)
The action already checks event.defaultPrevented before dispatching
clickoutside, but that branch had no test. Add the missing case and
add a one-line comment explaining why capture phase is used.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 12:46:04 +02:00
Marcel
731cdc75ab refactor(frontend): delete dead conversations/ route (#193)
Remove the old conversations page that was superseded by briefwechsel/.
No navigation link pointed to /conversations; it was unreachable through
the UI. Deletes 5 files, removes 14 orphaned i18n keys from de/en/es
message bundles, and removes E2E tests that navigated to /conversations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 12:43:40 +02:00