Commit Graph

188 Commits

Author SHA1 Message Date
BOHA
18064a972c fix(mobile): tab bars scroll on phones + combobox 44px touch targets
- .admin-tabs: horizontal-scroll + 44px tabs at <=640px so 4-tab bars
  (WarehouseReports, Invoices/Offers status filters, OffersTemplates) no longer
  overflow off-screen.
- Customer searchable dropdown + warehouse ItemPicker: option rows >=44px,
  clear button enlarged, list clamped to viewport width at <=640px.
Native selects/toggles were already mobile-safe (44px at <=768px). Mobile-only; desktop unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:54:36 +02:00
BOHA
c73b980ce7 feat(mobile): responsive Phase 1+2 — global small-phone rules + area fixes
All changes are mobile-only (max-width media queries); desktop unchanged.

Global (systemic):
- forms.css: all .admin-form-row* grids stack to 1 column at <=480px (fixes
  detail-page info grids, settings forms, modal forms staying 2-up on phones).
- components.css: .admin-kpi-4/-3 stat grids collapse to 1 column at <=480px.
- tables.css: row-action icons get 44px touch targets at <=768px.
- datepicker.css: constrain the date-picker popper to the viewport at <=480px.
- filemanager.css: toolbar wraps, new-folder input full-width, breadcrumb scrolls.

Area specifics:
- offers.css: Quill picker dropdowns kept on-screen (max-width) at <=480px.
- invoices.css: month-nav wraps + 44px touch targets at <=640px.
- attendance.css: Leaflet map height scales with viewport; clock-card padding
  tightened at <=480px.

Audit confirmed all data tables (warehouse incl.) are already wrapped in the
scroll container, so no table overflow/markup changes were needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:44:53 +02:00
BOHA
80803cc868 refactor(modals): migrate 8 ad-hoc modals to the shared FormModal
BulkAttendanceModal, ShiftFormModal, OrderConfirmationModal, DashQuickActions
trip modal, the Attendance leave modal, and DashProfile's 3 modals (edit
profile, 2FA setup, 2FA disable) now use the shared FormModal instead of
hand-rolled overlays, inheriting the canonical open/close animation, blurred
backdrop, ESC-to-close, click-outside, scroll-lock, staggered reveal, mobile
full-screen and reduced-motion. Footers stay pinned via the real FormModal
footer + submitDisabled; multi-step modals (2FA setup, order confirmation)
drive title/footer/close-guards per step. Behaviour preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:53:28 +02:00
BOHA
55fa4045ad feat(modals): FormModal gains submitDisabled + subtitle props
submitDisabled greys out the primary (so callers can gate it on validity
instead of a clickable-but-inert button); subtitle renders a muted line under
the title in the header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:53:28 +02:00
BOHA
7f156cc721 fix(modals): ConfirmModal locks body scroll + respects loading on backdrop
ConfirmModal never called useModalLock, so the page scrolled behind every
confirmation dialog (8+ usages). Add the ref-counted scroll lock and guard
backdrop-click against the loading state, matching FormModal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:34:48 +02:00
BOHA
e0d2fccf50 fix(projects): edit-page responsible picker shows only active users (keeps current assignee)
Mirror the create-modal fix on ProjectDetail: filter the 'Zodpovědná osoba'
select to active users (already scoped to projects.view), but keep the
project's currently-assigned user selectable even if inactive, labelled
'(neaktivní)', so the saved value still shows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:24:41 +02:00
BOHA
a1c251650b fix(projects): responsible-person picker shows only active users with projects.view
The create-project modal's 'Zodpovědná osoba' select listed every user
(including inactive ones). Filter the query server-side by projects.view and
hide inactive users client-side.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:19:15 +02:00
BOHA
337feb8b3a feat(orders-ui): manual order price line item + PO upload (hybrid submit)
Adds price/quantity fields (→ one line item) and a PDF attachment picker
to the manual-order create modal. Submit now uses apiFetch directly:
FormData (multipart) when a file is attached, JSON otherwise. Navigates
to the new order on success. Removes the old useApiMutation-based
createMutation; deleteMutation is untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 13:58:21 +02:00
BOHA
30dd5a3f3b feat(orders-ui): add manual order create modal (header only, optional project)
Mirrors the Projects.tsx pattern: useQuery-driven customers + next-number
fetches (enabled only when modal is open), OrderCreatePayload type normalises
customer_id "" → null so the server's CreateOrderSchema never receives 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 11:17:53 +02:00
BOHA
5140d23d73 feat(projects-ui): add project create modal, type badge, empty-state copy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 11:13:43 +02:00
BOHA
a373102f3a feat(queries): next-number options for project/order create modals 2026-06-06 11:11:18 +02:00
BOHA
fdf180809d fix(plan): make Plán prací usable on mobile + dev port → 3050
Mobile work-plan (Plán prací) responsive fixes — desktop unchanged:
- Toolbar stacks into clean full-width rows on ≤640px (nav group,
  centered range label, full-width segmented view toggle, full-width
  category button); drops the fixed 230px label min-width and the
  margin-left:auto that made the toolbar ragged on phones.
- Grid scroll container: 100dvh-based max-height, momentum scroll, and
  overscroll containment so a fling does not bounce the whole page.
- ≤480px tightens columns (date col 72px via the colgroup <col>, person
  cols 132px) so ~2 people are comfortably visible at 360–390px.
- Touch (@media hover:none): faint persistent + on empty editable
  cells, since the hover-reveal add hint never fires on a phone.

Dev: `npm run dev` (backend) now listens on 3050 instead of 3000 to
avoid colliding with other local apps; CLAUDE.md dev-port note updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:16:00 +02:00
BOHA
744baec2ec feat(security): audit-log session termination (single + all-others)
The two session-revocation endpoints wrote no audit entry. Added a 'session' EntityType (+ Czech label 'Relace') and logAudit on both deletes, so revoking sessions is recorded in the forensic trail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 02:40:41 +02:00
BOHA
1f05ef6a55 fix(dates): use local 'today' for date-input defaults instead of the UTC date
11 form defaults across 6 files used new Date().toISOString().split('T')[0] (the UTC date), which lands on yesterday during the post-midnight Prague window (UTC+1/+2). Added todayLocalStr() (local YYYY-MM-DD) in formatters and replaced them. Future-date expressions (e.g. invoice due_date +14d) left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 02:38:58 +02:00
BOHA
9ae49c0d6a refactor: route/schema consistency (parseId, broad invalidation, Czech messages, Zod 4 strictObject)
- OfferDetail: invalidate broad ["offers"] not ["offers","list"] (CLAUDE.md convention)
- trips.ts/sessions.ts: use parseId helper (validated 400) instead of raw parseInt for route ids
- audit-log.ts: z.object().strict() -> z.strictObject() (Zod 4 idiom)
- attendance.ts, orders/offers schemas: English user-facing strings -> Czech
- project-files.ts: unify 'not found' phrasing to the codebase-dominant 'nenalezen' form

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 02:29:04 +02:00
BOHA
522afefc80 refactor(frontend): fix undefined --danger-color, dedup formatDate & require2FAOptions, drop double plan.css import
- base.css: var(--danger-color) (undefined, no fallback -> inherited color) -> var(--danger)
- attendanceHelpers: re-export formatDate from formatters instead of a byte-identical copy
- dashboard.ts: remove dead duplicate require2FAOptions (canonical copy is in settings.ts)
- settings.ts: remove unused @deprecated systemSettingsOptions alias
- PlanWork: drop redundant per-page plan.css import (loaded globally in AdminApp)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 02:22:51 +02:00
BOHA
c5f986adc1 fix(audit): correct + unify entity_type label map to match server values
Audit Log + dashboard feed used legacy keys (invoices_invoice, offers_quotation, trips, vehicles) that never matched the server's entity_type (invoice, quotation, trip, vehicle, ...) and omitted all warehouse_* entities, so many audit rows showed raw English. Single source of truth in lib/entityTypeLabels.ts, keyed to the actual EntityType values, with Czech labels for every type the server writes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 02:19:10 +02:00
BOHA
86e4cbf345 fix(modals): commit FormModal footerLeft/hideCloseButton enhancements that committed code already depends on
PlanCellModal (and the modal system) reference FormModal's footerLeft slot and hideCloseButton, but those props lived only in an uncommitted working-tree change — so committed code did not typecheck (TS2322) and a build-from-committed (e.g. the v1.9.0 release) silently dropped the footer-left delete button in the plan entry/override edit modal. Commits the enhancements + their CSS so committed == working.

NOTE: production v1.9.0 is affected (plan edit-modal delete button missing); needs a patch release. Flagged in the overnight audit report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:56:18 +02:00
BOHA
4a78d31a7f fix(types): resolve all client TypeScript errors (attendance + plan rollback)
- AttendanceAdmin: declare worked_hours_raw on UserTotalData (the hook sets it at runtime; the local interface omitted it)
- usePlanWork.rollbackMutation: type the mutation param as unknown + explicit cast so passing the TanStack mutation result (with the dynamically-stashed _rolled) no longer trips the weak-type check
tsc -p tsconfig.app.json --noEmit is now clean (0 errors, was 9).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:20:24 +02:00
BOHA
e845400fca fix(plan): keep retired category usable when editing an entry's note
Update validates the category only when it changes, so a note-only edit on an entry whose category was later hidden/deleted no longer 400s. The edit select also shows the current (retired) category marked '(skryta)' instead of silently snapping to the first active option; create defaults to an active category.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:17:23 +02:00
BOHA
fce27633a9 fix(ui): add admin-btn-danger variant so category delete confirm is styled
admin-btn-danger was referenced but never defined, so the 'Opravdu smazat' confirm rendered as a plain button. Define a solid danger button (uses --danger), matching the primary button's structure; the per-row delete trigger stays an outline via plan.css. (Includes the transparent-border button refinement so variants don't layout-shift.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:15:12 +02:00
BOHA
4d47897e27 feat(plan): add hard-delete for categories (blocked when in use)
DELETE /plan/categories/:id now hard-deletes the row, guarded: refuses when any live entry/override uses the key (suggests hide instead) and keeps >=1 active category. Modal gains a per-row Smazat with inline confirm. Hiding stays via PATCH is_active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:12:40 +02:00
BOHA
aef4ab92ec feat(plan): label plan_category audit rows in Czech
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:00:30 +02:00
BOHA
5f36c34d48 refactor(plan): commit category color on blur to avoid PATCH/audit spam
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:59:41 +02:00
BOHA
b94f4879e3 feat(plan): add Sprava kategorii management modal and button
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:55:20 +02:00
BOHA
dab5ad8aa5 feat(plan): drive category select and view label from DB categories
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:52:07 +02:00
BOHA
8b77a0a905 feat(plan): render category colors from DB via --cat-color
Replace 14 hardcoded per-category CSS rules with a single --cat-color
custom property set inline on each filled cell button, driven by the DB
categories list threaded from PlanWork → PlanGrid → PlanRangeChips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:47:53 +02:00
BOHA
4b1c42b17f feat(plan): add categories query, type, and map helpers (frontend)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:44:28 +02:00
BOHA
4a9c283789 fix(plan): readable audit descriptions, project labels, dashboard invalidation, view-only & sticky-column UI
Work-plan fixes from this session:
- Czech audit descriptions for plan entries/overrides (was empty '-')
- server-embedded project label on grid cells (was '-' past the 100-project cap)
- dashboard activity + audit-log cache invalidation on plan mutations
- read-only cells: no '+' on empty, keep hover on cells with a record
- view modal: Czech category + formatted dates
- sticky date column made opaque (no bleed-through on horizontal scroll)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:24:33 +02:00
BOHA
2f76fe0bc1 fix(plan): add 'Upravit celý rozsah' button, use class-based action rows 2026-06-05 13:58:07 +02:00
BOHA
9a11a8f001 feat(plan): show project name instead of raw id in cell 2026-06-05 13:51:27 +02:00
BOHA
f0816b126b fix(plan): make mutations throw on non-2xx so errors surface as alerts 2026-06-05 13:46:50 +02:00
BOHA
f31797fb5b fix(plan): allow empty notes, use local time for past-date gate
Three related fixes from manual smoke testing:
- Zod schema: drop min(1) on note field across all four schemas — note is
  optional in real usage, and the modal initialized it to empty.
- assertNotPastDate: replace toISOString() (UTC) with local-time getters
  to match the rest of the codebase. Fixes off-by-one near day boundaries.
- createEntry / updateEntry: also check the date_to endpoint for past
  dates, so a range can't extend backwards into the past even when its
  start is today or future. Defense in depth.

