Kalendář
Cesta: / nebo /Calendar
Komponenta: src/pages/Calendar.jsx
Role: Admin
Centrální rozhraní aplikace. Slouží ke správě všech termínů, blokací a dovolených.
Pohledy
| Pohled | Popis |
|---|---|
| Týdenní — terapeuté | Každý terapeut má vlastní sloupec, zobrazuje celý tým najednou |
| Týdenní — místnosti | Každá místnost jako sloupec, viditelnost obsazenosti prostor |
| Měsíční přehled | Přehled termínů v rámci měsíce |
| Agenda | Seřazený seznam nadcházejících termínů |
Funkce
- Kliknutí na volný slot → otevře
EventDialogs předvyplněným časem, terapeutem a místností - Drag & drop pro přesunutí termínu na jiný čas
- Filtry: výběr konkrétních terapeutů a místností v postranním panelu
- Detekce konfliktů v reálném čase (překryv termínů, kapacita místnosti)
- Automatické logování všech změn do ActivityLog
EventDialog — vytvoření termínu
Nejkomplexnější komponenta aplikace (src/components/calendar/EventDialog.jsx).
Workflow
flowchart TD
A[Klik na slot v kalendáři] --> B[Otevře EventDialog]
B --> C[Výběr typu: termín / blokace / dovolená]
C --> D[Výběr data a terapeuta]
D --> E[Výpočet volných slotů]
E --> F[Výběr výkonu a slotu]
F --> G[Výběr místnosti]
G --> H[Výběr klienta — povinné pro termín]
H --> I[Uložení → CalendarEvent.create]
I --> J[ActivityLog záznam]
J --> K{Nový termín?}
K -- ano --> L[PaymentMethodDialog — volba způsobu úhrady]
K -- ne --> M[Konec]
Změna logiky (export 19. 8. 2026): po uložení termínu se místo prosté nabídky platebního odkazu otevře PaymentMethodDialog, který ukazuje všechny dostupné způsoby úhrady i jejich hodnotu:
- čerpat z balíčku (se zbývajícím počtem sezení)
- zaplatit kreditem (zůstatek vs. cena)
- výzva k platbě (e-mail / odkaz klientovi, nově i SMS)
- platba na místě — hotovost nebo karta na recepci, s ID transakce pro spárování (
internal_payment_id)
U výkonů s is_insurance se fáze platby přeskočí úplně — rezervace vznikne s payment_method = 'insurance' a klient neplatí.
Vedle toho je v dialogu BookingLinkBox s veřejným rezervačním odkazem podle vybraného výkonu a terapeuta (/client?service=…&therapist=…) a u zaplacených termínů RefundDialog pro vratku.
Logika volných slotů
Pro každý AvailabilityBlock terapeuta na dané datum:
1. Filtr podle service_types (pokud vybrán výkon)
2. Generuj sloty po 30 min od start_time do end_time − duration
3. Vyřaď sloty s konfliktem (překryv s existujícími CalendarEvent)
4. Zobraz jen :00 a :30 sloty (čistší UX)
Ruční mód: Admin může přepnout na ruční zadání časů — obejde logiku volných slotů.
Validace před uložením
- Povinná pole (terapeut, datum, čas, klient pro appointment)
- Konflikt s existující událostí terapeuta
- Kapacita místnosti (
room.capacity) - Zda termín leží v aktivním AvailabilityBlock
Typy událostí
| Typ | Popis |
|---|---|
appointment |
Termín s klientem — vyžaduje klienta, výkon |
blockage |
Blokace terapeuta (osobní, administrativa) |
vacation |
Dovolená — může být celodenní |
Stavy termínu
reserved → confirmed → completed
Alternativní stavy: excused, no_show_paid, no_show_unpaid, no_show_insurance, cancelled, cancelled_late, auto_cancelled_unpaid
Poznámka: stav
paidbyl z enumustatusodebrán už dřív. Zaplacení se sleduje výhradně polempayment_status(unpaid/pending/paid/refunded/partially_refunded).
Nedostavil se — storno pojišťovna (nové)
Ověřený fakt — stav no_show_insurance se nabízí jen u klientů ve skupině s is_insurance na výkonu s is_insurance. Backend (clientBooking, akce process_insurance_no_show):
- nastaví termín i rezervaci na
no_show_insuranceapayment_status = 'unpaid' - spočítá stornopoplatek z
SystemSettings.insurance_cancellation_fee(default 1 000 Kč) - odešle klientovi e-mail (volitelně SMS) s odkazem
/storno?token=…k úhradě - po zaplacení (
confirm_insurance_cancellation_fee_payment) vystaví doklad typupenalty
Změna logiky: poplatek nese klient, i když samotný výkon hradí pojišťovna a klient za něj neplatí nic.
Účetní návaznost stavů
Změna logiky: stav termínu nově spouští účetní akci na pozadí (Base44 entitní automat):
| Přechod | Automat | Účetní dopad |
|---|---|---|
→ completed |
onServiceRealized |
vznik výnosu, případně doklad k dodávce nebo marketingový náklad |
→ cancelled_late |
onLateCancellation |
storno poplatek (document_type = penalty) |
Samotný způsob označení termínu v UI se nezměnil.