Thực hiện chức năng ngày phép
This commit is contained in:
parent
2cc8472bc6
commit
2fdd687fc9
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Admin\app\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\InitializeLeaveDays;
|
||||
use App\Models\LeaveDays;
|
||||
use App\Models\Notes;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class LeaveManagementController extends Controller
|
||||
{
|
||||
public function get(Request $request)
|
||||
{
|
||||
$yearNow = $request->query('year', now()->year);
|
||||
$year = $request->year ?? $yearNow;
|
||||
|
||||
$leaveDays = self::getDataByYear($year);
|
||||
if ($leaveDays->count() == 0) {
|
||||
InitializeLeaveDays::dispatch($year);
|
||||
$leaveDays = self::getDataByYear($year);
|
||||
}
|
||||
return AbstractController::ResultSuccess($leaveDays);
|
||||
}
|
||||
|
||||
public function getDataByYear($year)
|
||||
{
|
||||
$totalLeaveDaysByMonth = 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('notes.n_month as month'),
|
||||
DB::raw('SUM(categories.c_value) as leave_days')
|
||||
)
|
||||
->where('notes.n_year', $year)
|
||||
->where('notes.n_reason', 'ONLEAVE')
|
||||
->groupBy("notes.n_user_id", DB::raw('notes.n_month'), DB::raw('notes.n_year'))
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
return [
|
||||
"n_user_id" => $item->n_user_id,
|
||||
"month" => $item->month,
|
||||
"leave_days" => $item->leave_days
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
|
||||
$leaveDays = LeaveDays::join('users', 'leave_days.ld_user_id', '=', 'users.id')
|
||||
->select(
|
||||
'leave_days.*',
|
||||
'users.id as user_id',
|
||||
'users.name as user_name',
|
||||
'users.email',
|
||||
'users.created_at as user_created_at',
|
||||
'users.permission',
|
||||
'users.updated_at as user_updated_at',
|
||||
'users.remember_token',
|
||||
'users.email_verified_at'
|
||||
)
|
||||
->where('leave_days.ld_year', $year)
|
||||
->get()
|
||||
->map(function ($item) use ($totalLeaveDaysByMonth) {
|
||||
|
||||
$monthlyLeaveDays = [];
|
||||
foreach ($totalLeaveDaysByMonth as $key => $totalDays) {
|
||||
if ($item->ld_user_id == $totalDays["n_user_id"]) {
|
||||
$monthlyLeaveDays[] = $totalDays;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'user' => [
|
||||
'id' => $item->user_id,
|
||||
'name' => $item->user_name,
|
||||
'email' => $item->email,
|
||||
'created_at' => $item->user_created_at,
|
||||
'permission' => $item->permission,
|
||||
'updated_at' => $item->user_updated_at,
|
||||
'remember_token' => $item->remember_token,
|
||||
'email_verified_at' => $item->email_verified_at,
|
||||
],
|
||||
'leaveDay' => [
|
||||
'id' => $item->id,
|
||||
'ld_user_id' => $item->ld_user_id,
|
||||
'ld_day' => $item->ld_day,
|
||||
'ld_year' => $item->ld_year,
|
||||
'ld_date_additional' => $item->ld_date_additional,
|
||||
'ld_note' => $item->ld_note,
|
||||
'created_at' => $item->created_at,
|
||||
'updated_at' => $item->updated_at,
|
||||
],
|
||||
'monthlyLeaveDays' => $monthlyLeaveDays,
|
||||
];
|
||||
});
|
||||
return $leaveDays;
|
||||
}
|
||||
|
||||
public function saveNoteLeave(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'totalLeave' => 'required|numeric|min:0|max:20',
|
||||
// 'dayAdditional' => 'required|numeric|min:0|max:20',
|
||||
// 'note' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return AbstractController::ResultError($validator->errors());
|
||||
}
|
||||
|
||||
$validatedData = $request->all();
|
||||
$leaveDays = LeaveDays::find($validatedData['id']);
|
||||
|
||||
$leaveDays->ld_day = $validatedData['totalLeave'];
|
||||
$leaveDays->ld_date_additional = $validatedData['dayAdditional']; // Assuming you have this field to store additional days
|
||||
$leaveDays->ld_note = $validatedData['note'];
|
||||
|
||||
$leaveDays->save();
|
||||
|
||||
return response()->json(['status' => true, 'message' => 'Updated successfully']);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ use Modules\Admin\app\Http\Controllers\CountryController;
|
|||
use Modules\Admin\app\Http\Controllers\CustomThemeController;
|
||||
use Modules\Admin\app\Http\Controllers\DashboardController;
|
||||
use Modules\Admin\app\Http\Controllers\JiraController;
|
||||
use Modules\Admin\app\Http\Controllers\LeaveManagementController;
|
||||
use Modules\Admin\app\Http\Controllers\SettingController;
|
||||
use Modules\Admin\app\Http\Controllers\TimekeepingController;
|
||||
use Modules\Admin\app\Http\Controllers\TrackingController;
|
||||
|
|
@ -126,6 +127,14 @@ Route::middleware('api')
|
|||
Route::get('/get-list-master', [CategoryController::class, 'getListMaster']);
|
||||
|
||||
});
|
||||
|
||||
Route::group([
|
||||
'prefix' => 'leave-management',
|
||||
], function () {
|
||||
Route::get('/', [LeaveManagementController::class, 'get'])->middleware('check.permission:admin.hr.staff');
|
||||
Route::post('/saveNoteLeave', [LeaveManagementController::class, 'saveNoteLeave'])->middleware('check.permission:admin.hr');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Jobs\DeductLeaveDays;
|
||||
|
||||
class DeductLeaveDaysCommand extends Command
|
||||
{
|
||||
protected $signature = 'leave:deduct {year?}';
|
||||
protected $description = 'Trừ đi số ngày nghỉ thêm vào năm hiện tại';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$year = $this->argument('year');
|
||||
DeductLeaveDays::dispatch($year);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Jobs\InitializeLeaveDays;
|
||||
|
||||
class InitializeLeaveDaysCommand extends Command
|
||||
{
|
||||
protected $signature = 'initialize:leavedays {year?}';
|
||||
protected $description = 'Initialize leave days for users';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$year = $this->argument('year');
|
||||
InitializeLeaveDays::dispatch($year);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,20 +2,30 @@
|
|||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\DeductLeaveDays;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
protected $commands = [
|
||||
\App\Console\Commands\InitializeLeaveDaysCommand::class,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$schedule->command('clean_logs')->daily();
|
||||
// Chạy command 'daily:api-call' vào mỗi ngày lúc 9h sáng
|
||||
// Chạy command 'daily:api-call' vào mỗi ngày lúc 9h sáng
|
||||
// $schedule->command('daily:api-call')
|
||||
// ->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('leave:deduct')->yearlyOn(3, 31, '23:59:59');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -23,7 +33,7 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\LeaveDays;
|
||||
use App\Models\Notes;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
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
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
protected $year;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($year = null)
|
||||
{
|
||||
// Nếu không có năm được truyền vào, sử dụng năm hiện tại
|
||||
$this->year = $year ?? Carbon::now()->year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$users = User::get();
|
||||
foreach ($users as $user) {
|
||||
$existingData = LeaveDays::where('ld_user_id', $user->id)
|
||||
->where('ld_year', $this->year)
|
||||
->where('ld_date_additional', ">", 0)
|
||||
->first();
|
||||
if (!$existingData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$totalLeaveDaysByMonth = 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();
|
||||
|
||||
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 đó
|
||||
if ($existingData->ld_date_additional > $totalLeaveDaysByMonth->leave_days) {
|
||||
LeaveDays::where('ld_year', $this->year)
|
||||
->where('ld_user_id', $user->id)
|
||||
->update([
|
||||
'ld_date_additional' => $totalLeaveDaysByMonth->leave_days,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
LeaveDays::where('ld_year', $this->year)
|
||||
->where('ld_user_id', $user->id)
|
||||
->update([
|
||||
'ld_date_additional' => "0",
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\LeaveDays;
|
||||
use App\Models\Notes;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 InitializeLeaveDays implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $year;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($year = null)
|
||||
{
|
||||
// Nếu không có năm được truyền vào, sử dụng năm hiện tại
|
||||
$this->year = $year ?? Carbon::now()->year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$users = User::get();
|
||||
$ld_day = 12;
|
||||
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)
|
||||
->where('ld_year', $this->year)
|
||||
->first();
|
||||
|
||||
if ($existingData) {
|
||||
// Nếu dữ liệu đã tồn tại, bỏ qua user này
|
||||
continue;
|
||||
}
|
||||
|
||||
// Kiểm tra dữ liệu của user này trong năm trước
|
||||
$previousYearData = LeaveDays::where('ld_user_id', $user->id)
|
||||
->where('ld_year', $this->year - 1)
|
||||
->first();
|
||||
|
||||
$ld_date_additional = 0;
|
||||
$ld_note = '';
|
||||
|
||||
if ($previousYearData) {
|
||||
$ld_date_additional = $previousYearData->ld_day;
|
||||
$totalLeaveDaysByMonth = 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 - 1)
|
||||
->where('notes.n_user_id', $user->id)
|
||||
->where('notes.n_reason', 'ONLEAVE')
|
||||
->groupBy(DB::raw('notes.n_year'))
|
||||
->first();
|
||||
if ($totalLeaveDaysByMonth) {
|
||||
$ld_date_additional = $ld_date_additional - $totalLeaveDaysByMonth->leave_days;
|
||||
if ($ld_date_additional < 0) {
|
||||
$ld_date_additional = 0;
|
||||
}
|
||||
}
|
||||
$ld_note = 'Cộng dồn ngày phép năm cũ';
|
||||
}
|
||||
|
||||
// Tạo dữ liệu cho năm hiện tại
|
||||
LeaveDays::insert([
|
||||
'ld_user_id' => $user->id,
|
||||
'ld_day' => $ld_day,
|
||||
'ld_year' => $this->year,
|
||||
'ld_date_additional' => $ld_date_additional,
|
||||
'ld_note' => $ld_note,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class LeaveDays extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'id', 'ld_user_id', 'ld_day', 'ld_year', 'ld_date_additional', 'ld_note'
|
||||
];
|
||||
|
||||
protected $table = 'leave_days';
|
||||
}
|
||||
|
|
@ -19,9 +19,6 @@ return new class extends Migration
|
|||
$table->float('ld_date_additional')->default(0);
|
||||
$table->text('ld_note')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
// Nếu cần khóa ngoại, uncomment dòng dưới và điều chỉnh tên bảng và cột phù hợp
|
||||
// $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,8 @@ 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'
|
||||
export const getListMaster = API_URL + 'v1/admin/category/get-list-master'
|
||||
|
||||
//LeaveManagement
|
||||
export const getLeaveManagement = API_URL + 'v1/admin/leave-management'
|
||||
export const updateNoteLeave = API_URL + 'v1/admin/leave-management/saveNoteLeave'
|
||||
|
|
@ -13,7 +13,7 @@ import {
|
|||
Text,
|
||||
TextInput,
|
||||
useComputedColorScheme,
|
||||
useMantineColorScheme
|
||||
useMantineColorScheme,
|
||||
} from '@mantine/core'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import {
|
||||
|
|
@ -27,7 +27,8 @@ import {
|
|||
IconReport,
|
||||
IconScan,
|
||||
IconSubtask,
|
||||
IconSun
|
||||
IconSun,
|
||||
IconCalendarClock,
|
||||
} from '@tabler/icons-react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
|
@ -39,6 +40,11 @@ const data = [
|
|||
{ link: '/timekeeping', label: 'Timekeeping', icon: IconCalendar },
|
||||
{ link: '/tracking', label: 'Check in/out', icon: IconScan },
|
||||
{ link: '/worklogs', label: 'Worklogs', icon: IconReport },
|
||||
{
|
||||
link: '/leave-management',
|
||||
label: 'Leave Management',
|
||||
icon: IconCalendarClock,
|
||||
},
|
||||
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
||||
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
||||
// { link: '/general-setting', label: 'General Setting', icon: IconSettings },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
.title {
|
||||
background-color: light-dark(var(white), var(--mantine-color-dark-7));
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--mantine-spacing-sm) var(--mantine-spacing-lg)
|
||||
var(--mantine-spacing-sm);
|
||||
border-bottom: solid rgba(201, 201, 201, 0.377) 1px;
|
||||
}
|
||||
|
||||
.optionIcon {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.deleteIcon {
|
||||
color: red;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
border-radius: 25%;
|
||||
}
|
||||
|
||||
.deleteIcon:hover {
|
||||
background-color: rgba(203, 203, 203, 0.809);
|
||||
}
|
||||
|
||||
.editIcon {
|
||||
color: rgb(9, 132, 132);
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
border-radius: 25%;
|
||||
}
|
||||
|
||||
.editIcon:hover {
|
||||
background-color: rgba(203, 203, 203, 0.809);
|
||||
}
|
||||
|
||||
.dialog {
|
||||
background-color: light-dark(white, #2d353c);
|
||||
text-align: center;
|
||||
border: solid 1px rgb(255, 145, 0);
|
||||
}
|
||||
|
||||
.dialogText {
|
||||
color: light-dark(#2d353c, white);
|
||||
}
|
||||
|
||||
.tableTr:hover {
|
||||
background-color: rgb(205, 255, 255);
|
||||
}
|
||||
|
||||
.popoverFooter {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.historyRow td {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
|
@ -0,0 +1,465 @@
|
|||
import { getLeaveManagement, updateNoteLeave } from '@/api/Admin'
|
||||
import { update } from '@/rtk/helpers/CRUD'
|
||||
import { get } from '@/rtk/helpers/apiService'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Drawer,
|
||||
Menu,
|
||||
Select,
|
||||
Table,
|
||||
Text,
|
||||
Textarea,
|
||||
TextInput,
|
||||
Tooltip,
|
||||
} from '@mantine/core'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import moment from 'moment'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { IconEdit } from '@tabler/icons-react'
|
||||
|
||||
import classes from './LeaveManagement.module.css'
|
||||
|
||||
interface User {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
email_verified_at: string | null
|
||||
permission: string
|
||||
remember_token: string | null
|
||||
created_at: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
|
||||
interface LeaveDay {
|
||||
id: number
|
||||
ld_user_id: number
|
||||
ld_year: number
|
||||
ld_day: number
|
||||
ld_date_additional: number
|
||||
ld_note: string
|
||||
created_at: string | null
|
||||
updated_at: string | null
|
||||
}
|
||||
|
||||
interface MonthlyLeaveDays {
|
||||
month: number
|
||||
leave_days: number
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
user: User
|
||||
leaveDay: LeaveDay
|
||||
monthlyLeaveDays: MonthlyLeaveDays[]
|
||||
}
|
||||
|
||||
const LeaveManagement = () => {
|
||||
const [opened1, { open: open1, close: close1 }] = useDisclosure(false)
|
||||
const [disableBtn, setDisableBtn] = useState(false)
|
||||
const monthInYear = getMonthNames()
|
||||
const [customAddNotes, setCustomAddNotes] = useState<{
|
||||
id: number
|
||||
user: {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
note: string
|
||||
totalLeave: string
|
||||
dayAdditional: string
|
||||
}>({
|
||||
id: 0,
|
||||
user: {
|
||||
id: 0,
|
||||
name: '',
|
||||
},
|
||||
note: '',
|
||||
totalLeave: '',
|
||||
dayAdditional: '',
|
||||
})
|
||||
|
||||
const [data, setData] = useState<UserData[]>([])
|
||||
const [date, setDate] = useState({
|
||||
year: new Date().getFullYear().toString(),
|
||||
})
|
||||
const getLeaveList = async () => {
|
||||
try {
|
||||
const res = await get(getLeaveManagement, {
|
||||
year: date.year,
|
||||
})
|
||||
if (res.status) {
|
||||
setData(
|
||||
res.data.filter((u: UserData) => u.user.permission.includes('staff')),
|
||||
)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log(error)
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: error.message ?? error,
|
||||
color: 'red',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getLeaveList()
|
||||
}, [date])
|
||||
|
||||
const updateInfoNote = async (
|
||||
id: number,
|
||||
users: {
|
||||
id: number
|
||||
name: string
|
||||
},
|
||||
totalLeave: string,
|
||||
dayAdditional: string,
|
||||
note: string,
|
||||
) => {
|
||||
try {
|
||||
await update(
|
||||
updateNoteLeave,
|
||||
{
|
||||
id: id,
|
||||
users: users,
|
||||
totalLeave: totalLeave,
|
||||
dayAdditional: dayAdditional,
|
||||
note: note,
|
||||
},
|
||||
getLeaveList,
|
||||
)
|
||||
|
||||
setDisableBtn(false)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
function getMonthNames() {
|
||||
const monthNames = [
|
||||
{
|
||||
value: 1,
|
||||
name: 'January',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: 'February',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
name: 'March',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
name: 'April',
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
name: 'May',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
name: 'June',
|
||||
},
|
||||
{
|
||||
value: 7,
|
||||
name: 'July',
|
||||
},
|
||||
{
|
||||
value: 8,
|
||||
name: 'August',
|
||||
},
|
||||
{
|
||||
value: 9,
|
||||
name: 'September',
|
||||
},
|
||||
{
|
||||
value: 10,
|
||||
name: 'October',
|
||||
},
|
||||
{
|
||||
value: 11,
|
||||
name: 'November',
|
||||
},
|
||||
{
|
||||
value: 12,
|
||||
name: 'December',
|
||||
},
|
||||
]
|
||||
return monthNames.map((month) => {
|
||||
return {
|
||||
value: month.value,
|
||||
name: month.name.substring(0, 3),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// console.log(customAddNotes, 'customAddNotes')
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.title}>
|
||||
<h3>
|
||||
<Text>Admin/</Text> Leave Management
|
||||
</h3>
|
||||
</div>
|
||||
<Drawer
|
||||
opened={opened1}
|
||||
onClose={close1}
|
||||
position="right"
|
||||
title={<strong>Update Day Leave</strong>}
|
||||
>
|
||||
<TextInput
|
||||
mb={'md'}
|
||||
value={customAddNotes.totalLeave}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
if (value) {
|
||||
const floatValue = parseFloat(value)
|
||||
if (
|
||||
/^\d*\.?\d?$/.test(value) &&
|
||||
floatValue >= 0 &&
|
||||
floatValue <= 20
|
||||
) {
|
||||
setCustomAddNotes({
|
||||
...customAddNotes,
|
||||
totalLeave: value,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
setCustomAddNotes({
|
||||
...customAddNotes,
|
||||
totalLeave: value,
|
||||
})
|
||||
}
|
||||
}}
|
||||
label={'Total Leave'}
|
||||
placeholder="Input placeholder"
|
||||
/>
|
||||
<TextInput
|
||||
mb={'md'}
|
||||
value={customAddNotes.dayAdditional}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
if (value) {
|
||||
const floatValue = parseFloat(value)
|
||||
if (
|
||||
/^\d*\.?\d?$/.test(value) &&
|
||||
floatValue >= 0 &&
|
||||
floatValue <= 20
|
||||
) {
|
||||
setCustomAddNotes({
|
||||
...customAddNotes,
|
||||
dayAdditional: value,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
setCustomAddNotes({
|
||||
...customAddNotes,
|
||||
dayAdditional: '',
|
||||
})
|
||||
}
|
||||
}}
|
||||
label={'Day additional leave'}
|
||||
placeholder="Input placeholder"
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
mb={'md'}
|
||||
label="Note"
|
||||
value={customAddNotes.note}
|
||||
onChange={(e) => {
|
||||
setCustomAddNotes({ ...customAddNotes, note: e.target.value })
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setDisableBtn(true)
|
||||
if (
|
||||
customAddNotes.id === 0 ||
|
||||
customAddNotes.totalLeave === '' ||
|
||||
customAddNotes.totalLeave === '0'
|
||||
// customAddNotes.dayAdditional === 0 ||
|
||||
// customAddNotes.note === ''
|
||||
) {
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: 'Input data required',
|
||||
color: 'red',
|
||||
})
|
||||
setDisableBtn(false)
|
||||
} else {
|
||||
updateInfoNote(
|
||||
customAddNotes.id,
|
||||
customAddNotes.user,
|
||||
customAddNotes.totalLeave,
|
||||
customAddNotes.dayAdditional,
|
||||
customAddNotes.note,
|
||||
)
|
||||
}
|
||||
}}
|
||||
disabled={disableBtn}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Drawer>
|
||||
<Box display={'flex'}>
|
||||
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
|
||||
<Box w="100%" display={'flex'}>
|
||||
<Select
|
||||
w="50%"
|
||||
value={date.year}
|
||||
size="xs"
|
||||
ml={'sm'}
|
||||
label="Year"
|
||||
data={Array.from({ length: 10 }, (_, index) => {
|
||||
return {
|
||||
value: (
|
||||
parseInt(moment(Date.now()).format('YYYY')) -
|
||||
3 +
|
||||
index
|
||||
).toString(),
|
||||
label: (
|
||||
parseInt(moment(Date.now()).format('YYYY')) -
|
||||
3 +
|
||||
index
|
||||
).toString(),
|
||||
disabled:
|
||||
parseInt(moment(Date.now()).format('YYYY')) - 3 + index >
|
||||
parseInt(moment(Date.now()).format('YYYY')),
|
||||
}
|
||||
})}
|
||||
onChange={(e) => {
|
||||
setDate({ ...date, year: e! })
|
||||
}}
|
||||
></Select>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
w="70%"
|
||||
pl={200}
|
||||
style={{
|
||||
display: 'flex',
|
||||
// alignItems: 'end',
|
||||
justifyContent: 'end',
|
||||
}}
|
||||
>
|
||||
<Box display={'flex'} style={{ alignItems: 'end' }}>
|
||||
<Tooltip label="Save working days">
|
||||
<Button
|
||||
size="xs"
|
||||
ml={'sm'}
|
||||
onClick={() => {
|
||||
//form add user new
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
mt={'md'}
|
||||
>
|
||||
<Table.Thead>
|
||||
<Table.Tr bg={'#228be66b'}>
|
||||
<Table.Th></Table.Th>
|
||||
<Table.Th>User</Table.Th>
|
||||
{monthInYear.map((d) => {
|
||||
return (
|
||||
<Menu width={200} shadow="md" key={d.value}>
|
||||
<Menu.Target>
|
||||
<Table.Th ta={'center'} style={{ cursor: 'pointer' }}>
|
||||
<span>{d.name}</span>
|
||||
</Table.Th>
|
||||
</Menu.Target>
|
||||
</Menu>
|
||||
)
|
||||
})}
|
||||
<Table.Th ta={'center'}>Total Leave</Table.Th>
|
||||
<Table.Th ta={'center'}>Day Off</Table.Th>
|
||||
<Table.Th ta={'center'}>Remaining</Table.Th>
|
||||
<Table.Th ta={'center'}>Notes</Table.Th>
|
||||
<Table.Th ta={'center'}></Table.Th>
|
||||
</Table.Tr>
|
||||
</Table.Thead>
|
||||
<Table.Tbody>
|
||||
{data.map((user, index) => {
|
||||
let totalDayOff = 0
|
||||
let totalDayLeave =
|
||||
user.leaveDay.ld_day + user.leaveDay.ld_date_additional
|
||||
let ld_note = user.leaveDay.ld_note
|
||||
return (
|
||||
<Table.Tr key={user.user.id} className={classes.tableTr}>
|
||||
<Table.Td ta={'center'}>{index + 1}</Table.Td>
|
||||
<Table.Td>
|
||||
<Tooltip multiline label={user.user.name}>
|
||||
<div>{user.user.name}</div>
|
||||
</Tooltip>
|
||||
</Table.Td>
|
||||
|
||||
{monthInYear.map((d, i) => {
|
||||
let total =
|
||||
user.monthlyLeaveDays.find((item) => {
|
||||
return item.month == d.value
|
||||
})?.leave_days ?? 0
|
||||
totalDayOff = totalDayOff + total
|
||||
return (
|
||||
<Table.Td key={i} ta={'center'}>
|
||||
{total === 0 ? '' : total}
|
||||
</Table.Td>
|
||||
)
|
||||
})}
|
||||
|
||||
<Table.Td ta={'center'}>{totalDayLeave}</Table.Td>
|
||||
<Table.Td ta={'center'}>{totalDayOff}</Table.Td>
|
||||
<Table.Td ta={'center'}>
|
||||
{totalDayLeave - totalDayOff}
|
||||
</Table.Td>
|
||||
<Table.Td>{ld_note}</Table.Td>
|
||||
<Table.Td ta={'center'}>
|
||||
<IconEdit
|
||||
color="green"
|
||||
onClick={() => {
|
||||
let totalLeave =
|
||||
user.leaveDay.ld_day == 0
|
||||
? ''
|
||||
: String(user.leaveDay.ld_day)
|
||||
let dayAdditional =
|
||||
user.leaveDay.ld_date_additional == 0
|
||||
? ''
|
||||
: String(user.leaveDay.ld_date_additional)
|
||||
open1()
|
||||
setCustomAddNotes({
|
||||
...customAddNotes,
|
||||
id: user.leaveDay.id,
|
||||
note: ld_note,
|
||||
totalLeave: totalLeave,
|
||||
dayAdditional: dayAdditional,
|
||||
user: {
|
||||
id: user.user.id,
|
||||
name: user.user.name,
|
||||
},
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
)
|
||||
})}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LeaveManagement
|
||||
|
|
@ -7,6 +7,7 @@ import CustomTheme from '@/pages/CustomTheme/CustomTheme'
|
|||
import Dashboard from '@/pages/Dashboard/Dashboard'
|
||||
import GeneralSetting from '@/pages/GeneralSetting/GeneralSetting'
|
||||
import Jira from '@/pages/Jira/Jira'
|
||||
import LeaveManagement from '@/pages/LeaveManagement/LeaveManagement'
|
||||
import PageNotFound from '@/pages/NotFound/NotFound'
|
||||
import Timekeeping from '@/pages/Timekeeping/Timekeeping'
|
||||
import Tracking from '@/pages/Tracking/Tracking'
|
||||
|
|
@ -88,20 +89,20 @@ const mainRoutes = [
|
|||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/jira',
|
||||
element: (
|
||||
<ProtectedRoute mode="route">
|
||||
<BasePage
|
||||
main={
|
||||
<>
|
||||
<Jira />
|
||||
</>
|
||||
}
|
||||
></BasePage>
|
||||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// path: '/jira',
|
||||
// element: (
|
||||
// <ProtectedRoute mode="route">
|
||||
// <BasePage
|
||||
// main={
|
||||
// <>
|
||||
// <Jira />
|
||||
// </>
|
||||
// }
|
||||
// ></BasePage>
|
||||
// </ProtectedRoute>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
path: '/worklogs',
|
||||
element: (
|
||||
|
|
@ -130,6 +131,20 @@ const mainRoutes = [
|
|||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/leave-management',
|
||||
element: (
|
||||
<ProtectedRoute mode="route">
|
||||
<BasePage
|
||||
main={
|
||||
<>
|
||||
<LeaveManagement />
|
||||
</>
|
||||
}
|
||||
></BasePage>
|
||||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// path: '/packages',
|
||||
// element: (
|
||||
|
|
|
|||
Loading…
Reference in New Issue