Commit Graph

96 Commits

Author SHA1 Message Date
BOHA
25c8c39ba6 feat(odin): scope to invoice processing only (guard general chat)
Odin currently advertises general Q&A via the /chat path, which burns API
credits on open-ended questions. Guard it: a text-only message makes NO AI
call — it gets a canned reply telling the user to attach an invoice. The
invoice path (attachments → extract) is unchanged. Removing the guard
re-enables the general /chat path for a later phase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:26:54 +02:00
BOHA
4b2770a000 fix(odin): show conversation auto-title immediately (no refresh needed)
ensureActive() created the conversation and invalidated the list before the
server-side auto-title was applied (that happens on the message append), so
the sidebar showed "Nová konverzace" until a refresh. Move the
["ai","conversations"] invalidation to persist()'s success path — after the
append (and thus the auto-title) lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:22:31 +02:00
BOHA
434a12b4a8 feat(odin): mobile composer + responsive sidebar + message-entrance animation
- Composer rebuilt claude-style: a rounded pill with a multiline auto-growing
  textarea and attach/send ICON buttons (vertically centered), so there's room
  to type on mobile (was squeezed between two text buttons).
- Conversation list collapses into a slide-in Drawer below md, with a menu
  button in the chat header; chat is full-width on mobile.
- Each new message bubble animates in (fade + slide-up; fade-only under
  prefers-reduced-motion) via framer-motion, so sent messages and Odin's
  replies appear smoothly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:19:54 +02:00
BOHA
28fb399217 feat(odin): refine hero — Newsreader serif, red name, staggered entrance
- Swap Fraunces → Newsreader (literary serif, full Czech, optical sizing).
- Split the greeting so the user's first name renders in brand-red italic.
- Add a subtle staggered fade-in (framer-motion), skipped under
  prefers-reduced-motion.
- New description that names Odin and covers chat + invoice import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:03:16 +02:00
BOHA
c0ff7b4549 feat(odin): editorial serif hero — Fraunces greeting + italic subtitle
Drop the gradient "Odin" wordmark from the new-conversation hero and make the
personalized greeting the centerpiece in Fraunces (optical-sized serif), with
an italic Fraunces description — a refined, literary, claude-like treatment.
Loads Fraunces (upright + italic) via the existing Google Fonts link.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:57:15 +02:00
BOHA
1e21c12f33 feat(odin): personalized greeting hero on the new-conversation screen
Time-based Czech greeting + the user's first name (e.g. "Dobrý večer, Admin")
above the big gradient "Odin" wordmark, with a stylish description line. Drop
the redundant mark from the hero (it lives on the nav item + thinking state).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:51:00 +02:00
BOHA
ab12f9d791 feat(odin): sidebar brand is a big gradient "Odin" wordmark (drop the icon)
The mark already lives on the nav menu item; the conversation sidebar's brand
no longer duplicates it — just a larger gradient "Odin" wordmark above the new
chat button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:47:39 +02:00
BOHA
cf442b9a99 feat(odin): big claude.ai-style hero on the new-conversation screen
Replace the small empty-state with a large centred hero — the animated Odin
mark + a big gradient "Odin" wordmark (responsive clamp font) and the helper
line beneath.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:44:38 +02:00
BOHA
2e7caea5a6 feat(odin): use the Odin mark as the sidebar nav icon
Replace the chat-bubble glyph on the "Odin" nav item with the OdinMark, and
make the mark's SVG sizing !important so the nav's `& svg { width:18 }` rule
can't shrink it (its `size` prop stays authoritative everywhere).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:41:20 +02:00
BOHA
702a4984ee feat(odin): animated Odin brand mark (AI core orbiting business data)
A self-contained animated SVG mark in BOHA red: a 4-point AI spark (Odin) that
slow-rotates and breathes, a data node orbiting a faint ring (the assistant at
the centre of the business system). An "idle" and a "thinking" state (faster
orbit + red glow); honours prefers-reduced-motion. Used as the sidebar brand,
the empty-state hero, and the busy/thinking indicator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:31:48 +02:00
BOHA
769767c33d feat(odin): left sidebar + lazy conversation creation (claude.ai-style)
- Replace top tabs with a left sidebar (New chat + scrollable conversation
  list, per-row rename/delete menu, active highlight), chat on the right.
