Employee Dashboard Documentation

Part 1: USER GUIDE - Dashboard


Table of Contents


1. Dashboard Overview

The Employee Dashboard is your main entry point to the DTR System. It displays your current attendance status, allows you to select shifts and workplaces, and provides quick access to check-in/out functionality.

What You Can Do

  • ✅ View current shift assignment
  • ✅ Select active shift (before check-in)
  • ✅ View other available shifts
  • ✅ Choose workplace location
  • ✅ Select workstation
  • ✅ Check in to start work
  • ✅ Check out to end work
  • ✅ View calendar with attendance records

Dashboard Layout

┌─────────────────────────────────────────────────────────────┐
│                    EMPLOYEE DASHBOARD                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Current Shift | Shift Selector | Workplace | Workstation  │
│  [Select]       [Dropdown]       [Dropdown]  [Dropdown]     │
│                                                             │
│  Other Shifts [Toggle]                  [Check In] Button   │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                   ATTENDANCE CALENDAR                       │
│              (Grid view of attendance records)              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. Dashboard Components

2.1 Header Section

The top section contains all controls for shift and workplace selection.

Current Shift Display

Before Check-In:

Current Shift
[Select Shift ▼]  [Other Shifts Toggle]  [Workplace ▼] [Workstation ▼]
                                                    [Check In Button]

After Check-In:

Current Shift
[Morning (08:00 - 17:00) - DISABLED]  [Workplace (Disabled)]
                                                    [Check Out Button]

Key Feature: Once you check in, shift and workplace selectors are disabled to prevent accidental changes during your shift.

2.2 Control States

State When Selectors Check Button
Before Check-In No active attendance 🟢 Enabled Check In
During Shift Checked in 🔴 Disabled Check Out
After Check-Out Shift ended 🟢 Enabled Check In

3. Current Shift Management

3.1 What is a Shift?

A Shift defines your scheduled work hours for the day.

Examples:

Morning Shift:    08:00 AM - 05:00 PM (9 hours with 1 hour break)
Afternoon Shift:  02:00 PM - 11:00 PM (9 hours with 1 hour break)
Night Shift:      11:00 PM - 08:00 AM (9 hours with 1 hour break)

3.2 Select Your Shift

Step 1: Access Shift Dropdown

Before checking in, you'll see the shift selector dropdown:

Current Shift
[Morning (08:00 - 17:00) ▼]
 ├─ Morning (08:00 - 17:00)
 ├─ Afternoon (14:00 - 23:00)
 └─ Night (23:00 - 08:00)

Step 2: Click Dropdown

Shows all shifts assigned to you today.

Step 3: Select Shift

Click desired shift to activate it.

✅ Shift Selected: Morning (08:00 - 17:00)

3.3 View Other Shifts

See additional shifts available:

  1. Check the "Other Shifts" toggle switch
  2. A modal dialog opens showing all available shifts
┌─────────────────────────────────────┐
│         ASSIGN SHIFT                │
├─────────────────────────────────────┤
│                                     │
│ [Shift Name | Time ▼]               │
│  ├─ Morning | 08:00 - 17:00        │
│  ├─ Afternoon | 14:00 - 23:00      │
│  └─ Night | 23:00 - 08:00          │
│                                     │
│ [OK Button]                         │
│                                     │
└─────────────────────────────────────┘
  1. Select a shift from the modal
  2. Click [OK] to confirm

4. Workplace & Workstation Selection

4.1 What is a Workplace?

A Workplace is a physical location where you work (office, warehouse, branch office, etc).

Example Workplaces:

• Main Office - 3rd Floor
• Branch Office - Makati
• Warehouse - Cavite
• Service Center - Quezon City

4.2 What is a Workstation?

A Workstation is your specific desk/position within a workplace.

Example Workstations:

Main Office:
  ├─ Desk 5-A (your usual desk)
  ├─ Desk 5-B
  ├─ Conference Room 1
  └─ Meeting Space

Remote Work:
  ├─ Home Office
  └─ Client Site

4.3 Select Workplace

Step 1: Click Workplace Dropdown

[Select Work Place ▼]
 ├─ Main Office - 3rd Floor
 ├─ Branch Office - Makati
 ├─ Warehouse - Cavite
 └─ Service Center - Quezon City

Step 2: Choose Workplace

Select where you'll be working today.

✅ Selected: Main Office - 3rd Floor

Step 3: Workstation Selector Appears

After selecting workplace, workstation dropdown becomes available.

4.4 Select Workstation

Step 1: Click Workstation Dropdown

[Select Work Stations ▼]
 ├─ Desk 5-A (Your usual desk)
 ├─ Desk 5-B
 ├─ Conference Room 1
 └─ Meeting Space

Step 2: Choose Your Station

Select your desk or workspace for the day.

✅ Selected: Desk 5-A

4.5 Already Checked In

If you've already checked in:

Workplace:    [Main Office - 3rd Floor] (DISABLED - Gray)
Workstation:  [Desk 5-A] (DISABLED - Gray)

Both fields are read-only to maintain consistency during your shift.


5. Check In/Out Functionality

5.1 Check In Process

Before Check-In:

Status: NOT CHECKED IN
[Check In Button] (BLUE - Enabled)

Step 1: Click "Check In" Button

┌──────────────────────────────────┐
│    CONFIRMING CHECK-IN...         │
│                                  │
│    Please wait...                │
│    [Loading spinner]             │
│                                  │
└──────────────────────────────────┘

Step 2: System Validates

  • ✅ Shift selected
  • ✅ Workplace selected
  • ✅ Workstation selected
  • ✅ GPS location (if required)

Step 3: Check-In Confirmed

✅ CHECK-IN SUCCESSFUL

Time: 08:30 AM
Shift: Morning (08:00 - 17:00)
Workplace: Main Office - 3rd Floor
Workstation: Desk 5-A
Status: ✅ APPROVED

Step 4: Button Changes to Check Out

Status: CHECKED IN (8h 30m remaining)
[Check Out Button] (RED - Enabled)

Selectors Become Disabled:
[Morning (08:00 - 17:00)] (DISABLED)
[Main Office - 3rd Floor] (DISABLED)
[Desk 5-A] (DISABLED)

5.2 Check Out Process

During Shift:

Status: CHECKED IN
Time Worked: 8 hours 45 minutes
[Check Out Button] (RED - Enabled)

Step 1: Click "Check Out" Button

┌──────────────────────────────────┐
│    CONFIRMING CHECK-OUT...        │
│                                  │
│    Please wait...                │
│    [Loading spinner]             │
│                                  │
└──────────────────────────────────┘

Step 2: System Validates

  • ✅ Check-in exists
  • ✅ Duration calculated
  • ✅ Records saved

Step 3: Check-Out Confirmed

✅ CHECK-OUT SUCCESSFUL

Check-In:  08:30 AM
Check-Out: 17:15 PM
Duration:  8h 45m
Status: ✅ APPROVED

Step 4: Dashboard Reset

Status: NOT CHECKED IN (Ready for next day)
[Check In Button] (BLUE - Re-enabled)
Shift Selector: 🟢 ENABLED
Workplace Selector: 🟢 ENABLED
Workstation Selector: 🟢 ENABLED

5.3 Error Handling

Missing Shift Selection

❌ ERROR: "Please select a shift first"
[Check In Button - DISABLED]

Missing Workplace

❌ ERROR: "Select a workplace before checking in"
Workplace dropdown shows red border

Missing Workstation

❌ ERROR: "Select a workstation before checking in"
Workstation dropdown shows red border

System Issues

❌ ERROR: "Check-in failed. Please try again."
[Retry Button]

6. Attendance Calendar

6.1 Calendar Purpose

The calendar displays all your attendance records in a grid view, showing:

  • ✅ Which days you checked in
  • ✅ Your shifts for each day
  • ✅ Time worked
  • ✅ Status (approved/pending)

6.2 Calendar View

ATTENDANCE CALENDAR
════════════════════════════════════════════════════

DECEMBER 2025
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│     │     │     │     │     │  1  │  2  │
│  3  │  4  │  5  │  6  │  7  │  8  │  9  │
│ 10  │ 11  │ 12  │ 13  │ 14  │ 15  │ 16  │
│ 17  │ 18  │ 19  │ 20  │ 21  │ 22  │ 23  │
│ 24  │ 25  │ 26  │ 27  │ 28  │ 29  │ 30  │
│ 31  │     │     │     │     │     │     │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘

6.3 Calendar Colors

Color Meaning
🟢 Green Checked in (Approved)
🟡 Yellow Pending approval
🔴 Red Not checked in / Off day
Gray Future date (no data)

6.4 Click Calendar Date

Click any date to see details:

┌──────────────────────────────────┐
│      DECEMBER 4, 2025             │
├──────────────────────────────────┤
│                                  │
│ Status: ✅ CHECKED IN             │
│ Shift: Morning (08:00 - 17:00)   │
│ Workplace: Main Office - 3F      │
│ Workstation: Desk 5-A            │
│                                  │
│ Check-In: 08:30 AM               │
│ Check-Out: 17:15 PM              │
│ Duration: 8h 45m                 │
│                                  │
│ [Close]                          │
│                                  │
└──────────────────────────────────┘

7. Tips & Troubleshooting

7.1 Best Practices

DO:

  • Select your shift before arriving at workplace
  • Choose correct workplace on first day at location
  • Check in within 15 minutes of shift start
  • Check out before leaving at end of shift

DON'T:

  • Change shift after checking in
  • Skip selecting workstation
  • Leave without checking out
  • Check in multiple times in one day

7.2 Common Issues

Issue 1: "Check In button is disabled"

Solution:

  1. Ensure shift is selected (dropdown shows a shift name)
  2. Ensure workplace is selected
  3. Ensure workstation is selected
  4. Try refreshing page if still disabled

Issue 2: "Cannot change shift while checked in"

Solution: This is intentional. You must check out first:

  1. Click [Check Out] button
  2. After successful check-out, shift selector will be enabled

Issue 3: "Workstation dropdown is empty"

Solution:

  1. First, select a workplace
  2. Workstations for that workplace will load
  3. Then select workstation

Issue 4: "Check in failed error"

Solution:

  1. Check internet connection
  2. Refresh page and try again
  3. If persists, contact IT support
  4. Include error message in support ticket

7.3 FAQ

Q: Can I check in from home?
A: Yes, if your organization allows remote work. Select "Remote Work" workplace and "Home Office" workstation.

Q: What if I forget to check out?
A: Contact your Team Lead or HR. They can manually close your attendance record.

Q: Can I change my shift after checking in?
A: No, shift is locked once you check in. You must check out first to change shifts.

Q: Why is my workstation dropdown empty?
A: You must select a workplace first. Workstations are filtered by selected workplace.

Q: What time should I check in?
A: Check in before your shift start time (e.g., 08:00 AM for Morning Shift).

Q: Can I check in early?
A: Yes, but you'll be marked as "Early Arrival" in the system.


END OF USER GUIDE - DASHBOARD PART 1


PART 2: DEVELOPER GUIDE - Dashboard


Table of Contents


1. Architecture Overview

1.1 Component Hierarchy

DashboardController
    ├── ShiftServices (get user shifts)
    ├── AttendanceRecordServices (get attendance data)
    └── view('users.employee.dashboard')
        ├── x-dashboard.employee.base (Layout Component)
        │   └── dashboard.blade.php (Main View)
        │       ├── Alpine.js (gridTimeCalendar)
        │       ├── Shift Selector (Dropdown)
        │       ├── Workplace Selector (Dropdown)
        │       ├── Workstation Selector (Dropdown)
        │       ├── Check In/Out Button
        │       └── Attendance Calendar
        └── Modal Components
            └── toggle_modal (Shift Assignment Modal)

1.2 Data Flow

User Visits Dashboard
    ↓
DashboardController@dashboard
    ├─ ShiftServices->get() → Get all shifts
    ├─ UserShift Query → Get user's selected shift
    └─ AttendanceRecordServices->getShiftAttendances()
        ↓
View Data Passed to Blade
    ├─ shifts (array)
    ├─ attendanceRecords (array)
    └─ currentShift (object)
        ↓
Blade Template Rendered
    └─ Alpine.js Initializes
        ├─ loadUserShifts() → Load shift data
        ├─ loadAttendances() → Load attendance calendar
        ├─ loadCurrentAttance() → Load current status
        └─ Ready for user interaction

2. Controller Implementation

2.1 DashboardController

File: app/Http/Controllers/Web/Employee/DashboardController.php

Method: dashboard()

public function dashboard(
    ShiftServices $shiftServices,
    AttendanceRecordServices $attendanceRecordServices
) {
    // Get all available shifts
    $shifts = $shiftServices->get();

    // Get user's currently selected shift
    $currentShift = UserShift::where('user_id', Auth::user()->id)
        ->where('is_selected', true)
        ->first();

    // Get attendance records for current shift
    $attendanceRecords = $attendanceRecordServices
        ->getShiftAttendances($currentShift->shift->id);

    return view('users.employee.dashboard', compact([
        'shifts',
        'attendanceRecords'
    ]));
}

