Calendar Module
Appointments są planowanymi wizytami, które mogą stać się Visits. ~25 plików, ~15k LOC.
Calendar -> Visits (Appointments) Flow
Dział zatytułowany „Calendar -> Visits (Appointments) Flow”sequenceDiagram participant User participant Calendar as CalendarView participant AppService as appointmentsService participant Rust as Tauri Commands participant DB as SQLite
%% Tworzenie appointment User->>Calendar: Schedule appointment Calendar->>AppService: createAppointment(request) AppService->>Rust: create_appointment Rust->>DB: INSERT INTO appointments DB-->>Rust: appointment_id Rust-->>Calendar: Appointment created
%% Konwersja na wizytę User->>Calendar: Start Visit from appointment Calendar->>AppService: completeAppointment(aptId, visitId, userId) AppService->>Rust: complete_appointment Rust->>DB: UPDATE appointments SET status='completed', visit_id=? DB-->>Calendar: Appointment linked to visitAppointment Model
Dział zatytułowany „Appointment Model”erDiagram APPOINTMENTS ||--o| VISITS : "becomes" APPOINTMENTS ||--|| PATIENTS : "for" APPOINTMENTS ||--|| USERS : "veterinarian"
APPOINTMENTS { string appointment_id PK string patient_id FK string veterinarian_id FK string scheduled_date string scheduled_time int duration_minutes string appointment_type enum status "scheduled|completed|cancelled|no_show" string visit_id FK "nullable - set on complete" string notes bool is_recurring string recurrence_pattern bool reminder_enabled bool reminder_email_sent }Appointment Status Transitions
Dział zatytułowany „Appointment Status Transitions”stateDiagram-v2 [*] --> scheduled: create_appointment scheduled --> completed: complete_appointment (link visit_id) scheduled --> cancelled: cancel_appointment scheduled --> no_show: mark_no_show completed --> [*] cancelled --> [*] no_show --> [*]Appointments Service API
Dział zatytułowany „Appointments Service API”| FE Method | Rust Command | Description |
|---|---|---|
createAppointment(request) | create_appointment | Schedule new appointment |
updateAppointment(request) | update_appointment | Modify appointment |
cancelAppointment(id) | cancel_appointment | Cancel appointment |
completeAppointment(aptId, visitId) | complete_appointment | Link to visit, mark done |
deleteAppointment(id) | delete_appointment | Remove appointment |
getAppointments(filter) | get_appointments | Query appointments |
checkForConflicts(...) | check_comprehensive_staff_conflicts | Check time conflicts |
Calendar System Architecture
Dział zatytułowany „Calendar System Architecture”erDiagram USERS ||--o{ APPOINTMENTS : creates PATIENTS ||--o{ APPOINTMENTS : "scheduled for" APPOINTMENTS ||--o| VISITS : "converts to" USERS ||--o{ USER_WORKING_HOURS : "has availability" USERS ||--o{ TIME_BLOCKS : "has blocked time"
APPOINTMENTS { string appointment_id PK string patient_id FK string veterinarian_id FK string scheduled_date "ISO date" string scheduled_time "HH:MM" int duration_minutes "default 30" string appointment_type "consultation|surgery|etc" string status "scheduled|confirmed|completed" string visit_id FK "nullable" bool is_recurring string recurrence_pattern json additional_staff "array of user_ids" }
USER_WORKING_HOURS { string id PK string user_id FK int day_of_week "0-6 (0=Sunday)" string start_time "HH:MM" string end_time "HH:MM" bool is_available string break_start_time "optional" string break_end_time "optional" }
TIME_BLOCKS { string time_block_id PK string user_id FK string title string start_date "ISO" string end_date "ISO" string start_time "HH:MM" string end_time "HH:MM" string block_type "busy|available|break|meeting" bool is_recurring }Conflict Detection Logic
Dział zatytułowany „Conflict Detection Logic”#[tauri::command]pub async fn check_comprehensive_staff_conflicts( db: State<'_, Database>, veterinarian_id: String, date: String, // "2025-09-04" start_time: String, // "14:30" duration_minutes: i32, // 30) -> Result<ConflictResult, String> {
// Check 1: Existing appointments let existing_appointments = sqlx::query!( "SELECT * FROM appointments WHERE veterinarian_id = ? AND scheduled_date = ? AND status NOT IN ('cancelled', 'completed')", veterinarian_id, date ).fetch_all(&db.pool).await?;
// Check 2: Working hours let working_hours = sqlx::query!( "SELECT * FROM user_working_hours WHERE user_id = ? AND day_of_week = ? AND is_available = true", veterinarian_id, get_day_of_week(&date)? ).fetch_all(&db.pool).await?;
// Check 3: Time blocks (meetings, breaks, etc.) let time_blocks = sqlx::query!( "SELECT * FROM time_blocks WHERE user_id = ? AND start_date <= ? AND end_date >= ? AND block_type = 'busy'", veterinarian_id, date, date ).fetch_all(&db.pool).await?;
// Complex overlap detection logic let conflicts = detect_time_overlaps( existing_appointments, working_hours, time_blocks, &start_time, duration_minutes )?;
Ok(ConflictResult { has_conflicts: !conflicts.is_empty(), conflicts, suggested_times: suggest_alternative_times(/* ... */)?, })}Calendar Views
Dział zatytułowany „Calendar Views”Responsive calendar system:
- Mobile: Day view with swipe navigation
- Desktop: Week view with drag-and-drop
- Analytics: Month view with statistics
- Search: Global appointment search
View components:
DayView.tsx- Detailed hourly scheduleWeekView.tsx- 7-day overview with staff columnsMonthView.tsx- Monthly calendar with indicatorsMiniCalendar.tsx- Date picker component