Bổ sung note cho Timekepping
This commit is contained in:
		
							parent
							
								
									b203e8d82c
								
							
						
					
					
						commit
						ae5737c3bf
					
				| 
						 | 
					@ -4,6 +4,7 @@ namespace Modules\Admin\app\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Helper\Cache\CurrentMonthTimekeeping;
 | 
					use App\Helper\Cache\CurrentMonthTimekeeping;
 | 
				
			||||||
use App\Http\Controllers\Controller;
 | 
					use App\Http\Controllers\Controller;
 | 
				
			||||||
 | 
					use App\Models\Notes;
 | 
				
			||||||
use App\Traits\AnalyzeData;
 | 
					use App\Traits\AnalyzeData;
 | 
				
			||||||
use App\Traits\HasFilterRequest;
 | 
					use App\Traits\HasFilterRequest;
 | 
				
			||||||
use App\Traits\HasOrderByRequest;
 | 
					use App\Traits\HasOrderByRequest;
 | 
				
			||||||
| 
						 | 
					@ -23,7 +24,7 @@ class TimekeepingController extends Controller
 | 
				
			||||||
    use HasFilterRequest;
 | 
					    use HasFilterRequest;
 | 
				
			||||||
    use HasSearchRequest;
 | 
					    use HasSearchRequest;
 | 
				
			||||||
    use AnalyzeData;
 | 
					    use AnalyzeData;
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    public function get(Request $request)
 | 
					    public function get(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $currentDate = Carbon::now();
 | 
					        $currentDate = Carbon::now();
 | 
				
			||||||
| 
						 | 
					@ -32,11 +33,9 @@ class TimekeepingController extends Controller
 | 
				
			||||||
        $data = MonthlyTimekeeping::where('month', '=', $request->month)->where('year', '=', $request->year)->first();
 | 
					        $data = MonthlyTimekeeping::where('month', '=', $request->month)->where('year', '=', $request->year)->first();
 | 
				
			||||||
        if ($currentMonth == (int)$request->month && $currentYear == (int)$request->year) {
 | 
					        if ($currentMonth == (int)$request->month && $currentYear == (int)$request->year) {
 | 
				
			||||||
            $cacheData = CurrentMonthTimekeeping::getCacheCurrentMonthTimekeeping();
 | 
					            $cacheData = CurrentMonthTimekeeping::getCacheCurrentMonthTimekeeping();
 | 
				
			||||||
            // $result = $this->analyzeCurrentMonthTimeKeepingData($currentMonth, $currentYear);
 | 
					 | 
				
			||||||
            // dd($result);die;
 | 
					 | 
				
			||||||
            if ($cacheData) {
 | 
					            if ($cacheData) {
 | 
				
			||||||
                $cacheData->data = json_decode($cacheData->data, true);
 | 
					                $cacheData->data = json_decode($cacheData->data, true);
 | 
				
			||||||
                return response()->json(['status' => true, 'data' => $cacheData->data, 'working_days'=> $cacheData->working_days, 'message' => 'Get from cache']);
 | 
					                return response()->json(['status' => true, 'data' => $cacheData->data, 'working_days' => $cacheData->working_days, 'message' => 'Get from cache']);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                $result = $this->analyzeCurrentMonthTimeKeepingData($currentMonth, $currentYear);
 | 
					                $result = $this->analyzeCurrentMonthTimeKeepingData($currentMonth, $currentYear);
 | 
				
			||||||
                if ($data) {
 | 
					                if ($data) {
 | 
				
			||||||
| 
						 | 
					@ -49,7 +48,7 @@ class TimekeepingController extends Controller
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if ($data) {
 | 
					            if ($data) {
 | 
				
			||||||
                $data['data'] = json_decode($data['data']);
 | 
					                $data['data'] = json_decode($data['data']);
 | 
				
			||||||
                return response()->json(['status' => true, 'data' => $data['data'], 'working_days'=> $data['working_days'], 'message' => 'Get from DB']);
 | 
					                return response()->json(['status' => true, 'data' => $data['data'], 'working_days' => $data['working_days'], 'message' => 'Get from DB']);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                $result = $this->analyzeCurrentMonthTimeKeepingData($request->month, $request->year);
 | 
					                $result = $this->analyzeCurrentMonthTimeKeepingData($request->month, $request->year);
 | 
				
			||||||
                MonthlyTimekeeping::create(['month' => $request->month, 'year' => $request->year, 'working_days' => Carbon::create((int)$request->year, (int)$request->month)->daysInMonth, 'data' => json_encode($result)]);
 | 
					                MonthlyTimekeeping::create(['month' => $request->month, 'year' => $request->year, 'working_days' => Carbon::create((int)$request->year, (int)$request->month)->daysInMonth, 'data' => json_encode($result)]);
 | 
				
			||||||
| 
						 | 
					@ -95,12 +94,42 @@ class TimekeepingController extends Controller
 | 
				
			||||||
    public function saveWorkingDays(Request $request)
 | 
					    public function saveWorkingDays(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $data = MonthlyTimekeeping::where('month', '=', $request->month)->where('year', '=', $request->year)->first();
 | 
					        $data = MonthlyTimekeeping::where('month', '=', $request->month)->where('year', '=', $request->year)->first();
 | 
				
			||||||
        if($data){
 | 
					        if ($data) {
 | 
				
			||||||
            $data->update(['working_days'=>$request->working_days]);
 | 
					            $data->update(['working_days' => $request->working_days]);
 | 
				
			||||||
            $this->createOrUpdateRecordForCurrentMonth($request->month, $request->year);
 | 
					            $this->createOrUpdateRecordForCurrentMonth($request->month, $request->year);
 | 
				
			||||||
            return response()->json(['status' => true, 'message' => 'Update successful']);
 | 
					            return response()->json(['status' => true, 'message' => 'Update successful']);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return response()->json(['status' => false, 'message' => 'Update failed']);
 | 
					        return response()->json(['status' => false, 'message' => 'Update failed']);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function addNoteForUser(Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user_id = $request->users["id"] ?? "";
 | 
				
			||||||
 | 
					        $month = $request->month;
 | 
				
			||||||
 | 
					        $year = $request->year;
 | 
				
			||||||
 | 
					        $day = $request->day;
 | 
				
			||||||
 | 
					        $time_type = $request->type;
 | 
				
			||||||
 | 
					        $reason = $request->reason;
 | 
				
			||||||
 | 
					        $note = $request->note;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($user_id == "") {
 | 
				
			||||||
 | 
					            return response()->json(['status' => false, 'message' => 'User not found!']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Notes::insert([
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                "n_user_id" => $user_id,
 | 
				
			||||||
 | 
					                "n_day" => $day,
 | 
				
			||||||
 | 
					                "n_month" => $month,
 | 
				
			||||||
 | 
					                "n_year" => $year,
 | 
				
			||||||
 | 
					                "n_time_type" => $time_type,
 | 
				
			||||||
 | 
					                "n_reason" => $reason,
 | 
				
			||||||
 | 
					                "n_note" => $note
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->createOrUpdateRecordForCurrentMonth($month, $year);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response()->json(['status' => true, 'message' => 'Add successfully']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,7 @@ Route::middleware('api')
 | 
				
			||||||
            ], function () {
 | 
					            ], function () {
 | 
				
			||||||
                Route::get('/', [TimekeepingController::class, 'get'])->middleware('check.permission:admin.hr.staff');
 | 
					                Route::get('/', [TimekeepingController::class, 'get'])->middleware('check.permission:admin.hr.staff');
 | 
				
			||||||
                Route::post('/addMutilple', [TimekeepingController::class, 'addWorkingTimeForMultipleUser'])->middleware('check.permission:admin.hr');
 | 
					                Route::post('/addMutilple', [TimekeepingController::class, 'addWorkingTimeForMultipleUser'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
 | 
					                Route::post('/addNote', [TimekeepingController::class, 'addNoteForUser'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
                Route::post('/update-working-days', [TimekeepingController::class, 'saveWorkingDays'])->middleware('check.permission:admin.hr');
 | 
					                Route::post('/update-working-days', [TimekeepingController::class, 'saveWorkingDays'])->middleware('check.permission:admin.hr');
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\DB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Notes extends Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use HasFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $fillable = [
 | 
				
			||||||
 | 
					        'n_user_id', 'n_day', 'n_month', 'n_year', 'n_time_type', 'n_reason', 'n_note',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Lấy thông tin bảng notes dựa vào tháng và năm.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param int $month
 | 
				
			||||||
 | 
					     * @param int $year
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Collection
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static function getNotesByMonthAndYear($month, $year)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return self::leftJoin("categories as reason", function ($join) {
 | 
				
			||||||
 | 
					            $join->on('n_reason', '=', 'reason.c_code');
 | 
				
			||||||
 | 
					            $join->on('reason.c_type', DB::raw("CONCAT('REASON')"));
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            ->leftJoin("categories as timeTypes", function ($join) {
 | 
				
			||||||
 | 
					                $join->on('n_time_type', '=', 'timeTypes.c_code');
 | 
				
			||||||
 | 
					                $join->on('timeTypes.c_type', DB::raw("CONCAT('TIME_TYPE')"));
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            ->where('n_month', $month)
 | 
				
			||||||
 | 
					            ->where('n_year', $year)
 | 
				
			||||||
 | 
					            ->select(
 | 
				
			||||||
 | 
					                'n_user_id',
 | 
				
			||||||
 | 
					                'n_day',
 | 
				
			||||||
 | 
					                'n_month',
 | 
				
			||||||
 | 
					                'n_year',
 | 
				
			||||||
 | 
					                'n_time_type',
 | 
				
			||||||
 | 
					                'n_reason',
 | 
				
			||||||
 | 
					                'n_note',
 | 
				
			||||||
 | 
					                'reason.c_name as reason_name',
 | 
				
			||||||
 | 
					                'timeTypes.c_name as time_type_name'
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            ->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
namespace App\Traits;
 | 
					namespace App\Traits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Helper\Cache\CurrentMonthTimekeeping;
 | 
					use App\Helper\Cache\CurrentMonthTimekeeping;
 | 
				
			||||||
 | 
					use App\Models\Notes;
 | 
				
			||||||
use Carbon\Carbon;
 | 
					use Carbon\Carbon;
 | 
				
			||||||
use Illuminate\Http\JsonResponse;
 | 
					use Illuminate\Http\JsonResponse;
 | 
				
			||||||
use Illuminate\Support\Facades\DB;
 | 
					use Illuminate\Support\Facades\DB;
 | 
				
			||||||
| 
						 | 
					@ -32,44 +33,72 @@ trait AnalyzeData
 | 
				
			||||||
        $endOfMonth = $now->endOfMonth()->endOfDay()->toDateTimeString();
 | 
					        $endOfMonth = $now->endOfMonth()->endOfDay()->toDateTimeString();
 | 
				
			||||||
        $admins = Admin::all();
 | 
					        $admins = Admin::all();
 | 
				
			||||||
        $history = DB::table('tracking')->select('*')->whereBetween('tracking.created_at', [$startOfMonth, $endOfMonth])->orderBy('tracking.created_at', 'asc')->get();
 | 
					        $history = DB::table('tracking')->select('*')->whereBetween('tracking.created_at', [$startOfMonth, $endOfMonth])->orderBy('tracking.created_at', 'asc')->get();
 | 
				
			||||||
 | 
					        $dataNotes = Notes::getNotesByMonthAndYear((int)$month, (int)$year);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $history = collect($history);
 | 
					        $history = collect($history);
 | 
				
			||||||
        $result = [];
 | 
					        $result = [];
 | 
				
			||||||
        foreach ($admins as $key => $admin) {
 | 
					        foreach ($admins as $key => $admin) {
 | 
				
			||||||
            if ($key == 0) {
 | 
					            $user_data = [];
 | 
				
			||||||
                $user_data = [];
 | 
					            for ($i = 1; $i <= $daysInMonth; $i++) {
 | 
				
			||||||
                for ($i = 1; $i <= $daysInMonth; $i++) {
 | 
					                // Tạo ngày cụ thể trong tháng
 | 
				
			||||||
                    // Tạo ngày cụ thể trong tháng
 | 
					                $date = Carbon::create($now->year, $now->month, $i)->setTimezone(env('TIME_ZONE'))->format('Y-m-d');
 | 
				
			||||||
                    $date = Carbon::create($now->year, $now->month, $i)->setTimezone(env('TIME_ZONE'))->format('Y-m-d');
 | 
					                // Kiểm tra xem có mục nào trong $history có created_at trùng với $date
 | 
				
			||||||
                    // Kiểm tra xem có mục nào trong $history có created_at trùng với $date
 | 
					                $hasEntry = $history->filter(function ($entry) use ($date, $admin) {
 | 
				
			||||||
                    $hasEntry = $history->filter(function ($entry) use ($date, $admin) {
 | 
					 | 
				
			||||||
                        // echo($hasEntry);
 | 
					 | 
				
			||||||
                        return Carbon::parse($entry->created_at)->setTimezone(env('TIME_ZONE'))->format('Y-m-d') === $date && $entry->user_id == $admin->id;
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    // echo($hasEntry);
 | 
					                    // echo($hasEntry);
 | 
				
			||||||
                    // dd($date,$admin,$history,$daysInMonth);
 | 
					                    return Carbon::parse($entry->created_at)->setTimezone(env('TIME_ZONE'))->format('Y-m-d') === $date && $entry->user_id == $admin->id;
 | 
				
			||||||
                    if (count($hasEntry) > 0) {
 | 
					                });
 | 
				
			||||||
                        $values = array_values($hasEntry->toArray());
 | 
					                $hasNotes = $dataNotes->filter(function ($entry) use ($i, $admin) {
 | 
				
			||||||
                        $last_checkin = null;
 | 
					                    return $entry->n_user_id == $admin->id && $entry->n_day == $i;
 | 
				
			||||||
                        $total = 0;
 | 
					                });
 | 
				
			||||||
                        foreach ($values as $value) {
 | 
					                // dd($date,$admin,$history,$daysInMonth);
 | 
				
			||||||
                            $createdAt = Carbon::parse($value->created_at)->setTimezone(env('TIME_ZONE'));
 | 
					                if (count($hasEntry) > 0) {
 | 
				
			||||||
                            if ($value->status == 'check out' && $last_checkin != null) {
 | 
					                    $values = array_values($hasEntry->toArray());
 | 
				
			||||||
                                $lastCheckInTime = Carbon::parse($last_checkin)->setTimezone(env('TIME_ZONE'));
 | 
					                    $last_checkin = null;
 | 
				
			||||||
                                // Tính thời gian làm việc bằng hiệu của thời gian check out và check in
 | 
					                    $total = 0;
 | 
				
			||||||
                                $workingTime = $createdAt->diffInSeconds($lastCheckInTime);
 | 
					                    foreach ($values as $value) {
 | 
				
			||||||
                                $total += $workingTime;
 | 
					                        $createdAt = Carbon::parse($value->created_at)->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
                            }
 | 
					                        if ($value->status == 'check out' && $last_checkin != null) {
 | 
				
			||||||
 | 
					                            $lastCheckInTime = Carbon::parse($last_checkin)->setTimezone(env('TIME_ZONE'));
 | 
				
			||||||
                            if ($value->status == 'check in') {
 | 
					                            // Tính thời gian làm việc bằng hiệu của thời gian check out và check in
 | 
				
			||||||
                                $last_checkin = $createdAt;
 | 
					                            $workingTime = $createdAt->diffInSeconds($lastCheckInTime);
 | 
				
			||||||
                            }
 | 
					                            $total += $workingTime;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        $user_data[] = ['values' => array_values($hasEntry->toArray()), 'total' => $total, 'day' => $i];
 | 
					
 | 
				
			||||||
 | 
					                        if ($value->status == 'check in') {
 | 
				
			||||||
 | 
					                            $last_checkin = $createdAt;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $notes = [];
 | 
				
			||||||
 | 
					                    if (count($hasNotes) > 0) {
 | 
				
			||||||
 | 
					                        foreach ($hasNotes as $k_Note => $value_Note) {
 | 
				
			||||||
 | 
					                            $notes[$k_Note] = [
 | 
				
			||||||
 | 
					                                'timeType' => $value_Note->n_time_type,
 | 
				
			||||||
 | 
					                                'timeTypeName' => $value_Note->time_type_name,
 | 
				
			||||||
 | 
					                                'reason' => $value_Note->n_reason,
 | 
				
			||||||
 | 
					                                'reasonName' => $value_Note->reason_name,
 | 
				
			||||||
 | 
					                                'note' => $value_Note->n_note
 | 
				
			||||||
 | 
					                            ];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $user_data[] = ['values' => array_values($hasEntry->toArray()), 'notes' => array_values($notes), 'total' => $total, 'day' => $i];
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    if (count($hasNotes) > 0) {
 | 
				
			||||||
 | 
					                        $notes = [];
 | 
				
			||||||
 | 
					                        foreach ($hasNotes as $k_Note => $value_Note) {
 | 
				
			||||||
 | 
					                            $notes[$k_Note] = [
 | 
				
			||||||
 | 
					                                'timeType' => $value_Note->n_time_type,
 | 
				
			||||||
 | 
					                                'timeTypeName' => $value_Note->time_type_name,
 | 
				
			||||||
 | 
					                                'reason' => $value_Note->n_reason,
 | 
				
			||||||
 | 
					                                'reasonName' => $value_Note->reason_name,
 | 
				
			||||||
 | 
					                                'note' => $value_Note->n_note
 | 
				
			||||||
 | 
					                            ];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        $user_data[] = ['values' => [], 'notes' => array_values($notes), 'total' => 0, 'day' => $i];
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                $result[] = ['user' => $admin, 'history' => $user_data];
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $result[] = ['user' => $admin, 'history' => $user_data];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return $result;
 | 
					        return $result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Migrations\Migration;
 | 
				
			||||||
 | 
					use Illuminate\Database\Schema\Blueprint;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return new class extends Migration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Run the migrations.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function up(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::create('notes', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->id();
 | 
				
			||||||
 | 
					            $table->string('n_user_id');
 | 
				
			||||||
 | 
					            $table->integer('n_day');
 | 
				
			||||||
 | 
					            $table->integer('n_month');
 | 
				
			||||||
 | 
					            $table->integer('n_year');
 | 
				
			||||||
 | 
					            $table->string('n_time_type');
 | 
				
			||||||
 | 
					            $table->string('n_reason');
 | 
				
			||||||
 | 
					            $table->text('n_note');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->timestamps();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reverse the migrations.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function down(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::dropIfExists('notes');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -67,4 +67,8 @@ export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
 | 
				
			||||||
//Timekeeping
 | 
					//Timekeeping
 | 
				
			||||||
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
 | 
					export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
 | 
				
			||||||
export const updateMultipleUserWorkingTime = API_URL + 'v1/admin/timekeeping/addMutilple'
 | 
					export const updateMultipleUserWorkingTime = API_URL + 'v1/admin/timekeeping/addMutilple'
 | 
				
			||||||
export const updateWorkingDays = API_URL + 'v1/admin/timekeeping/update-working-days'
 | 
					export const updateNote = API_URL + 'v1/admin/timekeeping/addNote'
 | 
				
			||||||
 | 
					export const updateWorkingDays = API_URL + 'v1/admin/timekeeping/update-working-days'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Category
 | 
				
			||||||
 | 
					export const getListMaster = API_URL + 'v1/admin/category/get-list-master'
 | 
				
			||||||
| 
						 | 
					@ -55,3 +55,8 @@
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: end;
 | 
					  justify-content: end;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.historyRow td {
 | 
				
			||||||
 | 
					  padding-top: 5px;
 | 
				
			||||||
 | 
					  padding-bottom: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  getListMaster,
 | 
				
			||||||
  getTheTimesheet,
 | 
					  getTheTimesheet,
 | 
				
			||||||
  updateMultipleUserWorkingTime,
 | 
					  updateMultipleUserWorkingTime,
 | 
				
			||||||
 | 
					  updateNote,
 | 
				
			||||||
  updateWorkingDays,
 | 
					  updateWorkingDays,
 | 
				
			||||||
} from '@/api/Admin'
 | 
					} from '@/api/Admin'
 | 
				
			||||||
import { update } from '@/rtk/helpers/CRUD'
 | 
					import { update } from '@/rtk/helpers/CRUD'
 | 
				
			||||||
| 
						 | 
					@ -15,6 +17,7 @@ import {
 | 
				
			||||||
  Select,
 | 
					  Select,
 | 
				
			||||||
  Table,
 | 
					  Table,
 | 
				
			||||||
  Text,
 | 
					  Text,
 | 
				
			||||||
 | 
					  Textarea,
 | 
				
			||||||
  TextInput,
 | 
					  TextInput,
 | 
				
			||||||
  Tooltip,
 | 
					  Tooltip,
 | 
				
			||||||
} from '@mantine/core'
 | 
					} from '@mantine/core'
 | 
				
			||||||
| 
						 | 
					@ -39,6 +42,18 @@ interface User {
 | 
				
			||||||
  updated_at: string | null
 | 
					  updated_at: string | null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DataReason {
 | 
				
			||||||
 | 
					  id: number
 | 
				
			||||||
 | 
					  c_code: string
 | 
				
			||||||
 | 
					  c_name: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DataTimeType {
 | 
				
			||||||
 | 
					  id: number
 | 
				
			||||||
 | 
					  c_code: string
 | 
				
			||||||
 | 
					  c_name: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface HistoryValue {
 | 
					interface HistoryValue {
 | 
				
			||||||
  id: number
 | 
					  id: number
 | 
				
			||||||
  name: string
 | 
					  name: string
 | 
				
			||||||
| 
						 | 
					@ -50,10 +65,19 @@ interface HistoryValue {
 | 
				
			||||||
  updated_at: string
 | 
					  updated_at: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface NoteValue {
 | 
				
			||||||
 | 
					  note: string
 | 
				
			||||||
 | 
					  reason: string
 | 
				
			||||||
 | 
					  timeType: string
 | 
				
			||||||
 | 
					  reasonName: string
 | 
				
			||||||
 | 
					  timeTypeName: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface History {
 | 
					interface History {
 | 
				
			||||||
  values: HistoryValue[]
 | 
					  values: HistoryValue[]
 | 
				
			||||||
  total: number
 | 
					  total: number
 | 
				
			||||||
  day: number
 | 
					  day: number
 | 
				
			||||||
 | 
					  notes: NoteValue[]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface UserData {
 | 
					interface UserData {
 | 
				
			||||||
| 
						 | 
					@ -62,7 +86,8 @@ interface UserData {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Timekeeping = () => {
 | 
					const Timekeeping = () => {
 | 
				
			||||||
  const [opened, { open, close }] = useDisclosure(false)
 | 
					  const [opened1, { open: open1, close: close1 }] = useDisclosure(false)
 | 
				
			||||||
 | 
					  const [opened2, { open: open2, close: close2 }] = useDisclosure(false)
 | 
				
			||||||
  const [disableBtn, setDisableBtn] = useState(false)
 | 
					  const [disableBtn, setDisableBtn] = useState(false)
 | 
				
			||||||
  const [daysInMonth, setDaysInMonth] = useState(
 | 
					  const [daysInMonth, setDaysInMonth] = useState(
 | 
				
			||||||
    Array.from({ length: 31 }, (_, index) => index + 1),
 | 
					    Array.from({ length: 31 }, (_, index) => index + 1),
 | 
				
			||||||
| 
						 | 
					@ -76,31 +101,67 @@ const Timekeeping = () => {
 | 
				
			||||||
    type: '',
 | 
					    type: '',
 | 
				
			||||||
    day: 0,
 | 
					    day: 0,
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  const [workingDays, setWorkingDays] = useState(30)
 | 
					  const [customAddNotes, setCustomAddNotes] = useState<{
 | 
				
			||||||
  const [isOpen, setIsOpen] = useState('')
 | 
					    user: {
 | 
				
			||||||
  const popoverRef = useRef<HTMLElement>(null)
 | 
					      id: number
 | 
				
			||||||
 | 
					      name: string
 | 
				
			||||||
  const [selectedOption1, setSelectedOption1] = useState('')
 | 
					 | 
				
			||||||
  const [selectedOption2, setSelectedOption2] = useState('')
 | 
					 | 
				
			||||||
  const [textValue, setTextValue] = useState('')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleSave = () => {
 | 
					 | 
				
			||||||
    // Send data to API
 | 
					 | 
				
			||||||
    const data = {
 | 
					 | 
				
			||||||
      option1: selectedOption1,
 | 
					 | 
				
			||||||
      option2: selectedOption2,
 | 
					 | 
				
			||||||
      text: textValue,
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    console.log(data) // Replace with actual API call
 | 
					    type: string
 | 
				
			||||||
    setIsOpen(false)
 | 
					    reason: string
 | 
				
			||||||
  }
 | 
					    note: string
 | 
				
			||||||
 | 
					    day: number
 | 
				
			||||||
 | 
					  }>({
 | 
				
			||||||
 | 
					    user: {
 | 
				
			||||||
 | 
					      id: 0,
 | 
				
			||||||
 | 
					      name: '',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    type: '',
 | 
				
			||||||
 | 
					    reason: '',
 | 
				
			||||||
 | 
					    note: '',
 | 
				
			||||||
 | 
					    day: 0,
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [workingDays, setWorkingDays] = useState(30)
 | 
				
			||||||
  const [data, setData] = useState<UserData[]>([])
 | 
					  const [data, setData] = useState<UserData[]>([])
 | 
				
			||||||
  const [date, setDate] = useState({
 | 
					  const [date, setDate] = useState({
 | 
				
			||||||
    month: (new Date().getMonth() + 1).toString(),
 | 
					    month: (new Date().getMonth() + 1).toString(),
 | 
				
			||||||
    year: new Date().getFullYear().toString(),
 | 
					    year: new Date().getFullYear().toString(),
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [dataTimeType, setDataTimeType] = useState<DataTimeType[]>([])
 | 
				
			||||||
 | 
					  const [dataReason, setDataReason] = useState<DataReason[]>([])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getListMasterByType = async (type: string) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const params = {
 | 
				
			||||||
 | 
					        type: type,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const res = await get(getListMaster, params)
 | 
				
			||||||
 | 
					      if (res.status) {
 | 
				
			||||||
 | 
					        return res.data
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      notifications.show({
 | 
				
			||||||
 | 
					        title: 'Error',
 | 
				
			||||||
 | 
					        message: error.message ?? error,
 | 
				
			||||||
 | 
					        color: 'red',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    const fetchData = async () => {
 | 
				
			||||||
 | 
					      const resultTimeType = await getListMasterByType('TIME_TYPE')
 | 
				
			||||||
 | 
					      setDataTimeType(resultTimeType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const resultReason = await getListMasterByType('REASON')
 | 
				
			||||||
 | 
					      setDataReason(resultReason)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fetchData()
 | 
				
			||||||
 | 
					  }, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getTimeSheet = async () => {
 | 
					  const getTimeSheet = async () => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const res = await get(getTheTimesheet, {
 | 
					      const res = await get(getTheTimesheet, {
 | 
				
			||||||
| 
						 | 
					@ -173,6 +234,37 @@ const Timekeeping = () => {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const updateInfoNote = async (
 | 
				
			||||||
 | 
					    users: {
 | 
				
			||||||
 | 
					      id: number
 | 
				
			||||||
 | 
					      name: string
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    day: number,
 | 
				
			||||||
 | 
					    type: string,
 | 
				
			||||||
 | 
					    reason: string,
 | 
				
			||||||
 | 
					    note: string,
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      await update(
 | 
				
			||||||
 | 
					        updateNote,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          month: date.month,
 | 
				
			||||||
 | 
					          year: date.year,
 | 
				
			||||||
 | 
					          users: users,
 | 
				
			||||||
 | 
					          type: type,
 | 
				
			||||||
 | 
					          reason: reason,
 | 
				
			||||||
 | 
					          note: note,
 | 
				
			||||||
 | 
					          day: day,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getTimeSheet,
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setDisableBtn(false)
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.log(error)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleUpdateWorkingDays = async () => {
 | 
					  const handleUpdateWorkingDays = async () => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await update(
 | 
					      await update(
 | 
				
			||||||
| 
						 | 
					@ -193,49 +285,87 @@ const Timekeeping = () => {
 | 
				
			||||||
    getTimeSheet()
 | 
					    getTimeSheet()
 | 
				
			||||||
  }, [date])
 | 
					  }, [date])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // useEffect(() => {
 | 
					  const showTooltipNote = (user: UserData, d: number) => {
 | 
				
			||||||
  //   const handleClickOutside = (event: MouseEvent | React.MouseEvent) => {
 | 
					    return user.history
 | 
				
			||||||
  //     if (
 | 
					      .find((h) => h.day === d && h.notes && h.notes.length > 0)
 | 
				
			||||||
  //       popoverRef.current &&
 | 
					      ?.notes.map((v, index) => {
 | 
				
			||||||
  //       !(popoverRef.current as HTMLElement).contains(event.target as Node)
 | 
					        return (
 | 
				
			||||||
  //     ) {
 | 
					          <p key={index}>
 | 
				
			||||||
  //       setIsOpen('')
 | 
					            - {v.reasonName} ({v.timeTypeName}): {v.note}
 | 
				
			||||||
  //     }
 | 
					          </p>
 | 
				
			||||||
  //   }
 | 
					        )
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const showTooltipAllNote = (user: UserData) => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <table style={{ borderCollapse: 'collapse', width: '100%' }}>
 | 
				
			||||||
 | 
					        <tbody>
 | 
				
			||||||
 | 
					          {user.history
 | 
				
			||||||
 | 
					            .filter((h) => h.notes && h.notes.length > 0)
 | 
				
			||||||
 | 
					            .map((h, index) => (
 | 
				
			||||||
 | 
					              <tr key={index} className={classes.historyRow}>
 | 
				
			||||||
 | 
					                <td
 | 
				
			||||||
 | 
					                  style={{
 | 
				
			||||||
 | 
					                    border: '0',
 | 
				
			||||||
 | 
					                    verticalAlign: 'top',
 | 
				
			||||||
 | 
					                    fontWeight: 'bold',
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  Day {h.day}:
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td style={{ border: '0', paddingLeft: '10px' }}>
 | 
				
			||||||
 | 
					                  {h.notes.map((v, noteIndex) => (
 | 
				
			||||||
 | 
					                    <p key={noteIndex} style={{ margin: '0' }}>
 | 
				
			||||||
 | 
					                      - {v.reasonName} ({v.timeTypeName}): {v.note}
 | 
				
			||||||
 | 
					                    </p>
 | 
				
			||||||
 | 
					                  ))}
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					        </tbody>
 | 
				
			||||||
 | 
					      </table>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //   document.addEventListener('click', handleClickOutside)
 | 
					  const showTooltip = (user: UserData, total: number, d: number) => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
  //   return () => {
 | 
					      <div key={d}>
 | 
				
			||||||
  //     document.removeEventListener('click', handleClickOutside)
 | 
					        {`Total: ${(total / 60 / 60).toFixed(1)}h`}
 | 
				
			||||||
  //   }
 | 
					        {user.history
 | 
				
			||||||
  // }, [popoverRef])
 | 
					          .find((h) => h.day === d)
 | 
				
			||||||
 | 
					          ?.values.map((v) => {
 | 
				
			||||||
  useEffect(() => {
 | 
					            return (
 | 
				
			||||||
    const handleClickOutside = (event: React.MouseEvent) => {
 | 
					              <Box
 | 
				
			||||||
      if (
 | 
					                style={{
 | 
				
			||||||
        popoverRef.current &&
 | 
					                  display: 'flex',
 | 
				
			||||||
        !(popoverRef.current as HTMLElement).contains(event.target as Node)
 | 
					                  alignItems: 'center',
 | 
				
			||||||
      ) {
 | 
					                  justifyContent: 'space-between',
 | 
				
			||||||
        setIsOpen('')
 | 
					                }}
 | 
				
			||||||
      }
 | 
					                key={v.id}
 | 
				
			||||||
    }
 | 
					              >
 | 
				
			||||||
 | 
					                <p>{v.status + ': ' + v.time_string}</p>{' '}
 | 
				
			||||||
    document.addEventListener('mousedown', handleClickOutside)
 | 
					                {v.image && (
 | 
				
			||||||
    document.addEventListener('scroll', handleClickOutside)
 | 
					                  <Image
 | 
				
			||||||
    document
 | 
					                    w={100}
 | 
				
			||||||
      .getElementById('my-child-div')
 | 
					                    h={100}
 | 
				
			||||||
      ?.addEventListener('scroll', handleClickOutside)
 | 
					                    src={
 | 
				
			||||||
 | 
					                      import.meta.env.VITE_BACKEND_URL.includes('local')
 | 
				
			||||||
    return () => {
 | 
					                        ? import.meta.env.VITE_BACKEND_URL +
 | 
				
			||||||
      document.removeEventListener('mousedown', handleClickOutside)
 | 
					                          'storage/' +
 | 
				
			||||||
      document.removeEventListener('scroll', handleClickOutside)
 | 
					                          v.image
 | 
				
			||||||
      document
 | 
					                        : import.meta.env.VITE_BACKEND_URL +
 | 
				
			||||||
        .getElementById('my-child-div')
 | 
					                          'image/storage/' +
 | 
				
			||||||
        ?.removeEventListener('scroll', handleClickOutside)
 | 
					                          v.image
 | 
				
			||||||
    }
 | 
					                    }
 | 
				
			||||||
  }, [popoverRef])
 | 
					                  />
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
  // console.log(daysInMonth, 'daysInMonth')
 | 
					              </Box>
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        {showTooltipNote(user, d)}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <div className={classes.title}>
 | 
					      <div className={classes.title}>
 | 
				
			||||||
| 
						 | 
					@ -245,8 +375,8 @@ const Timekeeping = () => {
 | 
				
			||||||
        </h3>
 | 
					        </h3>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <Drawer
 | 
					      <Drawer
 | 
				
			||||||
        opened={opened}
 | 
					        opened={opened1}
 | 
				
			||||||
        onClose={close}
 | 
					        onClose={close1}
 | 
				
			||||||
        position="right"
 | 
					        position="right"
 | 
				
			||||||
        title={<strong>Add custom worklog</strong>}
 | 
					        title={<strong>Add custom worklog</strong>}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
| 
						 | 
					@ -299,6 +429,85 @@ const Timekeeping = () => {
 | 
				
			||||||
          Submit
 | 
					          Submit
 | 
				
			||||||
        </Button>
 | 
					        </Button>
 | 
				
			||||||
      </Drawer>
 | 
					      </Drawer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {/* Form Save Note */}
 | 
				
			||||||
 | 
					      <Drawer
 | 
				
			||||||
 | 
					        opened={opened2}
 | 
				
			||||||
 | 
					        onClose={close2}
 | 
				
			||||||
 | 
					        position="right"
 | 
				
			||||||
 | 
					        title={<strong>Save Note</strong>}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					          <span style={{ fontWeight: 'bold' }}>User</span>:{' '}
 | 
				
			||||||
 | 
					          {customAddNotes.user.name}
 | 
				
			||||||
 | 
					          <span style={{ paddingLeft: '10px', paddingRight: '10px' }}>|</span>
 | 
				
			||||||
 | 
					          <span style={{ fontWeight: 'bold' }}>Day</span>: {customAddNotes.day}
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <Select
 | 
				
			||||||
 | 
					          mb={'md'}
 | 
				
			||||||
 | 
					          searchable
 | 
				
			||||||
 | 
					          label="Reason"
 | 
				
			||||||
 | 
					          data={dataReason.map((user) => ({
 | 
				
			||||||
 | 
					            value: user.c_code.toString(),
 | 
				
			||||||
 | 
					            label: user.c_name,
 | 
				
			||||||
 | 
					          }))}
 | 
				
			||||||
 | 
					          onChange={(e) => {
 | 
				
			||||||
 | 
					            setCustomAddNotes({ ...customAddNotes, reason: e! })
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        {customAddNotes.reason != '' && (
 | 
				
			||||||
 | 
					          <Select
 | 
				
			||||||
 | 
					            mb={'md'}
 | 
				
			||||||
 | 
					            label="Time Type"
 | 
				
			||||||
 | 
					            data={dataTimeType.map((item) => {
 | 
				
			||||||
 | 
					              return { value: item.c_code.toString(), label: item.c_name }
 | 
				
			||||||
 | 
					            })}
 | 
				
			||||||
 | 
					            onChange={(e) => {
 | 
				
			||||||
 | 
					              setCustomAddNotes({ ...customAddNotes, type: e! })
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        {customAddNotes.type != '' && (
 | 
				
			||||||
 | 
					          <Textarea
 | 
				
			||||||
 | 
					            mb={'md'}
 | 
				
			||||||
 | 
					            label="Note"
 | 
				
			||||||
 | 
					            onChange={(e) => {
 | 
				
			||||||
 | 
					              setCustomAddNotes({ ...customAddNotes, note: e.target.value })
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        <Button
 | 
				
			||||||
 | 
					          onClick={() => {
 | 
				
			||||||
 | 
					            setDisableBtn(true)
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					              customAddNotes.type === '' ||
 | 
				
			||||||
 | 
					              customAddNotes.reason === '' ||
 | 
				
			||||||
 | 
					              customAddNotes.note === '' ||
 | 
				
			||||||
 | 
					              customAddNotes.day === 0 ||
 | 
				
			||||||
 | 
					              customAddNotes.user.id === 0
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					              notifications.show({
 | 
				
			||||||
 | 
					                title: 'Error',
 | 
				
			||||||
 | 
					                message: 'Input data required',
 | 
				
			||||||
 | 
					                color: 'red',
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					              setDisableBtn(false)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              updateInfoNote(
 | 
				
			||||||
 | 
					                customAddNotes.user,
 | 
				
			||||||
 | 
					                customAddNotes.day,
 | 
				
			||||||
 | 
					                customAddNotes.type,
 | 
				
			||||||
 | 
					                customAddNotes.reason,
 | 
				
			||||||
 | 
					                customAddNotes.note,
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					          disabled={disableBtn}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Save
 | 
				
			||||||
 | 
					        </Button>
 | 
				
			||||||
 | 
					      </Drawer>
 | 
				
			||||||
      <Box display={'flex'}>
 | 
					      <Box display={'flex'}>
 | 
				
			||||||
        <Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
 | 
					        <Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
 | 
				
			||||||
          <Box w="100%" display={'flex'}>
 | 
					          <Box w="100%" display={'flex'}>
 | 
				
			||||||
| 
						 | 
					@ -493,7 +702,7 @@ const Timekeeping = () => {
 | 
				
			||||||
                        <Text
 | 
					                        <Text
 | 
				
			||||||
                          size="sm"
 | 
					                          size="sm"
 | 
				
			||||||
                          onClick={() => {
 | 
					                          onClick={() => {
 | 
				
			||||||
                            open()
 | 
					                            open1()
 | 
				
			||||||
                            setCustomAddData({ ...customAddData, day: d })
 | 
					                            setCustomAddData({ ...customAddData, day: d })
 | 
				
			||||||
                          }}
 | 
					                          }}
 | 
				
			||||||
                        >
 | 
					                        >
 | 
				
			||||||
| 
						 | 
					@ -539,22 +748,11 @@ const Timekeeping = () => {
 | 
				
			||||||
                <Table.Tr key={user.user.id} className={classes.tableTr}>
 | 
					                <Table.Tr key={user.user.id} className={classes.tableTr}>
 | 
				
			||||||
                  <Table.Td>
 | 
					                  <Table.Td>
 | 
				
			||||||
                    <Tooltip
 | 
					                    <Tooltip
 | 
				
			||||||
 | 
					                      // position={'auto'}
 | 
				
			||||||
                      multiline
 | 
					                      multiline
 | 
				
			||||||
                      label={
 | 
					                      // opened
 | 
				
			||||||
                        <div>
 | 
					                      // offset={{ mainAxis: 5, crossAxis: 0 }}
 | 
				
			||||||
                          <p style={{ fontWeight: 'bold' }}>Day 1:</p>
 | 
					                      label={showTooltipAllNote(user)}
 | 
				
			||||||
                          <p style={{ paddingLeft: '10px' }}>
 | 
					 | 
				
			||||||
                            - Work For Home (Buổi Sáng): Bị bể bánh xe
 | 
					 | 
				
			||||||
                          </p>
 | 
					 | 
				
			||||||
                          <p style={{ paddingLeft: '10px' }}>- Nghỉ phép (Buổi Chiều): Bị cảm</p>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                          <p style={{ fontWeight: 'bold' }}>Day 2:</p>
 | 
					 | 
				
			||||||
                          <p style={{ paddingLeft: '10px' }}>
 | 
					 | 
				
			||||||
                            - Work For Home (Buổi Sáng): Bị bể bánh xe
 | 
					 | 
				
			||||||
                          </p>
 | 
					 | 
				
			||||||
                          <p style={{ paddingLeft: '10px' }}>- Nghỉ phép (Buổi Chiều): Bị cảm</p>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                      }
 | 
					 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      <div>{user.user.name}</div>
 | 
					                      <div>{user.user.name}</div>
 | 
				
			||||||
                    </Tooltip>
 | 
					                    </Tooltip>
 | 
				
			||||||
| 
						 | 
					@ -577,52 +775,13 @@ const Timekeeping = () => {
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                      >
 | 
					                      >
 | 
				
			||||||
                        {total / 60 / 60 < 7 &&
 | 
					                        {total / 60 / 60 < 7 &&
 | 
				
			||||||
                        user.history.find((h) => h.day === d) ? (
 | 
					                        user.history.find(
 | 
				
			||||||
 | 
					                          (h) => h.day === d && h.values && h.values.length > 0,
 | 
				
			||||||
 | 
					                        ) ? (
 | 
				
			||||||
                          total / 60 / 60 >= 3.5 ? (
 | 
					                          total / 60 / 60 >= 3.5 ? (
 | 
				
			||||||
                            <Tooltip
 | 
					                            <Tooltip
 | 
				
			||||||
                              multiline
 | 
					                              multiline
 | 
				
			||||||
                              label={
 | 
					                              label={showTooltip(user, total, d)}
 | 
				
			||||||
                                <div key={d}>
 | 
					 | 
				
			||||||
                                  {`Total: ${(total / 60 / 60).toFixed(1)}h`}
 | 
					 | 
				
			||||||
                                  {user.history
 | 
					 | 
				
			||||||
                                    .find((h) => h.day === d)
 | 
					 | 
				
			||||||
                                    ?.values.map((v) => {
 | 
					 | 
				
			||||||
                                      return (
 | 
					 | 
				
			||||||
                                        <Box
 | 
					 | 
				
			||||||
                                          style={{
 | 
					 | 
				
			||||||
                                            display: 'flex',
 | 
					 | 
				
			||||||
                                            alignItems: 'center',
 | 
					 | 
				
			||||||
                                            justifyContent: 'space-between',
 | 
					 | 
				
			||||||
                                          }}
 | 
					 | 
				
			||||||
                                          key={v.id}
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                          <p>
 | 
					 | 
				
			||||||
                                            {v.status + ': ' + v.time_string}
 | 
					 | 
				
			||||||
                                          </p>{' '}
 | 
					 | 
				
			||||||
                                          {v.image && (
 | 
					 | 
				
			||||||
                                            <Image
 | 
					 | 
				
			||||||
                                              w={100}
 | 
					 | 
				
			||||||
                                              h={100}
 | 
					 | 
				
			||||||
                                              src={
 | 
					 | 
				
			||||||
                                                import.meta.env.VITE_BACKEND_URL.includes(
 | 
					 | 
				
			||||||
                                                  'local',
 | 
					 | 
				
			||||||
                                                )
 | 
					 | 
				
			||||||
                                                  ? import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                                  : import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'image/storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                              }
 | 
					 | 
				
			||||||
                                            />
 | 
					 | 
				
			||||||
                                          )}
 | 
					 | 
				
			||||||
                                        </Box>
 | 
					 | 
				
			||||||
                                      )
 | 
					 | 
				
			||||||
                                    })}
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                              }
 | 
					 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                              <IconCheck
 | 
					                              <IconCheck
 | 
				
			||||||
                                size={20}
 | 
					                                size={20}
 | 
				
			||||||
| 
						 | 
					@ -633,53 +792,23 @@ const Timekeeping = () => {
 | 
				
			||||||
                                  padding: '2px',
 | 
					                                  padding: '2px',
 | 
				
			||||||
                                  fontWeight: 700,
 | 
					                                  fontWeight: 700,
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
 | 
					                                onClick={() => {
 | 
				
			||||||
 | 
					                                  open2()
 | 
				
			||||||
 | 
					                                  setCustomAddNotes({
 | 
				
			||||||
 | 
					                                    ...customAddNotes,
 | 
				
			||||||
 | 
					                                    day: d,
 | 
				
			||||||
 | 
					                                    user: {
 | 
				
			||||||
 | 
					                                      id: user.user.id,
 | 
				
			||||||
 | 
					                                      name: user.user.name,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  })
 | 
				
			||||||
 | 
					                                }}
 | 
				
			||||||
                              />
 | 
					                              />
 | 
				
			||||||
                            </Tooltip>
 | 
					                            </Tooltip>
 | 
				
			||||||
                          ) : (
 | 
					                          ) : (
 | 
				
			||||||
                            <Tooltip
 | 
					                            <Tooltip
 | 
				
			||||||
                              multiline
 | 
					                              multiline
 | 
				
			||||||
                              label={
 | 
					                              label={showTooltip(user, total, d)}
 | 
				
			||||||
                                <div>
 | 
					 | 
				
			||||||
                                  {`Total: ${(total / 60 / 60).toFixed(1)}h`}
 | 
					 | 
				
			||||||
                                  {user.history
 | 
					 | 
				
			||||||
                                    .find((h) => h.day === d)
 | 
					 | 
				
			||||||
                                    ?.values.map((v) => {
 | 
					 | 
				
			||||||
                                      return (
 | 
					 | 
				
			||||||
                                        <Box
 | 
					 | 
				
			||||||
                                          style={{
 | 
					 | 
				
			||||||
                                            display: 'flex',
 | 
					 | 
				
			||||||
                                            alignItems: 'center',
 | 
					 | 
				
			||||||
                                            justifyContent: 'space-between',
 | 
					 | 
				
			||||||
                                          }}
 | 
					 | 
				
			||||||
                                          key={v.id}
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                          <p>
 | 
					 | 
				
			||||||
                                            {v.status + ': ' + v.time_string}
 | 
					 | 
				
			||||||
                                          </p>{' '}
 | 
					 | 
				
			||||||
                                          {v.image && (
 | 
					 | 
				
			||||||
                                            <Image
 | 
					 | 
				
			||||||
                                              w={100}
 | 
					 | 
				
			||||||
                                              h={100}
 | 
					 | 
				
			||||||
                                              src={
 | 
					 | 
				
			||||||
                                                import.meta.env.VITE_BACKEND_URL.includes(
 | 
					 | 
				
			||||||
                                                  'local',
 | 
					 | 
				
			||||||
                                                )
 | 
					 | 
				
			||||||
                                                  ? import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                                  : import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'image/storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                              }
 | 
					 | 
				
			||||||
                                            />
 | 
					 | 
				
			||||||
                                          )}
 | 
					 | 
				
			||||||
                                        </Box>
 | 
					 | 
				
			||||||
                                      )
 | 
					 | 
				
			||||||
                                    })}
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                              }
 | 
					 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                              <IconExclamationMark
 | 
					                              <IconExclamationMark
 | 
				
			||||||
                                size={20}
 | 
					                                size={20}
 | 
				
			||||||
| 
						 | 
					@ -690,6 +819,17 @@ const Timekeeping = () => {
 | 
				
			||||||
                                  padding: '2px',
 | 
					                                  padding: '2px',
 | 
				
			||||||
                                  fontWeight: 700,
 | 
					                                  fontWeight: 700,
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
 | 
					                                onClick={() => {
 | 
				
			||||||
 | 
					                                  open2()
 | 
				
			||||||
 | 
					                                  setCustomAddNotes({
 | 
				
			||||||
 | 
					                                    ...customAddNotes,
 | 
				
			||||||
 | 
					                                    day: d,
 | 
				
			||||||
 | 
					                                    user: {
 | 
				
			||||||
 | 
					                                      id: user.user.id,
 | 
				
			||||||
 | 
					                                      name: user.user.name,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  })
 | 
				
			||||||
 | 
					                                }}
 | 
				
			||||||
                              />
 | 
					                              />
 | 
				
			||||||
                            </Tooltip>
 | 
					                            </Tooltip>
 | 
				
			||||||
                          )
 | 
					                          )
 | 
				
			||||||
| 
						 | 
					@ -697,48 +837,7 @@ const Timekeeping = () => {
 | 
				
			||||||
                          <>
 | 
					                          <>
 | 
				
			||||||
                            <Tooltip
 | 
					                            <Tooltip
 | 
				
			||||||
                              multiline
 | 
					                              multiline
 | 
				
			||||||
                              label={
 | 
					                              label={showTooltip(user, total, d)}
 | 
				
			||||||
                                <div>
 | 
					 | 
				
			||||||
                                  {`Total: ${(total / 60 / 60).toFixed(1)}h`}
 | 
					 | 
				
			||||||
                                  {user.history
 | 
					 | 
				
			||||||
                                    .find((h) => h.day === d)
 | 
					 | 
				
			||||||
                                    ?.values.map((v) => {
 | 
					 | 
				
			||||||
                                      return (
 | 
					 | 
				
			||||||
                                        <Box
 | 
					 | 
				
			||||||
                                          style={{
 | 
					 | 
				
			||||||
                                            display: 'flex',
 | 
					 | 
				
			||||||
                                            alignItems: 'center',
 | 
					 | 
				
			||||||
                                            justifyContent: 'space-between',
 | 
					 | 
				
			||||||
                                          }}
 | 
					 | 
				
			||||||
                                          key={v.id}
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                          <p>
 | 
					 | 
				
			||||||
                                            {v.status + ': ' + v.time_string}
 | 
					 | 
				
			||||||
                                          </p>{' '}
 | 
					 | 
				
			||||||
                                          {v.image && (
 | 
					 | 
				
			||||||
                                            <Image
 | 
					 | 
				
			||||||
                                              w={100}
 | 
					 | 
				
			||||||
                                              h={100}
 | 
					 | 
				
			||||||
                                              src={
 | 
					 | 
				
			||||||
                                                import.meta.env.VITE_BACKEND_URL.includes(
 | 
					 | 
				
			||||||
                                                  'local',
 | 
					 | 
				
			||||||
                                                )
 | 
					 | 
				
			||||||
                                                  ? import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                                  : import.meta.env
 | 
					 | 
				
			||||||
                                                      .VITE_BACKEND_URL +
 | 
					 | 
				
			||||||
                                                    'image/storage/' +
 | 
					 | 
				
			||||||
                                                    v.image
 | 
					 | 
				
			||||||
                                              }
 | 
					 | 
				
			||||||
                                            />
 | 
					 | 
				
			||||||
                                          )}
 | 
					 | 
				
			||||||
                                        </Box>
 | 
					 | 
				
			||||||
                                      )
 | 
					 | 
				
			||||||
                                    })}
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                              }
 | 
					 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                              <IconCheck
 | 
					                              <IconCheck
 | 
				
			||||||
                                size={20}
 | 
					                                size={20}
 | 
				
			||||||
| 
						 | 
					@ -748,155 +847,53 @@ const Timekeeping = () => {
 | 
				
			||||||
                                  borderRadius: '5px',
 | 
					                                  borderRadius: '5px',
 | 
				
			||||||
                                  padding: '2px',
 | 
					                                  padding: '2px',
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                                id={`indexBySN${user.user.id}_${d}`}
 | 
					 | 
				
			||||||
                                onClick={() => {
 | 
					                                onClick={() => {
 | 
				
			||||||
                                  setIsOpen(
 | 
					                                  open2()
 | 
				
			||||||
                                    isOpen == user.user.email + d
 | 
					                                  setCustomAddNotes({
 | 
				
			||||||
                                      ? ''
 | 
					                                    ...customAddNotes,
 | 
				
			||||||
                                      : user.user.email + d,
 | 
					                                    day: d,
 | 
				
			||||||
                                  )
 | 
					                                    user: {
 | 
				
			||||||
 | 
					                                      id: user.user.id,
 | 
				
			||||||
 | 
					                                      name: user.user.name,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  })
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                              />
 | 
					                              />
 | 
				
			||||||
                            </Tooltip>
 | 
					                            </Tooltip>
 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <Popover
 | 
					 | 
				
			||||||
                              placement="bottom"
 | 
					 | 
				
			||||||
                              isOpen={isOpen === user.user.email + d}
 | 
					 | 
				
			||||||
                              target={`indexBySN${user.user.id}_${d}`}
 | 
					 | 
				
			||||||
                              toggle={() =>
 | 
					 | 
				
			||||||
                                setIsOpen(
 | 
					 | 
				
			||||||
                                  isOpen == user.user.email + d
 | 
					 | 
				
			||||||
                                    ? ''
 | 
					 | 
				
			||||||
                                    : user.user.email + d,
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                              }
 | 
					 | 
				
			||||||
                              innerRef={popoverRef}
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                              <PopoverBody
 | 
					 | 
				
			||||||
                                style={{
 | 
					 | 
				
			||||||
                                  width: '300px',
 | 
					 | 
				
			||||||
                                  backgroundColor: 'white',
 | 
					 | 
				
			||||||
                                  boxShadow:
 | 
					 | 
				
			||||||
                                    '0 5px 15px rgba(30, 32, 37, 0.12)',
 | 
					 | 
				
			||||||
                                }}
 | 
					 | 
				
			||||||
                              >
 | 
					 | 
				
			||||||
                                <div>
 | 
					 | 
				
			||||||
                                  <div>
 | 
					 | 
				
			||||||
                                    <label htmlFor="option1">
 | 
					 | 
				
			||||||
                                      Select Option 1:
 | 
					 | 
				
			||||||
                                    </label>
 | 
					 | 
				
			||||||
                                    <select
 | 
					 | 
				
			||||||
                                      id="option1"
 | 
					 | 
				
			||||||
                                      value={selectedOption1}
 | 
					 | 
				
			||||||
                                      onChange={(e) =>
 | 
					 | 
				
			||||||
                                        setSelectedOption1(e.target.value)
 | 
					 | 
				
			||||||
                                      }
 | 
					 | 
				
			||||||
                                      className="form-select"
 | 
					 | 
				
			||||||
                                    >
 | 
					 | 
				
			||||||
                                      <option value="">Select...</option>
 | 
					 | 
				
			||||||
                                      <option value="option1">Option 1</option>
 | 
					 | 
				
			||||||
                                      <option value="option2">Option 2</option>
 | 
					 | 
				
			||||||
                                    </select>
 | 
					 | 
				
			||||||
                                  </div>
 | 
					 | 
				
			||||||
                                  {selectedOption1 && (
 | 
					 | 
				
			||||||
                                    <div className="mt-2">
 | 
					 | 
				
			||||||
                                      <label htmlFor="option2">
 | 
					 | 
				
			||||||
                                        Select Option 2:
 | 
					 | 
				
			||||||
                                      </label>
 | 
					 | 
				
			||||||
                                      <select
 | 
					 | 
				
			||||||
                                        id="option2"
 | 
					 | 
				
			||||||
                                        value={selectedOption2}
 | 
					 | 
				
			||||||
                                        onChange={(e) =>
 | 
					 | 
				
			||||||
                                          setSelectedOption2(e.target.value)
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        className="form-select"
 | 
					 | 
				
			||||||
                                      >
 | 
					 | 
				
			||||||
                                        <option value="">Select...</option>
 | 
					 | 
				
			||||||
                                        <option value="optionA">
 | 
					 | 
				
			||||||
                                          Option A
 | 
					 | 
				
			||||||
                                        </option>
 | 
					 | 
				
			||||||
                                        <option value="optionB">
 | 
					 | 
				
			||||||
                                          Option B
 | 
					 | 
				
			||||||
                                        </option>
 | 
					 | 
				
			||||||
                                      </select>
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                  )}
 | 
					 | 
				
			||||||
                                  {selectedOption2 && (
 | 
					 | 
				
			||||||
                                    <div className="mt-2">
 | 
					 | 
				
			||||||
                                      <label htmlFor="textInput">
 | 
					 | 
				
			||||||
                                        Enter Text:
 | 
					 | 
				
			||||||
                                      </label>
 | 
					 | 
				
			||||||
                                      <textarea
 | 
					 | 
				
			||||||
                                        id="textInput"
 | 
					 | 
				
			||||||
                                        value={textValue}
 | 
					 | 
				
			||||||
                                        onChange={(e) =>
 | 
					 | 
				
			||||||
                                          setTextValue(e.target.value)
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        className="form-control"
 | 
					 | 
				
			||||||
                                      />
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                  )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                  <MultiSelect
 | 
					 | 
				
			||||||
                                    mb={'md'}
 | 
					 | 
				
			||||||
                                    searchable
 | 
					 | 
				
			||||||
                                    label="User(s)"
 | 
					 | 
				
			||||||
                                    data={data.map((user) => {
 | 
					 | 
				
			||||||
                                      return {
 | 
					 | 
				
			||||||
                                        value: user.user.id.toString(),
 | 
					 | 
				
			||||||
                                        label: user.user.name,
 | 
					 | 
				
			||||||
                                      }
 | 
					 | 
				
			||||||
                                    })}
 | 
					 | 
				
			||||||
                                    onChange={(e) => {
 | 
					 | 
				
			||||||
                                      setCustomAddData({
 | 
					 | 
				
			||||||
                                        ...customAddData,
 | 
					 | 
				
			||||||
                                        data: e,
 | 
					 | 
				
			||||||
                                      })
 | 
					 | 
				
			||||||
                                    }}
 | 
					 | 
				
			||||||
                                  />
 | 
					 | 
				
			||||||
                                  <Select
 | 
					 | 
				
			||||||
                                    mb={'md'}
 | 
					 | 
				
			||||||
                                    label="Type"
 | 
					 | 
				
			||||||
                                    data={[
 | 
					 | 
				
			||||||
                                      { value: 'half', label: 'Half day' },
 | 
					 | 
				
			||||||
                                      { value: 'one', label: 'A day' },
 | 
					 | 
				
			||||||
                                    ]}
 | 
					 | 
				
			||||||
                                    onChange={(e) => {
 | 
					 | 
				
			||||||
                                      setCustomAddData({
 | 
					 | 
				
			||||||
                                        ...customAddData,
 | 
					 | 
				
			||||||
                                        type: e!,
 | 
					 | 
				
			||||||
                                      })
 | 
					 | 
				
			||||||
                                    }}
 | 
					 | 
				
			||||||
                                  />
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                                <div className={classes.popoverFooter}>
 | 
					 | 
				
			||||||
                                  <Button
 | 
					 | 
				
			||||||
                                    variant="filled"
 | 
					 | 
				
			||||||
                                    color="red"
 | 
					 | 
				
			||||||
                                    onClick={() => setIsOpen('')}
 | 
					 | 
				
			||||||
                                  >
 | 
					 | 
				
			||||||
                                    Close
 | 
					 | 
				
			||||||
                                  </Button>
 | 
					 | 
				
			||||||
                                  <Button variant="filled" onClick={handleSave}>
 | 
					 | 
				
			||||||
                                    Save
 | 
					 | 
				
			||||||
                                  </Button>
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                              </PopoverBody>
 | 
					 | 
				
			||||||
                            </Popover>
 | 
					 | 
				
			||||||
                          </>
 | 
					                          </>
 | 
				
			||||||
                        ) : (
 | 
					                        ) : (
 | 
				
			||||||
                          <>
 | 
					                          <>
 | 
				
			||||||
                            <Tooltip
 | 
					                            {user.history.find(
 | 
				
			||||||
                              multiline
 | 
					                              (h) =>
 | 
				
			||||||
                              label={
 | 
					                                h.day === d && h.notes && h.notes.length > 0,
 | 
				
			||||||
                                <div key={d}>
 | 
					                            ) ? (
 | 
				
			||||||
                                  <p>
 | 
					                              <Tooltip
 | 
				
			||||||
                                    - Work For Home (Buổi Sáng): Bị bể bánh xe
 | 
					                                multiline
 | 
				
			||||||
                                  </p>
 | 
					                                label={showTooltipNote(user, d)}
 | 
				
			||||||
                                  <p>- Nghỉ phép (Buổi Chiều): Bị cảm</p>
 | 
					                              >
 | 
				
			||||||
                                </div>
 | 
					                                <IconX
 | 
				
			||||||
                              }
 | 
					                                  size={20}
 | 
				
			||||||
                            >
 | 
					                                  style={{
 | 
				
			||||||
 | 
					                                    backgroundColor: '#ff4646',
 | 
				
			||||||
 | 
					                                    color: 'white',
 | 
				
			||||||
 | 
					                                    borderRadius: '5px',
 | 
				
			||||||
 | 
					                                    padding: '2px',
 | 
				
			||||||
 | 
					                                  }}
 | 
				
			||||||
 | 
					                                  id={`indexBySN${user.user.id}_${d}`}
 | 
				
			||||||
 | 
					                                  onClick={() => {
 | 
				
			||||||
 | 
					                                    open2()
 | 
				
			||||||
 | 
					                                    setCustomAddNotes({
 | 
				
			||||||
 | 
					                                      ...customAddNotes,
 | 
				
			||||||
 | 
					                                      day: d,
 | 
				
			||||||
 | 
					                                      user: {
 | 
				
			||||||
 | 
					                                        id: user.user.id,
 | 
				
			||||||
 | 
					                                        name: user.user.name,
 | 
				
			||||||
 | 
					                                      },
 | 
				
			||||||
 | 
					                                    })
 | 
				
			||||||
 | 
					                                  }}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                              </Tooltip>
 | 
				
			||||||
 | 
					                            ) : (
 | 
				
			||||||
                              <IconX
 | 
					                              <IconX
 | 
				
			||||||
                                size={20}
 | 
					                                size={20}
 | 
				
			||||||
                                style={{
 | 
					                                style={{
 | 
				
			||||||
| 
						 | 
					@ -907,140 +904,18 @@ const Timekeeping = () => {
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                                id={`indexBySN${user.user.id}_${d}`}
 | 
					                                id={`indexBySN${user.user.id}_${d}`}
 | 
				
			||||||
                                onClick={() => {
 | 
					                                onClick={() => {
 | 
				
			||||||
                                  setIsOpen(
 | 
					                                  open2()
 | 
				
			||||||
                                    isOpen == user.user.email + d
 | 
					                                  setCustomAddNotes({
 | 
				
			||||||
                                      ? ''
 | 
					                                    ...customAddNotes,
 | 
				
			||||||
                                      : user.user.email + d,
 | 
					                                    day: d,
 | 
				
			||||||
                                  )
 | 
					                                    user: {
 | 
				
			||||||
 | 
					                                      id: user.user.id,
 | 
				
			||||||
 | 
					                                      name: user.user.name,
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  })
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                              />
 | 
					                              />
 | 
				
			||||||
                            </Tooltip>
 | 
					                            )}
 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <Popover
 | 
					 | 
				
			||||||
                              placement="bottom"
 | 
					 | 
				
			||||||
                              isOpen={isOpen === user.user.email + d}
 | 
					 | 
				
			||||||
                              target={`indexBySN${user.user.id}_${d}`}
 | 
					 | 
				
			||||||
                              toggle={() =>
 | 
					 | 
				
			||||||
                                setIsOpen(
 | 
					 | 
				
			||||||
                                  isOpen == user.user.email + d
 | 
					 | 
				
			||||||
                                    ? ''
 | 
					 | 
				
			||||||
                                    : user.user.email + d,
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                              }
 | 
					 | 
				
			||||||
                              innerRef={popoverRef}
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                              <PopoverBody
 | 
					 | 
				
			||||||
                                style={{
 | 
					 | 
				
			||||||
                                  width: '300px',
 | 
					 | 
				
			||||||
                                  backgroundColor: 'white',
 | 
					 | 
				
			||||||
                                  boxShadow:
 | 
					 | 
				
			||||||
                                    '0 5px 15px rgba(30, 32, 37, 0.12)',
 | 
					 | 
				
			||||||
                                  padding: '20px',
 | 
					 | 
				
			||||||
                                }}
 | 
					 | 
				
			||||||
                              >
 | 
					 | 
				
			||||||
                                <div>
 | 
					 | 
				
			||||||
                                  <div>
 | 
					 | 
				
			||||||
                                    <label htmlFor="option1">
 | 
					 | 
				
			||||||
                                      Select Option 1:
 | 
					 | 
				
			||||||
                                    </label>
 | 
					 | 
				
			||||||
                                    <select
 | 
					 | 
				
			||||||
                                      id="option1"
 | 
					 | 
				
			||||||
                                      value={selectedOption1}
 | 
					 | 
				
			||||||
                                      onChange={(e) =>
 | 
					 | 
				
			||||||
                                        setSelectedOption1(e.target.value)
 | 
					 | 
				
			||||||
                                      }
 | 
					 | 
				
			||||||
                                      className="form-select"
 | 
					 | 
				
			||||||
                                    >
 | 
					 | 
				
			||||||
                                      <option value="">Select...</option>
 | 
					 | 
				
			||||||
                                      <option value="option1">Option 1</option>
 | 
					 | 
				
			||||||
                                      <option value="option2">Option 2</option>
 | 
					 | 
				
			||||||
                                    </select>
 | 
					 | 
				
			||||||
                                  </div>
 | 
					 | 
				
			||||||
                                  {selectedOption1 && (
 | 
					 | 
				
			||||||
                                    <div className="mt-2">
 | 
					 | 
				
			||||||
                                      <label htmlFor="option2">
 | 
					 | 
				
			||||||
                                        Select Option 2:
 | 
					 | 
				
			||||||
                                      </label>
 | 
					 | 
				
			||||||
                                      <select
 | 
					 | 
				
			||||||
                                        id="option2"
 | 
					 | 
				
			||||||
                                        value={selectedOption2}
 | 
					 | 
				
			||||||
                                        onChange={(e) =>
 | 
					 | 
				
			||||||
                                          setSelectedOption2(e.target.value)
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        className="form-select"
 | 
					 | 
				
			||||||
                                      >
 | 
					 | 
				
			||||||
                                        <option value="">Select...</option>
 | 
					 | 
				
			||||||
                                        <option value="optionA">
 | 
					 | 
				
			||||||
                                          Option A
 | 
					 | 
				
			||||||
                                        </option>
 | 
					 | 
				
			||||||
                                        <option value="optionB">
 | 
					 | 
				
			||||||
                                          Option B
 | 
					 | 
				
			||||||
                                        </option>
 | 
					 | 
				
			||||||
                                      </select>
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                  )}
 | 
					 | 
				
			||||||
                                  {selectedOption2 && (
 | 
					 | 
				
			||||||
                                    <div className="mt-2">
 | 
					 | 
				
			||||||
                                      <label htmlFor="textInput">
 | 
					 | 
				
			||||||
                                        Enter Text:
 | 
					 | 
				
			||||||
                                      </label>
 | 
					 | 
				
			||||||
                                      <textarea
 | 
					 | 
				
			||||||
                                        id="textInput"
 | 
					 | 
				
			||||||
                                        value={textValue}
 | 
					 | 
				
			||||||
                                        onChange={(e) =>
 | 
					 | 
				
			||||||
                                          setTextValue(e.target.value)
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        className="form-control"
 | 
					 | 
				
			||||||
                                      />
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                  )}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                  <MultiSelect
 | 
					 | 
				
			||||||
                                    mb={'md'}
 | 
					 | 
				
			||||||
                                    searchable
 | 
					 | 
				
			||||||
                                    label="User(s)"
 | 
					 | 
				
			||||||
                                    data={data.map((user) => {
 | 
					 | 
				
			||||||
                                      return {
 | 
					 | 
				
			||||||
                                        value: user.user.id.toString(),
 | 
					 | 
				
			||||||
                                        label: user.user.name,
 | 
					 | 
				
			||||||
                                      }
 | 
					 | 
				
			||||||
                                    })}
 | 
					 | 
				
			||||||
                                    onChange={(e) => {
 | 
					 | 
				
			||||||
                                      setCustomAddData({
 | 
					 | 
				
			||||||
                                        ...customAddData,
 | 
					 | 
				
			||||||
                                        data: e,
 | 
					 | 
				
			||||||
                                      })
 | 
					 | 
				
			||||||
                                    }}
 | 
					 | 
				
			||||||
                                  />
 | 
					 | 
				
			||||||
                                  <Select
 | 
					 | 
				
			||||||
                                    mb={'md'}
 | 
					 | 
				
			||||||
                                    label="Type"
 | 
					 | 
				
			||||||
                                    data={[
 | 
					 | 
				
			||||||
                                      { value: 'half', label: 'Half day' },
 | 
					 | 
				
			||||||
                                      { value: 'one', label: 'A day' },
 | 
					 | 
				
			||||||
                                    ]}
 | 
					 | 
				
			||||||
                                    onChange={(e) => {
 | 
					 | 
				
			||||||
                                      setCustomAddData({
 | 
					 | 
				
			||||||
                                        ...customAddData,
 | 
					 | 
				
			||||||
                                        type: e!,
 | 
					 | 
				
			||||||
                                      })
 | 
					 | 
				
			||||||
                                    }}
 | 
					 | 
				
			||||||
                                  />
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                                <div className={classes.popoverFooter}>
 | 
					 | 
				
			||||||
                                  <Button
 | 
					 | 
				
			||||||
                                    variant="filled"
 | 
					 | 
				
			||||||
                                    color="red"
 | 
					 | 
				
			||||||
                                    onClick={() => setIsOpen('')}
 | 
					 | 
				
			||||||
                                  >
 | 
					 | 
				
			||||||
                                    Close
 | 
					 | 
				
			||||||
                                  </Button>
 | 
					 | 
				
			||||||
                                  <Button variant="filled" onClick={handleSave}>
 | 
					 | 
				
			||||||
                                    Save
 | 
					 | 
				
			||||||
                                  </Button>
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                              </PopoverBody>
 | 
					 | 
				
			||||||
                            </Popover>
 | 
					 | 
				
			||||||
                          </>
 | 
					                          </>
 | 
				
			||||||
                        )}
 | 
					                        )}
 | 
				
			||||||
                      </Table.Td>
 | 
					                      </Table.Td>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue