Update Working review #105
			
				
			
		
		
		
	| 
						 | 
					@ -337,4 +337,20 @@ class JiraController extends Controller
 | 
				
			||||||
            Mail::to([$email])->cc(['admin@apactech.io', 'joseph@apactech.io'])->send(new WarningLongTask($user_info[$email]));
 | 
					            Mail::to([$email])->cc(['admin@apactech.io', 'joseph@apactech.io'])->send(new WarningLongTask($user_info[$email]));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUserProjectParticipating(Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $userID = $request->input('userID');
 | 
				
			||||||
 | 
					        $startDate = $request->input('fromDate');
 | 
				
			||||||
 | 
					        $endDate = $request->input('toDate');
 | 
				
			||||||
 | 
					        $user = User::find($userID);
 | 
				
			||||||
 | 
					        $userJira = $this->jiraService->getUserByEmail($user->email);
 | 
				
			||||||
 | 
					        $projects = $this->jiraService->getUserWorkLogs($userJira[0]['accountId'], $startDate, $endDate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response()->json([
 | 
				
			||||||
 | 
					            'data' => $projects,
 | 
				
			||||||
 | 
					            "accountId" => $userJira[0]['accountId'],
 | 
				
			||||||
 | 
					            'status' => true
 | 
				
			||||||
 | 
					        ], 200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ class TrackingController extends Controller
 | 
				
			||||||
    use HasFilterRequest;
 | 
					    use HasFilterRequest;
 | 
				
			||||||
    use HasSearchRequest;
 | 
					    use HasSearchRequest;
 | 
				
			||||||
    use AnalyzeData;
 | 
					    use AnalyzeData;
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    private $CHECK_IN = 'check in';
 | 
					    private $CHECK_IN = 'check in';
 | 
				
			||||||
    private $CHECK_OUT = 'check out';
 | 
					    private $CHECK_OUT = 'check out';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,15 +207,14 @@ class TrackingController extends Controller
 | 
				
			||||||
        // $status = $this->CHECK_IN;
 | 
					        // $status = $this->CHECK_IN;
 | 
				
			||||||
        // $lastCheck =Tracking::find(1)->created_at;
 | 
					        // $lastCheck =Tracking::find(1)->created_at;
 | 
				
			||||||
        // $user = Admin::where('name', 'LE TAN LUAN')->first();
 | 
					        // $user = Admin::where('name', 'LE TAN LUAN')->first();
 | 
				
			||||||
        if($status === $this->CHECK_IN){
 | 
					        if ($status === $this->CHECK_IN) {
 | 
				
			||||||
            $morning_time = Carbon::createFromTimeString('07:30AM')->setTimezone(env('TIME_ZONE'));
 | 
					            $morning_time = Carbon::createFromTimeString('07:30AM')->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
            $morning_condition_time = Carbon::createFromTimeString('07:40AM')->setTimezone(env('TIME_ZONE'));
 | 
					            $morning_condition_time = Carbon::createFromTimeString('07:40AM')->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
            $afternoon_time = Carbon::createFromTimeString('11:30AM')->setTimezone(env('TIME_ZONE'));
 | 
					            $afternoon_time = Carbon::createFromTimeString('11:30AM')->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
            $afternoon_condition_time = Carbon::createFromTimeString('01:10PM')->setTimezone(env('TIME_ZONE'));
 | 
					            $afternoon_condition_time = Carbon::createFromTimeString('01:10PM')->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
            $admin_mails = Admin::where('permission', 'like', '%admin%')->pluck('email');
 | 
					            $admin_mails = Admin::where('permission', 'like', '%admin%')->pluck('email');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ($time->greaterThan($morning_condition_time) && $time->lessThan($afternoon_time))
 | 
					            if ($time->greaterThan($morning_condition_time) && $time->lessThan($afternoon_time)) {
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                $period = 'morning';
 | 
					                $period = 'morning';
 | 
				
			||||||
                $minutes_late = $morning_time->diffInMinutes($time);
 | 
					                $minutes_late = $morning_time->diffInMinutes($time);
 | 
				
			||||||
                $data = array(
 | 
					                $data = array(
 | 
				
			||||||
| 
						 | 
					@ -223,9 +222,9 @@ class TrackingController extends Controller
 | 
				
			||||||
                    "email" => $user->email,
 | 
					                    "email" => $user->email,
 | 
				
			||||||
                    "name" => $user->name,
 | 
					                    "name" => $user->name,
 | 
				
			||||||
                    "admin_mails" => $admin_mails,
 | 
					                    "admin_mails" => $admin_mails,
 | 
				
			||||||
                    "message1" => "Your ". $period ." starts ". $minutes_late ." minutes late",
 | 
					                    "message1" => "Your " . $period . " starts " . $minutes_late . " minutes late",
 | 
				
			||||||
                    "message2" => "You checked in at [" . $time ."]",
 | 
					                    "message2" => "You checked in at [" . $time . "]",
 | 
				
			||||||
                    "url" => env('ADMIN_URL')."/tracking?search=&per_page=10&page=1&timezone=Asia%2FSaigon&name=".$user->name."&time_string=".$time->format("Y-m-d H:i")."&status=check+in",
 | 
					                    "url" => env('ADMIN_URL') . "/tracking?search=&per_page=10&page=1&timezone=Asia%2FSaigon&name=" . $user->name . "&time_string=" . $time->format("Y-m-d H:i") . "&status=check+in",
 | 
				
			||||||
                    "subject" => "[Management System] Late warning - " . $user->name
 | 
					                    "subject" => "[Management System] Late warning - " . $user->name
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                Mail::to($user->email)->cc($admin_mails)->send(new CheckinLateMail($data));
 | 
					                Mail::to($user->email)->cc($admin_mails)->send(new CheckinLateMail($data));
 | 
				
			||||||
| 
						 | 
					@ -247,7 +246,81 @@ class TrackingController extends Controller
 | 
				
			||||||
            //     Mail::to($user->email)->cc($admin_mails)->send(new CheckinLateMail($data));
 | 
					            //     Mail::to($user->email)->cc($admin_mails)->send(new CheckinLateMail($data));
 | 
				
			||||||
            // }
 | 
					            // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getSummaryTracking(Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $request->validate([
 | 
				
			||||||
 | 
					            'userID' => 'required|exists:users,id',
 | 
				
			||||||
 | 
					            'fromDate' => 'nullable|date',
 | 
				
			||||||
 | 
					            'toDate' => 'nullable|date',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $userID = $request->input('userID');
 | 
				
			||||||
 | 
					        $startDate = $request->input('fromDate');
 | 
				
			||||||
 | 
					        $endDate = $request->input('toDate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $trackingData = Tracking::where('user_id', $userID)
 | 
				
			||||||
 | 
					            ->where('status', 'check in');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($startDate && $endDate) {
 | 
				
			||||||
 | 
					            $trackingData->whereBetween('updated_at', [$startDate, $endDate . ' 23:59:59']);
 | 
				
			||||||
 | 
					        } elseif ($startDate) {
 | 
				
			||||||
 | 
					            $trackingData->where('updated_at', '>=', $startDate);
 | 
				
			||||||
 | 
					        } elseif ($endDate) {
 | 
				
			||||||
 | 
					            $trackingData->where('updated_at', '<=', $endDate . ' 23:59:59');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $onTimeMorning = 0;
 | 
				
			||||||
 | 
					        $lateMorning = 0;
 | 
				
			||||||
 | 
					        $onTimeAfternoon = 0;
 | 
				
			||||||
 | 
					        $lateAfternoon = 0;
 | 
				
			||||||
 | 
					        $datesChecked = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $trackingData->get()->groupBy(function ($record) {
 | 
				
			||||||
 | 
					            return Carbon::parse($record->time_string)->toDateString();
 | 
				
			||||||
 | 
					        })->each(function ($records, $date) use (&$onTimeMorning, &$lateMorning, &$onTimeAfternoon, &$lateAfternoon, &$datesChecked) {
 | 
				
			||||||
 | 
					            $morningCheck = $records->filter(function ($record) {
 | 
				
			||||||
 | 
					                return Carbon::parse($record->time_string)->hour < 12;
 | 
				
			||||||
 | 
					            })->sortBy('time_string')->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $afternoonCheck = $records->filter(function ($record) {
 | 
				
			||||||
 | 
					                return Carbon::parse($record->time_string)->hour >= 12;
 | 
				
			||||||
 | 
					            })->sortBy('time_string')->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $morningTime = Carbon::parse($date)->setTime(7, 40, 0);
 | 
				
			||||||
 | 
					            $afternoonTime = Carbon::parse($date)->setTime(13, 10, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($morningCheck) {
 | 
				
			||||||
 | 
					                $checkInTime = Carbon::parse($morningCheck->time_string);
 | 
				
			||||||
 | 
					                if ($checkInTime->lessThanOrEqualTo($morningTime)) {
 | 
				
			||||||
 | 
					                    $onTimeMorning++;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    $lateMorning++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($afternoonCheck) {
 | 
				
			||||||
 | 
					                $checkInTime = Carbon::parse($afternoonCheck->time_string);
 | 
				
			||||||
 | 
					                if ($checkInTime->lessThanOrEqualTo($afternoonTime)) {
 | 
				
			||||||
 | 
					                    $onTimeAfternoon++;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    $lateAfternoon++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Default to on time if no afternoon check-in
 | 
				
			||||||
 | 
					                $onTimeAfternoon++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return AbstractController::ResultSuccess([
 | 
				
			||||||
 | 
					            'on_time_morning' => $onTimeMorning,
 | 
				
			||||||
 | 
					            'late_morning' => $lateMorning,
 | 
				
			||||||
 | 
					            'on_time_afternoon' => $onTimeAfternoon,
 | 
				
			||||||
 | 
					            'late_afternoon' => $lateAfternoon,
 | 
				
			||||||
 | 
					            'value' => $trackingData->get()
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,7 @@ Route::middleware('api')
 | 
				
			||||||
                Route::get('/worklogs', [JiraController::class, 'getAllUserWorkLogs'])->middleware('check.permission:admin.staff');
 | 
					                Route::get('/worklogs', [JiraController::class, 'getAllUserWorkLogs'])->middleware('check.permission:admin.staff');
 | 
				
			||||||
                Route::get('/allocation', [JiraController::class, 'getAllUserDoing'])->middleware('check.permission:admin.staff');
 | 
					                Route::get('/allocation', [JiraController::class, 'getAllUserDoing'])->middleware('check.permission:admin.staff');
 | 
				
			||||||
                Route::get('/issue/detail', [JiraController::class, 'getDetailIssueById'])->middleware('check.permission:admin.staff');
 | 
					                Route::get('/issue/detail', [JiraController::class, 'getDetailIssueById'])->middleware('check.permission:admin.staff');
 | 
				
			||||||
 | 
					                Route::get('/project-participating', [JiraController::class, 'getUserProjectParticipating'])->middleware('check.permission:admin');
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Route::group([
 | 
					            Route::group([
 | 
				
			||||||
| 
						 | 
					@ -136,6 +137,7 @@ Route::middleware('api')
 | 
				
			||||||
                Route::post('/create', [TrackingController::class, 'create'])->middleware('check.permission:admin.hr');
 | 
					                Route::post('/create', [TrackingController::class, 'create'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
                Route::post('/update', [TrackingController::class, 'update'])->middleware('check.permission:admin.hr');
 | 
					                Route::post('/update', [TrackingController::class, 'update'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
                Route::get('/delete', [TrackingController::class, 'delete'])->middleware('check.permission:admin.hr');
 | 
					                Route::get('/delete', [TrackingController::class, 'delete'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
 | 
					                Route::get('/summary', [TrackingController::class, 'getSummaryTracking'])->middleware('check.permission:admin');
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Route::group([
 | 
					            Route::group([
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,12 +231,12 @@ class JiraService
 | 
				
			||||||
        $users_data = [];
 | 
					        $users_data = [];
 | 
				
			||||||
        $user_warning = [];
 | 
					        $user_warning = [];
 | 
				
			||||||
        foreach ($users as $user) {
 | 
					        foreach ($users as $user) {
 | 
				
			||||||
            $user = (array)$user[0];
 | 
					            $user = (array) $user[0];
 | 
				
			||||||
            $users_data[$user['displayName']]['user'] = $user;
 | 
					            $users_data[$user['displayName']]['user'] = $user;
 | 
				
			||||||
            $users_data[$user['displayName']]['total_spent'] = 0;
 | 
					            $users_data[$user['displayName']]['total_spent'] = 0;
 | 
				
			||||||
            $users_data[$user['displayName']]['total_est'] = 0;
 | 
					            $users_data[$user['displayName']]['total_est'] = 0;
 | 
				
			||||||
            $body = [
 | 
					            $body = [
 | 
				
			||||||
                'expand' => ['names', 'schema','changelog'],
 | 
					                'expand' => ['names', 'schema', 'changelog'],
 | 
				
			||||||
                'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project', 'updated'],
 | 
					                'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project', 'updated'],
 | 
				
			||||||
                'jql' => sprintf(
 | 
					                'jql' => sprintf(
 | 
				
			||||||
                    "assignee = '%s' AND status IN ('to do', 'todo', 'in progress') ORDER BY updated DESC",
 | 
					                    "assignee = '%s' AND status IN ('to do', 'todo', 'in progress') ORDER BY updated DESC",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@codemirror/lang-javascript": "^6.2.2",
 | 
					    "@codemirror/lang-javascript": "^6.2.2",
 | 
				
			||||||
 | 
					    "@mantine/charts": "^7.16.3",
 | 
				
			||||||
    "@mantine/core": "^7.13.2",
 | 
					    "@mantine/core": "^7.13.2",
 | 
				
			||||||
    "@mantine/dates": "^7.13.2",
 | 
					    "@mantine/dates": "^7.13.2",
 | 
				
			||||||
    "@mantine/form": "^7.13.2",
 | 
					    "@mantine/form": "^7.13.2",
 | 
				
			||||||
| 
						 | 
					@ -36,7 +37,7 @@
 | 
				
			||||||
    "react-redux": "^8.1.3",
 | 
					    "react-redux": "^8.1.3",
 | 
				
			||||||
    "react-router-dom": "^6.19.0",
 | 
					    "react-router-dom": "^6.19.0",
 | 
				
			||||||
    "reactstrap": "^9.2.2",
 | 
					    "reactstrap": "^9.2.2",
 | 
				
			||||||
    "recharts": "^2.11.0",
 | 
					    "recharts": "^2.15.1",
 | 
				
			||||||
    "tailwind-merge": "^2.0.0",
 | 
					    "tailwind-merge": "^2.0.0",
 | 
				
			||||||
    "tests": "^0.4.2"
 | 
					    "tests": "^0.4.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ import { BrowserRouter, useRoutes } from 'react-router-dom'
 | 
				
			||||||
import mainRoutes from '@/routes/main'
 | 
					import mainRoutes from '@/routes/main'
 | 
				
			||||||
import classes from '@/App.module.css'
 | 
					import classes from '@/App.module.css'
 | 
				
			||||||
import '@mantine/dates/styles.css'
 | 
					import '@mantine/dates/styles.css'
 | 
				
			||||||
 | 
					import '@mantine/charts/styles.css'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const App = () => {
 | 
					export const App = () => {
 | 
				
			||||||
  const element = useRoutes(mainRoutes)
 | 
					  const element = useRoutes(mainRoutes)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ export const getListTracking = API_URL + 'v1/admin/tracking'
 | 
				
			||||||
export const addTracking = API_URL + 'v1/admin/tracking/create'
 | 
					export const addTracking = API_URL + 'v1/admin/tracking/create'
 | 
				
			||||||
export const updateTracking = API_URL + 'v1/admin/tracking/update'
 | 
					export const updateTracking = API_URL + 'v1/admin/tracking/update'
 | 
				
			||||||
export const deleteTracking = API_URL + 'v1/admin/tracking/delete'
 | 
					export const deleteTracking = API_URL + 'v1/admin/tracking/delete'
 | 
				
			||||||
 | 
					export const getListTrackingSummary = API_URL + 'v1/admin/tracking/summary'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Worklogs
 | 
					// Worklogs
 | 
				
			||||||
export const fetchAllIssues = API_URL + 'v1/admin/jira/fetch-issues'
 | 
					export const fetchAllIssues = API_URL + 'v1/admin/jira/fetch-issues'
 | 
				
			||||||
| 
						 | 
					@ -17,6 +18,8 @@ export const getAllIssuesByProject =
 | 
				
			||||||
export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
 | 
					export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
 | 
				
			||||||
export const getAllUserDoing = API_URL + 'v1/admin/jira/allocation'
 | 
					export const getAllUserDoing = API_URL + 'v1/admin/jira/allocation'
 | 
				
			||||||
export const getDetailIssByKey = API_URL + 'v1/admin/jira/issue/detail'
 | 
					export const getDetailIssByKey = API_URL + 'v1/admin/jira/issue/detail'
 | 
				
			||||||
 | 
					export const getPJParticipating =
 | 
				
			||||||
 | 
					  API_URL + 'v1/admin/jira/project-participating'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Timekeeping
 | 
					//Timekeeping
 | 
				
			||||||
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
 | 
					export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,3 +200,46 @@
 | 
				
			||||||
  width: rem(20px);
 | 
					  width: rem(20px);
 | 
				
			||||||
  height: rem(22px);
 | 
					  height: rem(22px);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.chartContainer {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.boxContainer {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pjParticipatingContainer {
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.boxColorLime {
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  background-color: #82c91e;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.boxColorRed {
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  background-color: #fa5252;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.boxColorOrange {
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  background-color: #fd7e14;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.boxColorTeal {
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  background-color: #12b886;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,8 @@ import {
 | 
				
			||||||
  projectReviewUpdate,
 | 
					  projectReviewUpdate,
 | 
				
			||||||
  projectReviewDelete,
 | 
					  projectReviewDelete,
 | 
				
			||||||
  evaluationReportAllUsers,
 | 
					  evaluationReportAllUsers,
 | 
				
			||||||
 | 
					  getListTrackingSummary,
 | 
				
			||||||
 | 
					  getPJParticipating,
 | 
				
			||||||
} from '@/api/Admin'
 | 
					} from '@/api/Admin'
 | 
				
			||||||
import DataTableAll from '@/components/DataTable/DataTable'
 | 
					import DataTableAll from '@/components/DataTable/DataTable'
 | 
				
			||||||
import ProjectInvolvement from '@/components/ProjectInvolvement/ProjectInvolvement'
 | 
					import ProjectInvolvement from '@/components/ProjectInvolvement/ProjectInvolvement'
 | 
				
			||||||
| 
						 | 
					@ -35,10 +37,12 @@ import {
 | 
				
			||||||
  IconClearAll,
 | 
					  IconClearAll,
 | 
				
			||||||
  IconEdit,
 | 
					  IconEdit,
 | 
				
			||||||
  IconPresentationAnalytics,
 | 
					  IconPresentationAnalytics,
 | 
				
			||||||
 | 
					  IconReportAnalytics,
 | 
				
			||||||
  IconX,
 | 
					  IconX,
 | 
				
			||||||
} from '@tabler/icons-react'
 | 
					} from '@tabler/icons-react'
 | 
				
			||||||
import { useForm } from '@mantine/form'
 | 
					import { useForm } from '@mantine/form'
 | 
				
			||||||
import { update, Xdelete } from '@/rtk/helpers/CRUD'
 | 
					import { update, Xdelete } from '@/rtk/helpers/CRUD'
 | 
				
			||||||
 | 
					import { PieChart } from '@mantine/charts'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface User {
 | 
					interface User {
 | 
				
			||||||
  id: number
 | 
					  id: number
 | 
				
			||||||
| 
						 | 
					@ -76,8 +80,32 @@ interface DataProjectReview {
 | 
				
			||||||
  updated_at: string
 | 
					  updated_at: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DataPJParticipating {
 | 
				
			||||||
 | 
					  name: string
 | 
				
			||||||
 | 
					  total_task: number
 | 
				
			||||||
 | 
					  total_time_spent: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TLog = {
 | 
				
			||||||
 | 
					  id: number
 | 
				
			||||||
 | 
					  name: string
 | 
				
			||||||
 | 
					  status: string
 | 
				
			||||||
 | 
					  time_string: Date
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DataSummaryTracking {
 | 
				
			||||||
 | 
					  on_time_morning: number
 | 
				
			||||||
 | 
					  late_morning: number
 | 
				
			||||||
 | 
					  on_time_afternoon: number
 | 
				
			||||||
 | 
					  late_afternoon: number
 | 
				
			||||||
 | 
					  value: TLog[]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StaffEvaluation = () => {
 | 
					const StaffEvaluation = () => {
 | 
				
			||||||
  const [loading, setLoading] = useState(false)
 | 
					  const [loading, setLoading] = useState(false)
 | 
				
			||||||
 | 
					  const [loadingReview, setLoadingReview] = useState(false)
 | 
				
			||||||
 | 
					  const [loadingWorkingStyle, setLoadingWorkingStyle] = useState(false)
 | 
				
			||||||
 | 
					  const [loadingPJParticipating, setLoadingPJParticipating] = useState(false)
 | 
				
			||||||
  const [loadingTechnical, setLoadingTechnical] = useState(false)
 | 
					  const [loadingTechnical, setLoadingTechnical] = useState(false)
 | 
				
			||||||
  const [dataProfile, setDataProfile] = useState<any>([])
 | 
					  const [dataProfile, setDataProfile] = useState<any>([])
 | 
				
			||||||
  const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
 | 
					  const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
 | 
				
			||||||
| 
						 | 
					@ -96,6 +124,17 @@ const StaffEvaluation = () => {
 | 
				
			||||||
  const [activeBtn, setActiveBtn] = useState(false)
 | 
					  const [activeBtn, setActiveBtn] = useState(false)
 | 
				
			||||||
  const [loadingExport, setLoadingExport] = useState(false)
 | 
					  const [loadingExport, setLoadingExport] = useState(false)
 | 
				
			||||||
  const [loadingExportAll, setLoadingExportAll] = useState(false)
 | 
					  const [loadingExportAll, setLoadingExportAll] = useState(false)
 | 
				
			||||||
 | 
					  const [dataPJParticipating, setDataPJParticipating] = useState<
 | 
				
			||||||
 | 
					    DataPJParticipating[]
 | 
				
			||||||
 | 
					  >([])
 | 
				
			||||||
 | 
					  const [dataSummaryTracking, setDataSummaryTracking] =
 | 
				
			||||||
 | 
					    useState<DataSummaryTracking>({
 | 
				
			||||||
 | 
					      on_time_morning: 0,
 | 
				
			||||||
 | 
					      late_morning: 0,
 | 
				
			||||||
 | 
					      on_time_afternoon: 0,
 | 
				
			||||||
 | 
					      late_afternoon: 0,
 | 
				
			||||||
 | 
					      value: [],
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const form = useForm({
 | 
					  const form = useForm({
 | 
				
			||||||
    initialValues: {
 | 
					    initialValues: {
 | 
				
			||||||
| 
						 | 
					@ -298,17 +337,147 @@ const StaffEvaluation = () => {
 | 
				
			||||||
    return []
 | 
					    return []
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getListSummaryTracking = async (filterSearch: Filter) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const params = {
 | 
				
			||||||
 | 
					        userID: filterSearch.userID ?? '',
 | 
				
			||||||
 | 
					        fromDate: filterSearch.fromDate
 | 
				
			||||||
 | 
					          ? moment(filterSearch.fromDate).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					          : null,
 | 
				
			||||||
 | 
					        toDate: filterSearch.toDate
 | 
				
			||||||
 | 
					          ? moment(filterSearch.toDate).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					          : null,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const res = await get(getListTrackingSummary, params)
 | 
				
			||||||
 | 
					      if (res.status) {
 | 
				
			||||||
 | 
					        return res.data
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      notifications.show({
 | 
				
			||||||
 | 
					        title: 'Error',
 | 
				
			||||||
 | 
					        message: error.message ?? error,
 | 
				
			||||||
 | 
					        color: 'red',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getListProjectParticipating = async (filterSearch: Filter) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const fromDate = filterSearch.fromDate
 | 
				
			||||||
 | 
					        ? moment(filterSearch.fromDate).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					        : moment(new Date()).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					      const toDate = filterSearch.toDate
 | 
				
			||||||
 | 
					        ? moment(filterSearch.toDate).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					        : moment(new Date()).format('YYYY-MM-DD')
 | 
				
			||||||
 | 
					      const params = {
 | 
				
			||||||
 | 
					        userID: filterSearch.userID ?? '',
 | 
				
			||||||
 | 
					        fromDate: fromDate,
 | 
				
			||||||
 | 
					        toDate: toDate,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const res = await get(getPJParticipating, params)
 | 
				
			||||||
 | 
					      if (res.status) {
 | 
				
			||||||
 | 
					        const value = processJiraData(res.data, fromDate, toDate, res.accountId)
 | 
				
			||||||
 | 
					        return value
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      notifications.show({
 | 
				
			||||||
 | 
					        title: 'Error',
 | 
				
			||||||
 | 
					        message: error.message ?? error,
 | 
				
			||||||
 | 
					        color: 'red',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function processJiraData(
 | 
				
			||||||
 | 
					    data: any,
 | 
				
			||||||
 | 
					    startDate: any,
 | 
				
			||||||
 | 
					    endDate: any,
 | 
				
			||||||
 | 
					    accountId: string,
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    const projectSummary: any = {}
 | 
				
			||||||
 | 
					    const start = new Date(startDate)
 | 
				
			||||||
 | 
					    const end = new Date(endDate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data.issues.forEach((issue: any) => {
 | 
				
			||||||
 | 
					      const projectName = issue.fields.project.name
 | 
				
			||||||
 | 
					      const worklogs = issue.fields.worklog.worklogs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Filter worklogs based on 'started' date range
 | 
				
			||||||
 | 
					      const filteredWorklogs = worklogs.filter((log: any) => {
 | 
				
			||||||
 | 
					        const logDate = new Date(log.started)
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					          logDate >= start &&
 | 
				
			||||||
 | 
					          logDate <= end &&
 | 
				
			||||||
 | 
					          accountId === log?.updateAuthor?.accountId
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (filteredWorklogs.length === 0) return // Skip if no worklogs in range
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!projectSummary[projectName]) {
 | 
				
			||||||
 | 
					        projectSummary[projectName] = {
 | 
				
			||||||
 | 
					          project_name: projectName,
 | 
				
			||||||
 | 
					          total_task: 0,
 | 
				
			||||||
 | 
					          total_time_spent: 0,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Get unique issueIds within the filtered worklogs
 | 
				
			||||||
 | 
					      const uniqueIssues = new Set(
 | 
				
			||||||
 | 
					        filteredWorklogs.map((log: any) => log.issueId),
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Sum up total time spent from filtered worklogs
 | 
				
			||||||
 | 
					      const totalTimeSpent = filteredWorklogs.reduce(
 | 
				
			||||||
 | 
					        (sum: number, log: any) => sum + log.timeSpentSeconds,
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      projectSummary[projectName].total_task += uniqueIssues.size
 | 
				
			||||||
 | 
					      projectSummary[projectName].total_time_spent += totalTimeSpent
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const returnValue: DataPJParticipating[] = Object.values(projectSummary)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return returnValue
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (filter?.userID) {
 | 
					    if (filter?.userID) {
 | 
				
			||||||
      setLoading(true)
 | 
					      setLoading(true)
 | 
				
			||||||
 | 
					      setLoadingReview(true)
 | 
				
			||||||
 | 
					      setLoadingWorkingStyle(true)
 | 
				
			||||||
      const fetchData = async () => {
 | 
					      const fetchData = async () => {
 | 
				
			||||||
 | 
					        const result = await getListProfilesData(filter)
 | 
				
			||||||
 | 
					        setDataProfile(result ?? [])
 | 
				
			||||||
 | 
					        setLoading(false)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const fetchDataProject = async () => {
 | 
				
			||||||
        const result = await getListProfilesData(filter)
 | 
					        const result = await getListProfilesData(filter)
 | 
				
			||||||
        const resultProject = await getListProjectReview(filter)
 | 
					        const resultProject = await getListProjectReview(filter)
 | 
				
			||||||
        setDataProfile(result ?? [])
 | 
					        setDataProfile(result ?? [])
 | 
				
			||||||
        setDataProjectReview(resultProject ?? [])
 | 
					        setDataProjectReview(resultProject ?? [])
 | 
				
			||||||
        setLoading(false)
 | 
					        setLoadingReview(false)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const fetchDataTracking = async () => {
 | 
				
			||||||
 | 
					        const resultTracking = await getListSummaryTracking(filter)
 | 
				
			||||||
 | 
					        setDataSummaryTracking(resultTracking ?? [])
 | 
				
			||||||
 | 
					        setLoadingWorkingStyle(false)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const fetchDataPJParticipating = async () => {
 | 
				
			||||||
 | 
					        const resultPJParticipating = await getListProjectParticipating(filter)
 | 
				
			||||||
 | 
					        setDataPJParticipating(resultPJParticipating ?? [])
 | 
				
			||||||
 | 
					        setLoadingPJParticipating(false)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      fetchData()
 | 
					      fetchData()
 | 
				
			||||||
 | 
					      fetchDataProject()
 | 
				
			||||||
 | 
					      fetchDataTracking()
 | 
				
			||||||
 | 
					      if (filter?.fromDate && filter?.toDate) {
 | 
				
			||||||
 | 
					        setLoadingPJParticipating(true)
 | 
				
			||||||
 | 
					        fetchDataPJParticipating()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [filter])
 | 
					  }, [filter])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -433,7 +602,7 @@ const StaffEvaluation = () => {
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      name: 'name',
 | 
					      name: 'name',
 | 
				
			||||||
      size: '15%',
 | 
					      size: '15%',
 | 
				
			||||||
      header: 'Project Name',
 | 
					      header: 'Name',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      name: 'role',
 | 
					      name: 'role',
 | 
				
			||||||
| 
						 | 
					@ -512,6 +681,27 @@ const StaffEvaluation = () => {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const columnsPJParticipating = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'project_name',
 | 
				
			||||||
 | 
					      size: '50%',
 | 
				
			||||||
 | 
					      header: 'Name',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'total_task',
 | 
				
			||||||
 | 
					      size: '25%',
 | 
				
			||||||
 | 
					      header: 'Total task',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'total_time_spent',
 | 
				
			||||||
 | 
					      size: '25%',
 | 
				
			||||||
 | 
					      header: 'Total time spent',
 | 
				
			||||||
 | 
					      render: (row: any) => {
 | 
				
			||||||
 | 
					        return <div>{row?.total_time_spent / 60 / 60}h</div>
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleCreate = async (values: DataProjectReview) => {
 | 
					  const handleCreate = async (values: DataProjectReview) => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const res = await post(projectReviewAdd, {
 | 
					      const res = await post(projectReviewAdd, {
 | 
				
			||||||
| 
						 | 
					@ -717,6 +907,12 @@ const StaffEvaluation = () => {
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <span style={{ fontSize: '16px' }}>Project review</span>
 | 
					            <span style={{ fontSize: '16px' }}>Project review</span>
 | 
				
			||||||
          </Tabs.Tab>
 | 
					          </Tabs.Tab>
 | 
				
			||||||
 | 
					          <Tabs.Tab
 | 
				
			||||||
 | 
					            value="working_style"
 | 
				
			||||||
 | 
					            leftSection={<IconReportAnalytics size={16} color="#fab005" />}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <span style={{ fontSize: '16px' }}>Working review</span>
 | 
				
			||||||
 | 
					          </Tabs.Tab>
 | 
				
			||||||
        </Tabs.List>
 | 
					        </Tabs.List>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Tabs.Panel value="general">
 | 
					        <Tabs.Panel value="general">
 | 
				
			||||||
| 
						 | 
					@ -785,9 +981,12 @@ const StaffEvaluation = () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Tabs.Panel value="project_review">
 | 
					        <Tabs.Panel value="project_review">
 | 
				
			||||||
          <Box className={classes.userInfoSection} display="flex">
 | 
					          <Box className={classes.userInfoSection} display="flex">
 | 
				
			||||||
            {loading ? (
 | 
					            {loadingReview ? (
 | 
				
			||||||
              <Box
 | 
					              <Box
 | 
				
			||||||
                style={{ width: '100%', display: loading ? 'block' : 'none' }}
 | 
					                style={{
 | 
				
			||||||
 | 
					                  width: '100%',
 | 
				
			||||||
 | 
					                  display: loadingReview ? 'block' : 'none',
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <Box
 | 
					                <Box
 | 
				
			||||||
                  style={{
 | 
					                  style={{
 | 
				
			||||||
| 
						 | 
					@ -832,6 +1031,129 @@ const StaffEvaluation = () => {
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
          </Box>
 | 
					          </Box>
 | 
				
			||||||
        </Tabs.Panel>
 | 
					        </Tabs.Panel>
 | 
				
			||||||
 | 
					        <Tabs.Panel value="working_style">
 | 
				
			||||||
 | 
					          {loadingWorkingStyle ? (
 | 
				
			||||||
 | 
					            <Box
 | 
				
			||||||
 | 
					              style={{
 | 
				
			||||||
 | 
					                width: '100%',
 | 
				
			||||||
 | 
					                display: loadingWorkingStyle ? 'block' : 'none',
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <Box
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  marginTop: '10%',
 | 
				
			||||||
 | 
					                  textAlign: 'center',
 | 
				
			||||||
 | 
					                  // display: 'none',
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
 | 
				
			||||||
 | 
					                <Text fw={600} c={'gray'}>
 | 
				
			||||||
 | 
					                  Loading . . .
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					              </Box>
 | 
				
			||||||
 | 
					            </Box>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Box>
 | 
				
			||||||
 | 
					              <Box className={classes.chartContainer} display="flex">
 | 
				
			||||||
 | 
					                <PieChart
 | 
				
			||||||
 | 
					                  withLabelsLine
 | 
				
			||||||
 | 
					                  labelsPosition="outside"
 | 
				
			||||||
 | 
					                  labelsType="value"
 | 
				
			||||||
 | 
					                  withLabels={dataSummaryTracking.value.length > 0}
 | 
				
			||||||
 | 
					                  withTooltip
 | 
				
			||||||
 | 
					                  data={
 | 
				
			||||||
 | 
					                    dataSummaryTracking.value.length > 0
 | 
				
			||||||
 | 
					                      ? [
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            name: 'On time morning',
 | 
				
			||||||
 | 
					                            value: dataSummaryTracking?.on_time_morning ?? 0,
 | 
				
			||||||
 | 
					                            color: 'lime',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            name: 'Late morning',
 | 
				
			||||||
 | 
					                            value: dataSummaryTracking?.late_morning ?? 0,
 | 
				
			||||||
 | 
					                            color: 'red',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            name: 'On time afternoon',
 | 
				
			||||||
 | 
					                            value: dataSummaryTracking?.on_time_afternoon ?? 0,
 | 
				
			||||||
 | 
					                            color: 'teal',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            name: 'Late afternoon',
 | 
				
			||||||
 | 
					                            value: dataSummaryTracking?.late_afternoon ?? 0,
 | 
				
			||||||
 | 
					                            color: 'orange',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                      : [
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            name: 'No data',
 | 
				
			||||||
 | 
					                            value: 1,
 | 
				
			||||||
 | 
					                            color: 'gray.6',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </Box>
 | 
				
			||||||
 | 
					              <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					                <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					                  <div className={classes.boxColorLime}></div>
 | 
				
			||||||
 | 
					                  <div style={{ paddingLeft: '10px', paddingRight: '20px' }}>
 | 
				
			||||||
 | 
					                    On time morning
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					                <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					                  <div className={classes.boxColorRed}></div>
 | 
				
			||||||
 | 
					                  <div style={{ paddingLeft: '10px', paddingRight: '20px' }}>
 | 
				
			||||||
 | 
					                    Late morning
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					                <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					                  <div className={classes.boxColorTeal}></div>
 | 
				
			||||||
 | 
					                  <div style={{ paddingLeft: '10px', paddingRight: '20px' }}>
 | 
				
			||||||
 | 
					                    On time afternoon
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					                <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					                  <div className={classes.boxColorOrange}></div>
 | 
				
			||||||
 | 
					                  <div style={{ paddingLeft: '10px' }}>Late afternoon</div>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					              </Box>
 | 
				
			||||||
 | 
					            </Box>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          <Box className={classes.pjParticipatingContainer}>
 | 
				
			||||||
 | 
					            <Title order={4}>Project Participating</Title>
 | 
				
			||||||
 | 
					          </Box>
 | 
				
			||||||
 | 
					          <Box className={classes.boxContainer} display="flex">
 | 
				
			||||||
 | 
					            {loadingPJParticipating ? (
 | 
				
			||||||
 | 
					              <Box
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  width: '100%',
 | 
				
			||||||
 | 
					                  display: loadingPJParticipating ? 'block' : 'none',
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Box
 | 
				
			||||||
 | 
					                  style={{
 | 
				
			||||||
 | 
					                    marginTop: '10%',
 | 
				
			||||||
 | 
					                    textAlign: 'center',
 | 
				
			||||||
 | 
					                    // display: 'none',
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
 | 
				
			||||||
 | 
					                  <Text fw={600} c={'gray'}>
 | 
				
			||||||
 | 
					                    Analyzing . . .
 | 
				
			||||||
 | 
					                  </Text>
 | 
				
			||||||
 | 
					                </Box>
 | 
				
			||||||
 | 
					              </Box>
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <DataTableAll
 | 
				
			||||||
 | 
					                data={dataPJParticipating}
 | 
				
			||||||
 | 
					                columns={columnsPJParticipating}
 | 
				
			||||||
 | 
					                size=""
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </Box>
 | 
				
			||||||
 | 
					        </Tabs.Panel>
 | 
				
			||||||
      </Tabs>
 | 
					      </Tabs>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {/* Add/Edit User modal */}
 | 
					      {/* Add/Edit User modal */}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue