Skip to content

mp-c0de/CasinoRotaScheduler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Casino Rota Scheduler

Overview

A sophisticated casino shift management application built with SwiftData that enables floor managers to coordinate dealer schedules across multiple tables with real-time timeline visualization. The app features a comprehensive rota planning system with 20-minute time slot granularity, color-coded fatigue indicators, break management, and historical shift archiving. Designed for high-volume casino operations requiring precise dealer rotation tracking and workload distribution across 8-hour shifts.

Features

  • Shift Management: Three shift types (Graveyard 6am-2pm, Afternoon 2pm-10pm, Night 10pm-6am)
  • 20-Minute Time Slots: Precise dealer assignment tracking with 24 slots per 8-hour shift
  • Real-Time Playhead: Red vertical line showing current time within active shift
  • Fatigue Indicators: Color-coded cells (green/yellow/red) warning of excessive consecutive table time
  • Break Tracking: Special "BREAK" placeholder table for dealer rest periods
  • Multi-Table Support: Assign dealers across multiple table locations (Roulette, Blackjack, Poker, Baccarat)
  • Employee Management: Track dealers with ranks (Trainee, Junior, Senior) and roles
  • Timeline View: Horizontal scrolling grid showing entire shift schedule at a glance
  • On-Duty Roster: Dynamic dealer list management with add/remove functionality
  • Shift History: Archive view for reviewing past schedules
  • Auto-Centering: Jump to current time slot with animated scrolling
  • SwiftData Persistence: Robust relational database with Assignment, Employee, Table, Shift, and Rank entities

Technical Stack

  • Language: Swift 5.9+
  • Framework: SwiftUI
  • Platform: iOS 17.0+
  • Data Persistence: SwiftData with complex relationships
  • Architecture: MVVM with @Query dynamic fetching
  • State Management: @AppStorage, @State, @Environment
  • UI Components: LazyVStack, ScrollViewReader, Menu, Picker

Key Learning Concepts

SwiftData Complex Relationships

  • One-to-many relationships (Shift → Assignments, Employee → Assignments, Table → Assignments)
  • Cascade delete rules for maintaining data integrity
  • Inverse relationship configuration
  • @Relationship property wrapper
  • Bidirectional navigation through relationships

Advanced SwiftData Queries

  • @Query with dynamic sort descriptors
  • FetchDescriptor with predicates
  • Direct context fetching for real-time data
  • Filtering assignments by shift date and code
  • Grouping query results by employee ID

Timeline Visualization

  • Horizontal/vertical ScrollView coordination
  • LazyVStack for performance with large datasets
  • ScrollViewReader for programmatic scrolling
  • Overlay positioning for playhead indicator
  • Dynamic cell background coloring based on state

Date & Time Calculations

  • Calendar-based slot generation (20-minute intervals)
  • Shift start time computation across day boundaries
  • Night shift date anchor handling (crosses midnight)
  • Real-time playhead position calculation
  • Time-based filtering and comparisons

Real-Time Updates

  • Timer.publish for clock updates (60-second intervals)
  • .onReceive for reactive time-based UI updates
  • Live playhead rendering synchronized with system clock
  • Auto-refresh on shift date/code changes

State Persistence

  • @AppStorage for shift selection persistence
  • TimeInterval storage for Date values
  • User preference synchronization across app launches

Project Structure

CasinoRotaScheduler/
├── VicRotaManager/
│   ├── VicRotaManagerApp.swift                # Main app entry point
│   ├── ContentView.swift                      # Tab view container
│   ├── ShiftSheetView.swift                   # Main timeline grid interface
│   ├── ManagerDashboardView.swift             # Statistics and overview
│   ├── EmployeeCreationView.swift             # Add new employees
│   ├── ShiftArchiveView.swift                 # Historical shift browser
│   ├── DealerShiftModels.swift                # SwiftData models (Employee, Table, Shift, Assignment, Rank)
│   ├── DataSeeder.swift                       # Demo data generator
│   ├── AssignmentBlock.swift                  # Assignment cell component
│   └── TimeRulerView.swift                    # Timeline header component

Code Highlights

SwiftData Relationship Models

Complex entity relationships for shift scheduling:

@Model
final class Assignment: Identifiable {
    @Attribute(.unique) var id: UUID
    @Relationship var employee: Employee
    @Relationship var table: Table
    @Relationship var shift: Shift

    var position: Int        // 1 = current, 2 = next
    var startAt: Date
    var endAt: Date
    var confirmedAt: Date?
}

@Model
final class Employee: Identifiable {
    @Attribute(.unique) var id: UUID
    var firstName: String
    var lastName: String
    var role: Role
    var rank: Rank?
    var isActive: Bool

    @Relationship(deleteRule: .cascade, inverse: \Assignment.employee)
    var assignments: [Assignment] = []
}

@Model
final class Shift: Identifiable {
    @Attribute(.unique) var id: UUID
    var date: Date
    var shiftCode: String   // "DAY", "SWING", "NIGHT"

    @Relationship(deleteRule: .cascade, inverse: \Assignment.shift)
    var assignments: [Assignment] = []
}

