refactor create, handle ticket #125
			
				
			
		
		
		
	
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -17,6 +17,7 @@ use Modules\Admin\app\Models\MonthlyTimekeeping;
 | 
			
		|||
use Modules\Admin\app\Models\Tracking;
 | 
			
		||||
use Maatwebsite\Excel\Facades\Excel;
 | 
			
		||||
use App\Exports\TimekeepingExport;
 | 
			
		||||
use Modules\Admin\app\Models\Ticket;
 | 
			
		||||
 | 
			
		||||
class TimekeepingController extends Controller
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -177,78 +178,92 @@ class TimekeepingController extends Controller
 | 
			
		|||
        $year = $request->year;
 | 
			
		||||
 | 
			
		||||
        $note = Notes::find($id);
 | 
			
		||||
        if ($note) {
 | 
			
		||||
            $n_month = $note->n_month;
 | 
			
		||||
            $n_year = $note->n_year;
 | 
			
		||||
        if (!$note) {
 | 
			
		||||
            return response()->json(['message' => 'Note not found', 'status' => false]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            if ($note->n_reason == "ONLEAVE") {
 | 
			
		||||
                // Get note reason ONLEAVE by $n_month, $n_year not include $note->id & include $note->n_user_id
 | 
			
		||||
                // $onleave = Notes::getNotesByMonthAndYearAndUserId($n_month, $n_year, $note->n_user_id, $note->id);
 | 
			
		||||
        $ticket = Ticket::find($note->ticket_id);
 | 
			
		||||
        if (!$ticket) {
 | 
			
		||||
            return response()->json(['message' => 'Ticket not found, can not delete note', 'status' => false]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                // Get note reason LEAVE_WITHOUT_PAY by $n_month, $n_year & include $note->n_user_id
 | 
			
		||||
                $leaveWithoutPay = Notes::getNotesByMonthAndYearAndUserIdAndReason($n_month, $n_year, $note->n_user_id, 'LEAVE_WITHOUT_PAY');
 | 
			
		||||
        $admin = auth('admins')->user();
 | 
			
		||||
        $ticket->updated_by = $admin->name;
 | 
			
		||||
        $ticket->status = "REFUSED";
 | 
			
		||||
        $ticket->save();
 | 
			
		||||
 | 
			
		||||
                if (count($leaveWithoutPay) > 0) {
 | 
			
		||||
                    $deletedValue = ($note->n_time_type === 'ALL') ? 1.0 : 0.5;
 | 
			
		||||
                    $needUpdate = $deletedValue;
 | 
			
		||||
                    // dd($needUpdate, $leaveWithoutPay);
 | 
			
		||||
                    foreach ($leaveWithoutPay as $lwNote) {
 | 
			
		||||
                        if ($needUpdate <= 0) break;
 | 
			
		||||
 | 
			
		||||
                        if ($lwNote->n_time_type === 'ALL') {
 | 
			
		||||
                            if ($needUpdate == 1.0) {
 | 
			
		||||
                                // Chuyển cả note ALL thành phép
 | 
			
		||||
                                $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
                                $needUpdate = 0;
 | 
			
		||||
                                break;
 | 
			
		||||
                            } else { // $needUpdate == 0.5
 | 
			
		||||
                                // Tách ALL thành 2 note S và C, chuyển S thành phép, C giữ không phép
 | 
			
		||||
                                Notes::create([
 | 
			
		||||
                                    'n_user_id' => $lwNote->n_user_id,
 | 
			
		||||
                                    'n_day' => $lwNote->n_day,
 | 
			
		||||
                                    'n_month' => $lwNote->n_month,
 | 
			
		||||
                                    'n_year' => $lwNote->n_year,
 | 
			
		||||
                                    'n_time_type' => 'S',
 | 
			
		||||
                                    'n_reason' => 'ONLEAVE',
 | 
			
		||||
                                    'n_note' => $lwNote->n_note
 | 
			
		||||
                                ]);
 | 
			
		||||
                                Notes::create([
 | 
			
		||||
                                    'n_user_id' => $lwNote->n_user_id,
 | 
			
		||||
                                    'n_day' => $lwNote->n_day,
 | 
			
		||||
                                    'n_month' => $lwNote->n_month,
 | 
			
		||||
                                    'n_year' => $lwNote->n_year,
 | 
			
		||||
                                    'n_time_type' => 'C',
 | 
			
		||||
                                    'n_reason' => 'LEAVE_WITHOUT_PAY',
 | 
			
		||||
                                    'n_note' => $lwNote->n_note
 | 
			
		||||
                                ]);
 | 
			
		||||
                                $lwNote->delete();
 | 
			
		||||
                                $needUpdate = 0;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Nếu $lwNote->n_time_type == 'S' hoặc 'C' => 0.5
 | 
			
		||||
                            if ($needUpdate == 1.0) {
 | 
			
		||||
                                // Chuyển cả note ALL thành phép
 | 
			
		||||
                                $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
                                $needUpdate -= 0.5;
 | 
			
		||||
                            } else { // $needUpdate == 0.5
 | 
			
		||||
                                // S hoặc C, chỉ cần chuyển đúng 0.5 ngày
 | 
			
		||||
                                $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
                                $needUpdate = 0;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Khi note phép và k tồn tại nghỉ không phép => phép + dồn cho tháng sau
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $note->delete();
 | 
			
		||||
        Notes::where('ticket_id', $ticket->id)->delete();
 | 
			
		||||
        $this->createOrUpdateRecordForCurrentMonth($month, $year);
 | 
			
		||||
        return response()->json(['message' => 'Delete success', 'status' => true]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['message' => 'Delete fail', 'status' => false]);
 | 
			
		||||
        // $n_month = $note->n_month;
 | 
			
		||||
        // $n_year = $note->n_year;
 | 
			
		||||
 | 
			
		||||
        // if ($note->n_reason == "ONLEAVE") {
 | 
			
		||||
        //     // Get note reason ONLEAVE by $n_month, $n_year not include $note->id & include $note->n_user_id
 | 
			
		||||
        //     // $onleave = Notes::getNotesByMonthAndYearAndUserId($n_month, $n_year, $note->n_user_id, $note->id);
 | 
			
		||||
 | 
			
		||||
        //     // Get note reason LEAVE_WITHOUT_PAY by $n_month, $n_year & include $note->n_user_id
 | 
			
		||||
        //     $leaveWithoutPay = Notes::getNotesByMonthAndYearAndUserIdAndReason($n_month, $n_year, $note->n_user_id, 'LEAVE_WITHOUT_PAY');
 | 
			
		||||
 | 
			
		||||
        //     if (count($leaveWithoutPay) > 0) {
 | 
			
		||||
        //         $deletedValue = ($note->n_time_type === 'ALL') ? 1.0 : 0.5;
 | 
			
		||||
        //         $needUpdate = $deletedValue;
 | 
			
		||||
        //         // dd($needUpdate, $leaveWithoutPay);
 | 
			
		||||
        //         foreach ($leaveWithoutPay as $lwNote) {
 | 
			
		||||
        //             if ($needUpdate <= 0) break;
 | 
			
		||||
 | 
			
		||||
        //             if ($lwNote->n_time_type === 'ALL') {
 | 
			
		||||
        //                 if ($needUpdate == 1.0) {
 | 
			
		||||
        //                     // Chuyển cả note ALL thành phép
 | 
			
		||||
        //                     $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
        //                     $needUpdate = 0;
 | 
			
		||||
        //                     break;
 | 
			
		||||
        //                 } else { // $needUpdate == 0.5
 | 
			
		||||
        //                     // Tách ALL thành 2 note S và C, chuyển S thành phép, C giữ không phép
 | 
			
		||||
        //                     Notes::create([
 | 
			
		||||
        //                         'n_user_id' => $lwNote->n_user_id,
 | 
			
		||||
        //                         'n_day' => $lwNote->n_day,
 | 
			
		||||
        //                         'n_month' => $lwNote->n_month,
 | 
			
		||||
        //                         'n_year' => $lwNote->n_year,
 | 
			
		||||
        //                         'n_time_type' => 'S',
 | 
			
		||||
        //                         'n_reason' => 'ONLEAVE',
 | 
			
		||||
        //                         'n_note' => $lwNote->n_note
 | 
			
		||||
        //                     ]);
 | 
			
		||||
        //                     Notes::create([
 | 
			
		||||
        //                         'n_user_id' => $lwNote->n_user_id,
 | 
			
		||||
        //                         'n_day' => $lwNote->n_day,
 | 
			
		||||
        //                         'n_month' => $lwNote->n_month,
 | 
			
		||||
        //                         'n_year' => $lwNote->n_year,
 | 
			
		||||
        //                         'n_time_type' => 'C',
 | 
			
		||||
        //                         'n_reason' => 'LEAVE_WITHOUT_PAY',
 | 
			
		||||
        //                         'n_note' => $lwNote->n_note
 | 
			
		||||
        //                     ]);
 | 
			
		||||
        //                     $lwNote->delete();
 | 
			
		||||
        //                     $needUpdate = 0;
 | 
			
		||||
        //                     break;
 | 
			
		||||
        //                 }
 | 
			
		||||
        //             } else {
 | 
			
		||||
        //                 // Nếu $lwNote->n_time_type == 'S' hoặc 'C' => 0.5
 | 
			
		||||
        //                 if ($needUpdate == 1.0) {
 | 
			
		||||
        //                     // Chuyển cả note ALL thành phép
 | 
			
		||||
        //                     $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
        //                     $needUpdate -= 0.5;
 | 
			
		||||
        //                 } else { // $needUpdate == 0.5
 | 
			
		||||
        //                     // S hoặc C, chỉ cần chuyển đúng 0.5 ngày
 | 
			
		||||
        //                     $lwNote->update(['n_reason' => 'ONLEAVE']);
 | 
			
		||||
        //                     $needUpdate = 0;
 | 
			
		||||
        //                     break;
 | 
			
		||||
        //                 }
 | 
			
		||||
        //             }
 | 
			
		||||
        //         }
 | 
			
		||||
        //     } else {
 | 
			
		||||
        //         // Khi note phép và k tồn tại nghỉ không phép => phép + dồn cho tháng sau
 | 
			
		||||
        //     }
 | 
			
		||||
        // }
 | 
			
		||||
        // $note->delete();
 | 
			
		||||
        // $this->createOrUpdateRecordForCurrentMonth($month, $year);
 | 
			
		||||
        // return response()->json(['message' => 'Delete success', 'status' => true]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function export(Request $request)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,6 +164,7 @@ Route::middleware('api')
 | 
			
		|||
            ], function () {
 | 
			
		||||
                Route::get('/all', [TicketController::class, 'getAll'])->middleware('check.permission:admin.hr');
 | 
			
		||||
                Route::get('/getByUserId', [TicketController::class, 'getByUserId'])->middleware('check.permission:admin.hr.staff');
 | 
			
		||||
                Route::post('/update', [TicketController::class, 'updateTicket'])->middleware('check.permission:admin.hr');
 | 
			
		||||
                Route::post('/create', [TicketController::class, 'createTicket'])->middleware('check.permission:admin.hr.staff');
 | 
			
		||||
                Route::get('/delete', [TicketController::class, 'deleteTicket'])->middleware('check.permission:admin.hr.staff');
 | 
			
		||||
                Route::post('/handle-ticket', [TicketController::class, 'handleTicket'])->middleware('check.permission:admin');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,13 +3,15 @@
 | 
			
		|||
namespace Modules\Auth\app\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Models\LeaveDays;
 | 
			
		||||
use App\Traits\IsAPI;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Illuminate\Support\Facades\Http;
 | 
			
		||||
use Illuminate\Support\Facades\Storage;
 | 
			
		||||
use Modules\Auth\app\Models\User;
 | 
			
		||||
use Illuminate\Support\Str;
 | 
			
		||||
use Modules\Admin\app\Models\Category;
 | 
			
		||||
use SimpleSoftwareIO\QrCode\Facades\QrCode;
 | 
			
		||||
 | 
			
		||||
class UserController extends Controller
 | 
			
		||||
| 
						 | 
				
			
			@ -34,9 +36,36 @@ class UserController extends Controller
 | 
			
		|||
        ]);
 | 
			
		||||
 | 
			
		||||
        if ($request->has('id')) {
 | 
			
		||||
            $payload = $request->only(['name', 'email', 'permission']);
 | 
			
		||||
            $payload = $request->only(['name', 'email', 'permission', 'is_permanent']);
 | 
			
		||||
            $user = User::find($request->id);
 | 
			
		||||
 | 
			
		||||
            // Không cho chuyển từ chính thức thành lại thử việc
 | 
			
		||||
            if (!$request->is_permanent && $user->is_permanent) {
 | 
			
		||||
                return response()->json(['status' => false, 'message' => 'You cannot change an employee from permanent to probationary.']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Thêm ngày phép khi thành nhân viên chính thức
 | 
			
		||||
            if ($request->is_permanent && !$user->is_permanent) {
 | 
			
		||||
                $userLeaveDay = LeaveDays::where('ld_user_id', $user->id)
 | 
			
		||||
                    ->where('ld_year', Carbon::now()->year)
 | 
			
		||||
                    ->first();
 | 
			
		||||
 | 
			
		||||
                if ($userLeaveDay) {
 | 
			
		||||
                    $permanentCategory = Category::where('c_type', 'PERMANENT_ONLEAVE')->where('c_code', "PERMANENT")->first();
 | 
			
		||||
                    $permanentDefault = (int) $permanentCategory->c_value; // Ngày phép khi thành nv chính thức
 | 
			
		||||
                    $userLeaveDay->ld_day_total = $permanentDefault;
 | 
			
		||||
 | 
			
		||||
                    $newNote = "Cộng ngày phép cho nhân viên chính thức"; // Thêm ghi chú
 | 
			
		||||
                    if (!empty($userLeaveDay->ld_note)) {
 | 
			
		||||
                        $userLeaveDay->ld_note = $userLeaveDay->ld_note . "\n" . $newNote;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $userLeaveDay->ld_note = $newNote;
 | 
			
		||||
                    }
 | 
			
		||||
                    $userLeaveDay->save();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $payload['permanent_date'] = Carbon::now()->toDateString();
 | 
			
		||||
            $user->update($payload);
 | 
			
		||||
            return response()->json(['data' => $user, 'status' => true, 'message' => 'Update successful']);
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +73,19 @@ class UserController extends Controller
 | 
			
		|||
                'name' => $request->name,
 | 
			
		||||
                'email' => $request->email,
 | 
			
		||||
                'password' => bcrypt('Work@1234'),
 | 
			
		||||
                'permission' => $request->permission
 | 
			
		||||
                'permission' => $request->permission,
 | 
			
		||||
                'is_permanent' => false
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            // Khởi tạo LeaveDays cho nhân viên mới
 | 
			
		||||
            LeaveDays::insert([
 | 
			
		||||
                'ld_user_id' => $user->id,
 | 
			
		||||
                'ld_day_total' => 0,
 | 
			
		||||
                'ld_year' => Carbon::now()->year,
 | 
			
		||||
                'ld_additional_day' => 0,
 | 
			
		||||
                'ld_note' => '',
 | 
			
		||||
                'created_at' => now(),
 | 
			
		||||
                'updated_at' => now(),
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            $user_res = [
 | 
			
		||||
| 
						 | 
				
			
			@ -98,8 +139,6 @@ class UserController extends Controller
 | 
			
		|||
                return response()->json(['data' => ['user' => $user_res, 'gitea' => "dev", 'zulip' => "dev"], 'status' => true, 'message' => 'Create successful']);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['status' => false, 'message' => 'Process fail']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function delete(Request $request)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,9 @@ class User extends Authenticatable implements JWTSubject
 | 
			
		|||
        'name',
 | 
			
		||||
        'email',
 | 
			
		||||
        'password',
 | 
			
		||||
        'permission'
 | 
			
		||||
        'permission',
 | 
			
		||||
        'is_permanent',
 | 
			
		||||
        'permanent_date'
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ class Kernel extends ConsoleKernel
 | 
			
		|||
        // ->dailyAt('18:00');
 | 
			
		||||
 | 
			
		||||
        // Chạy command vào ngày 31/12 lúc 23:59:59 mỗi năm
 | 
			
		||||
        // $schedule->command('initialize:leavedays')->yearlyOn(12, 31, '23:59:59');
 | 
			
		||||
        $schedule->command('initialize:leavedays')->yearlyOn(12, 31, '23:59:59');
 | 
			
		||||
        $schedule->command('leave:deduct')->yearlyOn(3, 31, '23:59:59');
 | 
			
		||||
 | 
			
		||||
        // Chạy buổi sáng lúc 12:00
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		|||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
use Modules\Admin\app\Models\Category;
 | 
			
		||||
 | 
			
		||||
class AddMonthlyLeaveDays implements ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,8 @@ class AddMonthlyLeaveDays implements ShouldQueue
 | 
			
		|||
  protected $month;
 | 
			
		||||
  protected $year;
 | 
			
		||||
 | 
			
		||||
  private const ONLEAVE_PER_MONTH = 1; // Ngày phép cộng mỗi tháng
 | 
			
		||||
 | 
			
		||||
  public function __construct($month = null, $year = null)
 | 
			
		||||
  {
 | 
			
		||||
    $this->month = $month ?? Carbon::now()->month;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +32,11 @@ class AddMonthlyLeaveDays implements ShouldQueue
 | 
			
		|||
    $users = User::get();
 | 
			
		||||
 | 
			
		||||
    foreach ($users as $user) {
 | 
			
		||||
      // Nếu là nhân viên chưa chính thức, ko cộng phép
 | 
			
		||||
      if (!$user->is_permanent) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $leaveDay = LeaveDays::where('ld_user_id', $user->id)
 | 
			
		||||
        ->where('ld_year', $this->year)
 | 
			
		||||
        ->first();
 | 
			
		||||
| 
						 | 
				
			
			@ -46,11 +54,36 @@ class AddMonthlyLeaveDays implements ShouldQueue
 | 
			
		|||
        ]);
 | 
			
		||||
        $leaveDay->save();
 | 
			
		||||
      } else {
 | 
			
		||||
        // Kiểm tra nếu số ngày phép hiện tại nhỏ hơn tháng hiện tại
 | 
			
		||||
        // Check có phải là nhân viên chính thức trong năm nay (Nhân viên mới)
 | 
			
		||||
        if ($user->permanent_date && $user->permanent_date !== '0000-00-00') {
 | 
			
		||||
          $permenantYear  = Carbon::parse($user->permanent_date)->year;
 | 
			
		||||
 | 
			
		||||
          if ($permenantYear === $this->year) {
 | 
			
		||||
            $permanentCategory = Category::where('c_type', 'PERMANENT_ONLEAVE')->where('c_code', "PERMANENT")->first();
 | 
			
		||||
            $permanentDefault = (int) $permanentCategory->c_value; // Ngày phép khi thành nv chính thức
 | 
			
		||||
 | 
			
		||||
            $permanentMonth = Carbon::parse($user->permanent_date)->month;
 | 
			
		||||
            if ($this->month > $leaveDay->ld_day_total - ($permanentDefault - $permanentMonth)) {
 | 
			
		||||
              $leaveDay->ld_day_total += self::ONLEAVE_PER_MONTH;
 | 
			
		||||
 | 
			
		||||
              // Xử lý ghi chú
 | 
			
		||||
              $newNote = "Cập nhật ngày phép đến tháng " . $this->month;
 | 
			
		||||
              if (!empty($leaveDay->ld_note)) {
 | 
			
		||||
                // Nếu đã có ghi chú, thêm ghi chú mới vào và xuống dòng
 | 
			
		||||
                $leaveDay->ld_note = $leaveDay->ld_note . "\n" . $newNote;
 | 
			
		||||
              } else {
 | 
			
		||||
                // Nếu chưa có ghi chú, gán ghi chú mới
 | 
			
		||||
                $leaveDay->ld_note = $newNote;
 | 
			
		||||
              }
 | 
			
		||||
              $leaveDay->save();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Kiểm tra nếu số ngày phép hiện tại nhỏ hơn tháng hiện tại (Nhân viên cũ)
 | 
			
		||||
        if ($leaveDay->ld_day_total < $this->month) {
 | 
			
		||||
          // Cập nhật số ngày phép bằng với tháng hiện tại
 | 
			
		||||
          $oldDays = $leaveDay->ld_day_total;
 | 
			
		||||
          $leaveDay->ld_day_total = $this->month;
 | 
			
		||||
          // Cộng mỗi tháng 1 ngày phép cho nhân viên
 | 
			
		||||
          $leaveDay->ld_day_total += self::ONLEAVE_PER_MONTH;
 | 
			
		||||
 | 
			
		||||
          // Xử lý ghi chú
 | 
			
		||||
          $newNote = "Cập nhật ngày phép đến tháng " . $this->month;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,6 @@ use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		|||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
 | 
			
		||||
class DeductLeaveDays implements ShouldQueue
 | 
			
		||||
| 
						 | 
				
			
			@ -42,38 +41,19 @@ class DeductLeaveDays implements ShouldQueue
 | 
			
		|||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $totalLeaveDaysByMonth = Notes::join('categories', function ($join) {
 | 
			
		||||
            // Lấy tổng ngày nghỉ phép 3 tháng đầu trong năm
 | 
			
		||||
            $usedOnleaveDaysTotal = Notes::join('categories', function ($join) {
 | 
			
		||||
                $join->on('notes.n_time_type', '=', 'categories.c_code')
 | 
			
		||||
                    ->where('categories.c_type', 'TIME_TYPE');
 | 
			
		||||
            })
 | 
			
		||||
                ->select(
 | 
			
		||||
                    DB::raw('notes.n_user_id as n_user_id'),
 | 
			
		||||
                    DB::raw('notes.n_year as year'),
 | 
			
		||||
                    DB::raw('SUM(categories.c_value) as leave_days')
 | 
			
		||||
                )
 | 
			
		||||
                ->where('notes.n_year', $this->year)
 | 
			
		||||
                ->where('notes.n_user_id', $user->id)
 | 
			
		||||
                ->where('notes.n_reason', 'ONLEAVE')
 | 
			
		||||
                ->groupBy(DB::raw('notes.n_year'))
 | 
			
		||||
                ->first();
 | 
			
		||||
                ->where('n_user_id', $user->id)
 | 
			
		||||
                ->where('n_year', $this->year)
 | 
			
		||||
                ->where('n_month', "<=", 3)
 | 
			
		||||
                ->where('n_reason', 'ONLEAVE')
 | 
			
		||||
                ->sum('categories.c_value');
 | 
			
		||||
 | 
			
		||||
            if ($totalLeaveDaysByMonth) {
 | 
			
		||||
                //Nếu ngày phép thừa năm trước chưa sử dụng hết => cập nhật lại ngày đó (Ngày tồn đọng - ngày sử dụng)
 | 
			
		||||
                if ($existingData->ld_additional_day > $totalLeaveDaysByMonth->leave_days) {
 | 
			
		||||
                    LeaveDays::where('ld_year', $this->year)
 | 
			
		||||
                        ->where('ld_user_id', $user->id)
 | 
			
		||||
                        ->update([
 | 
			
		||||
                            'ld_additional_day' => $totalLeaveDaysByMonth->leave_days,
 | 
			
		||||
                        ]);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                //Nếu không sử dụng ngày nghỉ còn lại ở năm rồi thì xóa => theo luật ld
 | 
			
		||||
                LeaveDays::where('ld_year', $this->year)
 | 
			
		||||
                    ->where('ld_user_id', $user->id)
 | 
			
		||||
                    ->update([
 | 
			
		||||
                        'ld_additional_day' => "0",
 | 
			
		||||
                    ]);
 | 
			
		||||
            }
 | 
			
		||||
            $existingData->ld_additional_day = $usedOnleaveDaysTotal ?? 0;
 | 
			
		||||
            $existingData->save();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,8 @@ class InitializeLeaveDays implements ShouldQueue
 | 
			
		|||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
        $users = User::get();
 | 
			
		||||
        $ld_day_total = 12;
 | 
			
		||||
        $ld_day_total = Carbon::now()->month; // Khởi tạo phép hiện có bằng tháng hiện tại
 | 
			
		||||
 | 
			
		||||
        foreach ($users as $user) {
 | 
			
		||||
            // Kiểm tra xem dữ liệu của user này đã tồn tại cho năm hiện tại chưa
 | 
			
		||||
            $existingData = LeaveDays::where('ld_user_id', $user->id)
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +83,7 @@ class InitializeLeaveDays implements ShouldQueue
 | 
			
		|||
            // Tạo dữ liệu cho năm hiện tại
 | 
			
		||||
            LeaveDays::insert([
 | 
			
		||||
                'ld_user_id' => $user->id,
 | 
			
		||||
                'ld_day_total' => $ld_day_total,
 | 
			
		||||
                'ld_day_total' => $user->is_permanent ? $ld_day_total : 0, // Nếu là nhân viên mới, ko cấp phép
 | 
			
		||||
                'ld_year' => $this->year,
 | 
			
		||||
                'ld_additional_day' => $ld_additional_day,
 | 
			
		||||
                'ld_note' => $ld_note,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ class Notes extends Model
 | 
			
		|||
        'n_time_type',
 | 
			
		||||
        'n_reason',
 | 
			
		||||
        'n_note',
 | 
			
		||||
        'ticket_id'
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
return new class extends Migration
 | 
			
		||||
{
 | 
			
		||||
    public function up(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('notes', function (Blueprint $table) {
 | 
			
		||||
            $table->foreignId('ticket_id')
 | 
			
		||||
                ->nullable()
 | 
			
		||||
                ->constrained('tickets')
 | 
			
		||||
                ->onDelete('cascade');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('notes', function (Blueprint $table) {
 | 
			
		||||
            $table->dropForeign(['ticket_id']);
 | 
			
		||||
            $table->dropColumn('ticket_id');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
return new class extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     */
 | 
			
		||||
    public function up(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('users', function (Blueprint $table) {
 | 
			
		||||
            $table->boolean('is_permanent')->default(true);
 | 
			
		||||
            $table->date('permanent_date');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     */
 | 
			
		||||
    public function down(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('users', function (Blueprint $table) {
 | 
			
		||||
            $table->dropColumn('is_permanent');
 | 
			
		||||
            $table->dropColumn('permanent_date');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
return new class extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     */
 | 
			
		||||
    public function up(): void
 | 
			
		||||
    {
 | 
			
		||||
        DB::table('categories')->insert([
 | 
			
		||||
            [
 | 
			
		||||
                'c_code' => 'PERMANENT',
 | 
			
		||||
                'c_name' => 'Phép cộng nhân viên chính thức',
 | 
			
		||||
                'c_type' => 'PERMANENT_ONLEAVE',
 | 
			
		||||
                'c_value' => 3,
 | 
			
		||||
                'c_active' => 1,
 | 
			
		||||
                'created_at' => now(),
 | 
			
		||||
                'updated_at' => now(),
 | 
			
		||||
            ],
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     */
 | 
			
		||||
    public function down(): void
 | 
			
		||||
    {
 | 
			
		||||
        DB::table('categories')->where('c_code', 'PERMANENT')->delete();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,8 +36,6 @@
 | 
			
		|||
    <title>{{ $data['subject'] }}</title>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<body style="
 | 
			
		||||
        font-family: Arial, Helvetica, sans-serif;
 | 
			
		||||
        background-color: #edf2f7;
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +80,7 @@
 | 
			
		|||
                    <tr>
 | 
			
		||||
                        <td>
 | 
			
		||||
                            <p style=" white-space:pre-line; margin: 0; margin-bottom: 5px">
 | 
			
		||||
                                    Employee <span style="color: #222222;font-weight: bold;">{{ $data['name'] }}</span> has sent a request ticket, the specific content is as follows:
 | 
			
		||||
                                Employee <span style="color: #222222;font-weight: bold;">{{ $data['name'] }}</span> has sent a <a href="{{ config('app.client_url') . $data['link'] }}"> request ticket</a>, the specific content is as follows:
 | 
			
		||||
                            </p>
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
| 
						 | 
				
			
			@ -101,42 +98,8 @@
 | 
			
		|||
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>
 | 
			
		||||
                            <p
 | 
			
		||||
                                style="
 | 
			
		||||
                                    margin: 0 0 16px;
 | 
			
		||||
                                    padding: 5px;
 | 
			
		||||
                                    margin: 5px;
 | 
			
		||||
                                    text-align: center;
 | 
			
		||||
                                "
 | 
			
		||||
                            >
 | 
			
		||||
                                <a
 | 
			
		||||
                                    href="{{ config('app.client_url') . $data['link'] }}"
 | 
			
		||||
                                    style="
 | 
			
		||||
                                        color: #fff;
 | 
			
		||||
                                        border-radius: 10px;
 | 
			
		||||
                                        background-color: rgba(68, 115, 196);
 | 
			
		||||
                                        background-image: linear-gradient(
 | 
			
		||||
                                            to top left,
 | 
			
		||||
                                            rgba(0, 0, 0, 0.2),
 | 
			
		||||
                                            rgba(0, 0, 0, 0.2) 30%,
 | 
			
		||||
                                            rgba(0, 0, 0, 0)
 | 
			
		||||
                                        );
 | 
			
		||||
                                        text-decoration: none;
 | 
			
		||||
                                        display: inline-block;
 | 
			
		||||
                                        font-weight: 600;
 | 
			
		||||
                                        font-size: 16px;
 | 
			
		||||
                                        line-height: 150%;
 | 
			
		||||
                                        text-align: center;
 | 
			
		||||
                                        margin: 0;
 | 
			
		||||
                                        padding: 10px 12px;
 | 
			
		||||
                                    "
 | 
			
		||||
                                >
 | 
			
		||||
                                    Check now</a
 | 
			
		||||
                                >
 | 
			
		||||
                            </p>
 | 
			
		||||
 | 
			
		||||
                            <p style="text-align: center">
 | 
			
		||||
                                Or you can quick
 | 
			
		||||
                                You can quick
 | 
			
		||||
                                <span style="font-weight: bold">Confirm</span> or
 | 
			
		||||
                                <span style="font-weight: bold">Refuse</span> here:
 | 
			
		||||
                            </p>
 | 
			
		||||
| 
						 | 
				
			
			@ -147,8 +110,7 @@
 | 
			
		|||
                                        justify-content: center;
 | 
			
		||||
                                        gap: 10px;
 | 
			
		||||
                                        margin-top: 10px;
 | 
			
		||||
                                "
 | 
			
		||||
                            >
 | 
			
		||||
                                    ">
 | 
			
		||||
                                <a
 | 
			
		||||
                                    href="{{ route('email.ticket.handle', ['ticket_id' => $data['ticket_id'], 'action' => 'confirm', 'admin_email' => $data['admin_email']]) }}"
 | 
			
		||||
                                    style="
 | 
			
		||||
| 
						 | 
				
			
			@ -169,10 +131,8 @@
 | 
			
		|||
                                            text-align: center;
 | 
			
		||||
                                            margin: 0;
 | 
			
		||||
                                            padding: 10px 12px;
 | 
			
		||||
                                    "
 | 
			
		||||
                                >
 | 
			
		||||
                                    Confirm</a
 | 
			
		||||
                                >
 | 
			
		||||
                                        ">
 | 
			
		||||
                                    Confirm</a>
 | 
			
		||||
 | 
			
		||||
                                <a
 | 
			
		||||
                                    href="{{ route('email.ticket.handle', ['ticket_id' => $data['ticket_id'], 'action' => 'refuse', 'admin_email' => $data['admin_email']]) }}"
 | 
			
		||||
| 
						 | 
				
			
			@ -194,10 +154,18 @@
 | 
			
		|||
                                            text-align: center;
 | 
			
		||||
                                            margin: 0;
 | 
			
		||||
                                            padding: 10px 12px;
 | 
			
		||||
                                    "
 | 
			
		||||
                                >
 | 
			
		||||
                                    Refuse</a
 | 
			
		||||
                                >
 | 
			
		||||
                                        ">
 | 
			
		||||
                                    Refuse</a>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td style="color: #222222;">
 | 
			
		||||
                            <div style="margin-top: 3rem">
 | 
			
		||||
                                <p><span style="font-weight: bold">Note</span>: If you are redirected to a <span style="font-weight: bold">404 page</span>, it means:</p>
 | 
			
		||||
                                <p>1. The ticket has already been approved by another admin.</p>
 | 
			
		||||
                                <p>2. The ticket has been deleted.</p>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +198,5 @@
 | 
			
		|||
        </tr>
 | 
			
		||||
    </table>
 | 
			
		||||
</body>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 124 KiB  | 
| 
						 | 
				
			
			@ -48,6 +48,7 @@ export const getTickets = API_URL + 'v1/admin/ticket/all'
 | 
			
		|||
export const getTicketsOfUser = API_URL + 'v1/admin/ticket/getByUserId'
 | 
			
		||||
export const deleteTicket = API_URL + 'v1/admin/ticket/delete'
 | 
			
		||||
export const addTicket = API_URL + 'v1/admin/ticket/create'
 | 
			
		||||
export const updateTicket = API_URL + 'v1/admin/ticket/update'
 | 
			
		||||
export const handleTicket = API_URL + 'v1/admin/ticket/handle-ticket'
 | 
			
		||||
 | 
			
		||||
//Users
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,42 @@
 | 
			
		|||
export const PageNotFound = () => {
 | 
			
		||||
  return <>{'Not found!'}</>
 | 
			
		||||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
  Button,
 | 
			
		||||
  Container,
 | 
			
		||||
  Image,
 | 
			
		||||
  SimpleGrid,
 | 
			
		||||
  Text,
 | 
			
		||||
  Title,
 | 
			
		||||
} from '@mantine/core'
 | 
			
		||||
import image404 from '../../../public/404Image.jpg'
 | 
			
		||||
import { useNavigate } from 'react-router-dom'
 | 
			
		||||
 | 
			
		||||
const PageNotFound = () => {
 | 
			
		||||
  const navigate = useNavigate()
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Container mt="lg">
 | 
			
		||||
      <SimpleGrid spacing={{ base: 40, sm: 80 }} cols={{ base: 1, sm: 2 }}>
 | 
			
		||||
        <Box py="3rem">
 | 
			
		||||
          <Title> Something is not right...</Title>
 | 
			
		||||
          <Text c="dimmed" size="lg">
 | 
			
		||||
            Page you are trying to open does not exist. You may have mistyped
 | 
			
		||||
            the address, or the page has been moved to another URL. If you think
 | 
			
		||||
            this is an error contact support.
 | 
			
		||||
          </Text>
 | 
			
		||||
          <Button
 | 
			
		||||
            variant="outline"
 | 
			
		||||
            size="md"
 | 
			
		||||
            mt="xl"
 | 
			
		||||
            onClick={() => navigate('/')}
 | 
			
		||||
          >
 | 
			
		||||
            Get back to home page
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Box>
 | 
			
		||||
 | 
			
		||||
        <Image src={image404} />
 | 
			
		||||
      </SimpleGrid>
 | 
			
		||||
    </Container>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default PageNotFound
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,3 +46,37 @@
 | 
			
		|||
  .dialogText {
 | 
			
		||||
    color: light-dark(#2d353c, white);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Thêm styles cho Modal xác nhận xóa */
 | 
			
		||||
.deleteModal {
 | 
			
		||||
  background-color: light-dark(white, #2d353c);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border: solid 1px #ff4646;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalTitle {
 | 
			
		||||
  color: #ff4646;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 1.2rem;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalContent {
 | 
			
		||||
  color: light-dark(#2d353c, white);
 | 
			
		||||
  margin-bottom: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalFooter {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: flex-end;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  margin-top: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton {
 | 
			
		||||
  background-color: #ff4646;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton:hover {
 | 
			
		||||
  background-color: #ff6b6b;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,11 @@
 | 
			
		|||
import { getListMaster, getTickets, handleTicket } from '@/api/Admin'
 | 
			
		||||
import {
 | 
			
		||||
  getListMaster,
 | 
			
		||||
  getTickets,
 | 
			
		||||
  handleTicket,
 | 
			
		||||
  updateTicket,
 | 
			
		||||
} from '@/api/Admin'
 | 
			
		||||
import { DataTablePagination } from '@/components/DataTable/DataTable'
 | 
			
		||||
import { create } from '@/rtk/helpers/CRUD'
 | 
			
		||||
import { create, update } from '@/rtk/helpers/CRUD'
 | 
			
		||||
import { get } from '@/rtk/helpers/apiService'
 | 
			
		||||
import {
 | 
			
		||||
  Badge,
 | 
			
		||||
| 
						 | 
				
			
			@ -9,12 +14,13 @@ import {
 | 
			
		|||
  HoverCard,
 | 
			
		||||
  Modal,
 | 
			
		||||
  Select,
 | 
			
		||||
  Switch,
 | 
			
		||||
  Text,
 | 
			
		||||
  Textarea,
 | 
			
		||||
} from '@mantine/core'
 | 
			
		||||
import { useForm } from '@mantine/form'
 | 
			
		||||
import { notifications } from '@mantine/notifications'
 | 
			
		||||
import { IconCheckbox, IconSquareXFilled } from '@tabler/icons-react'
 | 
			
		||||
import { IconCheckbox, IconEdit, IconSquareXFilled } from '@tabler/icons-react'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import { useEffect, useState } from 'react'
 | 
			
		||||
import classes from './TicketsManagement.module.css'
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +30,7 @@ type TTickets = {
 | 
			
		|||
  ticket_id: number
 | 
			
		||||
  admin_note: string
 | 
			
		||||
  action: string
 | 
			
		||||
  status: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TListTickets = {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +85,7 @@ const TicketsManagement = () => {
 | 
			
		|||
    end_period: '',
 | 
			
		||||
    reason: '',
 | 
			
		||||
    type: '',
 | 
			
		||||
    status: '',
 | 
			
		||||
  })
 | 
			
		||||
  const [disableBtn, setDisableBtn] = useState(false)
 | 
			
		||||
  const [filter, setFilter] = useState({
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +94,7 @@ const TicketsManagement = () => {
 | 
			
		|||
  })
 | 
			
		||||
  const [dataTimeType, setDataTimeType] = useState<DataTimeType[]>([])
 | 
			
		||||
  const [dataReason, setDataReason] = useState<DataReason[]>([])
 | 
			
		||||
  const [isRefuseConfirmOpen, setIsRefuseConfirmOpen] = useState<boolean>(false)
 | 
			
		||||
 | 
			
		||||
  const getListMasterByType = async (type: string) => {
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +165,7 @@ const TicketsManagement = () => {
 | 
			
		|||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'reason',
 | 
			
		||||
      size: '15%',
 | 
			
		||||
      size: '10%',
 | 
			
		||||
      header: 'Notes',
 | 
			
		||||
      render: (row: any) => {
 | 
			
		||||
        return (
 | 
			
		||||
| 
						 | 
				
			
			@ -198,7 +207,7 @@ const TicketsManagement = () => {
 | 
			
		|||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'admin_note',
 | 
			
		||||
      size: '15%',
 | 
			
		||||
      size: '10%',
 | 
			
		||||
      header: 'Admin Notes',
 | 
			
		||||
      render: (row: any) => {
 | 
			
		||||
        return (
 | 
			
		||||
| 
						 | 
				
			
			@ -226,6 +235,18 @@ const TicketsManagement = () => {
 | 
			
		|||
      size: '10%',
 | 
			
		||||
      header: 'Updated By',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'updated_at',
 | 
			
		||||
      size: '10%',
 | 
			
		||||
      header: 'Updated At',
 | 
			
		||||
      render: (row: any) => {
 | 
			
		||||
        if (row?.updated_at) {
 | 
			
		||||
          return (
 | 
			
		||||
            <Box>{moment(row?.updated_at).format('HH:mm:ss DD/MM/YYYY')}</Box>
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: '#',
 | 
			
		||||
      size: '5%',
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +275,23 @@ const TicketsManagement = () => {
 | 
			
		|||
              height={20}
 | 
			
		||||
            />
 | 
			
		||||
          </Box>
 | 
			
		||||
        ) : null
 | 
			
		||||
        ) : (
 | 
			
		||||
          <Box className={classes.optionIcon}>
 | 
			
		||||
            <IconEdit
 | 
			
		||||
              className={classes.editIcon}
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                setAction('update')
 | 
			
		||||
                setItem(row)
 | 
			
		||||
                form.reset()
 | 
			
		||||
                console.log(row)
 | 
			
		||||
                form.setFieldValue('status', row.status)
 | 
			
		||||
                form.setFieldValue('admin_note', row.admin_note)
 | 
			
		||||
              }}
 | 
			
		||||
              width={20}
 | 
			
		||||
              height={20}
 | 
			
		||||
            />
 | 
			
		||||
          </Box>
 | 
			
		||||
        )
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
| 
						 | 
				
			
			@ -347,6 +384,27 @@ const TicketsManagement = () => {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const handleUpdate = async (values: TTickets) => {
 | 
			
		||||
    try {
 | 
			
		||||
      const res = await update(
 | 
			
		||||
        updateTicket + `?ticket_id=${item?.id}`,
 | 
			
		||||
        {
 | 
			
		||||
          ticket_id: item.id,
 | 
			
		||||
          admin_note: values.admin_note,
 | 
			
		||||
          status: values.status,
 | 
			
		||||
        },
 | 
			
		||||
        getAllTickets,
 | 
			
		||||
      )
 | 
			
		||||
      if (res === true) {
 | 
			
		||||
        setAction('')
 | 
			
		||||
        setIsRefuseConfirmOpen(false)
 | 
			
		||||
        form.reset()
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.log(error)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    getAllTickets()
 | 
			
		||||
  }, [filter])
 | 
			
		||||
| 
						 | 
				
			
			@ -356,6 +414,7 @@ const TicketsManagement = () => {
 | 
			
		|||
      ticket_id: 0,
 | 
			
		||||
      action: '',
 | 
			
		||||
      admin_note: '',
 | 
			
		||||
      status: '',
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -416,21 +475,38 @@ const TicketsManagement = () => {
 | 
			
		|||
      </Box>
 | 
			
		||||
 | 
			
		||||
      <Modal
 | 
			
		||||
        opened={action === 'confirm' || action === 'refuse'}
 | 
			
		||||
        opened={
 | 
			
		||||
          action === 'confirm' || action === 'refuse' || action === 'update'
 | 
			
		||||
        }
 | 
			
		||||
        onClose={() => {
 | 
			
		||||
          setAction('')
 | 
			
		||||
          setIsRefuseConfirmOpen(false)
 | 
			
		||||
          form.reset()
 | 
			
		||||
        }}
 | 
			
		||||
        title={
 | 
			
		||||
          <Text pl={'sm'} fw={700} fz={'lg'}>
 | 
			
		||||
            {action === 'confirm' ? 'Confirm Ticket' : 'Refuse Ticket'}
 | 
			
		||||
            {action === 'confirm'
 | 
			
		||||
              ? 'Confirm Ticket'
 | 
			
		||||
              : action === 'refuse'
 | 
			
		||||
              ? 'Refuse Ticket'
 | 
			
		||||
              : 'Update Ticket'}
 | 
			
		||||
          </Text>
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <form
 | 
			
		||||
          onSubmit={form.onSubmit(async (values) => {
 | 
			
		||||
            setDisableBtn(true)
 | 
			
		||||
 | 
			
		||||
            if (action === 'update') {
 | 
			
		||||
              if (values.status === 'REFUSED') {
 | 
			
		||||
                setIsRefuseConfirmOpen(true)
 | 
			
		||||
              } else {
 | 
			
		||||
                await handleUpdate(values)
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              await handleSave(values)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setDisableBtn(false)
 | 
			
		||||
          })}
 | 
			
		||||
        >
 | 
			
		||||
| 
						 | 
				
			
			@ -509,14 +585,39 @@ const TicketsManagement = () => {
 | 
			
		|||
 | 
			
		||||
            <Textarea
 | 
			
		||||
              label="Admin Notes"
 | 
			
		||||
              // required
 | 
			
		||||
              value={form.values.admin_note}
 | 
			
		||||
              onChange={(e) => form.setFieldValue('admin_note', e.target.value)}
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            {action === 'update' && item.status !== 'REFUSED' ? (
 | 
			
		||||
              <Switch
 | 
			
		||||
                mt="md"
 | 
			
		||||
                color="red"
 | 
			
		||||
                label={
 | 
			
		||||
                  <Text size="sm">
 | 
			
		||||
                    Change status to{' '}
 | 
			
		||||
                    <Text span color="red" fw="bold">
 | 
			
		||||
                      Refuse
 | 
			
		||||
                    </Text>
 | 
			
		||||
                  </Text>
 | 
			
		||||
                }
 | 
			
		||||
                style={{ width: 'fit-content' }}
 | 
			
		||||
                checked={form.values.status === 'REFUSED'}
 | 
			
		||||
                onChange={(event) =>
 | 
			
		||||
                  form.setFieldValue(
 | 
			
		||||
                    'status',
 | 
			
		||||
                    event.currentTarget.checked ? 'REFUSED' : 'CONFIRMED',
 | 
			
		||||
                  )
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            ) : (
 | 
			
		||||
              ''
 | 
			
		||||
            )}
 | 
			
		||||
 | 
			
		||||
            <Box ta={'center'}>
 | 
			
		||||
              <Button
 | 
			
		||||
                mt={'lg'}
 | 
			
		||||
                bg={'green'}
 | 
			
		||||
                bg={action === 'update' ? 'blue' : 'green'}
 | 
			
		||||
                type="submit"
 | 
			
		||||
                disabled={disableBtn}
 | 
			
		||||
              >
 | 
			
		||||
| 
						 | 
				
			
			@ -526,6 +627,50 @@ const TicketsManagement = () => {
 | 
			
		|||
          </Box>
 | 
			
		||||
        </form>
 | 
			
		||||
      </Modal>
 | 
			
		||||
 | 
			
		||||
      <Modal
 | 
			
		||||
        opened={isRefuseConfirmOpen}
 | 
			
		||||
        onClose={() => {
 | 
			
		||||
          setIsRefuseConfirmOpen(false)
 | 
			
		||||
        }}
 | 
			
		||||
        centered
 | 
			
		||||
        size="sm"
 | 
			
		||||
        classNames={{
 | 
			
		||||
          content: classes.deleteModal,
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <Text className={classes.deleteModalTitle}>Confirm Update</Text>
 | 
			
		||||
        <Text className={classes.deleteModalContent}>
 | 
			
		||||
          Changing ticket status to <strong>Refused</strong> will also delete
 | 
			
		||||
          all related notes.
 | 
			
		||||
        </Text>
 | 
			
		||||
        <Text className={classes.deleteModalContent}>
 | 
			
		||||
          Are you sure you want to proceed?
 | 
			
		||||
        </Text>
 | 
			
		||||
 | 
			
		||||
        <Box className={classes.deleteModalFooter}>
 | 
			
		||||
          <Button
 | 
			
		||||
            variant="outline"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              setIsRefuseConfirmOpen(false)
 | 
			
		||||
            }}
 | 
			
		||||
            disabled={disableBtn}
 | 
			
		||||
          >
 | 
			
		||||
            Cancel
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
            className={classes.deleteButton}
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              setDisableBtn(true)
 | 
			
		||||
              await handleUpdate(form.values)
 | 
			
		||||
              setDisableBtn(false)
 | 
			
		||||
            }}
 | 
			
		||||
            disabled={disableBtn}
 | 
			
		||||
          >
 | 
			
		||||
            Confirm
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </Modal>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -493,7 +493,11 @@ const Timekeeping = () => {
 | 
			
		|||
    >
 | 
			
		||||
      <Text className={classes.deleteModalTitle}>Confirm Delete</Text>
 | 
			
		||||
      <Text className={classes.deleteModalContent}>
 | 
			
		||||
        Are you sure you want to delete this note?
 | 
			
		||||
        This action will change the ticket status to <strong>Refused</strong>{' '}
 | 
			
		||||
        and delete all related notes.
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Text className={classes.deleteModalContent}>
 | 
			
		||||
        Are you sure you want to proceed?
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Box className={classes.deleteModalFooter}>
 | 
			
		||||
        <Button
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,3 +45,37 @@
 | 
			
		|||
.dialogText {
 | 
			
		||||
  color: light-dark(#2d353c, white);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Thêm styles cho Modal xác nhận xóa */
 | 
			
		||||
.deleteModal {
 | 
			
		||||
  background-color: light-dark(white, #2d353c);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border: solid 1px rgb(9, 132, 132);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalTitle {
 | 
			
		||||
  color: rgb(9, 132, 132);
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 1.2rem;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalContent {
 | 
			
		||||
  color: light-dark(#2d353c, white);
 | 
			
		||||
  margin-bottom: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalFooter {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: flex-end;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  margin-top: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton {
 | 
			
		||||
  background-color: rgb(9, 132, 132);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton:hover {
 | 
			
		||||
  background-color: rgb(9, 132, 132);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import {
 | 
			
		|||
  Group,
 | 
			
		||||
  Modal,
 | 
			
		||||
  MultiSelect,
 | 
			
		||||
  Switch,
 | 
			
		||||
  Text,
 | 
			
		||||
  TextInput,
 | 
			
		||||
} from '@mantine/core'
 | 
			
		||||
| 
						 | 
				
			
			@ -24,28 +25,31 @@ const UsersManagement = () => {
 | 
			
		|||
  const [users, setUsers] = useState<TUser[]>([])
 | 
			
		||||
  const [action, setAction] = useState('')
 | 
			
		||||
  const [activeBtn, setActiveBtn] = useState(false)
 | 
			
		||||
  const [item, setItem] = useState({ id: 0 })
 | 
			
		||||
  const [item, setItem] = useState({ id: 0, is_permanent: false })
 | 
			
		||||
  const [disableBtn, setDisableBtn] = useState(false)
 | 
			
		||||
  const [info, setInfo] = useState('')
 | 
			
		||||
  const [isPermanentConfirmOpen, setIsPermanentConfirmOpen] =
 | 
			
		||||
    useState<boolean>(false)
 | 
			
		||||
 | 
			
		||||
  const columns = [
 | 
			
		||||
    {
 | 
			
		||||
      name: 'id',
 | 
			
		||||
      size: '3%',
 | 
			
		||||
      size: '5%',
 | 
			
		||||
      header: 'ID',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'name',
 | 
			
		||||
      size: '17%',
 | 
			
		||||
      size: '20%',
 | 
			
		||||
      header: 'Name',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'email',
 | 
			
		||||
      size: '26%',
 | 
			
		||||
      size: '25%',
 | 
			
		||||
      header: 'Email',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'permission',
 | 
			
		||||
      size: '10%',
 | 
			
		||||
      size: '20%',
 | 
			
		||||
      header: 'Permission',
 | 
			
		||||
      render: (row: TUser) => {
 | 
			
		||||
        if (row.permission.includes(',')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,9 +61,21 @@ const UsersManagement = () => {
 | 
			
		|||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'is_permanent',
 | 
			
		||||
      size: '20%',
 | 
			
		||||
      header: 'Employment Type',
 | 
			
		||||
      render: (row: TUser) => {
 | 
			
		||||
        return row.is_permanent ? (
 | 
			
		||||
          <Badge color="teal">Permanent</Badge>
 | 
			
		||||
        ) : (
 | 
			
		||||
          <Badge color="violet">Probation</Badge>
 | 
			
		||||
        )
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: '#',
 | 
			
		||||
      size: '5%',
 | 
			
		||||
      size: '10%',
 | 
			
		||||
      header: 'Action',
 | 
			
		||||
      render: (row: TUser) => {
 | 
			
		||||
        return (
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +84,8 @@ const UsersManagement = () => {
 | 
			
		|||
              className={classes.editIcon}
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                setAction('edit')
 | 
			
		||||
                setItem(row)
 | 
			
		||||
                form.reset()
 | 
			
		||||
                form.setValues(row)
 | 
			
		||||
              }}
 | 
			
		||||
              width={20}
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +112,7 @@ const UsersManagement = () => {
 | 
			
		|||
      name: '',
 | 
			
		||||
      email: '',
 | 
			
		||||
      permission: '',
 | 
			
		||||
      is_permanent: false,
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +147,7 @@ const UsersManagement = () => {
 | 
			
		|||
      const res = await update(createOrUpdateUser, values, getAll)
 | 
			
		||||
      if (res === true) {
 | 
			
		||||
        setAction('')
 | 
			
		||||
        setIsPermanentConfirmOpen(false)
 | 
			
		||||
        form.reset()
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +192,7 @@ const UsersManagement = () => {
 | 
			
		|||
        opened={action === 'add' || action === 'edit'}
 | 
			
		||||
        onClose={() => {
 | 
			
		||||
          setAction('')
 | 
			
		||||
          setIsPermanentConfirmOpen(false)
 | 
			
		||||
          form.reset()
 | 
			
		||||
        }}
 | 
			
		||||
        title={
 | 
			
		||||
| 
						 | 
				
			
			@ -183,9 +204,15 @@ const UsersManagement = () => {
 | 
			
		|||
        <form
 | 
			
		||||
          onSubmit={form.onSubmit(async (values) => {
 | 
			
		||||
            setDisableBtn(true)
 | 
			
		||||
            action === 'edit'
 | 
			
		||||
              ? await handleUpdate(values)
 | 
			
		||||
              : await handleCreate(values)
 | 
			
		||||
            if (action === 'edit') {
 | 
			
		||||
              if (values.is_permanent && !item.is_permanent) {
 | 
			
		||||
                setIsPermanentConfirmOpen(true)
 | 
			
		||||
              } else {
 | 
			
		||||
                await handleUpdate(values)
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              await handleCreate(values)
 | 
			
		||||
            }
 | 
			
		||||
            setDisableBtn(false)
 | 
			
		||||
          })}
 | 
			
		||||
        >
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +223,7 @@ const UsersManagement = () => {
 | 
			
		|||
              value={form.values.name}
 | 
			
		||||
              error={form.errors.name}
 | 
			
		||||
              onChange={(e) => form.setFieldValue('name', e.target.value)}
 | 
			
		||||
              required
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <TextInput
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +232,7 @@ const UsersManagement = () => {
 | 
			
		|||
              value={form.values.email}
 | 
			
		||||
              error={form.errors.email}
 | 
			
		||||
              onChange={(e) => form.setFieldValue('email', e.target.value)}
 | 
			
		||||
              required
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <MultiSelect
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +253,25 @@ const UsersManagement = () => {
 | 
			
		|||
                  e!.filter((p) => p.trim() !== '').join(','),
 | 
			
		||||
                )
 | 
			
		||||
              }
 | 
			
		||||
              mb={'md'}
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            {action === 'edit' && !item.is_permanent ? (
 | 
			
		||||
              <Switch
 | 
			
		||||
                label="Permanent employee"
 | 
			
		||||
                style={{ width: 'fit-content' }}
 | 
			
		||||
                checked={form.values.is_permanent}
 | 
			
		||||
                onChange={(event) =>
 | 
			
		||||
                  form.setFieldValue(
 | 
			
		||||
                    'is_permanent',
 | 
			
		||||
                    event.currentTarget.checked,
 | 
			
		||||
                  )
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            ) : (
 | 
			
		||||
              ''
 | 
			
		||||
            )}
 | 
			
		||||
 | 
			
		||||
            <Box ta={'center'}>
 | 
			
		||||
              {action === 'add' ? (
 | 
			
		||||
                <Button
 | 
			
		||||
| 
						 | 
				
			
			@ -273,6 +320,50 @@ const UsersManagement = () => {
 | 
			
		|||
          {info}
 | 
			
		||||
        </Code>
 | 
			
		||||
      </Modal>
 | 
			
		||||
 | 
			
		||||
      {/* Confirm change to permanent employee */}
 | 
			
		||||
      <Modal
 | 
			
		||||
        opened={isPermanentConfirmOpen}
 | 
			
		||||
        onClose={() => setIsPermanentConfirmOpen(false)}
 | 
			
		||||
        centered
 | 
			
		||||
        size="sm"
 | 
			
		||||
        classNames={{
 | 
			
		||||
          content: classes.deleteModal,
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <Text className={classes.deleteModalTitle}>Confirm Update</Text>
 | 
			
		||||
        <Text className={classes.deleteModalContent}>
 | 
			
		||||
          This action will change the employment type from{' '}
 | 
			
		||||
          <strong>Probation</strong> to <strong>Permanent</strong>.
 | 
			
		||||
        </Text>
 | 
			
		||||
        <Text className={classes.deleteModalContent}>
 | 
			
		||||
          Are you sure you want to proceed?
 | 
			
		||||
        </Text>
 | 
			
		||||
 | 
			
		||||
        <Box className={classes.deleteModalFooter}>
 | 
			
		||||
          <Button
 | 
			
		||||
            variant="outline"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              setIsPermanentConfirmOpen(false)
 | 
			
		||||
            }}
 | 
			
		||||
            disabled={disableBtn}
 | 
			
		||||
          >
 | 
			
		||||
            Cancel
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
            className={classes.deleteButton}
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              setDisableBtn(true)
 | 
			
		||||
              await handleUpdate(form.values)
 | 
			
		||||
              setDisableBtn(false)
 | 
			
		||||
            }}
 | 
			
		||||
            disabled={disableBtn}
 | 
			
		||||
          >
 | 
			
		||||
            Confirm
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </Modal>
 | 
			
		||||
 | 
			
		||||
      <Dialog
 | 
			
		||||
        className={classes.dialog}
 | 
			
		||||
        opened={action === 'delete'}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,6 +76,7 @@ export type TUser = {
 | 
			
		|||
  email: string
 | 
			
		||||
  name: string
 | 
			
		||||
  permission: string
 | 
			
		||||
  is_permanent: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type DataReason = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue