Commit Graph

38 Commits

Author SHA1 Message Date
BOHA
5593c2a229 fix: read-only rich text content overflowing container
Added section-content class with proper ul/ol/li/p margins and
overflow:hidden. Browser defaults for lists were causing content
to extend outside the form input box.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:14:24 +01:00
BOHA
f8210d667f fix: locked offers — selects, checkboxes, date pickers, rich editor all read-only
Added isLockedByOther check to:
- All disabled={} on selects (currency, language) and checkboxes (apply_vat)
- All conditional renders that swap date pickers for read-only inputs
- Rich editor conditional that swaps editor for static HTML display

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:12:39 +01:00
BOHA
0ad0e88853 feat: pessimistic locking for offer editing
When user A opens an offer, a lock is acquired (locked_by + locked_at).
User B opening the same offer sees a warning banner and the form is
read-only. Lock expires after 5 minutes without heartbeat.

Backend:
- POST /:id/lock — acquire lock (returns 423 if locked by another)
- POST /:id/heartbeat — refresh lock timestamp (every 2 min)
- POST /:id/unlock — release lock
- GET /:id — includes locked_by info
- PUT /:id — auto-releases lock on save

Frontend:
- Acquires lock on page load (edit mode only)
- Sends heartbeat every 2 minutes
- Releases lock on page unmount (navigate away)
- Shows warning banner with locker's name
- All inputs read-only + action buttons hidden when locked

Migration: adds locked_by (INT) and locked_at (DATETIME) to quotations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:08:41 +01:00
BOHA
96cbaf3315 fix: stack item description fields vertically with flex column 2026-03-24 07:54:10 +01:00
BOHA
a866384f08 feat: add item_description field to offer items editor (matches PHP) 2026-03-24 07:53:08 +01:00
BOHA
d92c5c56ac fix: remove Content-Type header from logout request (no body to send) 2026-03-23 20:46:29 +01:00
BOHA
33268b38ae fix: TOTP login flow loses remember_me — sessions expire after 1 hour
The TOTP verification endpoint always created refresh tokens with
remember_me=false and 1-hour expiry, regardless of what the user
selected at login.

Fix:
- Frontend now sends remember_me in the TOTP verify request body
- Backend reads remember_me and uses it for token expiry (30 days)
  and cookie maxAge

Users with 2FA who checked "remember me" will now stay logged in
for 30 days instead of being kicked out after 1 hour.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:28:54 +01:00
BOHA
c4c4433561 feat: editable billing text on invoices
- Added billing_text column to invoices table (VARCHAR 500)
- Prisma migration: 20260323_add_billing_text
- Form field on invoice create page with placeholder
- PDF uses billing_text, falls back to default translation
- Stored on create and editable on draft invoices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:47:15 +01:00
BOHA
2540efbec2 refactor: merge InvoiceCreate into InvoiceDetail (single page for create + edit)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:34:16 +01:00
BOHA
5285c3c7c9 fix: VAT select in invoices — use admin-form-select instead of admin-form-input 2026-03-23 19:27:46 +01:00
BOHA
93ea9911f8 fix: invoice items table — match offer detail card style
Changed from offers-editor-section + offers-items-table to
admin-card + admin-card-body + admin-table-responsive, matching
the offer detail page structure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:22:01 +01:00
BOHA
892d83cd90 feat: add drag-and-drop item reordering to invoice create and edit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:18:01 +01:00
BOHA
2b4a98b958 fix: save item position after drag-and-drop reordering 2026-03-23 19:06:21 +01:00
BOHA
bfb3a975ea fix: restrict item drag to parent table bounds 2026-03-23 19:04:55 +01:00
BOHA
3bef879ff9 fix: move useSensors hook to component top level (React hooks rules) 2026-03-23 19:03:38 +01:00
BOHA
185157fe86 feat: offer items drag-and-drop reordering + fix scope template insertion
1. Item reordering: replaced placeholder with @dnd-kit drag-and-drop.
   Each item row has a drag handle for reordering via vertical drag.
   Uses SortableContext with verticalListSortingStrategy.

2. Scope template insertion: fixed template loading to use already-fetched
   data instead of re-fetching from non-existent endpoint. Templates with
   sections are now stored fully and inserted directly on selection.
   Also copies template description to scope_description.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:02:15 +01:00
BOHA
95065f54eb fix: offer scope sections — add blue EN / red CZ language badges on title labels
Matches PHP styling with offers-lang-badge and offers-lang-badge-cz classes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:56:12 +01:00
BOHA
bcad377f92 fix: dashboard — gate all sections by user permissions
API now only returns data sections the user has permission to see:
- my_shift: attendance.record
- attendance: attendance.admin
- offers: offers.view
- projects: projects.view
- invoices: invoices.view
- orders: orders.view
- leave_pending: attendance.approve
- recent_activity: settings.audit