Responsibilities:

  • 📋 Retrieve all shifts
  • 👤 Find user's selected shift
  • 📊 Get attendance data
  • 🔄 Pass data to view

Method: getWorkPlaces() (API)

public function getWorkPlaces()
{
    $workPlaces = WorkPlace::with(['workStations'])
        ->whereHas('employees', function ($q) {
            $q->whereHas('profile', function ($q) {
                $q->where('user_id', Auth::user()->id);
            });
        })
        ->get();

    return response([
        'workPlaces' => $workPlaces
    ]);
}

Purpose: Fetch available workplaces with nested workstations for current user

2.2 Service Classes

ShiftServices

class ShiftServices
{
    public function get()
    {
        return Shift::where('is_active', true)->get();
    }
}

AttendanceRecordServices

class AttendanceRecordServices
{
    public function getShiftAttendances($shiftId)
    {
        return AttendanceRecord::where('shift_id', $shiftId)
            ->where('user_id', Auth::user()->id)
            ->get();
    }
}

3. Blade Template Structure

3.1 Template File

File: resources/views/users/employee/dashboard.blade.php

Layout Inheritance

<x-dashboard.employee.base>
    <!-- Dashboard content -->
</x-dashboard.employee.base>

Base Layout Component: components/dashboard/employee/base.blade.php

3.2 Main Section

<div x-data="gridTimeCalendar" 
     class="flex flex-col gap-2"
     x-init="loadAttendances({{ json_encode($attendanceRecords) }})">

Alpine.js Component: gridTimeCalendar

Initialization:

  • Loads attendance records
  • Sets up calendar view
  • Initializes event listeners

3.3 Header Controls Section

<div class="flex flex-col sm:flex-row sm:justify-between">
    <!-- Shift Selector -->
    <!-- Workplace Selector -->
    <!-- Workstation Selector -->
    <!-- Check In/Out Button -->
</div>

Shift Selector

