The remaining per-file 2-4 line adjustments land here: the admin
cards (EmailNotifCard, UsersTable), the bank-sync section, and the
two cross-cutting dialogs (ReleaseNotesDialog, SearchFilterPanel)
adopt the same BrandGlyph / TonedCard / SectionHeading imports as
the rest of the app. Each file is independently buildable on top of
the previous 6 commits.
This is commit 7 of 9 in the v0.42.0 brand refresh. Depends on
0eb024d (pages).
The daily reminder job ran at a hardcoded 6 AM. Make the hour configurable:
- dailyWorker: resolveReminderHour() reads the global 'reminder_hour' setting
(clamp 0–23, default 6) as the single source for both the cron expression and
the next-run display; the task is stored so rescheduleDailyWorker() can restart
it live (defensively wrapped so a bad value can't take the worker down).
- notifications admin GET/PUT expose reminder_hour; PUT clamps, persists, and
live-reschedules the worker.
- Admin Email Notifications card: a "Reminder send time" select (account-wide).
It's a global setting by design — there's one shared daily job, so a per-user
hour would require an hourly-worker refactor (out of scope) and would otherwise
be a dead setting.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Extract parseUtc (was copy-pasted in 4 files) and settingEnabled (3 copies,
one named settingsBool) into client/lib/utils.ts as the single source.
- Replace all local copies with the shared import.
- Add tracker_show_safe_to_spend to the tracker's local settings defaults so it
matches SettingsPage's list (behavior unchanged; aligns the two sources).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The XLSX importer (workbook parse → per-row decision tree → bulk actions →
bill-history grouped import). Typed PreviewRow/Decision/BillGroup/ImportDetail
and the merged BillImportResult accumulator; fixed Date subtraction in the
duplicate-date sort to use getTime(). Dropped two unused imports (CountPill/fmt)
the original .jsx never used. Trimmed unused eslint-disable directives.
This completes the entire client/components/data/ directory (14 files) → .tsx.
typecheck 0, lint 0 errors, build green.
Completes the entire client/components/admin/ directory conversion to .tsx:
OidcForm/AuthConfigData/OidcTest types for the OIDC config form; Backup/
BackupSettings types for the backup manager. errMessage() on all strict
catch(unknown) sites. typecheck 0, lint 0 errors, build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
adminShared.tsx (SectionHeading/FieldRow/Toggle/formatDateTime/BackupTypeBadge —
shared by the admin cards) and AddUserCard.tsx. Deleted PrivacyAdminCard.jsx:
TypeScript surfaced that it's imported nowhere AND calls non-existent
api.privacySettings/setPrivacySettings (the geolocation toggle actually lives on
/profile/settings) — dead code with broken calls, so removed rather than
converted. typecheck 0, build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- bankSyncConfigService: SYNC_DAYS_MAX=90, getBankSyncConfig clamps on read,
setSyncDays rejects >90 with explanation
- bankSyncService: every sync requests full sync_days window, dedup handles
already-seen transactions
- dataSources status endpoint returns sync_days alongside enabled
- BankSyncAdminCard: input max 90, live clamp, description cites Bridge limit
- BankSyncSection: third stat tile showing History window X days
- bankSyncService: removed local syncDaysBack() reading env directly;
sinceEpoch() now calls getBankSyncConfig().sync_days
- bankSyncConfigService: added setSyncDays() with 1-730 day validation
- routes/admin: PUT accepts sync_days alongside enabled/sync_interval_hours
- BankSyncAdminCard: Transaction history days input, loaded from config,
defaults 90, dirty-checked on save
- Removed disable logic and key warning banner from BankSyncAdminCard
- Toggle works freely regardless of TOKEN_ENCRYPTION_KEY status
- encryptionKeyReady and encryption_key_set left as informational only