Frontend hides KPI cards, activity feed, and attendance sections
for users without the matching permissions.

Regular employees now only see their shift status, quick actions,
profile, and sessions — not company KPIs or admin data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:51:29 +01:00
BOHA
a1c70ba25f fix: force all spinners inside buttons to 16px (admin-spinner-sm size) 2026-03-23 18:48:06 +01:00
BOHA
98454edcf1 fix: prevent buttons from resizing during loading state
- Added white-space: nowrap to .admin-btn (prevents text wrapping)
- Modal footer buttons get min-width: 100px for consistent sizing
- Spinner in buttons doesn't add extra vertical space

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:46:18 +01:00
BOHA
a8a28d8472 fix: confirm modal — always use admin-btn-primary (admin-btn-danger has no CSS) 2026-03-23 14:17:31 +01:00
BOHA
040b41ed90 fix: pagination component — use correct CSS class names
Component used admin-pagination-btn/pages/dots but CSS has
admin-pagination-page/controls/ellipsis. Fixed to match existing CSS.
Added record count display.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:59:49 +01:00
BOHA
0b4b6b24e1 fix: attendance times showing +1 hour due to UTC timezone conversion
Times in the database are stored as local time (CET). JavaScript's
Date constructor treated them as UTC, then toLocaleTimeString added
+1 hour for CET timezone.

Fix: extract hours/minutes directly from the datetime string via regex
instead of going through Date object. No timezone conversion applied.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:50:30 +01:00
BOHA
2718a7b716 fix: attendance admin — add user_name to records, fix Czech diacritics in table headers
- listAttendance() now maps users.first_name + last_name to user_name
- Fixed escaped Unicode in table headers (Zaměstnanec, Příchod, Poznámka)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:41:55 +01:00
BOHA
c817e004b7 feat: supplier name autocomplete on received invoices
- Added GET /api/admin/received-invoices/suppliers endpoint (distinct names)
- Upload and edit forms use HTML datalist for browser-native autocomplete
- Suggestions loaded once on page mount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:32:38 +01:00
BOHA
a4c4a377c9 fix: frontend VAT preview — extract VAT from inclusive amount, not add on top 2026-03-23 13:27:50 +01:00
BOHA
fe12fde9db fix: convert dates to yyyy-MM-dd when opening received invoice edit form
ISO datetime strings from API caused "Invalid time value" in date picker.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:19:43 +01:00
BOHA
0baa604ade fix: remove duplicate canSecurity declaration in Settings 2026-03-23 11:43:27 +01:00
BOHA
f40f9d2a4b feat: wire up mandatory 2FA toggle in global settings
Connects the existing UI button to GET/POST /api/admin/totp/required
endpoints. Fetches current state on load, toggles on click.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:40:50 +01:00
BOHA
e0fbae1530 fix: received invoices — show skeleton only on initial load, not on sort/filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:03:22 +01:00
BOHA
d3a72c51a2 fix: table sort toggle — use single state object to prevent lost updates
Two separate useState calls (sort + order) caused React to skip
re-renders when clicking the same column — setSort returned the same
value so React bailed out, and the nested setOrder was lost.

Single state object guarantees a new reference on every click,
so React always re-renders and useListData always refetches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:58:56 +01:00
BOHA
635c6fd0ff fix: table sorting blocked by pointerEvents:none during loading
Root cause: useListData set loading=true on every refetch, and all 4
admin list pages (offers, orders, invoices, projects) applied
pointerEvents:'none' while loading — blocking all clicks including
sort column headers.

Fix: removed setLoading(true) from refetch (matching PHP behavior)
and removed pointerEvents from all list page cards. Opacity fade
kept as visual feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:57:17 +01:00
BOHA
56065c381b fix: align useTableSort with PHP version — userClicked ref, nullable activeSort
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:53:26 +01:00
BOHA
47fb4dc8ac feat: integrate ProjectFileManager into project detail page
Replace the file management placeholder with the actual ProjectFileManager
component, providing projectId, projectNumber, hasPermission, and hasNasFolder
props from the existing page state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:22:10 +01:00
BOHA
3c1a35ae9c feat: add ProjectFileManager component with file browser UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:20:49 +01:00
BOHA
373ea82279 fix: rewrite attendance print to match PHP design 1:1
- Dark table headers (#333), proper column widths, uppercase labels
- User header bar with gray background and total hours
- Records from userData.records (not filtered from global records)
- Fund row with covered/total and status badge
- Leave summary with vacation remaining
- Print wrapper table for repeating header
- Matching CSS: borders, fonts, spacing, badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:39:31 +01:00
BOHA
8c1fd07293 feat: implement attendance admin print functionality
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:33:43 +01:00
BOHA
4608494a3f initial commit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 08:46:51 +01:00