Skip to content

Commit

Permalink
report time tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
felixmpa committed Nov 23, 2022
1 parent 78945c8 commit c819365
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 68 deletions.
223 changes: 164 additions & 59 deletions app/Http/Controllers/Api/TimeTrackerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,38 @@
use App\Models\User;
use App\Models\TimeTracker;
use Carbon\Carbon;
use Carbon\CarbonInterval;


class TimeTrackerController extends Controller
{
public $currentDate;
public $sec, $min, $hour;
public $workedHour, $workedMin, $workedSec, $breakHour, $breakMin, $breakSec;

public function __construct()
{
$this->currentDate = Carbon::now();
$this->sec = 0;
$this->min = 0;
$this->hour= 0;
$this->workedHour = 0;
$this->workedMin = 0;
$this->workedSec = 0;
$this->breakHour = 0;
$this->breakMin = 0;
$this->breakSec = 0;
}

public function index(Request $request)
{

$trackers = $this->getTimeTrackerOfDateByUser($request);

$intervalList = [];

$trackers = $this->getTimeTrackerOfDateByUser($this->currentDate->format('Y-m-d'), $request->user()->id);

if($trackers->count() == 0)
User::where('id', $request->user()->id)->update(['is_time_tracker_started' => 0]);

if($trackers->count() > 0)
{
$initialCheckIn = Carbon::parse($trackers->firstOrFail()->tracked_at);

//If pause is the last item then diff with this tracked_at
if($trackers[$trackers->count()-1]->is_check_in == 0){
$clock = Carbon::parse($trackers[$trackers->count()-1]->tracked_at)->diff($initialCheckIn);
}else{
$clock = Carbon::now()->diff($initialCheckIn);
}

list($this->sec, $this->min, $this->hour) = array($clock->s, $clock->i, $clock->h);

foreach($trackers->sortBy(['tracked_at', 'asc']) as $index => $tracker)
{
if($index > 0 && $tracker->is_check_in == 1 && $trackers[$index - 1]->is_check_in == 0) {

$interval = Carbon::parse($tracker->tracked_at)->diff(Carbon::parse($trackers[$index - 1]->tracked_at));

$trackers[$index - 1]->duration = str_pad($interval->h, 2, 0, STR_PAD_LEFT) . ":" . str_pad($interval->i, 2, 0, STR_PAD_LEFT) . ":" . str_pad($interval->s, 2, 0, STR_PAD_LEFT);

if($this->hour > $interval->h){
$this->hour -= $interval->h;
}else{
$this->min -= round($interval->h / 60);
}

if($this->min > $interval->i){
$this->min -= $interval->i;
}else{
$this->sec -= round($interval->i / 60);
}

if($this->sec > $interval->s)
$this->sec -= $interval->s;
}
$intervalList[] = $tracker;
}

}
list($this->workedHour, $this->workedMin, $this->workedSec,
$this->breakHour, $this->breakMin, $this->breakSec,
$intervalList) = $this->calculateListTrackersResult($trackers);

$data = array (
'sec' => $this->sec,
'min' => $this->min,
'hour' => $this->hour,
'hour' => $this->workedHour,
'min' => $this->workedMin,
'sec' => $this->workedSec,
'user' => $request->user(),
'intervalList' => $intervalList
);
Expand All @@ -88,7 +49,7 @@ public function index(Request $request)

public function store(Request $request)
{
$total = $this->getTimeTrackerOfDateByUser($request)->count();
$total = $this->getTimeTrackerOfDateByUser($this->currentDate->format('Y-m-d'), $request->user()->id)->count();

User::where('id', $request->user()->id)->update([
'is_time_tracker_started' => ($request->user()->is_time_tracker_started == 1) ? 0 : 1
Expand All @@ -110,11 +71,155 @@ public function edit(Request $request, $id)
return $data;
}

public function getTimeTrackerOfDateByUser(Request $request)
public function getTimeTrackerOfDateByUser(string $date, int $user_id)
{
return TimeTracker::where(['date' => $this->currentDate->format('Y-m-d'),
'user_id' => $request->user()->id])
->get();
return TimeTracker::where(['date' => $date, 'user_id' => $user_id])->get();
}


public function report(Request $request)
{
$today = Carbon::now()->format('Y-m-d');
$fromDate = Carbon::now()->subDays(5)->format('Y-m-d');
$toDate = $today;

$usersGroupByDate = TimeTracker::select('user_id','date')
->whereBetween('date', [$fromDate, $toDate])
->groupBy(['user_id', 'date'])
->get();

$data = [];

foreach($usersGroupByDate as $row)
{
$user = User::where('id', $row->user_id)->first();

if(!$user->exists())
continue;

$trackers = $this->getTimeTrackerOfDateByUser($row->date, $row->user_id);

$interval = $this->calculateListTrackersResult($trackers);

$lastTrack = 'Missed Check-out';

if($trackers->last()->is_check_in == 0)
$lastTrack = $trackers->last()->tracked_at;

if($trackers->last()->is_check_in == 1 && $trackers->last()->date == $today)
$lastTrack = 'Reporting';

$data[] = array(
'date' => $row->date,
'user_id' => $user->id,
'user_name' => $user->name,
'user_email' => $user->email,
'workedHour ' => $interval[0],
'workedMin ' => $interval[1],
'workedSec ' => $interval[2],
'breakHour ' => $interval[3],
'breakMin ' => $interval[4],
'breakSec ' => $interval[5],
'workedTimeFormat' => sprintf('%s:%s:%s',
str_pad($interval[0], 2, "0", STR_PAD_LEFT),
str_pad($interval[1], 2, "0", STR_PAD_LEFT),
str_pad($interval[2], 2, "0", STR_PAD_LEFT)
),
'breakTimeFormat' => sprintf('%s:%s:%s',
str_pad($interval[3], 2, "0", STR_PAD_LEFT),
str_pad($interval[4], 2, "0", STR_PAD_LEFT),
str_pad($interval[5], 2, "0", STR_PAD_LEFT)
),
'initialTrack' => $trackers->first()->tracked_at,
'lastTrack' => $lastTrack
);
}

return $data;
}



public function calculateListTrackersResult($trackers)
{
$intervalList = [];
$workedHour = 0;
$workedMin = 0;
$workedSec = 0;
$breakHour = 0;
$breakMin = 0;
$breakSec = 0;

if($trackers->count() > 0)
{
$initialCheckIn = Carbon::parse($trackers->firstOrFail()->tracked_at);

//If pause is the last item then diff with this tracked_at
if($trackers[$trackers->count()-1]->is_check_in == 0){
$clock = Carbon::parse($trackers[$trackers->count()-1]->tracked_at)->diff($initialCheckIn);
}else{
$clock = Carbon::now()->diff($initialCheckIn);
}

list($workedSec, $workedMin, $workedHour) = array($clock->s, $clock->i, $clock->h);

foreach($trackers->sortBy(['tracked_at', 'asc']) as $index => $tracker)
{
if($index > 0 && $tracker->is_check_in == 1 && $trackers[$index - 1]->is_check_in == 0) {

$breakTaken = Carbon::parse($tracker->tracked_at)->diff(Carbon::parse($trackers[$index - 1]->tracked_at));

$trackers[$index - 1]->duration = str_pad($breakTaken->h, 2, 0, STR_PAD_LEFT) . ":" . str_pad($breakTaken->i, 2, 0, STR_PAD_LEFT) . ":" . str_pad($breakTaken->s, 2, 0, STR_PAD_LEFT);

if($workedHour > $breakTaken->h){
$workedHour -= $breakTaken->h;
}else{
$workedMin -= round($breakTaken->h / 60);
}
if($workedMin > $breakTaken->i){
$workedMin -= $breakTaken->i;
}else{
$workedSec -= round($breakTaken->i / 60);
}
if($workedSec > $breakTaken->s)
$workedSec -= $breakTaken->s;

$breakHour+= $breakTaken->h;
$breakMin += $breakTaken->i;
$breakSec += $breakTaken->s;
}
$intervalList[] = $tracker;
}

//RECALCULATE BREAK TIME
if($breakSec >= 60) {
$sec = $breakSec / 60;
$min = floor($sec);
$sec = $sec - $min;
$breakMin+= $min;
$breakSec = round($sec * 60);
}
if($breakMin >= 60) {
$min = $breakMin / 60;
$hour= floor($min);
$min = $min - $hour;
$breakHour += $hour;
$breakMin = round($min * 60);
}
}

return array($workedHour,
$workedMin,
$workedSec,
$breakHour,
$breakMin,
$breakSec,
$intervalList);
}






}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function up()
$table->string('password');
$table->string('identification')->nullable();
$table->boolean('is_time_tracker_started')->default(0);
$table->integer('role_id')->nullable();
$table->integer('role_id')->nullable()->default(0);
$table->rememberToken();
$table->timestamps();
});
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions resources/js/Components/Report/ReportTimeTracker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup>
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { AgGridVue } from "ag-grid-vue3";
</script>

<script>
export default {
components: {
"ag-grid-vue": AgGridVue
},
data() {
return {
columnDefs: [
{ headerName: "Date", field: "date" },
{ headerName: "User Name", field: "user_name" },
{ headerName: "User Email", field: "user_email" },
{ headerName: "Worked time", field: "workedTimeFormat" },
{ headerName: "Break time", field: "breakTimeFormat" },
{ headerName: "Check in", field: "initialTrack" },
{ headerName: "Check out", field: "lastTrack" },
],
gridApi: null,
columnApi: null,
defaultColDef: {
flex: 1,
minWidth: 100,
sortable: true,
filter: true,
},
rowData: null
};
},
methods: {
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
const updateData = (data) => params.api.setRowData(data);
fetch('api/report/time-tracker')
.then((resp) => resp.json())
.then((data) => updateData(data));
}
}
}
</script>


<template>
<ag-grid-vue
style="height: 500px"
class="ag-theme-alpine"
:columnDefs="columnDefs"
@grid-ready="onGridReady"
:defaultColDef="defaultColDef"
:rowData="rowData">
</ag-grid-vue>
</template>
8 changes: 2 additions & 6 deletions resources/js/Components/Timer.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<script setup>
import axios from 'axios';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import Dropdown from '@/Components/Dropdown.vue';
import DropdownLink from '@/Components/DropdownLink.vue';
import DropdownOption from '@/Components/DropdownLink.vue';
</script>

<script>
Expand Down Expand Up @@ -34,9 +30,9 @@ export default{
axios.get('/sanctum/csrf-cookie').then(response => {
axios.get('/api/time-tracker')
.then(response => {
this.sec = response.data.sec;
this.min = response.data.min;
this.hour = response.data.hour;
this.min = response.data.min;
this.sec = response.data.sec;
this.user = response.data.user;
this.intervalList = response.data.intervalList;
Expand Down
3 changes: 3 additions & 0 deletions resources/js/Layouts/AuthenticatedLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const showingNavigationDropdown = ref(false);
<NavLink :href="route('dashboard')" :active="route().current('dashboard')">
Dashboard
</NavLink>
<NavLink :href="route('report')" :active="route().current('report')">
Report
</NavLink>
</div>
</div>

Expand Down
Loading

0 comments on commit c819365

Please sign in to comment.