Fatigue Indicator Logic

Color-coded warnings for dealer workload:

private var consecutiveTables: Int {
    let assigns = (try? context.fetch(FetchDescriptor<Assignment>())) ?? []
    var n = 0
    var cursor = bounds.start

    // Count backwards from current slot
    while assigns.contains(where: {
        $0.employee.id == dealer.id &&
        $0.startAt == cursor &&
        $0.table.id != breakTable.id  // Skip breaks in count
    }) {
        n += 1
        cursor = Calendar.current.date(byAdding: .minute, value: -20, to: cursor)!
    }
    return n
}

private var colorForConsecutive: Color {
    switch consecutiveTables {
    case danger...: return .red      // 6+ consecutive slots (2 hours)
    case warn...:   return .yellow   // 4-5 consecutive slots (80-100 min)
    default:        return .green    // < 4 slots
    }
}

Real-Time Playhead Rendering

Live timeline indicator synchronized with system clock:

private var playheadX: CGFloat? {
    let startHour = ["GRAVEYARD":6, "AFTERNOON":14, "NIGHT":22][shiftCode]!
    let cal = Calendar.current
    let shiftStart = cal.date(bySettingHour: startHour,
                              minute: 0, second: 0,
                              of: shiftAnchorDate())!
    let shiftEnd = shiftStart.addingTimeInterval(Double(shiftHours * 60 * 60))

    guard now >= shiftStart && now < shiftEnd else { return nil }

    let minutes = now.timeIntervalSince(shiftStart) / 60
    return nameColWidth + CGFloat(minutes) / CGFloat(slotMinutes) * cellWidth
}

.overlay(alignment: .topLeading) {
    if showPlayhead, let x = playheadX {
        Rectangle()
            .fill(.red)
            .frame(width: 2)
            .frame(maxHeight: .infinity)
            .offset(x: x)
    }
}
.onReceive(clockTimer) { now = $0 }  // Update every 60 seconds

Dynamic Time Slot Generation

Calculating 20-minute intervals for shift duration:

private var timeSlots: [Date] {
    let cal = Calendar.current
    let startHour = ["GRAVEYARD":6, "AFTERNOON":14, "NIGHT":22][shiftCode]!

    // Handle night shift crossing midnight
    let anchor = (shiftCode == "NIGHT")
        ? cal.date(byAdding: .day, value: -1, to: shiftDate)!
        : shiftDate

    let shiftStart = cal.date(bySettingHour: startHour,
                              minute: 0, second: 0, of: anchor)!
    let count = (shiftHours * 60) / slotMinutes  // 24 slots

    return (0..<count).map {
        shiftStart.addingTimeInterval(Double($0 * slotMinutes * 60))
    }
}

Skills Demonstrated

  • SwiftData Mastery: Complex multi-entity relationships with cascade delete rules
  • Advanced Querying: Dynamic fetches with predicates and sort descriptors
  • Timeline Visualization: Custom scrollable grid with overlay indicators
  • Date/Time Programming: Calendar arithmetic and time zone handling
  • Real-Time UI: Live updates synchronized with system clock
  • State Persistence: AppStorage for user preferences across sessions
  • Performance Optimization: LazyVStack for efficient rendering of large datasets
  • UI/UX Design: Intuitive shift scheduling interface with visual workload indicators
  • Data Modeling: Comprehensive entity design for casino operations

Use Cases

Daily Shift Planning

Casino floor managers create and adjust dealer rotations across all tables for the current shift with drag-and-drop simplicity.

Break Management

Ensure compliance with labor regulations by tracking dealer breaks and preventing excessive consecutive table time.

Real-Time Adjustments

Monitor live dealer assignments with playhead indicator, making on-the-fly changes as needed during active shifts.

Historical Review

Analyze past shift assignments to identify patterns, optimize rotations, and resolve disputes about work assignments.

Workload Distribution

Visual fatigue indicators help managers distribute workload fairly and prevent dealer burnout from long consecutive assignments.

Future Enhancements

  • Drag & Drop: Touch-based drag-and-drop dealer assignment interface
  • Automatic Scheduling: AI-powered shift planning based on dealer preferences and skills
  • Conflict Detection: Real-time warnings for double-bookings or schedule conflicts
  • Break Alerts: Automated reminders when dealers exceed maximum consecutive time
  • Export Functionality: PDF/Excel export of shift schedules for printing
  • Mobile App: Companion app for dealers to view their schedules
  • Push Notifications: Alert dealers of shift changes or assignments
  • Analytics Dashboard: Charts showing dealer utilization and table coverage
  • Skill Matching: Assign dealers based on game type expertise and certifications
  • Overtime Tracking: Calculate and display overtime hours for payroll
  • Multi-Casino Support: Manage schedules across multiple casino locations
  • Integration: Connect with payroll and HR systems for seamless operations

Author: Martynas Prascevicius Contact: mpcode@icloud.com Project Type: Business Application - Casino Operations Management Frameworks: SwiftUI, SwiftData, Combine

About

Proof-of-concept shift management system for casino operations - SwiftUI, SwiftData, Timeline Views

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages