New worker: Kropáček Ondřej (TKB, part-time student) inserted between Dvořák Václav and Vondrák Pavel in data.json, the full-month Excel template (new row 13, everything below shifted) and the docházka template (13 person rows). Not added to the harmonogram/CIS roster — he has no CIS personal number. Also checkpoints the uncommitted work deployed to production between May and July 2026: - half-cell day/night preference marks (color + text per half) - cell copy/paste (Ctrl+C/V, context menu), incl. from info rows - light/dark theme toggle, TKB people filter, 162 filter - full-month Excel export (template) and harmonogram export for CIS - docházka export: half-time workers, retired flag, contractor handling - third login role "cis" (viewer + export access) - retired flag hides a person from UI/FPD while keeping past data Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
133 lines
4.3 KiB
Markdown
133 lines
4.3 KiB
Markdown
# Half-cell day/night preference marks — Design
|
||
|
||
**Date:** 2026-04-22
|
||
**Status:** approved, ready to implement
|
||
|
||
## Problem
|
||
|
||
In the original Excel schedule, each day cell was split horizontally
|
||
(left = night, right = day). Users marked preferences/obstacles by
|
||
filling the appropriate half with a color before shift planning began.
|
||
|
||
In the current app, each day = one cell. Users can only express
|
||
day-vs-night preferences via cell comments (small blue triangle), which
|
||
is not visual at a glance and therefore "annoying."
|
||
|
||
Multiple users have requested restoring the Excel behavior.
|
||
|
||
## Decisions
|
||
|
||
1. **Coexist with shifts** — preference marks stay visible after a shift
|
||
is assigned (so we can see whether we honored or violated the
|
||
request).
|
||
2. **Free color from palette** — same flexibility as the existing
|
||
whole-cell color picker; semantics are user-defined.
|
||
3. **Horizontal split: left = night, right = day** — matches the
|
||
original Excel.
|
||
4. **Visual when shift is assigned: corner triangles** — full shift
|
||
color fills the cell; small ~8×8 px triangles in the bottom corners
|
||
indicate the marks (bottom-left = night, bottom-right = day).
|
||
5. **Toggle in context menu** — segmented control `Celá | Noční | Denní`
|
||
above the color palette selects which field the next color click
|
||
updates.
|
||
|
||
## Data model
|
||
|
||
`CellValue` (in `types.ts`) gains two optional fields:
|
||
|
||
```ts
|
||
interface CellValue {
|
||
v?: string
|
||
color?: string // existing — full-cell background
|
||
dayColor?: string // NEW — right half / day mark
|
||
nightColor?: string // NEW — left half / night mark
|
||
}
|
||
```
|
||
|
||
The change is purely additive. Existing JSON files load unchanged.
|
||
|
||
## Rendering rules
|
||
|
||
| State | Look |
|
||
|-------|------|
|
||
| empty + no marks | empty (current) |
|
||
| `dayColor` and/or `nightColor` set, no shift | left half = `nightColor`, right half = `dayColor` (each independent; missing half = transparent or `color` fallback) |
|
||
| shift assigned, no marks | full shift color (current) |
|
||
| shift assigned + marks | full shift color + 8 px triangles: bottom-left = night, bottom-right = day |
|
||
|
||
Priority for picking renderer:
|
||
|
||
1. If `dayColor || nightColor` → split-half mode
|
||
2. Else if `color` → full-cell color (current behavior)
|
||
3. Else → empty
|
||
|
||
## Interaction
|
||
|
||
Right-click cell → existing context menu, with new segmented toggle
|
||
above the color palette:
|
||
|
||
```
|
||
Barva:
|
||
[ Celá ] [ Noční ] [ Denní ] ← default: Celá
|
||
● ● ● ● ● ● ● [Bez barvy]
|
||
```
|
||
|
||
- Toggle selects target field (`color`, `nightColor`, `dayColor`)
|
||
- Color click writes only to the selected target
|
||
- "Bez barvy" clears only the selected target
|
||
- Three fields are independent
|
||
|
||
## Drag-and-drop
|
||
|
||
Half marks are tied to the **day**, not the shift. When a user drags a
|
||
shift cell:
|
||
|
||
- Only `v` (and `color` of the shift) moves to the destination
|
||
- `dayColor` / `nightColor` stay on both source and destination days
|
||
|
||
## Compare / diff view
|
||
|
||
Differences in `dayColor` / `nightColor` count as cell changes — render
|
||
the same orange "modified" border as for value changes.
|
||
|
||
## Filters
|
||
|
||
- "Color only" filter (rainbow dot) — also hides cells whose only
|
||
content is `dayColor` / `nightColor` (no `v`)
|
||
- Hidden value filter (e.g. hide "A") — hides the cell entirely
|
||
including marks (marks are auxiliary)
|
||
|
||
## Scope
|
||
|
||
Half-mark editing is available on:
|
||
|
||
- ✅ Person cells (Pohotovost TKB / Pohotovost IT)
|
||
- ✅ Info rows (TKB / SAZLT / Metro / D8)
|
||
- ❌ PMS columns (month-end summary, doesn't make sense)
|
||
|
||
## Read-only
|
||
|
||
Existing `isReadOnly` guard handles viewer mode automatically. Viewers
|
||
see marks but cannot edit.
|
||
|
||
## Out of scope (phase 1)
|
||
|
||
- **Excel export/import** — original template has no clean
|
||
representation; round-trip would lose marks. Documented as a known
|
||
limitation; revisit if users request it.
|
||
- **PDF export** — will render half marks using same rules (no extra
|
||
work expected).
|
||
|
||
## Files to change
|
||
|
||
1. `web/src/types.ts` — extend `CellValue`
|
||
2. `web/src/useScheduleState.ts` — add `setCellHalfColor(personId,
|
||
dayIdx, target, color)` reducer + undo support
|
||
3. `web/src/ScheduleTable.tsx` — render split halves / corner triangles
|
||
in `PersonRow` and `renderInfoRowCells`
|
||
4. `web/src/ContextMenu.tsx` — add segmented toggle, route color clicks
|
||
to selected target
|
||
5. `web/src/cellColors.ts` — no change
|
||
|
||
Estimate: ~150 LoC across 4 files plus minimal CSS.
|