- Fix duplicate-empty-conversations bug: "Nová konverzace" now just opens an
  empty composer; a DB row is created only on the first successful message
  (and a failed AI call no longer leaves an orphan conversation). Repeated
  clicks never spawn empties, and nothing empty survives a refresh.
- Land on a fresh new chat on mount; deleting the open conversation returns
  to new chat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:07:07 +02:00
BOHA
d62abe81fd feat(odin): use the full page (full width + taller shell)
Drop the 1100px max-width cap and size the chat shell to fill the content
area (100dvh - 100px = top bar + main bottom padding), so Odin uses the whole
page now that it owns the route.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 19:51:23 +02:00
BOHA
ac7c220bb1 fix(odin): gate Uložit on invoices.create + correct invoice invalidation key
Final review caught two minor issues:
- saveInvoice invalidated ["received-invoices"], which matches no query (the
  received list/stats are keyed ["invoices","received",…]); use ["invoices"]
  so the list/stats actually refresh after an import.
- The Save button hit /received-invoices (requires invoices.create) while Odin
  is gated only on ai.use; disable Uložit (with a hint) when the user lacks
  invoices.create so the UI never offers a 403 action. Dormant today (ai.use is
  admin-only and admin bypasses checks) but correct going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 19:46:49 +02:00
BOHA
b7ebf04001 feat(odin): OdinChat orchestrator; render on /odin; remove DashAssistant
Wire OdinTabs/OdinThread/InvoiceReviewCard/OdinComposer into a single
OdinChat orchestrator; mount it on /odin (maxWidth 1100); delete the
old DashAssistant and its aiHistoryOptions query helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 19:39:15 +02:00
BOHA
441f46a471 feat(odin): tabs, thread, review-card, composer components
Add four presentational components + shared types under
src/admin/components/odin/ as props-driven building blocks for the
multi-conversation Odin page (Task 6 wires state/queries).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 19:34:22 +02:00
BOHA
e4ec08a5ef feat(ai): move the assistant to its own "Odin" sidebar page
Promote the AI chat from a dashboard widget to a dedicated page:
- new sidebar item "Odin" under the Přehled section, gated on ai.use, → /odin
- new /odin route + Odin page (reuses the assistant component, with a light
  ai.use guard)
- remove the widget from the dashboard
- rebrand the assistant header "Asistent" → "Odin" and give the thread more
  height now that it owns the page

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 18:38:35 +02:00
BOHA
f4bc038f8b fix(received-invoices): treat amount as gross (VAT-inclusive), back-calc VAT
The amount on a received invoice is the GROSS total the user pays (VAT
included), and VAT is the portion contained within it — not a net base with
VAT added on top. Switch the formula from amount*rate/100 to the
VAT-inclusive amount*rate/(100+rate) via a shared, tested vatFromGross()
helper used by both the create (manual upload + AI import share this
endpoint) and edit paths. Rate 0 → no VAT.