<template x-if="!currentAttendance?.status">
    <select @change="changeShiftAction($event)"
        class="select select-accent select-sm"
        x-init="loadUserShifts({{ json_encode($userShifts) }})">
        <template x-for="userShift in userShifts" :key="userShift.id">
            <option :value="JSON.stringify(userShift)">
                <span x-text="userShift.shift.name"></span> |
                <span x-text="`${userShift.shift.time_started} - 
                    ${userShift.shift.time_ended}`"></span>
            </option>
        </template>
    </select>
</template>

<template x-if="currentAttendance?.status == 'current'">
    <select disabled class="select select-accent select-sm">
        <!-- Same structure but disabled -->
    </select>
</template>

Behavior:

  • ✅ Enabled when not checked in
  • 🔴 Disabled when checked in
  • 📡 Loads from loadUserShifts()

Workplace & Workstation

<!-- Workplace Selector -->
<template x-if="!currentAttendance?.work_place">
    <select @change="pickWorkPlace($event)" 
        class="select select-accent select-sm">
        <option>Select Work Places</option>
        <template x-for="workPlace in workPlaces" :key="workPlace.id">
            <option :value="workPlace.id">
                <span x-text="workPlace.name"></span>
            </option>
        </template>
    </select>
</template>

<!-- Workstation Selector (conditional) -->
<template x-if="selectedWorkPlace">
    <select @change="pickWorkStation($event)" 
        class="select select-accent select-sm">
        <option>Select Work Stations</option>
        <template x-for="workStation in selectedWorkPlace.work_stations" 
            :key="workStation.id">
            <option :value="workStation.id">
                <span x-text="workStation.name"></span>
            </option>
        </template>
    </select>
</template>

Check In/Out Button

<template x-if="!currentAttendance?.status">
    <button @click="confirmCheckIn"
        :class="`text-white btn btn-accent btn-md ` + 
            (isLoading ? 'btn-disabled' : '')">
        Check In
        <span x-show="isLoading" class="loading loading-spinner">
        </span>
    </button>
</template>

<template x-if="currentAttendance?.status == 'current'">
    <button @click="confirmCheckOut"
        :class="`btn btn-error btn-sm ` + 
            (isLoading ? 'btn-disabled' : '')">
        <span>Check Out</span>
        <span x-show="isLoading" class="loading loading-spinner">
        </span>
    </button>
</template>

4. Alpine.js Components

4.1 gridTimeCalendar Object

x-data="gridTimeCalendar"

State Variables:

{
    currentAttendance: null,      // Current check-in record
    userShifts: [],                // User's available shifts
    workPlaces: [],                // Available workplaces
    selectedWorkPlace: null,       // Selected workplace object
    isLoading: false,              // Loading state
    errors: {},                    // Validation errors
    attendanceRecords: []          // Calendar data
}

4.2 Methods

loadAttendances(data)

loadAttendances(attendanceRecords) {
    this.attendanceRecords = attendanceRecords;
    // Render calendar grid
    this.renderCalendar();
}

loadCurrentAttance(records)

loadCurrentAttance(records) {
    this.currentAttendance = records
        .find(r => r.status === 'current');
}

loadUserShifts(shifts)

loadUserShifts(shifts) {
    this.userShifts = shifts;
}

changeShiftAction(event)

changeShiftAction(event) {
    const shift = JSON.parse(event.target.value);
    // Update selected shift
    // Dispatch to server
}

pickWorkPlace(event)

pickWorkPlace(event) {
    const workPlaceId = event.target.value;
    this.selectedWorkPlace = this.workPlaces
        .find(wp => wp.id == workPlaceId);
}

confirmCheckIn()

confirmCheckIn() {
    // Validate selections
    if (!this.validateCheckIn()) return;

    this.isLoading = true;

    // Send to server
    fetch('/api/attendance/check-in', {
        method: 'POST',
        body: JSON.stringify({
            shift_id: this.selectedShift.id,
            work_place_id: this.selectedWorkPlace.id,
            work_station_id: this.selectedWorkStation.id,
        })
    })
    .then(res => res.json())
    .then(data => {
        this.currentAttendance = data;
        this.isLoading = false;
    });
}

confirmCheckOut()

confirmCheckOut() {
    this.isLoading = true;

    fetch('/api/attendance/check-out', {
        method: 'POST'
    })
    .then(res => res.json())
    .then(data => {
        this.currentAttendance = null;
        this.isLoading = false;
        // Reset selectors
    });
}

5. API & Data Flow

5.1 Routes

// In routes/web.php
Route::middleware('auth')->group(function () {
    Route::get('/employee/dashboard', 
        [DashboardController::class, 'dashboard'])
        ->name('employee.dashboard');

    Route::get('/api/workplaces', 
        [DashboardController::class, 'getWorkPlaces'])
        ->name('api.workplaces');
});

5.2 Models & Relationships

UserShift Model

class UserShift extends Model
{
    public function user() {
        return $this->belongsTo(User::class);
    }

    public function shift() {
        return $this->belongsTo(Shift::class);
    }
}

AttendanceRecord Model

class AttendanceRecord extends Model
{
    public function user() {
        return $this->belongsTo(User::class);
    }

    public function shift() {
        return $this->belongsTo(Shift::class);
    }

    public function workplace() {
        return $this->belongsTo(WorkPlace::class);
    }

    public function workstation() {
        return $this->belongsTo(WorkStation::class);
    }
}

5.3 Data Structures

Shift Object

{
    "id": 1,
    "name": "Morning",
    "time_started": "08:00",
    "time_ended": "17:00",
    "is_active": true
}

Workplace Object

{
    "id": 1,
    "name": "Main Office - 3rd Floor",
    "work_stations": [
        {
            "id": 1,
            "name": "Desk 5-A"
        },
        {
            "id": 2,
            "name": "Desk 5-B"
        }
    ]
}

Attendance Record Object

{
    "id": 1,
    "user_id": 5,
    "shift_id": 1,
    "work_place_id": 1,
    "work_station_id": 1,
    "check_in": "2025-12-04 08:30:15",
    "check_out": "2025-12-04 17:15:00",
    "status": "current" | "approved" | "pending",
    "duration_minutes": 525
}

Summary

Component Responsibility
Controller Load data, validate requests
Service Business logic, data retrieval
Blade Render HTML, Alpine.js setup
Alpine.js Interactive UI, state management
API Handle async requests

File Structure:

app/Http/Controllers/Web/Employee/
└── DashboardController.php

resources/views/users/employee/
└── dashboard.blade.php

resources/components/dashboard/employee/
└── base.blade.php

Documentation Version: 1.0
Last Updated: December 4, 2025
Status: ✅ Complete