first change
This commit is contained in:
0
Modules/Employee/app/Http/Controllers/.gitkeep
Normal file
0
Modules/Employee/app/Http/Controllers/.gitkeep
Normal file
163
Modules/Employee/app/Http/Controllers/DepartmentController.php
Normal file
163
Modules/Employee/app/Http/Controllers/DepartmentController.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Employee\Models\Department;
|
||||
use Modules\Employee\Services\DepartmentService;
|
||||
use Modules\User\Services\UserService;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class DepartmentController extends Controller
|
||||
{
|
||||
protected $departmentService;
|
||||
protected $userService;
|
||||
|
||||
public function __construct(DepartmentService $departmentService, UserService $userService)
|
||||
{
|
||||
$this->departmentService = $departmentService;
|
||||
$this->userService = $userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(?int $id = null)
|
||||
{
|
||||
$isEditing = !is_null($id);
|
||||
$department = $isEditing ? $this->departmentService->getDepartmentById($id) : null;
|
||||
|
||||
if (request()->ajax()) {
|
||||
$model = Department::query()->orderBy('order');
|
||||
|
||||
return DataTables::eloquent($model)
|
||||
->addIndexColumn()
|
||||
->setRowClass('tableRow')
|
||||
->editColumn('status', function (Department $department) {
|
||||
$status = $department->status ? 'Published' : 'Draft';
|
||||
$color = $department->status ? 'text-success' : 'text-danger';
|
||||
return "<p class='{$color}'>{$status}</p>";
|
||||
})
|
||||
->addColumn('head', function (Department $department) {
|
||||
return $department->departmentHead?->name ?? '-';
|
||||
})
|
||||
->addColumn('action', 'employee::department.datatable.action')
|
||||
->rawColumns(['action', 'status', 'head'])
|
||||
->toJson();
|
||||
}
|
||||
|
||||
$userOptions = $this->userService->pluck();
|
||||
|
||||
return view('employee::department.index', [
|
||||
'department' => $department,
|
||||
'userOptions' => $userOptions,
|
||||
'title' => $isEditing ? 'Edit Department' : 'Add Department',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isEditing = $request->has('id');
|
||||
|
||||
$request->merge([
|
||||
'slug' => Str::slug($request->title),
|
||||
]);
|
||||
|
||||
if ($isEditing) {
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'max:255', 'unique:departments,title,' . $request->id],
|
||||
'slug' => ['required', 'string'],
|
||||
'user_id' => ['nullable', 'integer'],
|
||||
]);
|
||||
|
||||
$department = $this->departmentService->updateDepartment($request->id, $validated);
|
||||
flash()->success("Department for {$department->title} has been updated.");
|
||||
return to_route('department.index');
|
||||
}
|
||||
|
||||
$maxOrder = Department::max('order');
|
||||
$order = $maxOrder ? ++$maxOrder : 1;
|
||||
|
||||
$request->mergeIfMissing([
|
||||
'order' => $order
|
||||
]);
|
||||
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'unique:departments,title'],
|
||||
'slug' => ['required', 'string'],
|
||||
'order' => ['integer'],
|
||||
'user_id' => ['nullable', 'integer'],
|
||||
]);
|
||||
|
||||
$department = $this->departmentService->storeDepartment($validated);
|
||||
flash()->success("Department for {$department->title} has been created.");
|
||||
return to_route('department.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$department = $this->departmentService->deleteDepartment($id);
|
||||
return response()->json(['status' => 200, 'message' => "Department has been deleted."], 200);
|
||||
}
|
||||
|
||||
public function reorder(Request $request)
|
||||
{
|
||||
$departments = $this->departmentService->getAllDepartments();
|
||||
|
||||
foreach ($departments as $department) {
|
||||
foreach ($request->order as $order) {
|
||||
if ($order['id'] == $department->id) {
|
||||
$department->update(['order' => $order['position']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response(['status' => true, 'message' => 'Reordered successfully'], 200);
|
||||
}
|
||||
|
||||
public function toggle($id)
|
||||
{
|
||||
$department = Department::findOrFail($id);
|
||||
$department->update(['status' => !$department->status]);
|
||||
return response(['status' => 200, 'message' => 'Toggled successfully'], 200);
|
||||
}
|
||||
}
|
163
Modules/Employee/app/Http/Controllers/DesignationController.php
Normal file
163
Modules/Employee/app/Http/Controllers/DesignationController.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Employee\Models\Designation;
|
||||
use Modules\Employee\Services\DepartmentService;
|
||||
use Modules\Employee\Services\DesignationService;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class DesignationController extends Controller
|
||||
{
|
||||
protected $designationService;
|
||||
protected $departmentService;
|
||||
|
||||
public function __construct(DesignationService $designationService, DepartmentService $departmentService)
|
||||
{
|
||||
$this->designationService = $designationService;
|
||||
$this->departmentService = $departmentService;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(?int $id = null)
|
||||
{
|
||||
$isEditing = !is_null($id);
|
||||
$designation = $isEditing ? $this->designationService->getDesignationById($id) : null;
|
||||
|
||||
if (request()->ajax()) {
|
||||
$model = Designation::query()->orderBy('order');
|
||||
|
||||
return DataTables::eloquent($model)
|
||||
->addIndexColumn()
|
||||
->setRowClass('tableRow')
|
||||
->editColumn('status', function (Designation $designation) {
|
||||
$status = $designation->status ? 'Published' : 'Draft';
|
||||
$color = $designation->status ? 'text-success' : 'text-danger';
|
||||
return "<p class='{$color}'>{$status}</p>";
|
||||
})
|
||||
->editColumn('department_id', function (Designation $designation) {
|
||||
return $designation->department?->title ?? "-";
|
||||
})
|
||||
->addColumn('action', 'employee::designation.datatable.action')
|
||||
->rawColumns(['action', 'status'])
|
||||
->toJson();
|
||||
}
|
||||
|
||||
$departmentOptions = $this->departmentService->pluck();
|
||||
return view('employee::designation.index', [
|
||||
'designation' => $designation,
|
||||
'departmentOptions'=> $departmentOptions,
|
||||
'title' => $isEditing ? 'Edit Designation' : 'Add Designation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isEditing = $request->has('id');
|
||||
|
||||
$request->merge([
|
||||
'slug' => Str::slug($request->title),
|
||||
]);
|
||||
|
||||
if ($isEditing) {
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'max:255', 'unique:designations,title,' . $request->id],
|
||||
'slug' => ['required', 'string'],
|
||||
'department_id' => ['nullable', 'integer'],
|
||||
]);
|
||||
|
||||
$designation = $this->designationService->updateDesignation($request->id, $validated);
|
||||
flash()->success("Designation for {$designation->title} has been updated.");
|
||||
return to_route('designation.index');
|
||||
}
|
||||
|
||||
$maxOrder = Designation::max('order');
|
||||
$order = $maxOrder ? ++$maxOrder : 1;
|
||||
|
||||
$request->mergeIfMissing([
|
||||
'order' => $order
|
||||
]);
|
||||
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'unique:designations,title'],
|
||||
'slug' => ['required', 'string'],
|
||||
'order' => ['integer'],
|
||||
'department_id' => ['nullable', 'integer'],
|
||||
]);
|
||||
|
||||
$designation = $this->designationService->storeDesignation($validated);
|
||||
flash()->success("Designation for {$designation->title} has been created.");
|
||||
return to_route('designation.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$designation = $this->designationService->deleteDesignation($id);
|
||||
return response()->json(['status' => 200, 'message' => "Designation has been deleted."], 200);
|
||||
}
|
||||
|
||||
public function reorder(Request $request)
|
||||
{
|
||||
$designations = $this->designationService->getAllDesignations();
|
||||
|
||||
foreach ($designations as $designation) {
|
||||
foreach ($request->order as $order) {
|
||||
if ($order['id'] == $designation->id) {
|
||||
$designation->update(['order' => $order['position']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response(['status' => true, 'message' => 'Reordered successfully'], 200);
|
||||
}
|
||||
|
||||
public function toggle($id)
|
||||
{
|
||||
$designation = Designation::findOrFail($id);
|
||||
$designation->update(['status' => !$designation->status]);
|
||||
return response(['status' => 200, 'message' => 'Toggled successfully'], 200);
|
||||
}
|
||||
}
|
258
Modules/Employee/app/Http/Controllers/EmployeeController.php
Normal file
258
Modules/Employee/app/Http/Controllers/EmployeeController.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\CCMS\Models\Branch;
|
||||
use Modules\Employee\Interfaces\EmployeeInterface;
|
||||
use Modules\Employee\Models\Employee;
|
||||
use Modules\Employee\Services\DepartmentService;
|
||||
use Modules\Employee\Services\DesignationService;
|
||||
use Modules\User\Services\UserService;
|
||||
|
||||
class EmployeeController extends Controller
|
||||
{
|
||||
private $employee;
|
||||
private $userService;
|
||||
private $branchService;
|
||||
private $designationService;
|
||||
private $departmentService;
|
||||
|
||||
|
||||
public function __construct(EmployeeInterface $employee, UserService $userService, DesignationService $designationService, DepartmentService $departmentService)
|
||||
{
|
||||
$this->employee = $employee;
|
||||
$this->userService = $userService;
|
||||
$this->designationService = $designationService;
|
||||
$this->departmentService = $departmentService;
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$data['title'] = "Employee List";
|
||||
|
||||
if ($request->ajax()) {
|
||||
$data['employees'] = $this->employee->findAll(request: $request, query: function ($query) {
|
||||
$query->where('status', "!=", "terminated")->with('user')->latest();
|
||||
}, paginate:true, limit:12);
|
||||
|
||||
$view = view('employee::employee.partials.employee-list', $data)->render();
|
||||
|
||||
return response()->json(['status', 200, 'html' => $view], 200);
|
||||
}
|
||||
return view('employee::employee.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data['title'] = 'Create Employee';
|
||||
$data['editable'] = false;
|
||||
$data['genderOptions'] = config("constants.gender_options");
|
||||
$data['statusOptions'] = config("constants.employee_status_options");
|
||||
$data['branchOptions'] = Branch::pluck('title', 'id');
|
||||
$data['departmentOptions'] = $this->departmentService->pluck();
|
||||
$data['designationOptions'] = $this->designationService->pluck();
|
||||
return view('employee::employee.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'mobile' => [
|
||||
'required',
|
||||
'regex:/^(98|97)[0-9]{8}$/',
|
||||
],
|
||||
'photo' => 'nullable',
|
||||
'email' => 'required|email|unique:employees,email',
|
||||
], [
|
||||
'mobile.required' => 'Mobile number is required.',
|
||||
'mobile.regex' => 'Mobile number must start with 98 or 97 and be 10 digits long.',
|
||||
'email.required' => 'Email is required.',
|
||||
'email.email' => 'Invalid email format.',
|
||||
'email.unique' => 'The email has already been taken.',
|
||||
]);
|
||||
|
||||
$request->merge([
|
||||
'employee_code' => 'EMP' . mt_rand(1000, 9999),
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($validatedData, $request) {
|
||||
$employeeInput = $request->only(Employee::getFillableFields());
|
||||
$userInput = $request->only(User::getFillableFields());
|
||||
|
||||
$employee = $this->employee->create($employeeInput);
|
||||
|
||||
$userInput['name'] = $employee->full_name;
|
||||
$userInput['order'] = ($maxOrder = User::max('order')) !== null ? ++$maxOrder : 1;
|
||||
|
||||
$user = $this->userService->storeUser($userInput);
|
||||
|
||||
$employee->update(['user_id' => $user->id]);
|
||||
});
|
||||
|
||||
flash()->success('Employee has been created successfully!');
|
||||
return redirect()->route('employee.index');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
flash()->error($e->getMessage());
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$data['employee'] = $this->employee->findById($id);
|
||||
|
||||
// $data['leaves'] = $this->leave->getLeaveByEmployeeId(id: $id);
|
||||
// $data['leaveTypeList'] = $this->leaveType->pluck();
|
||||
// $data['status'] = Leave::PROGRESS_STATUS;
|
||||
// $data['duration'] = Leave::DURATION;
|
||||
// $data['attends'] = $this->attendance->getAttendanceByEmployeeId(id: $id);
|
||||
// $data['roleList'] = $this->role->pluck();
|
||||
// $data['desgination'] = $data['employee']->designation->name;
|
||||
// $data['department'] = $data['employee']->department_id ? optional($this->dropDown->getDropdownById($data['employee']->department_id))->title : null;
|
||||
// $data['leaveBalance'] = $this->leaveBalance->where([
|
||||
// 'employee_id' => $id,
|
||||
// ])->with(['leaveType:leave_type_id,name'])->get()
|
||||
// ->transform(function ($leaveBalance) {
|
||||
// return [
|
||||
// 'leave_type_id' => $leaveBalance->leave_type_id,
|
||||
// 'leave_type' => $leaveBalance->leaveType?->name,
|
||||
// 'total' => $leaveBalance->total,
|
||||
// 'remain' => $leaveBalance->remain,
|
||||
// ];
|
||||
// });
|
||||
|
||||
return view('employee::show', $data);
|
||||
}
|
||||
|
||||
/**ss
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$data['title'] = 'Edit Employee';
|
||||
$data['editable'] = true;
|
||||
$data['genderOptions'] = config("constants.gender_options");
|
||||
$data['statusOptions'] = config("constants.employee_status_options");
|
||||
$data['branchOptions'] = Branch::pluck('title', 'id');
|
||||
$data['departmentOptions'] = $this->departmentService->pluck();
|
||||
$data['designationOptions'] = $this->designationService->pluck();
|
||||
$data['employee'] = $this->employee->findById($id);
|
||||
return view('employee::employee.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'mobile' => [
|
||||
'required',
|
||||
'regex:/^(98|97)[0-9]{8}$/',
|
||||
],
|
||||
'email' => 'required|email|unique:employees,email,' . $id,
|
||||
], [
|
||||
'contact.required' => 'The contact number is required.',
|
||||
'contact.regex' => 'The contact number must start with 98 or 97 and be 10 digits long.',
|
||||
'email.required' => 'The email is required.',
|
||||
'email.email' => 'The email must be a valid email address.',
|
||||
'email.unique' => 'The email has already been taken.',
|
||||
]);
|
||||
|
||||
try {
|
||||
|
||||
DB::transaction(function () use ($request, $id) {
|
||||
$input = $request->only(Employee::getFillableFields());
|
||||
$employee = $this->employee->update($id, $input);
|
||||
|
||||
$userData = [
|
||||
'name' => $employee->full_name,
|
||||
'email' => $employee->email,
|
||||
];
|
||||
|
||||
if ($employee->isDirty("email")) {
|
||||
$userData["can_login"] = false;
|
||||
}
|
||||
|
||||
$employee->user->update($userData);
|
||||
});
|
||||
|
||||
flash()->success('Employee has been updated!');
|
||||
|
||||
return redirect()->route('employee.index');
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
|
||||
DB::transaction(function () use ($id) {
|
||||
$employee = $this->employee->delete($id);
|
||||
$employee->user->delete();
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'status' => 200,
|
||||
'message' => 'Employee has been deleted!',
|
||||
], 200);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => 500,
|
||||
'message' => 'Failed to delete employee!',
|
||||
'error' => $th->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function terminate($id)
|
||||
{
|
||||
try {
|
||||
|
||||
DB::transaction(function () use ($id) {
|
||||
$employee = $this->employee->terminate($id);
|
||||
$employee->user->update([
|
||||
"can_login" => false,
|
||||
]);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'status' => 200,
|
||||
'message' => 'Employee has been terminate!',
|
||||
], 200);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => 500,
|
||||
'message' => 'Failed to terminate employee!',
|
||||
'error' => $th->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
10
Modules/Employee/app/Interfaces/EmployeeInterface.php
Normal file
10
Modules/Employee/app/Interfaces/EmployeeInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Interfaces;
|
||||
|
||||
use App\Interfaces\ModelInterface;
|
||||
|
||||
interface EmployeeInterface extends ModelInterface
|
||||
{
|
||||
public function terminate($id);
|
||||
}
|
37
Modules/Employee/app/Models/Department.php
Normal file
37
Modules/Employee/app/Models/Department.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Modules\Employee\Database\Factories\DepartmentFactory;
|
||||
|
||||
class Department extends Model
|
||||
{
|
||||
use HasFactory, CreatedUpdatedBy;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'slug',
|
||||
'status',
|
||||
'order',
|
||||
'user_id',
|
||||
'createdby',
|
||||
'updatedby',
|
||||
];
|
||||
|
||||
public function departmentHead()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
protected static function newFactory(): DepartmentFactory
|
||||
{
|
||||
return DepartmentFactory::new();
|
||||
}
|
||||
}
|
37
Modules/Employee/app/Models/Designation.php
Normal file
37
Modules/Employee/app/Models/Designation.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Modules\Employee\Database\Factories\DesignationFactory;
|
||||
|
||||
class Designation extends Model
|
||||
{
|
||||
use HasFactory, CreatedUpdatedBy;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'slug',
|
||||
'status',
|
||||
'order',
|
||||
'department_id',
|
||||
'createdby',
|
||||
'updatedby',
|
||||
];
|
||||
|
||||
public function department()
|
||||
{
|
||||
return $this->belongsTo(Department::class, 'department_id');
|
||||
}
|
||||
|
||||
protected static function newFactory(): DesignationFactory
|
||||
{
|
||||
return DesignationFactory::new();
|
||||
}
|
||||
}
|
113
Modules/Employee/app/Models/Employee.php
Normal file
113
Modules/Employee/app/Models/Employee.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\CCMS\Models\Branch;
|
||||
use Modules\Employee\Database\Factories\EmployeeFactory;
|
||||
use Modules\User\Models\ActivityLog;
|
||||
|
||||
class Employee extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'first_name',
|
||||
'middle_name',
|
||||
'last_name',
|
||||
'dob',
|
||||
'email',
|
||||
'contact',
|
||||
'mobile',
|
||||
'photo',
|
||||
'guardian_name',
|
||||
'guardian_contact',
|
||||
'temporary_address',
|
||||
'permanent_address',
|
||||
'employee_code',
|
||||
'join_date',
|
||||
'gender_id',
|
||||
'designation_id',
|
||||
'department_id',
|
||||
'branch_id',
|
||||
'user_id',
|
||||
'status',
|
||||
'remarks',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the employee's full name.
|
||||
*/
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
"dob" => "date",
|
||||
"join_date" => "date",
|
||||
];
|
||||
}
|
||||
protected function fullName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => trim(
|
||||
implode(' ', array_filter([$this->first_name, $this->middle_name, $this->last_name]))
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function photo(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn(string $value) => asset($value),
|
||||
);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function department()
|
||||
{
|
||||
return $this->belongsTo(Department::class, 'department_id');
|
||||
}
|
||||
|
||||
public function designation()
|
||||
{
|
||||
return $this->belongsTo(Designation::class, 'designation_id');
|
||||
}
|
||||
|
||||
public function branch()
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function activityLogs()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
ActivityLog::class,
|
||||
User::class,
|
||||
'id',
|
||||
'loggable_id'
|
||||
)
|
||||
->where('loggable_type', User::class);
|
||||
}
|
||||
|
||||
protected static function newFactory(): EmployeeFactory
|
||||
{
|
||||
return EmployeeFactory::new();
|
||||
}
|
||||
|
||||
public static function getFillableFields()
|
||||
{
|
||||
return (new static())->getFillable();
|
||||
}
|
||||
}
|
0
Modules/Employee/app/Models/Scopes/.gitkeep
Normal file
0
Modules/Employee/app/Models/Scopes/.gitkeep
Normal file
0
Modules/Employee/app/Providers/.gitkeep
Normal file
0
Modules/Employee/app/Providers/.gitkeep
Normal file
138
Modules/Employee/app/Providers/EmployeeServiceProvider.php
Normal file
138
Modules/Employee/app/Providers/EmployeeServiceProvider.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Employee\Interfaces\EmployeeInterface;
|
||||
use Modules\Employee\Repositories\EmployeeRepository;
|
||||
use Nwidart\Modules\Traits\PathNamespace;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
class EmployeeServiceProvider extends ServiceProvider
|
||||
{
|
||||
use PathNamespace;
|
||||
|
||||
protected string $name = 'Employee';
|
||||
|
||||
protected string $nameLower = 'employee';
|
||||
|
||||
/**
|
||||
* Boot the application events.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->registerCommands();
|
||||
$this->registerCommandSchedules();
|
||||
$this->registerTranslations();
|
||||
$this->registerConfig();
|
||||
$this->registerViews();
|
||||
$this->loadMigrationsFrom(module_path($this->name, 'database/migrations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(EmployeeInterface::class, EmployeeRepository::class);
|
||||
$this->app->register(EventServiceProvider::class);
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register commands in the format of Command::class
|
||||
*/
|
||||
protected function registerCommands(): void
|
||||
{
|
||||
// $this->commands([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register command Schedules.
|
||||
*/
|
||||
protected function registerCommandSchedules(): void
|
||||
{
|
||||
// $this->app->booted(function () {
|
||||
// $schedule = $this->app->make(Schedule::class);
|
||||
// $schedule->command('inspire')->hourly();
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Register translations.
|
||||
*/
|
||||
public function registerTranslations(): void
|
||||
{
|
||||
$langPath = resource_path('lang/modules/'.$this->nameLower);
|
||||
|
||||
if (is_dir($langPath)) {
|
||||
$this->loadTranslationsFrom($langPath, $this->nameLower);
|
||||
$this->loadJsonTranslationsFrom($langPath);
|
||||
} else {
|
||||
$this->loadTranslationsFrom(module_path($this->name, 'lang'), $this->nameLower);
|
||||
$this->loadJsonTranslationsFrom(module_path($this->name, 'lang'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register config.
|
||||
*/
|
||||
protected function registerConfig(): void
|
||||
{
|
||||
$relativeConfigPath = config('modules.paths.generator.config.path');
|
||||
$configPath = module_path($this->name, $relativeConfigPath);
|
||||
|
||||
if (is_dir($configPath)) {
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($configPath));
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile() && $file->getExtension() === 'php') {
|
||||
$relativePath = str_replace($configPath . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
||||
$configKey = $this->nameLower . '.' . str_replace([DIRECTORY_SEPARATOR, '.php'], ['.', ''], $relativePath);
|
||||
$key = ($relativePath === 'config.php') ? $this->nameLower : $configKey;
|
||||
|
||||
$this->publishes([$file->getPathname() => config_path($relativePath)], 'config');
|
||||
$this->mergeConfigFrom($file->getPathname(), $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register views.
|
||||
*/
|
||||
public function registerViews(): void
|
||||
{
|
||||
$viewPath = resource_path('views/modules/'.$this->nameLower);
|
||||
$sourcePath = module_path($this->name, 'resources/views');
|
||||
|
||||
$this->publishes([$sourcePath => $viewPath], ['views', $this->nameLower.'-module-views']);
|
||||
|
||||
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->nameLower);
|
||||
|
||||
$componentNamespace = $this->module_namespace($this->name, $this->app_path(config('modules.paths.generator.component-class.path')));
|
||||
Blade::componentNamespace($componentNamespace, $this->nameLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*/
|
||||
public function provides(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getPublishableViewPaths(): array
|
||||
{
|
||||
$paths = [];
|
||||
foreach (config('view.paths') as $path) {
|
||||
if (is_dir($path.'/modules/'.$this->nameLower)) {
|
||||
$paths[] = $path.'/modules/'.$this->nameLower;
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
}
|
30
Modules/Employee/app/Providers/EventServiceProvider.php
Normal file
30
Modules/Employee/app/Providers/EventServiceProvider.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The event handler mappings for the application.
|
||||
*
|
||||
* @var array<string, array<int, string>>
|
||||
*/
|
||||
protected $listen = [];
|
||||
|
||||
/**
|
||||
* Indicates if events should be discovered.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $shouldDiscoverEvents = true;
|
||||
|
||||
/**
|
||||
* Configure the proper event listeners for email verification.
|
||||
*/
|
||||
protected function configureEmailVerification(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
50
Modules/Employee/app/Providers/RouteServiceProvider.php
Normal file
50
Modules/Employee/app/Providers/RouteServiceProvider.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected string $name = 'Employee';
|
||||
|
||||
/**
|
||||
* Called before routes are registered.
|
||||
*
|
||||
* Register any model bindings or pattern based filters.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the routes for the application.
|
||||
*/
|
||||
public function map(): void
|
||||
{
|
||||
$this->mapApiRoutes();
|
||||
$this->mapWebRoutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the "web" routes for the application.
|
||||
*
|
||||
* These routes all receive session state, CSRF protection, etc.
|
||||
*/
|
||||
protected function mapWebRoutes(): void
|
||||
{
|
||||
Route::middleware('web')->group(module_path($this->name, '/routes/web.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the "api" routes for the application.
|
||||
*
|
||||
* These routes are typically stateless.
|
||||
*/
|
||||
protected function mapApiRoutes(): void
|
||||
{
|
||||
Route::middleware('api')->prefix('api')->name('api.')->group(module_path($this->name, '/routes/api.php'));
|
||||
}
|
||||
}
|
93
Modules/Employee/app/Repositories/EmployeeRepository.php
Normal file
93
Modules/Employee/app/Repositories/EmployeeRepository.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Repositories;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Employee\Interfaces\EmployeeInterface;
|
||||
use Modules\Employee\Models\Employee;
|
||||
|
||||
class EmployeeRepository implements EmployeeInterface
|
||||
{
|
||||
public function findAll($request, callable $query = null, bool $paginate = false, int $limit = 10)
|
||||
{
|
||||
$baseQuery = Employee::query();
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$baseQuery->whereAny(
|
||||
[
|
||||
'first_name',
|
||||
'middle_name',
|
||||
'last_name',
|
||||
],
|
||||
'LIKE',
|
||||
"%{$request->search}%"
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->filled('email')) {
|
||||
$baseQuery->where('email', 'LIKE', "%{$$request->email}%");
|
||||
}
|
||||
|
||||
if ($query) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
if ($paginate) {
|
||||
return $baseQuery->paginate($limit);
|
||||
}
|
||||
|
||||
return $baseQuery->get();
|
||||
}
|
||||
|
||||
public function findById($id, callable $query = null)
|
||||
{
|
||||
$baseQuery = Employee::query();
|
||||
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
return $baseQuery->where('id', $id)->firstOrFail();
|
||||
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$employee = $this->findById($id);
|
||||
$employee->delete();
|
||||
return $employee;
|
||||
}
|
||||
|
||||
public function create(array $data)
|
||||
{
|
||||
$employee = Employee::create($data);
|
||||
return $employee;
|
||||
}
|
||||
|
||||
public function update($id, array $data)
|
||||
{
|
||||
$employee = $this->findById($id);
|
||||
$employee->update($data);
|
||||
return $employee;
|
||||
}
|
||||
|
||||
public function pluck(callable $query = null)
|
||||
{
|
||||
$baseQuery = Employee::query();
|
||||
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
return $baseQuery->get()->mapWithKeys(function ($employee) {
|
||||
return [$employee->id => $employee->full_name];
|
||||
});
|
||||
}
|
||||
|
||||
public function terminate($id){
|
||||
$employee = $this->findById($id);
|
||||
$employee->update(["status" => "terminated"]);
|
||||
return $employee;
|
||||
}
|
||||
|
||||
}
|
0
Modules/Employee/app/Services/.gitkeep
Normal file
0
Modules/Employee/app/Services/.gitkeep
Normal file
67
Modules/Employee/app/Services/DepartmentService.php
Normal file
67
Modules/Employee/app/Services/DepartmentService.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Employee\Models\Department;
|
||||
|
||||
class DepartmentService
|
||||
{
|
||||
|
||||
public function getAllDepartments(Request $request, callable $query = null, $paginate = false, $limit = 10)
|
||||
{
|
||||
$baseQuery = Department::query();
|
||||
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
if ($paginate) {
|
||||
return $baseQuery->paginate($limit);
|
||||
}
|
||||
|
||||
return $baseQuery->get();
|
||||
}
|
||||
|
||||
public function storeDepartment(array $departmentData): Department
|
||||
{
|
||||
return DB::transaction(function () use ($departmentData) {
|
||||
$department = Department::create($departmentData);
|
||||
|
||||
return $department;
|
||||
});
|
||||
}
|
||||
|
||||
public function getDepartmentById(int $id)
|
||||
{
|
||||
return Department::findOrFail($id);
|
||||
}
|
||||
|
||||
public function updateDepartment(int $id, array $departmentData)
|
||||
{
|
||||
$department = $this->getDepartmentById($id);
|
||||
|
||||
return DB::transaction(function () use ($department, $departmentData) {
|
||||
$department->update($departmentData);
|
||||
return $department;
|
||||
});
|
||||
}
|
||||
|
||||
public function deleteDepartment(int $id)
|
||||
{
|
||||
return DB::transaction(function () use ($id) {
|
||||
$department = $this->getDepartmentById($id);
|
||||
$department->delete();
|
||||
return $department;
|
||||
});
|
||||
}
|
||||
|
||||
public function pluck(callable $query = null)
|
||||
{
|
||||
$baseQuery = Department::query();
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
return $baseQuery->pluck('title', 'id');
|
||||
}
|
||||
}
|
67
Modules/Employee/app/Services/DesignationService.php
Normal file
67
Modules/Employee/app/Services/DesignationService.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Employee\Models\Designation;
|
||||
|
||||
class DesignationService
|
||||
{
|
||||
|
||||
public function getAllDesignations(Request $request, callable $query = null, $paginate = false, $limit = 10)
|
||||
{
|
||||
$baseQuery = Designation::query();
|
||||
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
if ($paginate) {
|
||||
return $baseQuery->paginate($limit);
|
||||
}
|
||||
|
||||
return $baseQuery->get();
|
||||
}
|
||||
|
||||
public function storeDesignation(array $designationData): Designation
|
||||
{
|
||||
return DB::transaction(function () use ($designationData) {
|
||||
$designation = Designation::create($designationData);
|
||||
|
||||
return $designation;
|
||||
});
|
||||
}
|
||||
|
||||
public function getDesignationById(int $id)
|
||||
{
|
||||
return Designation::findOrFail($id);
|
||||
}
|
||||
|
||||
public function updateDesignation(int $id, array $designationData)
|
||||
{
|
||||
$designation = $this->getDesignationById($id);
|
||||
|
||||
return DB::transaction(function () use ($designation, $designationData) {
|
||||
$designation->update($designationData);
|
||||
return $designation;
|
||||
});
|
||||
}
|
||||
|
||||
public function deleteDesignation(int $id)
|
||||
{
|
||||
return DB::transaction(function () use ($id) {
|
||||
$designation = $this->getDesignationById($id);
|
||||
$designation->delete();
|
||||
return $designation;
|
||||
});
|
||||
}
|
||||
|
||||
public function pluck(callable $query = null)
|
||||
{
|
||||
$baseQuery = Designation::query();
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
return $baseQuery->pluck('title', 'id');
|
||||
}
|
||||
}
|
30
Modules/Employee/composer.json
Normal file
30
Modules/Employee/composer.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "nwidart/employee",
|
||||
"description": "",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Widart",
|
||||
"email": "n.widart@gmail.com"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [],
|
||||
"aliases": {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Employee\\": "app/",
|
||||
"Modules\\Employee\\Database\\Factories\\": "database/factories/",
|
||||
"Modules\\Employee\\Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Modules\\Employee\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
0
Modules/Employee/config/.gitkeep
Normal file
0
Modules/Employee/config/.gitkeep
Normal file
5
Modules/Employee/config/config.php
Normal file
5
Modules/Employee/config/config.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Employee',
|
||||
];
|
0
Modules/Employee/database/factories/.gitkeep
Normal file
0
Modules/Employee/database/factories/.gitkeep
Normal file
34
Modules/Employee/database/factories/DepartmentFactory.php
Normal file
34
Modules/Employee/database/factories/DepartmentFactory.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DepartmentFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*/
|
||||
protected $model = \Modules\Employee\Models\Department::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
static $order = 1;
|
||||
$title = $this->faker->firstName();
|
||||
|
||||
return [
|
||||
'title' => $title,
|
||||
'slug' => Str::slug($title),
|
||||
'status' => $this->faker->randomElement([0, 1]),
|
||||
'order' => $order++,
|
||||
'user_id' => 1,
|
||||
'createdby' => 1,
|
||||
'updatedby' => 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
34
Modules/Employee/database/factories/DesignationFactory.php
Normal file
34
Modules/Employee/database/factories/DesignationFactory.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DesignationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*/
|
||||
protected $model = \Modules\Employee\Models\Designation::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
static $order = 1;
|
||||
$title = $this->faker->firstName();
|
||||
|
||||
return [
|
||||
'title' => $title,
|
||||
'slug' => Str::slug($title),
|
||||
'status' => $this->faker->randomElement([0, 1]),
|
||||
'order' => $order++,
|
||||
'department_id' => 1,
|
||||
'createdby' => 1,
|
||||
'updatedby' => 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
45
Modules/Employee/database/factories/EmployeeFactory.php
Normal file
45
Modules/Employee/database/factories/EmployeeFactory.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Modules\Employee\Models\Employee;
|
||||
|
||||
class EmployeeFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*/
|
||||
protected $model = Employee::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => $this->faker->firstName,
|
||||
'middle_name' => $this->faker->firstName,
|
||||
'last_name' => $this->faker->lastName,
|
||||
'dob' => $this->faker->date(),
|
||||
'email' => $this->faker->unique()->safeEmail,
|
||||
'contact' => $this->faker->phoneNumber,
|
||||
'mobile' => $this->faker->phoneNumber,
|
||||
'photo' => $this->faker->imageUrl(),
|
||||
'guardian_name' => $this->faker->name,
|
||||
'guardian_contact' => $this->faker->phoneNumber,
|
||||
'temporary_address' => $this->faker->address,
|
||||
'permanent_address' => $this->faker->address,
|
||||
'employee_code' => $this->faker->unique()->numberBetween(1000, 9999),
|
||||
'join_date' => $this->faker->date(),
|
||||
'gender_id' => $this->faker->randomElement([1, 2]),
|
||||
'designation_id' => $this->faker->randomElement([1, 2, 3, 4]),
|
||||
'department_id' => $this->faker->randomElement([1, 2, 3]),
|
||||
'branch_id' => $this->faker->randomElement([1, 2, 3]),
|
||||
'user_id' => $this->faker->randomElement([1, 2, 3]),
|
||||
'status' => $this->faker->randomElement([1, 0]),
|
||||
'remarks' => $this->faker->sentence,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
0
Modules/Employee/database/migrations/.gitkeep
Normal file
0
Modules/Employee/database/migrations/.gitkeep
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('employees', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('first_name');
|
||||
$table->string('middle_name')->nullable();
|
||||
$table->string('last_name');
|
||||
|
||||
$table->date('dob')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('contact', 20)->nullable();
|
||||
$table->string('mobile', 20)->nullable();
|
||||
$table->string('photo')->nullable();
|
||||
|
||||
$table->string('guardian_name')->nullable();
|
||||
$table->string('guardian_contact')->nullable();
|
||||
|
||||
$table->text('temporary_address')->nullable();
|
||||
$table->text('permanent_address')->nullable();
|
||||
|
||||
$table->string('employee_code')->unique();
|
||||
$table->date('join_date')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('gender_id')->nullable();
|
||||
$table->unsignedBigInteger('designation_id')->nullable();
|
||||
$table->unsignedBigInteger('department_id')->nullable();
|
||||
|
||||
$table->unsignedBigInteger('branch_id')->nullable();
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
|
||||
$table->string('status')->default("active");
|
||||
$table->unsignedBigInteger('createdby')->unsigned()->nullable();
|
||||
$table->unsignedBigInteger('updatedby')->unsigned()->nullable();
|
||||
$table->text('remarks')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('employees');
|
||||
}
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('departments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title')->nullable();
|
||||
$table->string('slug')->nullable();
|
||||
|
||||
$table->integer('status')->default(1);
|
||||
$table->integer('order')->unsigned()->nullable();
|
||||
|
||||
$table->unsignedBigInteger('user_id')->unsigned()->nullable();
|
||||
$table->unsignedBigInteger('createdby')->unsigned()->nullable();
|
||||
$table->unsignedBigInteger('updatedby')->unsigned()->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('departments');
|
||||
}
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('designations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title')->nullable();
|
||||
$table->string('slug')->nullable();
|
||||
|
||||
$table->integer('status')->default(1);
|
||||
$table->integer('order')->unsigned()->nullable();
|
||||
|
||||
$table->unsignedBigInteger('department_id')->unsigned()->nullable();
|
||||
$table->unsignedBigInteger('createdby')->unsigned()->nullable();
|
||||
$table->unsignedBigInteger('updatedby')->unsigned()->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('designations');
|
||||
}
|
||||
};
|
0
Modules/Employee/database/seeders/.gitkeep
Normal file
0
Modules/Employee/database/seeders/.gitkeep
Normal file
22
Modules/Employee/database/seeders/EmployeeDatabaseSeeder.php
Normal file
22
Modules/Employee/database/seeders/EmployeeDatabaseSeeder.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Employee\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Modules\Employee\Models\Department;
|
||||
use Modules\Employee\Models\Designation;
|
||||
use Modules\Employee\Models\Employee;
|
||||
|
||||
class EmployeeDatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Employee::factory(50)->create();
|
||||
Department::factory(5)->create();
|
||||
Designation::factory(5)->create();
|
||||
// $this->call([]);
|
||||
}
|
||||
}
|
11
Modules/Employee/module.json
Normal file
11
Modules/Employee/module.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Employee",
|
||||
"alias": "employee",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
"providers": [
|
||||
"Modules\\Employee\\Providers\\EmployeeServiceProvider"
|
||||
],
|
||||
"files": []
|
||||
}
|
15
Modules/Employee/package.json
Normal file
15
Modules/Employee/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.1.2",
|
||||
"laravel-vite-plugin": "^0.7.5",
|
||||
"sass": "^1.69.5",
|
||||
"postcss": "^8.3.7",
|
||||
"vite": "^4.0.0"
|
||||
}
|
||||
}
|
0
Modules/Employee/resources/assets/js/app.js
Normal file
0
Modules/Employee/resources/assets/js/app.js
Normal file
0
Modules/Employee/resources/assets/sass/app.scss
Normal file
0
Modules/Employee/resources/assets/sass/app.scss
Normal file
0
Modules/Employee/resources/views/.gitkeep
Normal file
0
Modules/Employee/resources/views/.gitkeep
Normal file
@@ -0,0 +1,33 @@
|
||||
{{ html()->form('POST', route('department.store'))->class('needs-validation')->attributes(['novalidate'])->open() }}
|
||||
|
||||
@isset($department)
|
||||
{{ html()->hidden('id', $department->id) }}
|
||||
@endisset
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Title')->for('title') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('title')->value($department->title ?? old('title'))->class('form-control')->placeholder('Enter Title')->required() }}
|
||||
{{ html()->div('Please enter a title.')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Slug')->for('slug') }}
|
||||
{{ html()->text('slug')->value($department->slug ?? old('slug'))->class('form-control')->placeholder('Enter Department Slug') }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Department Head')->class('form-label')->for('department_id') }}
|
||||
{{ html()->select('user_id', @$userOptions, @$designation->user_id)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-form-buttons :href="route('department.index')" :label="isset($department) ? 'Update' : 'Create'" />
|
||||
</div>
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
@@ -0,0 +1,10 @@
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('department.index', $id) }}" class="link-success fs-15 edit-item-btn"><i class="ri-edit-2-line"></i></a>
|
||||
|
||||
<a data-link="{{ route('department.toggle', $id) }}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Toggle" data-status="{{ $status == 1 ? 'Draft' : 'Published' }}"
|
||||
class="link-info fs-15 toggle-item"><i class="{{ $status == 1 ? 'ri-toggle-line' : 'ri-toggle-fill' }}"></i></a>
|
||||
|
||||
<a href="javascript:void(0);" data-link="{{ route('department.destroy', $id) }}" class="link-danger fs-15 remove-item"><i
|
||||
class="ri-delete-bin-line"></i>
|
||||
</a>
|
||||
</div>
|
50
Modules/Employee/resources/views/department/index.blade.php
Normal file
50
Modules/Employee/resources/views/department/index.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
@if ($errors->any())
|
||||
<x-flash-message type="danger" :messages="$errors->all()" />
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card profile-card">
|
||||
@include('employee::department.add-department-form')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-xl-8 col-lg-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@php
|
||||
$columns = [
|
||||
[
|
||||
'title' => 'S.N',
|
||||
'data' => 'DT_RowIndex',
|
||||
'name' => 'DT_RowIndex',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
],
|
||||
['title' => 'Name', 'data' => 'title', 'name' => 'title'],
|
||||
['title' => 'Slug', 'data' => 'slug', 'name' => 'slug'],
|
||||
['title' => 'Head', 'data' => 'head', 'name' => 'head'],
|
||||
['title' => 'Status', 'data' => 'status', 'name' => 'status'],
|
||||
[
|
||||
'title' => 'Action',
|
||||
'data' => 'action',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<x-data-table-script :route="route('department.index')" :reorder="route('department.reorder')" :columns="$columns" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,31 @@
|
||||
{{ html()->form('POST', route('designation.store'))->class('needs-validation')->attributes(['novalidate'])->open() }}
|
||||
|
||||
@isset($designation)
|
||||
{{ html()->hidden('id', $designation->id) }}
|
||||
@endisset
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Title')->for('title') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('title', @$designation->title)->class('form-control')->placeholder('Enter Title')->required() }}
|
||||
{{ html()->div('Please enter a title.')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Slug')->for('slug') }}
|
||||
{{ html()->text('slug', @$designation->slug)->class('form-control')->placeholder('Enter Designation Slug') }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Department')->class('form-label')->for('department_id') }}
|
||||
{{ html()->select('department_id', @$departmentOptions, @$designation->department_id)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-form-buttons :href="route('designation.index')" :label="isset($designation) ? 'Update' : 'Create'" />
|
||||
</div>
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
@@ -0,0 +1,10 @@
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('designation.index', $id) }}" class="link-success fs-15 edit-item-btn"><i class="ri-edit-2-line"></i></a>
|
||||
|
||||
<a data-link="{{ route('designation.toggle', $id) }}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Toggle" data-status="{{ $status == 1 ? 'Draft' : 'Published' }}"
|
||||
class="link-info fs-15 toggle-item"><i class="{{ $status == 1 ? 'ri-toggle-line' : 'ri-toggle-fill' }}"></i></a>
|
||||
|
||||
<a href="javascript:void(0);" data-link="{{ route('designation.destroy', $id) }}" class="link-danger fs-15 remove-item"><i
|
||||
class="ri-delete-bin-line"></i>
|
||||
</a>
|
||||
</div>
|
50
Modules/Employee/resources/views/designation/index.blade.php
Normal file
50
Modules/Employee/resources/views/designation/index.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
@if ($errors->any())
|
||||
<x-flash-message type="danger" :messages="$errors->all()" />
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card profile-card">
|
||||
@include('employee::designation.add-designation-form')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-xl-8 col-lg-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@php
|
||||
$columns = [
|
||||
[
|
||||
'title' => 'S.N',
|
||||
'data' => 'DT_RowIndex',
|
||||
'name' => 'DT_RowIndex',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
],
|
||||
['title' => 'Name', 'data' => 'title', 'name' => 'title'],
|
||||
['title' => 'Slug', 'data' => 'slug', 'name' => 'slug'],
|
||||
['title' => 'Department', 'data' => 'department_id', 'name' => 'department_id'],
|
||||
['title' => 'Status', 'data' => 'status', 'name' => 'status'],
|
||||
[
|
||||
'title' => 'Action',
|
||||
'data' => 'action',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<x-data-table-script :route="route('designation.index')" :reorder="route('designation.reorder')" :columns="$columns" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
14
Modules/Employee/resources/views/employee/create.blade.php
Normal file
14
Modules/Employee/resources/views/employee/create.blade.php
Normal file
@@ -0,0 +1,14 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb />
|
||||
|
||||
{{ html()->form('POST')->route('employee.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
|
||||
@include('employee::employee.partials.form')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
@endsection
|
15
Modules/Employee/resources/views/employee/edit.blade.php
Normal file
15
Modules/Employee/resources/views/employee/edit.blade.php
Normal file
@@ -0,0 +1,15 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb />
|
||||
|
||||
{{ html()->modelForm($employee, 'PUT')->route('employee.update', $employee->id)->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
|
||||
@include('employee::employee.partials.form')
|
||||
|
||||
{{ html()->closeModelForm() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
119
Modules/Employee/resources/views/employee/index.blade.php
Normal file
119
Modules/Employee/resources/views/employee/index.blade.php
Normal file
@@ -0,0 +1,119 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb />
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-4">
|
||||
<div class="search-box">
|
||||
<input type="text" name="searchMemberList" class="form-control" id="searchMemberList"
|
||||
placeholder="Search for name...">
|
||||
<i class="ri-search-line search-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-auto ms-auto">
|
||||
<div class="list-grid-nav hstack gap-1">
|
||||
<button type="button" id="grid-view-button"
|
||||
class="btn btn-soft-info nav-link btn-icon fs-14 active filter-button"><i
|
||||
class="ri-grid-fill"></i></button>
|
||||
<button type="button" id="list-view-button"
|
||||
class="btn btn-soft-info nav-link btn-icon fs-14 filter-button"><i
|
||||
class="ri-list-unordered"></i></button>
|
||||
@can('employee.create')
|
||||
<a class="btn btn-primary" href="{{ route('employee.create') }}"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Create</a>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div>
|
||||
<div id="teamlist">
|
||||
<div class="text-center mb-3 auto-load" style="display: none">
|
||||
<a href="javascript:void(0);" class="text-success"><i
|
||||
class="mdi mdi-loading mdi-spin fs-20 align-middle me-2"></i> Load More </a>
|
||||
</div>
|
||||
<div class="team-list grid-view-filter row" id="team-member-list">
|
||||
</div>
|
||||
<div class="py-4 mt-4 text-center" id="noresult" style="display: none">
|
||||
<lord-icon src="https://cdn.lordicon.com/msoeawqm.json" trigger="loop"
|
||||
colors="primary:#405189,secondary:#0ab39c" style="width:72px;height:72px"></lord-icon>
|
||||
<h5 class="mt-4">Sorry! No Result Found</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('user::user.modal.assign-role')
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
const debounce = (func, delay) => {
|
||||
let timer;
|
||||
return function(...args) {
|
||||
const context = this;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
func.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
function performSearch(page) {
|
||||
const input = $("#searchMemberList").val();
|
||||
$.ajax({
|
||||
url: '{{ route('employee.index') }}',
|
||||
method: 'GET',
|
||||
data: {
|
||||
search: input,
|
||||
page: page
|
||||
},
|
||||
beforeSend: function() {
|
||||
$(".auto-load").toggle();
|
||||
$('.team-list').html("");
|
||||
$("#noresult").hide();
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.html) {
|
||||
$('.team-list').html(response.html);
|
||||
}
|
||||
$('[data-bs-toggle="tooltip"]').tooltip('dispose').tooltip();
|
||||
},
|
||||
error: function(error) {
|
||||
console.log(error);
|
||||
$("#noresult").show();
|
||||
},
|
||||
complete: function() {
|
||||
$(".auto-load").toggle();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const debouncedSearch = debounce(performSearch, 500);
|
||||
|
||||
performSearch(1);
|
||||
|
||||
$('#searchMemberList').on('keyup', function() {
|
||||
debouncedSearch(1);
|
||||
});
|
||||
|
||||
$(document).on('click', '.pagination a', function(e) {
|
||||
e.preventDefault();
|
||||
const page = $(this).attr('href').split('page=')[1];
|
||||
performSearch(page);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@@ -0,0 +1,67 @@
|
||||
<div class="card">
|
||||
<div class="card-header align-items-center d-flex">
|
||||
<h5 class="card-title flex-grow-1 mb-0">Attendance Detail</h5>
|
||||
<div class="flex-shrink-0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="table-responsive">
|
||||
<table class="display table-sm table-bordered buttons-datatables table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="tb-col"><span class="overline-title">Name</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Date</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Clock In</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Clock Out</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Working Hours(hrs)</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Status</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($attends as $attend)
|
||||
<tr style=" vertical-align: middle;">
|
||||
<td class="p-1">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="me-2 flex-shrink-0">
|
||||
<img src="
|
||||
{{ $employee->profile_pic }}
|
||||
"
|
||||
alt="" class="avatar-sm p-2">
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="fs-14 fw-medium my-1">
|
||||
<a href="#" class="text-reset text-hover-success small">
|
||||
{{ $employee->full_name }}
|
||||
</a>
|
||||
</h5>
|
||||
<span class="text-muted">
|
||||
{{ $employee->email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ $attend->date }}</td>
|
||||
<td class="text-success">{{ $attend->clock_in_time ?? 'N/A'}}</td>
|
||||
<td class="text-danger">{{ $attend->clock_out_time ?? 'N/A'}}</td>
|
||||
<td class="text-center text-muted">{{ $attend->total_hours ?? 'N/A'}}</td>
|
||||
<td>
|
||||
@if ($attend->status == 10)
|
||||
<span class="badge bg-danger">Absent</span>
|
||||
@elseif ($attend->status == 11)
|
||||
<span class="badge bg-success">Present</span>
|
||||
@else
|
||||
<span class="badge bg-secondary">N/A</span>
|
||||
@endif
|
||||
</td>
|
||||
{{-- <td> <span class="badge bg-{{ $attend->status_name['color'] }}">{!! $attend->status_name['status'] !!}</td> --}}
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,96 @@
|
||||
<div class="py-2 text-center">
|
||||
{{ $employees->links() }}
|
||||
</div>
|
||||
|
||||
@forelse ($employees as $employee)
|
||||
<div class="col">
|
||||
<div class="card team-box ribbon-box mb-lg-0 material-shadow border shadow-none">
|
||||
<div class="team-cover">
|
||||
<img src="{{ asset('assets/images/small/img-9.jpg') }}" class="img-fluid">
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<div class="ribbon-two ribbon-two-success">
|
||||
{!! $employee?->user?->getRoles() !!}
|
||||
</div>
|
||||
<div class="row align-items-center team-row">
|
||||
<div class="col team-settings">
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col dropdown text-end">
|
||||
<a href="javascript:void(0);" data-bs-toggle="dropdown" aria-expanded="false"
|
||||
class="">
|
||||
<i class="ri-more-fill fs-17"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
@can('employee.destroy')
|
||||
<li>
|
||||
<a class="dropdown-item remove-item-btn" href="javascript:void(0);"
|
||||
data-link="{{ route('employee.destroy', $employee->id) }}"
|
||||
data-id="{{ $employee->id }}">
|
||||
<i class="ri-delete-bin-5-line text-muted me-2 align-bottom"></i>
|
||||
Delete
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col">
|
||||
<div class="team-profile-img">
|
||||
<div class="img-thumbnail rounded-circle flex-shrink-0">
|
||||
<img style="height: 90px; width:90px; object-fit:contain"
|
||||
src="{{ $employee->getRawOriginal('photo') ? $employee->photo : asset('assets/images/avatar.png') }}"
|
||||
alt="{{ $employee->full_name }}" class="img-fluid rounded-circle">
|
||||
</div>
|
||||
<div class="team-content">
|
||||
<a class="member-name" href="{{ route('employee.show', $employee->id) }}">
|
||||
<h5 class="fs-16 text-primary mb-1">{{ $employee->full_name }}</h5>
|
||||
</a>
|
||||
<p class="text-muted member-designation mb-0">
|
||||
{{ $employee?->designation?->title }}
|
||||
<span @class(['d-none' => !$employee->department || !$employee->branch])>
|
||||
({{ $employee->branch?->title ?? $employee->department?->title }})
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col">
|
||||
<ul class="list-inline mb-0 text-center">
|
||||
@can('employee.edit')
|
||||
<li class="list-inline-item avatar-xs">
|
||||
<a href="{{ route('employee.edit', $employee->id) }}" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" data-bs-title="Edit"
|
||||
class="avatar-title bg-info-subtle text-info fs-15 rounded">
|
||||
<i class="ri-edit-line"></i>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@if (auth()->user()->hasRole('admin'))
|
||||
@can('user.assignRole' && $employee->user)
|
||||
<li class="list-inline-item avatar-xs">
|
||||
<a href="javascript:void(0);" data-link="{{ route('user.assignRole', $employee->user?->id) }}" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" data-bs-title="Assign Role" class="avatar-title bg-dark-subtle text-dark fs-15 rounded assign-role-btn">
|
||||
<i class="ri-admin-line"></i>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="py-4 mt-4 text-center" id="noresult">
|
||||
<lord-icon src="https://cdn.lordicon.com/msoeawqm.json" trigger="loop"
|
||||
colors="primary:#405189,secondary:#0ab39c" style="width:72px;height:72px"></lord-icon>
|
||||
<h5 class="mt-4">Sorry! No Result Found</h5>
|
||||
</div>
|
||||
@endforelse
|
@@ -0,0 +1,22 @@
|
||||
{{ html()->form('GET')->route('employee.index')->class(['filter-form'])->attributes(['id' => 'filter-form'])->open() }}
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-3">
|
||||
{{ html()->label('Search')->class('form-label') }}
|
||||
<div class="search-box">
|
||||
{{ html()->text('search', request('search'))->class('form-control form-control-sm')->placeholder('Search...') }}
|
||||
<i class="ri-search-line search-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
{{ html()->label('Branch')->class('form-label') }}
|
||||
{{ html()->select('branch_id', $branch, request('branch_id'))->placeholder('-Select-')->class('form-select form-select-sm') }}
|
||||
</div>
|
||||
</div>
|
||||
<!--end row-->
|
||||
|
||||
<div class="d-flex justify-content-center list-grid-nav hstack mt-2 gap-1">
|
||||
<button type="submit" class="btn btn-warning btn-sm">Filter</button>
|
||||
<a href="{{ route('employee.index') }}" class="btn btn-danger btn-sm reset-filter">Reset</a>
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
@@ -0,0 +1,136 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-xl-9">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title text-primary mb-4">Personal Details</h6>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('First Name')->class('form-label')->for('first_name') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('first_name')->class('form-control')->placeholder('Enter First Name')->required() }}
|
||||
{{ html()->div('Please enter first name')->class('invalid-feedback') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Middle Name')->class('form-label')->for('middle_name') }}
|
||||
{{ html()->text('middle_name')->class('form-control')->placeholder('Enter Middle Name') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Last Name')->class('form-label')->for('last_name') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('last_name')->class('form-control')->placeholder('Enter Last Name')->required() }}
|
||||
{{ html()->div('Please enter last name')->class('invalid-feedback') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Gender')->class('form-label')->for('gender_id') }}
|
||||
{{ html()->select('gender_id', @$genderOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Date of Birth')->class('form-label')->for('dob') }}
|
||||
<x-flatpickr-input name="dob" id="dob" placeholder="Enter Date of Birth"
|
||||
data-default-date="{{ @$employee->dob }}" />
|
||||
{{ html()->div('Please choose dob')->class('invalid-feedback') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-1 border-dashed my-3"></div>
|
||||
|
||||
<h6 class="card-title text-primary mb-4">Contact Information</h6>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Email')->class('form-label')->for('email') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->email('email')->class('form-control')->placeholder('Enter Email')->required() }}
|
||||
{{ html()->div('Please enter email')->class('invalid-feedback') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Mobile')->class('form-label')->for('mobile') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('mobile')->class('form-control')->placeholder('Enter Mobile Number')->required() }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Phone Number')->class('form-label')->for('contact') }}
|
||||
{{ html()->text('contact')->class('form-control')->placeholder('Enter Phone Number') }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6">
|
||||
{{ html()->label('Permanent Address')->class('form-label')->for('permanent_address') }}
|
||||
{{ html()->text('permanent_address')->class('form-control')->placeholder('Enter Permanent Address') }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6">
|
||||
{{ html()->label('Temporary Address')->class('form-label')->for('temporary_address') }}
|
||||
{{ html()->text('temporary_address')->class('form-control')->placeholder('Enter Temporary Address') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-1 border-dashed my-3"></div>
|
||||
|
||||
<h6 class="card-title text-primary mb-4">Job Details</h6>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Branch')->class('form-label')->for('branch_id') }}
|
||||
{{ html()->select('branch_id', @$branchOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Department')->class('form-label')->for('department_id') }}
|
||||
{{ html()->select('department_id', @$departmentOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Designation')->class('form-label')->for('designation_id') }}
|
||||
{{ html()->select('designation_id', @$designationOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
{{ html()->label('Join Date')->class('form-label')->for('join_date') }}
|
||||
<x-flatpickr-input name="join_date" id="join_date" placeholder="Enter Join Date"
|
||||
data-default-date="{{ @$employee->join_date }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-1 border-dashed my-3"></div>
|
||||
|
||||
<h6 class="card-title text-primary mb-4">Additional Information</h6>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
{{ html()->label('Guardian Name')->class('form-label')->for('guardian_name') }}
|
||||
{{ html()->text('guardian_name')->class('form-control')->placeholder('Enter Guardian Name') }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6">
|
||||
{{ html()->label('Guardian Contact')->class('form-label')->for('guardian_contact') }}
|
||||
{{ html()->text('guardian_contact')->class('form-control')->placeholder('Enter Guardian Contact') }}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
{{ html()->label('About')->class('form-label')->for('about') }}
|
||||
{{ html()->textarea('remarks')->class('form-control ckeditor-classic')->placeholder('Enter Description...') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="card-title mb-0 fs-14">
|
||||
Status
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ html()->label('Status')->class('form-label visually-hidden')->for('status') }}
|
||||
{{ html()->select('status', @$statusOptions, @$employee->status)->class('form-select choices-select')->placeholder('Select')->required() }}
|
||||
</div>
|
||||
|
||||
<x-form-buttons :href="route('employee.index')" :label="isset($employee) ? 'Update' : 'Create'" />
|
||||
|
||||
</div>
|
||||
<div class="card featured-image-section">
|
||||
<div class="card-header">
|
||||
<h6 class="card-title mb-0 fs-14">
|
||||
Profile Picture
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Featured')->class('form-label visually-hidden')->for('photo') }}
|
||||
<x-image-input :data="$editable ? $employee->getRawOriginal('photo') : null" id="photo" name="photo" :editable="$editable" :multiple=false />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,76 @@
|
||||
<div class="modal fade" id="leaveModal" tabindex="-1" aria-labelledby="leaveLabel"
|
||||
aria-modal="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header model-primary">
|
||||
<h5 class="modal-title" id="leaveModalgridLabel">Apply Leave</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('leave.store') }}" class="needs-validation" novalidate method="post">
|
||||
@csrf
|
||||
<div class="row gy-2">
|
||||
<input type="hidden" id="employee_id" name="employee_id" value="{{ $employee->id }}">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Employee')->class('form-label') }}
|
||||
{{html()->span('*')->class('text-danger')}}
|
||||
{{ html()->select('employee_id', $employeeList)->class('form-select select2')->placeholder('Select Employee')->required() }}
|
||||
{{ html()->div('Please Select Employee')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Leave Type')->class('form-label') }}
|
||||
{{html()->span('*')->class('text-danger')}}
|
||||
{{ html()->select('leave_type_id', $leaveTypeList)->class('form-select select2')->attributes(['id' => 'leave_type_id'])->placeholder('Select Leave Type')->required() }}
|
||||
{{ html()->div('Please Select Leave Type')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Selet Duration')->class('form-label') }}
|
||||
{{html()->span('*')->class('text-danger')}}
|
||||
<div>
|
||||
|
||||
@php
|
||||
$leaveDuration = isset($leave) && is_object($leave) ? $leave->duration : null;
|
||||
@endphp
|
||||
|
||||
@foreach ($duration as $durationKey => $durationItem)
|
||||
<div class="form-check form-check-inline">
|
||||
{{ html()->radio('duration')->class('form-check-input duration')
|
||||
->checked(old('duration', $leaveDuration === $durationKey))
|
||||
->attributes(['id' => $durationKey])
|
||||
->value($durationKey)
|
||||
->required() }}
|
||||
{{ html()->label($durationItem)->class('form-check-label')->for($durationKey) }}
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Choose Date')->class('form-label') }}
|
||||
{{ html()->text('start_date')->class('form-control start-date')->placeholder('Select Start Date')->attributes([])->required() }}
|
||||
{{ html()->div('Please Select Start Date')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-8 leave-note">
|
||||
<ul class="list-group">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('description')->class('form-control')->placeholder('Write Reason for Leave') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,59 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<h5 class="card-title">Leave</h5>
|
||||
<div class="">
|
||||
{{-- <a href="javascript:void(0);" class="btn btn-sm btn-success float-end1" data-bs-toggle="modal" data-bs-target="#leaveModal"><i
|
||||
class="ri-edit-box-line align-bottom"></i> Apply Leave</a> --}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Small Tables -->
|
||||
<table class="display table-sm table-bordered align-center buttons-datatables1 table" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Leave Type</th>
|
||||
<th>Dates</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($leaves as $key => $leave)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="">
|
||||
<h5 class="fs-12 fw-medium my-1">
|
||||
{{ optional($leave->leaveType)->name }} <span class="text-danger">({{ $leave->total_days }}
|
||||
days)</span>
|
||||
</h5>
|
||||
<span class="fs-10 text-danger text-bold">{{ $leave->getDuration() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@foreach ($leave->start_date as $dates)
|
||||
@foreach ($dates as $date)
|
||||
<li class="fs-12">{{ $date }}</li>
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-{{ $leave->status_name['color'] }}">
|
||||
{!! $leave->status_name['status'] !!} </span>
|
||||
<p class="text-info fs-10 mb-0">{{ optional($leave->approveBy)->name }}</p>
|
||||
<p class="text-muted fs-10">{!! $leave->description !!}</p>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center"> No Leave Found</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--end card-body-->
|
||||
</div>
|
||||
@include('employee::partials.leave-modal')
|
||||
{{-- @include('lead::lead.section.followup.form') --}}
|
384
Modules/Employee/resources/views/employee/show.blade.php
Normal file
384
Modules/Employee/resources/views/employee/show.blade.php
Normal file
@@ -0,0 +1,384 @@
|
||||
@extends('layouts.app')
|
||||
@inject('dropdown', 'Modules\Admin\Repositories\DropdownRepository')
|
||||
|
||||
@section('content')
|
||||
<div class="page-content">
|
||||
<div class="container-fluid">
|
||||
<div class="profile-foreground position-relative mx-n4 mt-n5">
|
||||
<div class="employee-wid-bg profile-wid-bg">
|
||||
<img src="{{ asset('assets/images/profile-bg.jpg') }}" alt="" class="profile-wid-img">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-lg-3 pb-lg-4 profile-wrapper mb-4 pt-4">
|
||||
<div class="row g-4">
|
||||
<div class="col-auto">
|
||||
<div class="avatar-lg">
|
||||
<img src="{!! asset('storage/' . $employee->profile_picture) !!}" alt="user-img" class="img-thumbnail rounded-circle">
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
<div class="col">
|
||||
@if($employee->first_name && $employee->last_name)
|
||||
<div class="d-flex justify-content-between align-items-center p-2">
|
||||
<h3 class="mb-1 text-white">
|
||||
{{ $employee->first_name }} {{ $employee->middle_name }} {{ $employee->last_name }}
|
||||
</h3>
|
||||
</div>
|
||||
<div>
|
||||
<p class="ri-phone-line text-white text-opacity-75">
|
||||
{{ $employee->contact }}
|
||||
<span class="ri-mail-line p-3 text-opacity-75">
|
||||
{{ $employee->email }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if ($department || $desgination)
|
||||
<p class="text-white text-opacity-75">
|
||||
{{ $department }}{{ $department && $desgination ? ', ' : '' }}{{ $desgination }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if($employee->temporary_address || $employee->permanent_address)
|
||||
<div class="hstack text-white-50 gap-1">
|
||||
@if($employee->temporary_address)
|
||||
<div class="me-2">
|
||||
<i class="ri-map-pin-user-line fs-16 me-1 align-middle text-white text-opacity-75"></i>
|
||||
{{ $employee->temporary_address }}
|
||||
</div>
|
||||
@endif
|
||||
@if($employee->permanent_address)
|
||||
<div>
|
||||
<i class="ri-building-line fs-16 me-1 align-middle text-white text-opacity-75"></i>
|
||||
{{ $employee->permanent_address }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<!--end col-->
|
||||
<div class="col-12 col-lg-auto order-lg-0 order-last">
|
||||
<div class="row text text-white-50 text-center">
|
||||
<div class="col-lg-6 col-4">
|
||||
<div class="p-2">
|
||||
<h4 class="mb-1 text-white"></h4>
|
||||
<p class="fs-14 mb-0"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-4">
|
||||
<div class="p-2">
|
||||
<h4 class="mb-1 text-white"></h4>
|
||||
<p class="fs-14 mb-0"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-3">Basic Info</h5>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="flex-shrink-0">
|
||||
<p class="mb-0">Full Name:</p>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-2">
|
||||
<h6 class="mb-0">{{ $employee->full_name }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="flex-shrink-0">
|
||||
<p class="mb-0">DOB:</p>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-2">
|
||||
<h6 class="mb-0">{{ $employee->dob }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="flex-shrink-0">
|
||||
<p class="mb-0">Role:</p>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-2">
|
||||
@if ($employee->user)
|
||||
<span class="badge bg-success fs-12">{{ optional($employee->user)->getRoleNames()->first() }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- end card body -->
|
||||
</div><!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Leave Remaining</h5>
|
||||
</div>
|
||||
<div class="card-body p-2">
|
||||
<div class="table-responsive">
|
||||
<table class="table-nowrap table-sm mb-0 table align-middle">
|
||||
<thead class="table-dark text-white">
|
||||
<tr>
|
||||
<th scope="col" style="width: 62;">Leave Type</th>
|
||||
<th scope="col">Total</th>
|
||||
<th scope="col">Remain</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="leaveRemainTable">
|
||||
@forelse ($leaveBalance as $key => $leave)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $leave['leave_type'] ?: 'N/A' }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $leave['total'] }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $leave['remain'] }}
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center"> No Leave Found</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody><!-- end tbody -->
|
||||
</table><!-- end table -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-9">
|
||||
<div class="d-flex profile-wrapper">
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-pills animation-nav profile-nav gap-lg-3 flex-grow-1 gap-2" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link fs-14 active" data-bs-toggle="tab" href="#overview-tab" role="tab"
|
||||
aria-selected="true">
|
||||
<i class="ri-airplay-fill d-inline-block d-md-none"></i> <span
|
||||
class="d-none d-md-inline-block">Overview</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link fs-14" data-bs-toggle="tab" href="#activities" role="tab" aria-selected="false"
|
||||
tabindex="-1">
|
||||
<i class="ri-list-unordered d-inline-block d-md-none"></i> <span
|
||||
class="d-none d-md-inline-block">Leave</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link fs-14" data-bs-toggle="tab" href="#projects" role="tab" aria-selected="false"
|
||||
tabindex="-1">
|
||||
<i class="ri-price-tag-line d-inline-block d-md-none"></i> <span
|
||||
class="d-none d-md-inline-block">Attendance</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{{ route('employee.edit', $employee->id) }}" class="btn btn-success"><i
|
||||
class="ri-edit-box-line align-bottom"></i> Edit Profile</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content text-muted pt-4">
|
||||
<div class="tab-pane active" id="overview-tab" role="tabpanel">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-3">About</h5>
|
||||
<p>{{ $employee->remarks }}</p>
|
||||
|
||||
<div class="border-top border-top-dashed mt-4 pt-3">
|
||||
<div class="row gy-3">
|
||||
|
||||
<div class="col-lg-3 col-sm-6">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Join Date :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $employee->join_date ?? 'N/A' }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Designation :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $desgination ?? 'N/A' }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Department :</p>
|
||||
<div class="badge bg-danger fs-12">{{ $department ?? 'N/A' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Activity</h5>
|
||||
<div class="simplebar-scrollable-y py-3" data-simplebar style="max-height: 400px;">
|
||||
<div class="acitivity-timeline">
|
||||
@if ($employee->activityLogs != null)
|
||||
@foreach ($employee->activityLogs as $log)
|
||||
<div class="acitivity-item d-flex py-2">
|
||||
<div class="avatar-xs acitivity-avatar flex-shrink-0">
|
||||
<div class="avatar-title bg-primary-subtle text-primary rounded-circle">
|
||||
{{ substr($log->title, 0, 1) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h6 class="mb-1">{{ $log->title }} </h6>
|
||||
<p class="text-muted mb-0">{{ $log->data }}</p>
|
||||
</div>
|
||||
<div class="d-flex flex-column ms-3 flex-shrink-0">
|
||||
<span class="badge bg-secondary fs-12 text-white">{{ $log->createdBy?->name }}</span>
|
||||
<small class="text-danger mb-2">{{ $log->created_at?->format('d M, Y') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--end card-body-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="list-group">
|
||||
<li class="list-group-item active">Action</li>
|
||||
@can('employee.assignRole')
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal" data-bs-target="#assignRoleModal"
|
||||
data-email="{{ $employee->email }}"
|
||||
data-role="{{ $employee->user ? $employee->user->roles->first()->id ?? '' : '' }}"
|
||||
class="list-group-item list-group-item-action">
|
||||
<i class="ri-speed-fill text-primary me-2 align-middle"></i>
|
||||
Assign Roles
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal" data-bs-target="#changePasswordModal"
|
||||
class="list-group-item list-group-item-action" class="ri-speed-fill text-info me-2 align-middle"
|
||||
data-id="{{ $employee->id }}">
|
||||
<i class="ri-lock-unlock-line text-danger"></i> Change Password
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="activities" role="tabpanel">
|
||||
@include('employee::partials.leave')
|
||||
|
||||
</div>
|
||||
<div class="tab-pane fade" id="projects" role="tabpanel">
|
||||
@include('employee::partials.attendance')
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--end tab-content-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--end col-->
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="changePasswordModal" tabindex="-1" aria-labelledby="changePasswordLabel"
|
||||
aria-modal="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header model-primary">
|
||||
<h5 class="modal-title" id="exampleModalgridLabel">Change Password</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('employee.changePassword') }}" class="needs-validation" novalidate method="post">
|
||||
@csrf
|
||||
<div class="row gy-2">
|
||||
<input type="hidden" id="employee_id" name="employee_id" value="{{ $employee->id }}">
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('New Password')->class('form-label') }}
|
||||
{{ html()->password('password')->class('form-control')->placeholder('Enter New Password')->required() }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Confirm New Password')->class('form-label') }}
|
||||
{{ html()->password('confirm_password')->class('form-control')->placeholder('Confirm New Password')->required() }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="assignRoleModal" tabindex="-1" aria-labelledby="assignRoleLabel" aria-modal="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header model-primary">
|
||||
<h5 class="modal-title" id="exampleModalgridLabel">Assign Role</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ html()->form('POST')->route('employee.assignRole')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
<div class="row gy-2">
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Email')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->email('email')->class('form-control email-field')->placeholder('Enter Email')->isReadonly(false)->required() }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Role')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->select('role_id', $roleList)->class('form-select')->placeholder('Select Role')->required() }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/profile.init.js') }}"></script>
|
||||
<script src="{{ asset('assets/libs/swiper/swiper-bundle.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#assignRoleModal').on('show.bs.modal', function(event) {
|
||||
var button = $(event.relatedTarget);
|
||||
var email = button.data('email');
|
||||
var roleId = button.data('role');
|
||||
$(this).find('.email-field').val(email);
|
||||
$(this).find('select[name="role_id"]').val(roleId);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
7
Modules/Employee/resources/views/index.blade.php
Normal file
7
Modules/Employee/resources/views/index.blade.php
Normal file
@@ -0,0 +1,7 @@
|
||||
@extends('employee::layouts.master')
|
||||
|
||||
@section('content')
|
||||
<h1>Hello World</h1>
|
||||
|
||||
<p>Module: {!! config('employee.name') !!}</p>
|
||||
@endsection
|
29
Modules/Employee/resources/views/layouts/master.blade.php
Normal file
29
Modules/Employee/resources/views/layouts/master.blade.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>Employee Module - {{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<meta name="description" content="{{ $description ?? '' }}">
|
||||
<meta name="keywords" content="{{ $keywords ?? '' }}">
|
||||
<meta name="author" content="{{ $author ?? '' }}">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||
|
||||
{{-- Vite CSS --}}
|
||||
{{-- {{ module_vite('build-employee', 'resources/assets/sass/app.scss', storage_path('vite.hot')) }} --}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@yield('content')
|
||||
|
||||
{{-- Vite JS --}}
|
||||
{{-- {{ module_vite('build-employee', 'resources/assets/js/app.js', storage_path('vite.hot')) }} --}}
|
||||
</body>
|
0
Modules/Employee/routes/.gitkeep
Normal file
0
Modules/Employee/routes/.gitkeep
Normal file
19
Modules/Employee/routes/api.php
Normal file
19
Modules/Employee/routes/api.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Employee\Http\Controllers\EmployeeController;
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
* API Routes
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* Here is where you can register API routes for your application. These
|
||||
* routes are loaded by the RouteServiceProvider within a group which
|
||||
* is assigned the "api" middleware group. Enjoy building your API!
|
||||
*
|
||||
*/
|
||||
|
||||
Route::middleware(['auth:sanctum'])->prefix('v1')->group(function () {
|
||||
Route::apiResource('employee', EmployeeController::class)->names('employee');
|
||||
});
|
31
Modules/Employee/routes/web.php
Normal file
31
Modules/Employee/routes/web.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Employee\Http\Controllers\DepartmentController;
|
||||
use Modules\Employee\Http\Controllers\DesignationController;
|
||||
use Modules\Employee\Http\Controllers\EmployeeController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Web Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register web routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider within a group which
|
||||
| contains the "web" middleware group. Now create something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () {
|
||||
Route::resource('employee', EmployeeController::class)->names('employee');
|
||||
|
||||
Route::post('department/reorder', [DepartmentController::class, 'reorder'])->name('department.reorder');
|
||||
Route::get('department/toggle/{id}', [DepartmentController::class, 'toggle'])->name('department.toggle');
|
||||
Route::get('department/{id?}', [DepartmentController::class, 'index'])->name('department.index');
|
||||
Route::resource('department', DepartmentController::class)->names('department')->only(['store', 'edit', 'destroy']);
|
||||
|
||||
Route::post('designation/reorder', [DesignationController::class, 'reorder'])->name('designation.reorder');
|
||||
Route::get('designation/toggle/{id}', [DesignationController::class, 'toggle'])->name('designation.toggle');
|
||||
Route::get('designation/{id?}', [DesignationController::class, 'index'])->name('designation.index');
|
||||
Route::resource('designation', DesignationController::class)->names('designation')->only(['store', 'edit', 'destroy']);
|
||||
});
|
57
Modules/Employee/vite.config.js
Normal file
57
Modules/Employee/vite.config.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
import { readdirSync, statSync } from 'fs';
|
||||
import { join,relative,dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
outDir: '../../public/build-employee',
|
||||
emptyOutDir: true,
|
||||
manifest: true,
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
publicDirectory: '../../public',
|
||||
buildDirectory: 'build-employee',
|
||||
input: [
|
||||
__dirname + '/resources/assets/sass/app.scss',
|
||||
__dirname + '/resources/assets/js/app.js'
|
||||
],
|
||||
refresh: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
// Scen all resources for assets file. Return array
|
||||
//function getFilePaths(dir) {
|
||||
// const filePaths = [];
|
||||
//
|
||||
// function walkDirectory(currentPath) {
|
||||
// const files = readdirSync(currentPath);
|
||||
// for (const file of files) {
|
||||
// const filePath = join(currentPath, file);
|
||||
// const stats = statSync(filePath);
|
||||
// if (stats.isFile() && !file.startsWith('.')) {
|
||||
// const relativePath = 'Modules/Employee/'+relative(__dirname, filePath);
|
||||
// filePaths.push(relativePath);
|
||||
// } else if (stats.isDirectory()) {
|
||||
// walkDirectory(filePath);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// walkDirectory(dir);
|
||||
// return filePaths;
|
||||
//}
|
||||
|
||||
//const __filename = fileURLToPath(import.meta.url);
|
||||
//const __dirname = dirname(__filename);
|
||||
|
||||
//const assetsDir = join(__dirname, 'resources/assets');
|
||||
//export const paths = getFilePaths(assetsDir);
|
||||
|
||||
|
||||
//export const paths = [
|
||||
// 'Modules/Employee/resources/assets/sass/app.scss',
|
||||
// 'Modules/Employee/resources/assets/js/app.js',
|
||||
//];
|
Reference in New Issue
Block a user