- AI extraction now asks Claude for the total INCLUDING VAT (was "základ bez
  DPH"), reinforced in the structured-output schema description.
- Label the amount field "Částka s DPH" in the AI review card and the manual
  upload/edit forms so the gross convention is explicit.
- Add unit tests with the user-confirmed figures (22 542,91 @ 21% → 3 912,41,
  base 18 630,50) plus other rates and the no-VAT case.

Existing rows keep their stored (gross) amounts; their vat_amount recomputes
on next edit. A one-shot backfill can correct historical vat_amount if wanted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:27:56 +02:00
BOHA
58e5fd2b1d feat(ai): server-side chat history + assistant UX fixes
Server-side, per-user chat history (the thread now survives reload):
- new ai_chat_messages table + migration; getChatHistory/appendChatMessages/
  clearChatHistory; GET/POST/DELETE /api/admin/ai/history (ai.use-guarded);
  service + HTTP tests (isolation, ordering, clear, perm, validation).
- DashAssistant loads the thread on mount and persists each turn; "Vymazat"
  clears it. gcTime:0 so each mount re-reads the DB (no stale-cache resurrection);
  composer gated until history settles + seed flag flipped on submit (no
  seed/submit race clobbering a freshly-sent turn).

UX + correctness fixes from review/feedback:
- review cards moved OUT of the scrollable thread into a "Faktury k potvrzení"
  section so Uložit is always reachable; chat auto-scroll no longer fires on
  field edits.
- chat bubble text colour set on the Typography (GlobalStyles pins `p` to
  text.secondary, which was overriding the inherited bubble colour → unreadable).
- never clear input/staged PDFs on a failed submit (rollback + keep), so a
  budget error can't wipe staged invoices; roll back the optimistic user turn.
- stable attachment ids (no crypto.randomUUID — undefined over plain HTTP).
- editable Datum splatnosti + Popis fields; client-side extraction summary.

Security: DashProfile clipboard copy now uses an execCommand fallback (works
over plain HTTP) and only shows the success toast when the copy actually
succeeded — previously it falsely claimed to copy 2FA codes / the TOTP secret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:02:26 +02:00
BOHA
b665ea1d9b feat(ai): dashboard chat widget with invoice import + budget indicator 2026-06-08 15:01:52 +02:00
BOHA
1ddc0feccd fix(plan): always show notes for every record in a multi-record cell
Previously notes were hidden when a cell held 2-3 records (a density
choice). Show each record's note regardless of count — drop the
now-unused showNote prop on PlanRangeChips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:53:45 +02:00
BOHA
13d1fc2be3 feat(plan): bulk assignment modal on /plan-work
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 12:11:20 +02:00
BOHA
23ac924472 fix(plan): edit/add the clicked record + layer-aware add in exception mode
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:29:52 +02:00
BOHA
9370423fb0 feat(plan): day panel — list/add/edit up to 3 records per cell
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:16:52 +02:00
BOHA
a146fc26a3 feat(plan): grid renders up to 3 stacked records per cell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 11:08:48 +02:00
BOHA
72888bf9cd feat(plan): resolveCell/resolveGrid return arrays; dashboard shows up to 3
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:53:26 +02:00
BOHA
67d62a6df0 fix(dashboard): rename today-plan card to "Vaše dnešní zařazení"
Clearer, formal (matches the app's Vy/Vaše tone) and category-agnostic
(reads fine for work and absence days) so the employee plainly sees what
they're assigned to. Was "Můj plán na dnešek".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:25:35 +02:00
BOHA
512f1fd92b feat(dashboard): show the user's work plan for today
Adds a "Můj plán na dnešek" card near the clock-in: for the logged-in
user it shows today's work-plan entry — category (coloured dot + label),
the project/site (the "where"), the note, and a "součást rozsahu …" badge
only for genuinely multi-day ranges. A muted "Pro dnešek nemáte
naplánováno." empty state when nothing is scheduled.

Server: GET /api/admin/dashboard now returns today_plan, reusing
plan.service resolveCell (override-beats-range precedence) for the current
user + today's local (Prague) date, enriched with the category label +
colour so the widget needs no extra query. Gated by attendance.record /
attendance.manage (the plan permission); omitted otherwise. No migration.

Verified in Chrome: renders today's entry (Práce · OBJ-2026-006 — koko)
with the category colour. tsc -b --noEmit, npm run build, vitest 152/152.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:22:07 +02:00
BOHA
b00d18d0b3 fix(plan): drop duplicate 'Zrušit' in the view-mode cell modal
The read-only plan-cell detail modal (view mode) already has a "Zavřít"
submit button, but the kit Modal also rendered its built-in "Zrušit"
cancel — two buttons that do the same thing. Pass hideCancel so only
"Zavřít" remains (same fix as the category-management modal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:54:42 +02:00
BOHA
54f3c414f5 fix(ui): unify icon badges — solid tile + white glyph via shared helper
The labelled icon-badge tiles were inconsistent: some used a same-hue
light tile + colored glyph (e.g. the Settings 2FA row: success.light tile
+ success.main glyph — low contrast, the reported "badly visible" icon),
and the solid-tile ones used the bright .main fill in dark mode without
darkening, so a white glyph on bright green/amber was low-contrast too
(DashProfile's success badge was ~1.9:1).

Add a single `iconBadgeSx(color)` helper (theme.ts): solid `<color>.main`
fill + white glyph, darkened in dark mode (FILLED_DARK_BG) so white stays
legible; `default` = neutral grey. Applied to every badge so they can't
drift: StatCard, DashActivityFeed, DashProfile (2FA badge), Dashboard
(2FA banner icon), AttendanceHistory (month tile), and the Settings 2FA
row tile (now solid green when required / grey when optional + white lock,
instead of the low-contrast light-green tile). Also switched DashProfile's
backup-codes warning callout from warning.light to a subtle warning wash
so its amber text stays readable in dark mode.

tsc -b --noEmit, npm run build, vitest 152/152 all clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 21:34:06 +02:00
BOHA
03285c6ff6 refactor(css): migrate Login + file icons off legacy vars, delete variables.css
Phase 4 (final) of the "fully MUI" cleanup — no custom stylesheets remain
in src/admin (only the third-party quill.snow.css + leaflet.css imports).

- Login.tsx: every var(--glass-*/bg-*/text-*/accent-*/orb-*/border-*/
  font-*/transition) in its sx/inline styles is now an MUI token
  (bgcolor/color/borderColor: "background.paper" / "text.secondary" /
  "divider" / "primary.main"), a channel-alpha (rgba(var(--mui-palette-
  primary-mainChannel) / a)) for tints, or theme.applyStyles("dark", …)
  for the glass-card shadow. The card sx is now a (theme)=>({}) callback.
- Restores the orb drift animation via the MUI keyframes() helper — the
  @keyframes float had been dropped in Phase 1 (the dead-CSS scan missed
  its use inside an sx animation string); recovered verbatim from git.
- ProjectFileManager: the fallback file-icon color uses
  var(--mui-palette-text-secondary).
- variables.css deleted; its import removed from AdminApp (last one).

tsc -b --noEmit + npm run build clean. applyStyles dark-scheme output and
the channel-alpha pattern were both verified live in Chrome via the Quill
editor, which uses the identical constructs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:45:36 +02:00
BOHA
d424ef8c15 refactor(css): scope Quill editor into styled() and delete offers.css
Phase 3 of the "fully MUI" cleanup.

- New src/admin/ui/RichText.tsx exports two theme-aware styled() wrappers:
  RichEditorRoot (the .admin-rich-editor Quill overrides) and RichTextView
  (the .admin-rich-text-view read-only output). All colors resolve via
  theme.vars; picker/tooltip shadows use theme.applyStyles for the
  light/dark difference; the active-button tint uses the primary channel.
- Dropped the ~170 dead font/size picker rules from the old stylesheet —
  the editor toolbar exposes neither picker. Kept the .ql-font-* content
  classes (shared by editor + view) so legacy stored HTML still renders.
- RichEditor uses <RichEditorRoot> (min-height still via --re-min-height);
  InvoiceDetail + OrderDetail use <RichTextView> for the sanitized output.
- offers.css deleted; its import removed from AdminApp.

tsc -b --noEmit and npm run build clean. Verified the editor in Chrome
(light + dark): toolbar, editor surface, text, icon strokes and min-height
all correct and theme-reactive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:37:11 +02:00
BOHA
96e35df535 refactor(css): delete dead pre-MUI CSS and eliminate plan.css
Phase 1 of the "fully MUI" CSS cleanup.

- base.css 429->317: drop dead .admin-sidebar/header/card/modal,
  .admin-drag-handle/-kbd/-mono/-error-stack/-loading and the unused
  float/pulse keyframes. Keep reset, typography, scrollbar,
  ::view-transition cross-fade, the live .admin-spinner (App.tsx
  pre-React loader) and all utility classes.
- attendance.css 456->24: keep only the Leaflet .attendance-location-map
  rules; the old hand-rolled Attendance page is MUI now.
- offers.css 642->417: keep only the Quill (.admin-rich-editor/.ql-*)
  and .admin-rich-text-view rules; drop the dead offers table / filter /
  lang-badge / row-state rules.
- plan.css deleted: the grid already lives in PlanGrid's styled()
  wrapper; the last consumer (.plan-cat-color) is now an sx-styled
  Box input in PlanCategoriesModal.

tsc -b --noEmit and npm run build both clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:20:17 +02:00
BOHA
fa90bcc93b fix(plan): drop the redundant 'Zrušit' button in the category-management modal
The Správa kategorií modal footer had two buttons that both just close it (Zrušit + Zavřít). Added an opt-in hideCancel prop to the kit Modal (default false → every other modal unchanged) and set it on PlanCategoriesModal, leaving only 'Zavřít'. Verified: footer shows only Zavřít; close/Escape/backdrop intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:09:59 +02:00
BOHA
3117e80027 feat(plan): migrate the planner grid to MUI (theme-driven, off plan.css)
PlanGrid's bespoke plan.css surface is replaced by a styled(Box) wrapper that scopes all the grid + chip rules and pulls every color from the theme palette via theme.vars (auto light/dark — no more [data-theme] CSS-var blocks). Sticky header + date column, marker-tape cells, category color via the per-cell --cat-color var, weekend/today treatment, hover affordances, the '+' empty hint, and the one-shot mutation pulse are all preserved; the paper-grain/ruled-paper texture was dropped for a clean MUI surface. plan.css trimmed from ~1150 lines to just the category-manager modal rows (the grid is MUI now; the toolbar/banner/day-choice modal had already moved to MUI components). Verified on /plan-work in both light and dark.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:05:27 +02:00
BOHA
2367e8a0ff feat(ui): mobile card layout for the remaining item tables
OrderConfirmationModal (the order→confirmation editable items dialog) and InvoiceDetail's read-only paid-invoice items table now render stacked label:value cards on phones (< sm) instead of a wide horizontally-scrolling table; desktop keeps the table. Same pattern as the Offer/Invoice editors. Gates: tsc=0, build=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:48:47 +02:00
BOHA
58da09cdc0 chore(mui): swap remaining admin-spinner loaders for kit LoadingState
Replace the three remaining hand-written admin-loading/admin-spinner
markup blocks with the kit <LoadingState /> component:
- AdminApp.tsx Suspense fallback
- AppShell.tsx loading branch
- PlanGrid.tsx no-data branch (plan-* classes untouched)

After this the only remaining admin-* classes in TSX are
admin-rich-editor (RichEditor/Quill) and admin-rich-text-view
(sanitized HTML in Order/Invoice detail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:50:39 +02:00
BOHA
ccdf0b68ea refactor(mui): remove dead legacy FormModal and ConfirmModal
Both components have zero importers after the phase-25 migrations
(verified: no `./FormModal` or `./ConfirmModal` imports remain; build
passes). Their MUI kit replacements are ui/Modal and ui/ConfirmDialog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:25 +02:00
BOHA
3b072ceefa refactor(mui): migrate ReservationPicker to kit Select
Replace the raw admin-form-select with the MUI kit Select (string-based
value, converted at the boundary). Same query (warehouseReservationList,
ACTIVE, perPage 100), same option labels, same onChange contract
(reservationId|null, remainingQty).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:20 +02:00
BOHA
68a8dae0dc refactor(mui): migrate ProjectFileManager to MUI kit
Replace legacy ConfirmModal with the kit ConfirmDialog (delete-confirm).
Re-skin onto Card + DataTable (file/folder rows), Box toolbar/breadcrumb,
EmptyState, LoadingState, kit Button/TextField/IconButton. The hidden
multipart file input is kept (per-file NAS upload). All queries,
mutations, invalidate keys (["projects", id, "files"]), NAS upload/
download/rename/create-folder/drag-drop logic, permissions, and Czech
text preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:16 +02:00
BOHA
e13f977c4d refactor(mui): migrate OrderConfirmationModal to kit Modal
Replace legacy FormModal with the MUI kit Modal. Map the two-step
flow (choose/edit) onto the kit footer: submitText + onSubmit switch
per step, submitDisabled gates "Vygenerovat PDF" when there are no
items. Re-skin lang/VAT toggles (kit Button variants), item editor
(kit TextField + IconButton inside a Box table). All generate/preview
logic, props, and Czech text preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:43:10 +02:00
BOHA
6f428b2297 feat(mui): migrate AlertContainer off admin-* CSS
Replaces framer-motion animation + custom SVG icons + admin-toast markup
with MUI Snackbar + MUI Alert (filled variant). useAlertState() consumption
(alerts array, removeAlert) is preserved verbatim — alert lifecycle
(timing, types, auto-dismiss) is owned by AlertContext and unchanged.
Alerts stack bottom-right with 72px vertical offset per slot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:32 +02:00
BOHA
67f98c1f66 feat(mui): migrate ErrorBoundary off admin-* CSS
Class component lifecycle (getDerivedStateFromError, componentDidCatch,
console.error, state shape) preserved verbatim. Only the fallback render
is re-skinned: Box+Typography for layout/text, kit Button for the reload
action. Czech strings unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:19 +02:00
BOHA
85d7ffaa14 feat(mui): migrate Forbidden off admin-* CSS
Re-skins the 403 fallback with MUI Box + kit EmptyState + kit Button
(component=Link). Czech text and routing preserved verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:37:09 +02:00
BOHA
088fe39bab chore(mui): delete 8 dead legacy components replaced by the kit
Removed (zero importers, build-verified): FormField, Pagination, AdminDatePicker, SortIcon, warehouse Supplier/Location/Batch selects, WarehouseMovementTable. FormModal + ConfirmModal kept (still used by OrderConfirmationModal + ProjectFileManager — to be migrated before full removal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:34:58 +02:00
BOHA
177d3f1902 fix(mui): stop dark/light oscillation (single data-theme owner) + animated ThemeToggle + white avatars
Removed MuiColorSchemeSync: it called MUI setMode which ALSO wrote data-theme, fighting ThemeContext (the other writer) → theme flip-flop loop. ThemeContext is now the sole owner; MUI's cssVariables CSS (scoped by [data-theme]) applies from the attribute, no JS bridge needed. New animated ThemeToggle kit button (sun/moon crossfade+rotate) replaces the static AppShell toggle. DashAttendanceToday avatars now solid-fill + white initials (matches StatCard/activity badges).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:39:14 +02:00
BOHA
ef0bb9f27e fix(mui): Dashboard icon badges (activity feed + 2FA status) — solid tile + white glyph
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:29:52 +02:00
BOHA
ebda3ecf23 feat(mui): migrate PlanWork modals + toolbar onto MUI kit (planner grid kept bespoke)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 01:29:48 +02:00
BOHA
5459d8c325 feat(mui): migrate Dashboard (Přehled) onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 01:19:49 +02:00
BOHA
c690bd9a24 feat(mui): migrate Attendance Admin (Správa docházky) onto MUI kit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 00:57:26 +02:00
BOHA
f51d5fcba4 feat(mui): rewrite warehouse ItemPicker on MUI Autocomplete (same props)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 00:21:17 +02:00