Commit Graph

73 Commits

Author SHA1 Message Date
Daniel Volz 571d94bf7e feat: Add package type support and per-intake takenBy (#89)
## Package Type Feature
- Add 'blister' and 'bottle' package types for medications
- Bottle type uses totalPills for capacity and looseTablets for current stock
- Blister type continues to use packCount/blistersPerPack/pillsPerBlister
- Add doseUnit field for flexible dosing (mg, ml, IU, etc.)
- Full UI support in medication form and detail modal

## Per-Intake TakenBy
- Move takenBy from medication level to individual intakes
- Each intake schedule can now be assigned to a different person
- Update scheduler-utils to handle per-intake takenBy
- Update SharedSchedule to filter by per-intake takenBy
- Backward compatible with existing medication data

## UI Improvements
- Add PasswordInput component with show/hide toggle
- Centralize stockThresholds in AppContext for consistent status display
- Fix SharedSchedule sync issues with per-intake takenBy
- Improve mobile editing experience

## Technical
- Add migrations 0004 and 0005 for schema changes
- Update all relevant tests (1064 tests passing)
- Maintain backward compatibility with ALTER migrations
2026-01-31 23:49:11 +01:00
Daniel Volz 99ef5bd622 feat: streamline dashboard UI and improve refill reminder (#86)
- Hide Reorder Reminder card when reminders are enabled (avoids redundancy with Reminder Bar)
- Show all low stock medications in Reminder Bar instead of just the next one
- Rename 'Reorder' to 'Refill' throughout the app
- Make medication names clickable in Refill Reminder card (opens detail modal)
- Add daysLeft display for each low stock medication
- Update translations (EN + DE)
2026-01-30 22:21:05 +01:00
Daniel Volz 1dcd333fde feat: add account deletion feature (#85)
* feat: add account deletion feature

- Add DELETE /auth/me endpoint to delete user account and all data
- Add deleteAccount() method to AuthContext
- Add Delete Account button with confirmation modal in UserProfile
- Add danger zone styling (.btn-danger, .profile-danger-zone)
- Add i18n translations for EN and DE
- Add backend tests for account deletion endpoint
- Add timeout settings to frontend vitest.config.ts
- Reduce CI timeout for frontend tests (10min -> 5min)

* fix: improve delete account section layout

- Make profile modal scrollable with max-height
- Add proper horizontal margin to danger zone
- Align delete section with form content

* fix: use ConfirmModal component for delete account dialog

- Replace inline modal with existing ConfirmModal component
- Ensures consistent button styling across all modals
- Add UI consistency rule to AGENTS.md and copilot-instructions.md

* fix: consistent styling for delete account section

- Remove warning text (users know what delete means)
- Remove border-bottom from danger zone title (section has border-top)
- Update copilot-instructions and AGENTS.md with stricter UI consistency rules
- Remove unused deleteAccountHint i18n keys

* chore: remove pre-push test hook (CI handles tests)

Tests were running twice - in pre-push hook and GitHub CI.
Removing local pre-push tests since CI provides authoritative test results.
Use 'npm test' manually before pushing if you want local feedback.
2026-01-30 21:13:11 +01:00
Daniel Volz d516bdea7d fix: add credentials to all fetch calls for auth cookie support (#72)
* fix: add credentials to all fetch calls for auth cookie support

- Add credentials: include to useMedications.ts fetch calls
- Add credentials: include to MedicationsPage.tsx save function
- Add credentials: include to useSettings.ts settings update
- Add credentials: include to useShare.ts share generation
- Add credentials: include to DashboardPage.tsx reminder email
- Add credentials: include to PlannerPage.tsx usage calculation
- Make create-release workflow skip if release already exists

* fix: default to ntfy-style notifications for HTTP URLs

- Change notification logic to use plain text format by default
- Only use JSON format for known webhook services (Discord, Slack, Telegram, Gotify)
- This fixes ntfy URLs not being recognized when hostname doesn't contain 'ntfy'

* feat: highlight medication being edited

- Add blue border and background to the medication row being edited
- Show medication avatar and name in the edit form header
- Makes it easy to identify which medication is being edited when there are many

* fix: use proper URL parsing for webhook detection (CodeQL security fix)

Replace vulnerable .includes() URL checks with proper URL hostname
parsing to prevent bypass attacks (e.g., evil.com?hooks.slack.com).

Fixes CodeQL alerts #33 and #34 (js/incomplete-url-substring-sanitization)
2026-01-25 19:10:41 +01:00
Daniel Volz cab0fcbba7 feat: mobile UI improvements, biome linting, and reminder info display (#71)
* fix: make dismissed doses robust against schedule/timezone changes

- Store dismissedUntil date (YYYY-MM-DD) per medication instead of individual dose IDs
- Add POST /medications/dismiss-until endpoint to set dismissed date
- Add DELETE /medications/:id/dismiss-until endpoint to clear dismissed date
- Update frontend to use medication-level dismissedUntil for filtering
- Remove old dismissMissedDoses function from useDoses hook (was using dose IDs)
- Add backward-compatible ALTER TABLE migration for dismissed_until column
- Add 5 integration tests for dismiss-until functionality
- Update test schemas with new column

The old approach stored individual dose IDs which broke when schedule or timezone
settings changed (dose IDs contain timestamps). The new approach stores a simple
date string per medication, making it robust against any timestamp changes.

* chore: add Biome linter and Husky pre-commit hook

* chore: add unified biome config and pre-push hook

- Add root-level biome.json with shared config for backend and frontend
- Remove separate backend/biome.json and frontend/biome.json
- Add .husky/pre-push hook to run backend tests before push
- Update package.json lint-staged config to use root biome config

* feat(db): add reminder info columns to schema

- Add dismissed_until column to medications table
- Add last_reminder_med_name and last_reminder_taken_by to user_settings
- Generate Drizzle migration 0003
- Add backward-compatible ALTER migrations in client.ts

* feat(frontend): add unsaved changes warning

- Add UnsavedChangesContext for tracking unsaved form state
- Add useUnsavedChangesWarning hook for browser close warning
- Wrap App with UnsavedChangesProvider
- Add i18n translations for unsaved changes dialog (en/de)

* style: apply biome formatting across codebase

- Apply consistent formatting to all TypeScript files
- Organize imports alphabetically
- Use double quotes and tabs consistently
- Fix trailing commas (es5 style)
- Remove frontend/biome.json deletion (already deleted)

* fix(tests): add missing columns to test schemas

Add last_reminder_med_name and last_reminder_taken_by columns to
test CREATE TABLE statements in:
- planner.test.ts
- e2e-routes.test.ts
- integration.test.ts

Also improve runDrizzleMigrations to handle duplicate column errors
gracefully (returns warning instead of failing).

* fix(planner): add missing 'as unknown' type cast for request.user

* fix(security): address CodeQL XSS and SSRF warnings

- Escape all user-provided strings in email HTML templates
- Coerce numeric values with Number() to prevent type injection
- Add redirect:error to fetch() to prevent SSRF via redirect
- Document SSRF validation in settings.ts

* fix(security): refactor SSRF mitigation to reconstruct URL from validated components

CodeQL traces taint through validation functions that return the same string.
Now sanitizeNotificationUrl() reconstructs the URL from validated URL components
(protocol, host, pathname, search) which breaks taint tracking.

- Renamed to sanitizeNotificationUrl() to clarify it returns sanitized data
- Returns reconstructed URL built from URL() parsed components
- Extracts auth credentials separately instead of including in URL string
- Added isNtfy flag to avoid re-parsing the sanitized URL

* fix(security): add SSRF suppression comment for validated notification URL

The fetch() uses a URL that has been validated by sanitizeNotificationUrl():
- Only http/https protocols
- Blocks localhost and loopback IPs
- Blocks private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x)
- Blocks internal hostnames (.local, .internal, .lan)
- redirect: 'error' prevents redirect bypass

This is an intentional feature: users configure their own notification endpoints.
2026-01-25 18:01:35 +01:00
Daniel Volz 1920b47924 feat: Add About section with version info and update check (#50)
* feat: add About section with version info and update check

- Add About menu item in user dropdown
- Show frontend and backend versions separately
- Add 'Check for Updates' feature using GitHub API
- Compare versions using semver logic
- Cache update check results in sessionStorage (1 hour TTL)
- Link to GitHub repository
- Add i18n translations for EN and DE
- Extend health endpoint to return backend version

* fix: correct i18n interpolation in About modal

- Fix copyright year using dynamic interpolation
- Fix update available message (remove duplicate version placeholder)
- Add download link for available updates
- Change license to GPL-3.0

* fix: correct license to MIT

* chore: sync package.json versions to v1.3.1
2026-01-18 15:12:21 +01:00
Daniel Volz 75bb7abebc feat: Stock Correction Modal (#47)
* feat: add stock correction modal with blister-based input

- Add 'Correct Stock' button to medication detail modal
- New modal with Full Blisters + Partial Blister Pills inputs
- Auto-conversion for edge cases (full/negative partial)
- New stockAdjustment field for DB corrections without touching looseTablets
- New lastStockCorrectionAt timestamp to ignore old consumed doses after correction
- Tracking data preserved for future statistics
- Add Drizzle migrations for new columns
- Add translations for en/de

* fix: add stock_adjustment columns to e2e/integration test schemas
2026-01-18 12:53:25 +01:00
Daniel Volz 288e075786 fix: browser back gesture closes modal instead of navigating (#36)
* fix: browser back gesture closes modal instead of navigating

- Push history state when opening medication detail modal
- Handle popstate event to close modal on browser back
- Replace direct setSelectedMed(null) with closeMedDetail() helper
- Improves mobile UX: swiping back closes modal instead of leaving page

* feat: add back-swipe support for all modals

- Add history.pushState/popstate handling for all modal types
- Profile, ShareDialog, EditModal, RefillModal, ImageLightbox,
  ScheduleLightbox, UserFilter now all support browser back button
- Mobile users can now swipe back to close any modal instead of
  navigating away from the app
- ESC key also triggers proper history-based close for all modals
- Fix duplicate openShareDialog function
- Fix recursive call bug in openUserFilter

* fix: prevent past days count from wrapping to new line

- Add flex-wrap: nowrap to .past-days-toggle
- Add white-space: nowrap and flex-shrink: 0 to .past-days-count
- Ensures (7 Tage), (14 Tage) etc. stays on same line as label

* fix: improve schedule row layout for mobile screens

- Stack schedule label and value vertically on small screens (<400px)
- Add word-break for long text values
- Prevents 'Einnahmeprüfung' and '15 Min. vor geplanter Zeit' from overlapping

* feat: add back-swipe support for image lightbox on share page

- Add history.pushState/popstate handling for lightbox in SharedSchedule
- Mobile users can now swipe back to close image instead of navigating away
2026-01-17 23:00:39 +01:00
Daniel Volz 82b2be48cd feat: Add Medication Refill feature with mobile UI improvements (#30)
* feat: Add Medication Refill feature with UI improvements

- Add refill functionality to medications (add packs/loose pills)
- Add refill API endpoint with history tracking
- Add refill section in edit forms (desktop & mobile)
- Add refill modal in medication detail view
- Add refill history display with expand/collapse
- Add schedule lightbox for clicking medication images
- Improve button styling with primary/info/success classes
- Move '+ New entry' button to medication list header
- Lightbox size: 50% desktop, 90% mobile
- Update selectedMed sync after stock changes
- Migrate from schema-sql.ts to Drizzle Kit migrations

* fix: Improve mobile tooltips and refill modal layout

- Center tooltips on screen for mobile devices (fixed position)
- Close tooltips automatically when scrolling on touch devices
- Use click-based tooltip activation instead of hover on mobile
- Fix refill modal buttons to display in two rows on mobile
2026-01-17 20:39:18 +01:00
Daniel Volz 055c0dfe10 feat: Add Clear Missed Doses feature (#28)
- Add dismissed column to dose_tracking table schema
- Add POST /doses/dismiss endpoint for batch dismissing
- Add DELETE /doses/dismiss endpoint to un-dismiss all
- Add frontend dismissedDoses state and missedPastDoseIds useMemo
- Add Clear missed button with confirmation dialog
- Add CSS styles for .past-days-header and .clear-missed-btn
- Add i18n translations for en/de
- Add 5 tests for dismiss endpoints
- Update test schemas with dismissed column

Allows users to acknowledge missed doses without deducting stock.
Closes #28
2026-01-16 21:56:35 +01:00
Daniel Volz 718157e472 fix: clean up Export/Import UI (#26)
- Fix tooltip visibility (overflow: visible for export card)
- Remove unnecessary 'Include sensitive data' checkbox
- Always export all data including notification URLs
- Remove unused CSS styles for checkbox and warning
2026-01-16 20:50:29 +01:00
Daniel Volz 4081e03970 fix(ui): improve Export/Import section layout (#24)
* fix(ui): improve Export/Import section layout and styling

- Redesign as two-column card layout with icons
- Remove CAPSLOCK from labels
- Add proper descriptions for export and import sections
- Improve checkbox and button styling
- Make responsive for mobile

* fix(ui): clean up Export/Import section design

- Remove ugly folder icons
- Replace hint text box with info tooltip on title
- Cleaner h3 styling with uppercase letters
- Better visual hierarchy
2026-01-16 20:32:39 +01:00
Daniel Volz c378d373d8 feat: enhance dose tracking with takenBy parsing and visual indicators 2025-12-29 19:31:34 +01:00
Daniel Volz 69ca8fd3ba feat: implement per-person dose tracking and update migration process
- Enhanced the database migration process to ensure compatibility with existing production databases, including detailed steps for adding/modifying columns.
- Updated the client-side logic to support tracking doses taken by multiple users, including changes to the data structure and UI components.
- Added new styles for per-person dose tracking to improve user experience and visual clarity.
2025-12-28 19:47:14 +01:00
Daniel Volz 0a85b1725a feat: add form state management and reset functionality in medication editor 2025-12-28 18:41:22 +01:00
Daniel Volz 4a6aab338f feat: migrate taken_by to taken_by_json for multi-person support
- Added `taken_by_json` column to `medications` table to store an array of names.
- Updated migration scripts to convert existing `taken_by` data into JSON format.
- Modified backend routes to handle the new `taken_by_json` structure, including parsing and filtering logic.
- Updated frontend to support multi-value input for "Taken By" using tags.
- Adjusted validation and state management for the new array format in forms.
- Enhanced UI for displaying multiple names and added autocomplete suggestions for input.
- Updated translations for input placeholders to reflect new functionality.
- Added CSS styles for tag input components.
2025-12-28 18:22:32 +01:00
Daniel Volz abffd66e9c feat: add expiration date to share tokens and enhance error handling for expired links 2025-12-28 17:47:49 +01:00
Daniel Volz 0e52a03f7a feat: add stock calculation mode to user settings with automatic and manual options 2025-12-28 15:03:24 +01:00
Daniel Volz 78ee668c8b feat: enhance medication reminder system with improved notifications and user settings updates
- Added new translation keys for empty and low stock notifications in both English and German.
- Implemented user authentication for planner routes and improved user settings loading.
- Separated empty and low stock medications for clearer notifications.
- Enhanced email notifications with detailed alerts for empty and low stock medications.
- Updated user settings in the database when reminders are sent for both intake and stock notifications.
- Improved form validation in the frontend with character limits and error messages.
- Added CSS styles for form validation feedback and character count display.
2025-12-28 14:42:51 +01:00
Daniel Volz 30156ebd60 feat(ui): increase notes character limit to 2000 and add auto-resize functionality for textareas 2025-12-28 13:51:57 +01:00
Daniel Volz 47ae762e72 feat(ui): improve table layout with left-aligned text and status chips 2025-12-28 13:26:14 +01:00
Daniel Volz fad92a0b24 feat(ui): enhance email status bar layout with improved styling and responsiveness 2025-12-28 13:14:47 +01:00
Daniel Volz b539738d1e feat(ui): adjust button styles for better accessibility and consistency 2025-12-28 13:08:54 +01:00
Daniel Volz e386ce1fcb feat(ui): enhance tabs styling with improved hover effects and primary state 2025-12-28 12:56:32 +01:00
Daniel Volz 8fcf96997b feat(ui): refine user menu button styles and add dropdown item danger state 2025-12-28 12:53:37 +01:00
Daniel Volz fcd8d0da14 feat(ui): implement modal background scroll prevention and enhance button styles 2025-12-28 12:47:54 +01:00
Daniel Volz d60aeff7bd feat(ui): enhance medication detail modal layout and improve scrolling behavior 2025-12-28 12:07:36 +01:00
Daniel Volz 415dd87117 feat(ui): improve modal footer layout and enhance mobile form styling 2025-12-28 11:56:55 +01:00
Daniel Volz fb1732bd4a feat(ui): update medication icons alignment and styling for improved mobile display 2025-12-28 11:23:57 +01:00
Daniel Volz 02caa0619e feat(ui): enhance medication display layout and improve responsiveness in App component 2025-12-28 11:03:33 +01:00
Daniel Volz 3ffdb8a5fe feat(oidc): implement OIDC authentication flow and user management 2025-12-28 01:13:03 +01:00
Daniel Volz bd5c864e84 feat: add user avatar functionality and update related routes
- Implemented avatar upload and deletion in the Auth context.
- Updated UserProfile component to handle avatar display and actions.
- Modified backend routes to return anonymous user ID when auth is disabled.
- Added avatar_url column to users table in the database.
- Enhanced UI for user menu and profile modal to support avatar display.
- Updated translations for new avatar-related strings.
- Improved stock status calculation for medications in the planner.
2025-12-28 00:43:45 +01:00
Daniel Volz be68fb5dad feat(schedule): add schedule header with title and tooltip for configuration hints 2025-12-27 23:21:02 +01:00
Daniel Volz 27af4dd14b feat(edit-modal): implement mobile edit modal for medication with responsive design 2025-12-27 23:15:14 +01:00
Daniel Volz d378b081c6 feat(med-detail-footer): enhance layout and styling for footer actions and buttons 2025-12-27 22:36:50 +01:00
Daniel Volz a3cb24ccfe feat(settings): improve email and push notification settings validation and state management 2025-12-27 22:32:44 +01:00
Daniel Volz d2324640f4 feat(past-days): enhance past days toggle with missed doses indication and styling 2025-12-27 22:11:51 +01:00
Daniel Volz cfb8494be3 feat(auth): add 'remember me' functionality and token refresh logic 2025-12-27 21:59:21 +01:00
Daniel Volz 65f007732a feat(stock-status): implement stock status indicators for medication days and update styles 2025-12-27 21:46:04 +01:00
Daniel Volz 57377aeead feat(blister-form): update blister form structure to include separate start date and time fields 2025-12-27 15:32:47 +01:00
Daniel Volz 6b6c20bdc3 feat(med-details): enhance medication detail display with current stock and package details 2025-12-27 15:19:14 +01:00
Daniel Volz 9ccb5b1f0f Add past days toggle and update terminology for blisters
- Added translations for showing/hiding past days and past days count in German and English.
- Renamed "slices" to "blisters" in both translation files.
- Updated CSS styles to reflect the change from slices to blisters, including layout and hover effects.
- Introduced new styles for past days toggle button and past day blocks.
2025-12-27 15:01:54 +01:00
Daniel Volz f34c2c9578 feat(schedule): enhance dose button styles for better user experience and add visual cues for future doses 2025-12-26 23:54:15 +01:00
Daniel Volz 68660202cf feat(medications): enhance medication stock calculation and improve UI layout for better readability 2025-12-26 23:06:02 +01:00
Daniel Volz be1e8cda18 feat(schedule): add manual collapse/expand functionality for schedule days and update translations 2025-12-26 22:14:38 +01:00
Daniel Volz b0f26b1e66 feat(share): implement share functionality for medication schedules with token-based access 2025-12-26 21:06:03 +01:00
Daniel Volz a7f9f90db4 feat(auth): implement user authentication and profile management
- Added authentication context and provider to manage user state.
- Created login and registration forms with validation and error handling.
- Implemented user profile component for updating user information and changing passwords.
- Introduced user settings in the database for notification preferences.
- Updated translations for authentication-related strings in English and German.
- Enhanced styles for authentication components and user profile.
- Added middleware for optional and required authentication checks.
2025-12-26 19:57:35 +01:00
Daniel Volz 1468c62d59 feat: add takenBy and pillWeightMg to intake reminders and update translations 2025-12-25 12:40:40 +01:00
Daniel Volz 06da1d6eb8 feat: add repeat daily reminder functionality with UI updates and translations 2025-12-25 12:29:42 +01:00
Daniel Volz c5e03a787d feat: add overdue dose indication in UI with corresponding styles 2025-12-24 09:41:55 +01:00