Modal: drop `required` attribute and asterisk from the note field. Tests:
add 5 new cases covering empty note, past date HTTP rejection, and the
new to-endpoint check in updateEntry.
2026-06-05 13:42:21 +02:00
BOHA
9c110abf46 fix(plan): narrow mode in EditForm IIFE and style plan-banner 2026-06-05 13:21:06 +02:00
BOHA
a0f351b0aa feat(plan): page, sidebar entry, and route registration 2026-06-05 13:17:16 +02:00
BOHA
916cf34efd feat(plan): edit modal with create / edit-range / override / view modes 2026-06-05 13:02:52 +02:00
BOHA
003807a074 feat(plan): grid component with sticky headers and weekend tint 2026-06-05 12:57:41 +02:00
BOHA
ca911bf96c feat(plan): react query options and page state hook 2026-06-05 12:54:50 +02:00
BOHA
5233db2002 v1.8.0: warehouse module (16 commits), docházka mzda model, leave_type=holiday removal, api.ts race fix
Highlights:
- Warehouse module: receipts, issues, reservations, inventory, reports, dashboard,
  master data (categories, suppliers, locations), FIFO service, integration tests
- Docházka: mzda PDF counting model (Odpracováno / Vč. svátků / Přesčas / Svátek /
  So/Ne / Noc) with Czech weekday names and decimal hours
- AttendanceAdmin/AttendanceHistory KPI cards unified to mzda formula with
  fund bar colored by delta, badges for Práce/Dov/Nem/Sv/Nep
- Remove leave_type=holiday entirely (auto-computed from Czech public holidays)
- Allow multiple work shifts per day (overlap detection only)
- Pre-flight refresh in api.ts eliminates spurious 401s on fresh page loads
- Prisma: company_settings gets 6 nullable columns for warehouse numbering
  (PRI/VYD/INV prefixes, default patterns); migration seeds defaults
2026-06-03 23:13:10 +02:00
BOHA
f389c4b3cf feat(warehouse): add reservations, inventory, reports, and dashboard pages
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 14:36:31 +02:00
BOHA
fdc7037e60 feat(warehouse): add issue pages 2026-05-29 14:32:11 +02:00
BOHA
b02f6afe93 feat(warehouse): add receipt pages 2026-05-29 14:29:44 +02:00
BOHA
1b2ab7b4eb feat(warehouse): add items list and detail pages
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 14:27:15 +02:00
BOHA
29975ecad9 feat(warehouse): add categories, suppliers, locations pages 2026-05-29 14:23:31 +02:00
BOHA
e846f15126 feat(warehouse): add sidebar entry and routes 2026-05-29 14:21:35 +02:00
BOHA
86bebf9776 feat(warehouse): add shared warehouse components
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 14:20:42 +02:00
BOHA
7b7c6bde68 feat(warehouse): add TanStack Query options and types 2026-05-29 14:19:38 +02:00
BOHA
2254a13ad0 v1.7.0: fix offer created_at override, invoice PDF translations, remove has_order filter
- Add created_at to offer create/update schemas so user-selected date is stored instead of always defaulting to now()
- Translate payment method in invoice PDF based on language (Příkazem → Bank transfer, etc.)
- Add order_date and cnb_rate translation keys, replace hardcoded inline strings
- Remove duplicate has_order filter from offers backend route

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:35:36 +02:00
BOHA
705f58e3d1 v1.6.9: cleanup offer dead columns, add item template picker to offer form
- Remove dead DB columns: uuid, sync_version from quotations/quotation_items/scope_sections; is_deleted from quotation_items/scope_sections; content_editor_height from scope_sections
- Remove unused scope_title/scope_description from offer form state
- Remove dead CSS: offers-template-menu, offers-draft-indicator, exchange-rate
- Remove dead scope_title translation key from offers PDF
- Fix duplicate Customer interface in OfferDetail.tsx (use shared type)
- Add missing title field to ScopeTemplate interface
- Add item template picker dropdown next to "Přidat položku" button

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:20:22 +02:00
BOHA
0330453ad6 v1.6.8: remove offer exchange rate, add invoice item description, offer filters, table animations
- Remove exchange_rate and exchange_rate_date from quotations (schema, service, PDF, form)
- Add item_description field to invoice_items (schema, migration, service, form, PDF)
- Add offer status/customer/order filters with tab-based UI
- Clean up offer statuses to active/ordered/invalidated
- Allow invalidate action for non-ordered offers (not just expired)
- Add fade animations on offers and invoices table data changes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 12:58:51 +02:00