Commit Graph

211 Commits

Author SHA1 Message Date
Serhiy Bobrov 0b54fe255b feat: add recipes module with CRUD functionality and integrate with meals
- Implemented new recipes page with UI for managing recipes.
- Added REST API routes for recipes including create, read, update, and delete operations.
- Introduced database schema for recipes and recipe ingredients.
- Updated meals to link with recipes, allowing meals to reference specific recipes.
- Enhanced validation for recipe-related fields in meals.
- Added styles for the recipes page and components.
2026-04-21 14:15:39 +02:00
ulsklyc d1ec7367a0 fix(auth): resolve post-login navigate race condition and add version display (#68) (#70)
Root cause: when auth.me() failed during initial navigation, the catch block
called navigate('/login') without clearing _pendingLoginRedirect. The outer
finally then fired a second concurrent navigate('/login'), which held
isNavigating=true while running. If the user submitted the login form (or
iCloud Keychain autofilled credentials) before the second navigation
completed, navigate('/', user) was silently blocked by the isNavigating guard —
login appeared to succeed but the app never advanced to the dashboard.

Fix: clear _pendingLoginRedirect in the catch block so the finally handler
does not spawn the duplicate navigation.

Also adds a GET /api/v1/version endpoint (no auth required) and shows the
version on the login page, so users can verify their PWA has received the
latest cached JS.

Resolves #68

Co-authored-by: Ulas Kalayci <ulas.kalayci@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 08:19:53 +02:00
Ulas Kalayci 1859d6a55b fix(calendar): use dedicated resetToast key, explicit user_modified === 1 check 2026-04-21 00:06:53 +02:00
Ulas Kalayci 4aa8eefb51 feat(calendar): show reset link for user-modified ICS events in event popup 2026-04-21 00:04:29 +02:00
Ulas Kalayci 55cac140ef fix(settings): move ICS card below Apple Calendar, fix toast messages, use syncing key 2026-04-21 00:03:14 +02:00
Ulas Kalayci 4f10f334fb feat(settings): add ICS subscription management UI and i18n keys 2026-04-21 00:00:33 +02:00
Ulas Kalayci 09b339e5f9 fix: use CSS media query as authoritative dark mode source for system preference 2026-04-20 10:37:24 +02:00
Ulas Kalayci ca3da0eccd fix: system theme selection immediately applies OS preference instead of reverting to light 2026-04-20 10:20:18 +02:00
Ulas Kalayci e92487f464 feat: add FAB to meals page for quick meal creation (#62) 2026-04-20 10:15:04 +02:00
Ulas Kalayci aae895d704 feat: filter panel + english category keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 09:50:55 +02:00
Ulas Kalayci b867917995 feat: kanban touch drag, swipe undo, dashboard task deep-link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 09:44:50 +02:00
Ulas Kalayci c8e20b22c8 chore: release v0.20.21
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:36:07 +02:00
Ulas Kalayci 87be39364d chore: release v0.20.20
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:17:30 +02:00
ulsklyc 01ebf20a62 Merge pull request #59 from baragoon/dev
Unify shopping category localization and limit meal ingredient categories to food-relevant options
2026-04-20 06:56:29 +02:00
Ulas Kalayci a65de31dda fix: 'Sonstiges' aus Meal-Kategorie-Ausschluss entfernen, EOF-Newline ergänzen
'Sonstiges' ist DEFAULT_CATEGORY_NAME und dient als allgemeiner Fallback für
Zutaten (Gewürze, Saucen etc.). Beim Ausschluss würde die Kategorie bestehender
Zutaten beim Bearbeiten einer Mahlzeit lautlos überschrieben (Datenintegrität).
Nur haushaltsfremde Kategorien (Haushalt, Drogerie) werden ausgeblendet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 06:56:24 +02:00
Ulas Kalayci 888cd05437 fix: move nav-badge styles to layout.css so badge stays visible on all pages
The .nav-badge base styles (background, size, color) were defined in tasks.css,
which is dynamically unloaded when navigating away from /tasks. This caused the
overdue badge in the nav to become invisible on every other page, even though
the badge element remained in the DOM.

Also refactors subtask checkbox icon to use a CSS class instead of inline styles.

Resolves #56

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:10:06 +02:00
Serhiy Bobrov 819d9e8b1d Unify shopping category localization and limit meal ingredient categories to food-relevant options 2026-04-19 19:14:46 +03:00
Ulas Kalayci d656ad8bfc fix: use space token for nav-badge offset instead of hardcoded -4px 2026-04-19 18:06:38 +02:00
Ulas Kalayci 573ba52f63 fix: anchor overdue badge to icon via runtime wrapper (#56)
Root cause: the badge was `position: absolute` relative to the entire
`.nav-item`, which stretches to `flex: 1` on mobile (up to ~75 px wide).
With `right: 4px` the badge sat far from the icon on the bottom bar and
overlapped label text in the expanded desktop sidebar.

Fix: `updateOverdueBadge()` now wraps the nav icon in a
`.nav-item__icon-wrap` span (created once, reused on subsequent calls).
The badge is appended there instead of to the nav item root.

CSS changes:
- Remove `.nav-item .nav-badge` positional override
- Add `.nav-item__icon-wrap { position: relative; display: inline-flex }`
- Add `.nav-item__icon-wrap .nav-badge { position: absolute; top: -4px; right: -4px }`

The badge now consistently overlays the top-right corner of the icon
across all nav layouts (mobile column, collapsed sidebar row, expanded
sidebar row with label).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 17:26:12 +02:00
ulsklyc ccb41a056e fix: position overdue nav-badge absolutely to avoid flex layout distortion (closes #56) (#57)
The nav-badge was appended as an in-flow flex child, breaking nav-item
layout: on mobile (column flex) it appeared below the label, on desktop
sidebar (row flex + justify-content:center) it was pushed far right via
margin-left:auto. Fix positions it absolutely within the nav-item and
uses DOM API instead of insertAdjacentHTML per project convention.

Co-authored-by: Ulas Kalayci <ulas.kalayci@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:30:32 +02:00
ulsklyc c2d159fd7d Merge pull request #55 from baragoon/dev
feat: add income categories to budget management
2026-04-19 13:07:46 +02:00
Ulas Kalayci 52b494241e fix: replace innerHTML with DOM API in updateCategoryOptions; restore uk.json newline
innerHTML violates project convention (PostToolUse hook blocks it); use
replaceChildren with createElement/textContent instead. Also restore the
trailing newline removed from uk.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:07:32 +02:00
Serhiy Bobrov 7910636ffa feat: add income categories to budget management 2026-04-19 09:15:29 +03:00
Ulas Kalayci 39fd25eafc fix: tasks filters not applied on tab re-entry (closes #49)
render() always fetched /tasks without query params, so active filter
chips appeared selected but all tasks were shown after navigating away
and back. Fixed by building the same filter query in render() that
loadTasks() uses, keeping both parallel fetches and correct filtering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 07:23:46 +02:00
Ulas Kalayci 6746a5a175 feat: Ukrainian translation, UAH currency, shopping category i18n (closes #52)
- Add Ukrainian (uk) locale to SUPPORTED_LOCALES and locale picker
- Add public/locales/uk.json (622 keys, full Ukrainian translation)
- Add UAH (Ukrainian Hryvnia) to SUPPORTED_CURRENCIES and VALID_CURRENCIES
- Add CATEGORY_I18N map and catLabel() in settings.js to translate default
  shopping category names in the settings panel; rename and delete dialogs
  now also use the translated name instead of the raw German DB string
- Align server VALID_CURRENCIES with frontend: add missing AED, BRL, INR, SAR

Co-Authored-By: baragoon <baragoon@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 22:09:42 +02:00
Ulas fc6e4fb9f2 fix: resolve auth:expired race condition and force SW cache refresh
- Add _pendingLoginRedirect flag in router.js to handle auth:expired
  events that fire during active navigation (isNavigating=true).
  Previously the navigate('/login') call was silently dropped, leaving
  the user stuck on the dashboard with an error toast.
- Bump SHELL_CACHE v33→v34 and PAGES_CACHE v28→v29 to force cache
  invalidation on iOS devices still running the pre-CSRF-fix code.
- Add err.status to dashboard error log for easier diagnostics.
2026-04-16 08:15:04 +02:00
Ulas e384ae1037 feat: add reminders for tasks and calendar events (closes #13)
- DB migration #8: reminders table (entity_type, entity_id, remind_at, dismissed, created_by)
- REST API: GET /pending, GET /?entity, POST /, PATCH /:id/dismiss, DELETE
- Client polling module (reminders.js): 60s interval, toast + Browser Notification API
- Tasks: enable reminder with custom date/time in edit modal
- Calendar: reminder offset selector (at time / 15min / 1h / 1d before)
- Bell badge shows pending count; reminders auto-dismiss after 30s or on user action
- SW shell cache updated to include reminders.js + reminders.css
- 11 new DB tests covering CRUD, pending query, dismiss, upsert, cascade delete, constraints
2026-04-15 11:40:24 +02:00
Ulas d16919ef7c feat: per-ingredient category selection for shopping list transfer (closes #33)
When adding ingredients in the meal editor, each ingredient now has a
category dropdown. Categories are stored on the ingredient and applied
automatically when transferring to the shopping list, so items appear
pre-grouped by category without manual re-sorting.
2026-04-15 07:11:49 +02:00
Ulas 8af730e9cf feat: add Japanese, Arabic, Hindi, Portuguese locales + new currencies
- 4 new locale files (ja, ar, hi, pt) with 567 keys each - full coverage
- Japanese (日本語): Hiragana/Kanji script
- Arabic (العربية): RTL-ready text
- Hindi (हिन्दी): Devanagari script
- Portuguese (Português): Brazilian Portuguese
- SUPPORTED_LOCALES updated in i18n.js (10 → 14 locales)
- LOCALE_LABELS updated in oikos-locale-picker.js
- New currencies: AED, BRL, INR, SAR added to budget settings
- Service Worker v31: new locale files pre-cached in APP_SHELL
- Docs: README, SPEC.md, BACKLOG.md, CHANGELOG.md updated
2026-04-14 10:28:17 +02:00
Ulas fa1b0d0603 fix: restore weather widget position - display directly below greeting banner 2026-04-14 08:52:00 +02:00
Ulas 8f96e066f3 feat: customizable dashboard layout (#32)
Users can now show/hide widgets and reorder them via a settings button
in the greeting header. Configuration is persisted server-side in
sync_config (dashboard_widgets key) and shared across all family members.

- Greeting widget gets a settings icon button opening a customize modal
- Modal lists all widgets (tasks, calendar, shopping, meals, notes,
  weather) with toggle switches and up/down reorder buttons
- Reset to default layout available in the modal
- GET /preferences now returns dashboard_widgets; PUT accepts it
- All 10 locales updated with new i18n keys
2026-04-14 08:04:26 +02:00
Ulas e61644702c feat: add French, Turkish, Russian, Greek and Chinese UI languages + TRY/RUB currencies 2026-04-13 09:40:38 +02:00
Ulas 01d1f583b8 feat: add CNY (Chinese Yuan) to supported currencies (#42) 2026-04-13 09:22:42 +02:00
Ulas 61e663ef72 feat: add categorized settings tabs (#30)
Six tabs (General, Meals, Budget, Shopping, Calendar, Account) replace
the flat single-page layout. Active tab persists via sessionStorage.
Calendar tab auto-activates on OAuth redirect. Tab bar is sticky.
All labels translated in de/en/es/it/sv.
2026-04-06 14:33:49 +02:00
copilot-swe-agent[bot] 26919e2ee3 feat: modernize modal styling and align two-column modal boxes
Agent-Logs-Url: https://github.com/ulsklyc/oikos/sessions/7153de23-b6c6-423d-974c-cf3b961cbbad

Co-authored-by: ulsklyc <108589275+ulsklyc@users.noreply.github.com>
2026-04-06 10:31:54 +00:00
Ulas 3799a7f952 feat(meals): add optional recipe link to meal cards (#18)
- New optional recipe_url field in the meal modal (below Notes)
- Link icon appears on meal cards when a URL is set, opens in new tab
- DB migration v6: ALTER TABLE meals ADD COLUMN recipe_url TEXT
- API: recipe_url supported in POST /meals and PUT /meals/:id
- i18n: new keys recipeUrlLabel, recipeUrlPlaceholder, openRecipe (de, en, sv, it)
2026-04-05 18:03:05 +02:00
Ulas 2dc8984c3e feat(shopping): custom categories - add, rename, delete and reorder (#26)
- New DB table shopping_categories (migration v5) seeds 9 default
  categories with Lucide icons and sort_order
- Backend CRUD routes: GET/POST/PUT/DELETE /shopping/categories
  plus PATCH /shopping/categories/reorder
- Category validation now uses DB instead of hardcoded constant;
  items of deleted category are moved to the next available one
- Frontend shopping page loads categories from API, dropdown and
  grouping reflect custom order dynamically
- Settings -> Shopping section: list categories with up/down buttons,
  click-to-rename, delete with confirmation; add new categories inline
- i18n keys added in de/en/sv/it
2026-04-05 17:24:06 +02:00
Ulas 19a7161307 feat(tasks): add quick-status button to kanban cards (#24)
Adds a small button on each kanban card that cycles the task status
(open → in_progress → done → open) without requiring drag-and-drop.
Useful for touch devices and kiosk browsers (e.g. Fully Kiosk Browser)
where drag-and-drop is unavailable. All four locales updated.
2026-04-05 16:16:46 +02:00
Ulas 5b8ab7303f fix(i18n): translate shopping categories and recurrence UI fields
- Shopping category dropdown options now use CATEGORY_LABELS() for
  translated display text instead of raw German internal keys
- rrule-ui.js now imports t() from /i18n.js; all hardcoded German
  strings (freq options, weekday labels, form labels, unit labels)
  replaced with i18n keys under the new 'rrule' namespace
- Added 'rrule' section to de.json and en.json with 22 new keys

Fixes #21
2026-04-05 13:49:44 +02:00
Ulas 1722e70e7f fix(ux): microinteraction fixes - swipe hint, locale loading, haptics, weather toast, FAB backdrop
- tasks.js: add maybeShowSwipeHint (long loop, max 3x) - matches shopping.js pattern
- tasks.js: vibrate(15) on task status toggle
- oikos-locale-picker: show disabled/loading state for both reload and setLocale paths
- dashboard: show success toast after weather refresh (all 4 locales)
- dashboard: add semi-transparent FAB backdrop to signal open mode
2026-04-05 13:23:16 +02:00
Ulas a5ae0bac7e fix(ux): locale reload feedback, submit validation, dedup blur logic
- Locale-Picker: disable select + fade before location.reload() (system mode)
  gives visual feedback before the page jumps
- Extract _validateField() helper from wireBlurValidation to avoid duplication
- Add validateAll(formContainer): validates all required fields on demand,
  marks inline errors, focuses first invalid field
- tasks.js: call validateAll() at submit to catch untouched required fields
2026-04-05 12:33:57 +02:00
Ulas 44e5a879b9 fix(ux): replace native confirm() dialogs, add undo-toast, fix prefers-reduced-motion
- Replace all 13 native confirm() calls with confirmModal() across 7 page modules
- Add confirmModal() to modal.js (Promise-based, danger variant, focus management)
- Fix double-confirm bug in contacts.js and budget.js (modal + deleteContact/deleteEntry)
- Extend showToast() with onUndo callback and max-3-toast limit
- Implement optimistic undo-toast (4s window) for shopping item and bulk-checked delete
- Add prefers-reduced-motion guard to btnSuccess() and btnError() in modal.js
- Add btn--error-static CSS class as motion-reduced fallback for btnError()
- Add toast__undo button styles to layout.css
- Add common.confirm and common.undo i18n keys (de, en, it, sv)
- Add shopping.itemDeletedToast i18n key (de, en, it, sv)
2026-04-05 12:31:16 +02:00
Ulas 446b9b1388 feat(budget): configurable currency in settings (#20)
Add household-wide currency preference for the budget section.
Users can select from 13 currencies (EUR, USD, GBP, SEK, NOK, DKK,
CHF, PLN, CZK, HUF, JPY, AUD, CAD) in Settings → Budget.

- preferences API (GET/PUT) now includes currency field
- budget page loads currency from preferences on render
- formatAmount() uses locale-aware Intl.NumberFormat with chosen currency
- settings page gains a Budget section with a currency select
- all three locales (de, en, it) updated with new i18n keys
2026-04-05 11:55:38 +02:00
Ulas 1dccba8d96 fix(ux): add inputmode and autocomplete attributes for mobile UX
- inputmode=decimal on budget amount input for correct decimal keyboard
- inputmode=numeric on rrule interval input for numeric keyboard
- autocomplete attributes on contacts form (name, tel, email, street-address)
2026-04-05 01:39:01 +02:00
Ulas 8f8b3f7951 feat(ux): microinteraction improvements
- Zentralisiere @keyframes check-pop in layout.css (war dupliziert in shopping.css + tasks.css)
- Subtask-Checkbox erhaelt check-pop Animation (konsistent mit Haupt-Checkbox)
- Quick-Add: Checkmark-Feedback auf +-Button nach erfolgreichem Hinzufuegen (700ms, DOM-API)
- Swipe-Affordance Hint: swipe-row--hint via localStorage-Counter (max. 3x, nur Mobile)
2026-04-04 23:53:11 +02:00
Ulas 08159ec8b4 feat(meals): customizable meal type visibility in Settings (#14)
Users can now toggle which meal types (breakfast, lunch, dinner, snack)
are displayed in the meal planner via a new Settings section. Preference
is stored household-wide in sync_config and applied as a filter on the
meals page. Includes preferences API, i18n (DE/EN/IT), and Settings UI.
2026-04-04 22:51:57 +02:00
Ulas 0421b540cd feat(tasks): persist view mode and support ?view=kanban URL parameter
View mode (list/kanban) is now saved to localStorage and restored on
page load. URL parameter ?view=kanban takes precedence, enabling tablet
kiosk setups to default to Kanban view. Toggle buttons reflect the
active view correctly on initial render.

Closes #17
2026-04-04 22:34:29 +02:00
Ulas 2c36fa0307 feat(tasks): add optional "none" priority level for tasks without urgency
New tasks default to "none" priority instead of "medium". Tasks with no
priority hide the badge in list and dashboard views, reducing visual noise
for routine items. Includes DB migration v4 and i18n keys (de, en, it).

Closes #15
2026-04-04 22:13:51 +02:00
Ulas 7eb06ed905 fix(modal): replace native prompt() with custom modal dialogs
Native browser prompt() is unreliable on mobile browsers and PWAs,
often requiring multiple clicks to close. Replace all prompt() calls
with custom promptModal() and selectModal() functions that use the
existing modal system with proper focus management and animations.

Affected pages: shopping (create/rename list), tasks (add subtask),
meals (choose shopping list).

Fixes #12
2026-04-04 21:31:50 +02:00
Ulas c93be9049c feat(dashboard): add shopping list widget
Show shopping lists with open items directly on the dashboard.
Each list displays a progress bar, the first few unchecked items,
and a "+N more" overflow indicator. Widget only appears when there
are lists with open items.

Backend: new shoppingLists query in /api/v1/dashboard (up to 3 lists,
6 open items each). Frontend: renderShoppingLists() widget following
existing widget pattern. CSS: compact list/progress/item styles.
i18n: shoppingMore key added to de/en/it.

Requested in discussion #9
2026-04-04 14:30:31 +02:00