first change
This commit is contained in:
26
Modules/PMS/app/Exports/TaskExport.php
Normal file
26
Modules/PMS/app/Exports/TaskExport.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Modules\PMS\Exports;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
use Modules\PMS\Repositories\TaskRepository;
|
||||
|
||||
class TaskExport implements FromView
|
||||
{
|
||||
|
||||
protected $request;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
public function view(): View
|
||||
{
|
||||
$filters = $this->request;
|
||||
$tasks = (new TaskRepository())->findAll($filters);
|
||||
return view('pms::export.tasks', [
|
||||
'tasks' => $tasks,
|
||||
]);
|
||||
}
|
||||
}
|
0
Modules/PMS/app/Http/Controllers/.gitkeep
Normal file
0
Modules/PMS/app/Http/Controllers/.gitkeep
Normal file
67
Modules/PMS/app/Http/Controllers/CommentController.php
Normal file
67
Modules/PMS/app/Http/Controllers/CommentController.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('pms::index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('pms::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('pms::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('pms::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id): RedirectResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
187
Modules/PMS/app/Http/Controllers/KanbanColumnController.php
Normal file
187
Modules/PMS/app/Http/Controllers/KanbanColumnController.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\PMS\Models\KanbanColumn;
|
||||
use Modules\PMS\Repositories\KanbanColumnInterface;
|
||||
|
||||
class KanbanColumnController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
private $kanbanColumn;
|
||||
|
||||
public function __construct(KanbanColumnInterface $kanbanColumn)
|
||||
{
|
||||
$this->kanbanColumn = $kanbanColumn;
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
$data['editable'] = false;
|
||||
$data['title'] = 'Kanban Column Lists';
|
||||
$data['kanbanColumnLists'] = $this->kanbanColumn->findAll();
|
||||
return view('pms::kanbanColumn.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|unique:kanban_columns,name',
|
||||
'category' => 'required|in:pending,backlog,in_progress,completed,on_hold,cancelled'
|
||||
]);
|
||||
|
||||
$request->merge([
|
||||
'position' => KanbanColumn::max('position') + 1 ?? 1,
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
$errors = implode(', ', $validator->errors()->all());
|
||||
flash()->addError($errors);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
try {
|
||||
|
||||
$taskModel = $this->kanbanColumn->create($request->all());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $taskModel,
|
||||
'msg' => 'Task Created Created',
|
||||
]);
|
||||
}
|
||||
flash()->addSuccess('Kanban Column Created');
|
||||
return redirect()->back();
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
]);
|
||||
}
|
||||
flash()->addError($th->getMessage());
|
||||
return redirect()->back()->withError($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$data['title'] = 'View Kanban Column';
|
||||
$data['kanbanColumn'] = $this->kanbanColumn->getKanbanColumnById($id);
|
||||
return view('pms::kanbanColumn.show', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
$data['editable'] = true;
|
||||
$data['kanbanColumn'] = $this->kanbanColumn->getKanbanColumnById($id);
|
||||
return view('pms::kanbanColumn.partials.action', $data);
|
||||
}
|
||||
$data['editable'] = true;
|
||||
$data['title'] = 'Kanban Column Lists';
|
||||
$data['kanbanColumn'] = $this->kanbanColumn->getKanbanColumnById($id);
|
||||
$data['kanbanColumnLists'] = $this->kanbanColumn->findAll();
|
||||
return view('pms::kanbanColumn.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'position' => 'required|integer',
|
||||
'name' => 'required|unique:kanban_columns,name,' . $id,
|
||||
'category' => 'required|in:pending,backlog,in_progress,completed,on_hold,cancelled'
|
||||
]);
|
||||
|
||||
try {
|
||||
$kanbanColumn = $this->kanbanColumn->getKanbanColumnById($id);
|
||||
|
||||
$items = KanbanColumn::whereNot('id', $kanbanColumn->id)->orderBy('position')->get();
|
||||
|
||||
DB::transaction(function () use ($kanbanColumn, $items, $request) {
|
||||
|
||||
$items->splice($request->position - 1, 0, [$kanbanColumn]);
|
||||
|
||||
$items = $items->values();
|
||||
|
||||
foreach ($items as $index => $item) {
|
||||
$item->position = $index + 1;
|
||||
$item->save();
|
||||
}
|
||||
|
||||
$kanbanColumn->update($request->only(['name', 'color', 'category']));
|
||||
});
|
||||
|
||||
flash()->success('Kanban Column Updated Successfully');
|
||||
return redirect()->back();
|
||||
|
||||
} 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) {
|
||||
$column = KanbanColumn::findOrFail($id);
|
||||
$column->delete();
|
||||
|
||||
$items = KanbanColumn::where('position', '>', $column->position)
|
||||
->orderBy('position')
|
||||
->get();
|
||||
|
||||
foreach ($items as $item) {
|
||||
$item->position = $item->position - 1;
|
||||
$item->save();
|
||||
}
|
||||
});
|
||||
|
||||
flash()->success('Column has been deleted');
|
||||
return redirect()->back();
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
67
Modules/PMS/app/Http/Controllers/PMSController.php
Normal file
67
Modules/PMS/app/Http/Controllers/PMSController.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class PMSController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('pms::index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('pms::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('pms::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('pms::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id): RedirectResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
141
Modules/PMS/app/Http/Controllers/TaskCategoryController.php
Normal file
141
Modules/PMS/app/Http/Controllers/TaskCategoryController.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\PMS\Models\TaskCategory;
|
||||
use Modules\PMS\Repositories\TaskCategoryInterface;
|
||||
|
||||
class TaskCategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
private $taskCategory;
|
||||
|
||||
public function __construct(TaskCategoryInterface $taskCategory)
|
||||
{
|
||||
$this->taskCategory = $taskCategory;
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
$data['title'] = 'Task Category Lists';
|
||||
$data['taskCategoryLists'] = $this->taskCategory->findAll();
|
||||
return view('pms::task-category.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data['title'] = 'Create Task Category';
|
||||
$data['editable'] = false;
|
||||
$data['status'] = TaskCategory::STATUS;
|
||||
return view('pms::task-category.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => 'required',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
return to_route('taskCategory.create')->withError($validator->errors()->all());
|
||||
}
|
||||
try {
|
||||
if (!$request->has('status')) {
|
||||
$request->merge(['status' => 11]);
|
||||
}
|
||||
|
||||
$taskModel = $this->taskCategory->create($request->all());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $taskModel,
|
||||
'msg' => 'Task Created Created',
|
||||
]);
|
||||
}
|
||||
return redirect()->route('task.index')->withSucess('Task Category Created');
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
]);
|
||||
}
|
||||
return redirect()->route('task.index')->withError($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$data['title'] = 'View Task Category';
|
||||
$data['taskCategory'] = $this->taskCategory->getTaskCategoryById($id);
|
||||
return view('pms::task-category.show', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
try {
|
||||
$data['title'] = 'Edit Task Category';
|
||||
$data['editable'] = true;
|
||||
$data['status'] = TaskCategory::STATUS;
|
||||
$data['taskCategory'] = $this->taskCategory->getTaskCategoryById($id);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
}
|
||||
|
||||
return view('pms::task-category.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$this->taskCategory->update($id, $request->except(['_method', '_token']));
|
||||
flash()->success('Task Category Updated Successfully');
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
}
|
||||
return redirect()->route('task.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$this->taskCategory->delete($id);
|
||||
flash()->success('Task Category Deleted Successfully');
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
627
Modules/PMS/app/Http/Controllers/TaskController.php
Normal file
627
Modules/PMS/app/Http/Controllers/TaskController.php
Normal file
@@ -0,0 +1,627 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Employee\Models\Employee;
|
||||
use Modules\Employee\Interfaces\EmployeeInterface;
|
||||
use Modules\PMS\Exports\TaskExport;
|
||||
use Modules\PMS\Models\KanbanColumn;
|
||||
use Modules\PMS\Models\Task;
|
||||
use Modules\PMS\Repositories\KanbanColumnInterface;
|
||||
use Modules\PMS\Repositories\TaskCategoryInterface;
|
||||
use Modules\PMS\Repositories\TaskInterface;
|
||||
use Modules\Product\Interfaces\ProductInterface;
|
||||
use Modules\Template\Emails\SendMail;
|
||||
use Modules\Template\Repositories\TemplateInterface;
|
||||
use Modules\Template\Repositories\TemplateRepository;
|
||||
use Modules\User\Services\UserService;
|
||||
|
||||
class TaskController extends Controller
|
||||
{
|
||||
private $task;
|
||||
private $project;
|
||||
private $employee;
|
||||
private $taskCategory;
|
||||
private $product;
|
||||
private $kanbanColumn;
|
||||
private $template;
|
||||
|
||||
public function __construct(
|
||||
TaskInterface $task,
|
||||
EmployeeInterface $employee,
|
||||
TaskCategoryInterface $taskCategory,
|
||||
KanbanColumnInterface $kanbanColumn,
|
||||
ProductInterface $product,
|
||||
TemplateInterface $template,
|
||||
) {
|
||||
$this->task = $task;
|
||||
$this->employee = $employee;
|
||||
$this->taskCategory = $taskCategory;
|
||||
$this->product = $product;
|
||||
$this->kanbanColumn = $kanbanColumn;
|
||||
$this->template = $template;
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$filters = $request->all();
|
||||
$data['title'] = 'Task List';
|
||||
$data['editable'] = false;
|
||||
$data['tasks'] = $this->task->findAll($filters);
|
||||
$data['products'] = $this->product->findAll();
|
||||
$data['taskCategories'] = $this->taskCategory->findAll();
|
||||
$data['memberList'] = $this->employee->pluck();
|
||||
$data['statusList'] = $this->kanbanColumn->pluck(function ($query) {
|
||||
$query->orderBy('position');
|
||||
});
|
||||
return view('pms::task.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data['title'] = 'Create Task';
|
||||
$data['editable'] = false;
|
||||
$data['status'] = $this->kanbanColumn->pluck(function ($query) {
|
||||
$query->orderBy('position');
|
||||
});
|
||||
$data['priority'] = Task::PRIORITY;
|
||||
$data['product'] = $this->product->pluck();
|
||||
$data['memberList'] = $this->employee->pluck();
|
||||
$data['categoryList'] = $this->taskCategory->pluck();
|
||||
|
||||
return view('pms::task.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return to_route('task.create')->withError($validator->errors()->all());
|
||||
}
|
||||
|
||||
$inputData = $request->except(['_token', 'file']);
|
||||
|
||||
$task = $this->task->create($inputData);
|
||||
$statusName = $this->task->getTaskById($task->id)->statusName['status'];
|
||||
if ($request->hasFile('file')) {
|
||||
$path = 'uploads/task';
|
||||
$inputData['file'] = uploadImage($request->file, $path);
|
||||
$task->documents()->updateOrCreate([
|
||||
'documentable_id' => $task->id,
|
||||
'documentable_type' => 'Modules\PMS\Models\Task',
|
||||
], [
|
||||
'document_name' => 'Task Files',
|
||||
'document_path' => $inputData['file'],
|
||||
]);
|
||||
}
|
||||
$createdBy = UserService::getUserById($task->createdby);
|
||||
|
||||
$user = $task->assignedUser;
|
||||
|
||||
if (config('app.send_mail')) {
|
||||
$templateModel = (new TemplateRepository())->where(['alias' => 'task-assignee-template'])->first();
|
||||
$message = $templateModel->message;
|
||||
|
||||
$message = str_replace('#image', asset('storage/' . setting('logo_pic')), $message);
|
||||
$message = str_replace('#task_subject', $task->title, $message);
|
||||
$message = str_replace('#assigned_by', $createdBy->name, $message);
|
||||
$message = str_replace('#task_desc', $task->desc, $message);
|
||||
$message = str_replace('#task_deadline', $task->due_date, $message);
|
||||
|
||||
$data = [
|
||||
'subject' => 'New Task Created',
|
||||
'body' => $message,
|
||||
];
|
||||
Mail::to($user)->send(new SendMail($data));
|
||||
}
|
||||
|
||||
$priorityLabel = Task::PRIORITY[$inputData['priority']] ?? 'Unknown';
|
||||
$this->product->getProductById($inputData['product_id'])->client->createLog([
|
||||
'title' => 'Task Created',
|
||||
'data' => "Task titled '{$inputData['title']}' with an status '{$statusName}' has been created.",
|
||||
]);
|
||||
|
||||
foreach ($inputData['assigned_id'] as $employeeId) {
|
||||
$employee = $this->employee->getEmployeeById($employeeId);
|
||||
if (is_iterable($employee)) {
|
||||
foreach ($employee as $emp) {
|
||||
$emp->createLog([
|
||||
'title' => 'Task Has Been Assigned',
|
||||
'data' => "Task titled '{$inputData['title']}' with status '{$statusName}' and priority '{$priorityLabel}' has been created.",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$employee->user->createLog([
|
||||
'title' => 'Task Has Been Assigned',
|
||||
'data' => "Task titled '{$inputData['title']}' with status '{$statusName}' and priority '{$priorityLabel}' has been created.",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('task.index')->withSucess('Task Created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$data['title'] = 'View Task';
|
||||
$data['task'] = $this->task->getTaskById($id);
|
||||
$data['time'] = $data['task']->latest_task_time;
|
||||
$data['clientName'] = $this->product->getProductById($data['task']->product_id)->client->name;
|
||||
$data['status'] = $this->kanbanColumn->pluck(function ($query) {
|
||||
$query->orderBy('position');
|
||||
});
|
||||
$data['template'] = $this->template->pluck();
|
||||
return view('pms::task.show', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
||||
$data['title'] = 'Edit Task';
|
||||
$data['editable'] = true;
|
||||
$data['task'] = $this->task->getTaskById($id);
|
||||
$data['status'] = $this->kanbanColumn->pluck(function ($query) {
|
||||
$query->orderBy('position');
|
||||
});
|
||||
$data['priority'] = Task::PRIORITY;
|
||||
$data['categoryList'] = $this->taskCategory->pluck();
|
||||
$data['product'] = $this->product->pluck();
|
||||
$data['memberList'] = $this->employee->pluck();
|
||||
return view('pms::task.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$statusName = $this->task->getTaskById($id)->statusName['status'];
|
||||
$allAssignedIds = $request->assigned_id['ids'] ?? [];
|
||||
$currentAssignedIds = $this->task->getTaskById($id)->assigned_id['ids'] ?? [];
|
||||
$newAssignedEmployees = array_diff($allAssignedIds, $currentAssignedIds);
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return to_route('task.create')->withError($validator->errors()->all());
|
||||
}
|
||||
|
||||
$inputData = $request->except(['_method', '_token']);
|
||||
|
||||
try {
|
||||
// Updating Task
|
||||
$task = $this->task->update($id, $inputData);
|
||||
|
||||
// Handling File Upload
|
||||
if ($request->hasFile('file')) {
|
||||
$path = 'uploads/task';
|
||||
$inputData['file'] = uploadImage($request->file, $path);
|
||||
$task->documents()->updateOrCreate(
|
||||
[
|
||||
'documentable_id' => $task->id,
|
||||
'documentable_type' => 'Modules\Invoice\Models\ReceivedInvoice',
|
||||
],
|
||||
[
|
||||
'document_name' => 'Task Files',
|
||||
'document_path' => $inputData['file'],
|
||||
]
|
||||
);
|
||||
|
||||
// Log for file upload
|
||||
foreach ($currentAssignedIds as $empId) {
|
||||
$employee = Employee::find($empId);
|
||||
if ($employee) {
|
||||
$employee->user->createLog([
|
||||
'title' => 'Document Added',
|
||||
'data' => "A new document has been added to the task titled '{$task->title}'.",
|
||||
]);
|
||||
} else {
|
||||
flash()->addError("Employee with ID {$empId} not found while creating log for file upload.");
|
||||
}
|
||||
}
|
||||
$client = $this->product->getProductById($inputData['product_id'])->client;
|
||||
$client->createLog([
|
||||
'title' => 'Document Added',
|
||||
'data' => "A new document has been added to the task titled '{$task->title}'.",
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
// Creating Logs for Client
|
||||
$priority = Task::PRIORITY[$inputData['priority']] ?? 'Unknown';
|
||||
$client = $this->product->getProductById($inputData['product_id'])->client;
|
||||
if ($client) {
|
||||
$client->createLog([
|
||||
'title' => 'Task Updated',
|
||||
'data' => "Task titled '{$inputData['title']}' with status '{$statusName}' and priority '{$priority}' has been created.",
|
||||
]);
|
||||
} else {
|
||||
flash()->addError("Client not found for product ID {$inputData['product_id']}.");
|
||||
}
|
||||
|
||||
// Creating Logs for New Employees
|
||||
if ($newAssignedEmployees) {
|
||||
foreach ($newAssignedEmployees as $empId) {
|
||||
$employee = Employee::find($empId);
|
||||
if ($employee) {
|
||||
$employee->user->createLog([
|
||||
'title' => 'Task Assigned',
|
||||
'data' => "Task titled '{$inputData['title']}' with status '{$statusName}' and priority '{$priority}' has been created.",
|
||||
]);
|
||||
} else {
|
||||
flash()->addError("Employee with ID {$empId} not found while creating assignment log.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creating Logs for Current Employees
|
||||
if ($currentAssignedIds) {
|
||||
foreach ($currentAssignedIds as $empId) {
|
||||
$employee = Employee::find($empId);
|
||||
if ($employee) {
|
||||
$employee->user->createLog([
|
||||
'title' => 'Task Updated',
|
||||
'data' => "Task titled '{$inputData['title']}' with status '{$statusName}' and priority '{$priority}' has been created.",
|
||||
]);
|
||||
} else {
|
||||
flash()->addError("Employee with ID {$empId} not found while creating update log.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('task.index')->withSuccess('Task updated successfully.');
|
||||
} catch (\Throwable $th) {
|
||||
flash()->addError("Error while updating task: {$th->getMessage()}");
|
||||
return redirect()->route('task.index')->withErrors('Something went wrong, please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$this->task->delete($id);
|
||||
flash()->success('Task Deleted Succesfully');
|
||||
} catch (\Throwable $th) {
|
||||
flash()->error($th->getMessage());
|
||||
}
|
||||
return response()->json(['status' => true, 'message' => 'Task Delete Succesfully']);
|
||||
|
||||
}
|
||||
|
||||
public function kanban(Request $request)
|
||||
{
|
||||
$data['title'] = 'Kanban Board';
|
||||
$data['editable'] = false;
|
||||
$data['statusList'] = $this->kanbanColumn->pluck(function ($query) {
|
||||
$query->orderBy('position');
|
||||
});
|
||||
$data['memberList'] = $this->employee->pluck();
|
||||
|
||||
$data['columnsWithTasks'] = KanbanColumn::with([
|
||||
'tasks' => function ($query) use ($request) {
|
||||
$query->whereNull('parent_id');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('title', 'LIKE', "%$search%");
|
||||
}
|
||||
|
||||
if ($request->filled('status')) {
|
||||
$query->where('status', $request->status);
|
||||
}
|
||||
|
||||
if ($request->filled('priority')) {
|
||||
$query->where('priority', $request->priority);
|
||||
}
|
||||
|
||||
if ($request->filled('date')) {
|
||||
$dates = explode('to', $request->date);
|
||||
$startDate = trim($dates[0]);
|
||||
$endDate = isset($dates[1]) ? trim($dates[1]) : $startDate; // Handle single date or range
|
||||
$query->whereBetween('start_date', [$startDate, $endDate]);
|
||||
}
|
||||
|
||||
if ($request->filled('assigned_to')) {
|
||||
$query->whereJsonContains("assigned_id->ids", (string) $request->assigned_to);
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('employee')) {
|
||||
$assignedId = (string) auth()->user()->employee_id;
|
||||
$query->whereJsonContains('assigned_id->ids', $assignedId);
|
||||
}
|
||||
|
||||
$query->with('assignedUser:id,first_name,middle_name,last_name,profile_picture');
|
||||
},
|
||||
])
|
||||
// ->withCount('tasks')
|
||||
->orderBy('position')
|
||||
->get();
|
||||
// dd($data['columnsWithTasks']->toArray());
|
||||
$data['columnLists'] = KanbanColumn::select(DB::raw("id, LOWER(REPLACE(name, ' ', '-')) as slug"))
|
||||
->pluck('slug', 'id');
|
||||
|
||||
$data['taskCategories'] = $this->taskCategory->findAll();
|
||||
|
||||
return view('pms::task.kanban', $data);
|
||||
}
|
||||
|
||||
public function changeStatus(Request $request)
|
||||
{
|
||||
try {
|
||||
$taskModel = $this->task->getTaskById($request->id);
|
||||
$prevTaskStatus = Task::findOrFail($request->id)->statusName['status'];
|
||||
$client = $this->product->getProductById($taskModel->product_id)->client;
|
||||
$taskModel->status = $request->changeStatus;
|
||||
$taskModel->save();
|
||||
|
||||
$employeeIds = $taskModel->assigned_id['ids'];
|
||||
|
||||
// Creating logs for the client
|
||||
$client->createLog([
|
||||
'title' => 'Task Status Changed',
|
||||
'data' => "Task Title: {$taskModel->title} | Status: From {$prevTaskStatus} to {$taskModel->statusName['status']}",
|
||||
]);
|
||||
// Creating logs for each employee assigned to the task
|
||||
foreach ($employeeIds as $emp) {
|
||||
$employee = Employee::findOrFail($emp);
|
||||
$employee->user->createLog([
|
||||
'title' => 'Task Status Changed',
|
||||
'data' => "Task Title: {$taskModel->title} | Status: From {$prevTaskStatus} to {$taskModel->statusName['status']}",
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Status Changed',
|
||||
], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
], 400);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchComment($task_id)
|
||||
{
|
||||
$data['task'] = $this->task->getTaskById($task_id);
|
||||
return view('pms::task.partials.comment', $data);
|
||||
}
|
||||
|
||||
public function storeComment(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'content' => 'required',
|
||||
]);
|
||||
$task = $this->task->getTaskById($request->task_id);
|
||||
$task->comments()->create(['content' => $request->content, 'comment_by' => Auth::id()]);
|
||||
|
||||
$user = $task->assignedUser;
|
||||
|
||||
if (config('app.send_mail')) {
|
||||
$templateModel = (new TemplateRepository())->where(['alias' => 'comment-template'])->first();
|
||||
$message = $templateModel->message;
|
||||
|
||||
$message = str_replace('#image', asset('storage/' . setting('logo_pic')), $message);
|
||||
$message = str_replace('#content', $request->content, $message);
|
||||
|
||||
$data = [
|
||||
'subject' => 'New Comment Added on Your Task',
|
||||
'body' => $message,
|
||||
];
|
||||
|
||||
Mail::to($user)->send(new SendMail($data));
|
||||
}
|
||||
|
||||
// Creating Logs for Client and Employees
|
||||
$employeeIds = $this->task->getTaskById($request->task_id)->assigned_id['ids'];
|
||||
$commentPreview = substr($request->content, 0, 50);
|
||||
if (strlen($request->content) > 50) {
|
||||
$commentPreview .= '...';
|
||||
}
|
||||
|
||||
$task->product->client->createLog([
|
||||
'title' => 'Comment Added in Task: "' . $task->title . '"',
|
||||
'data' => 'Comment: ' . $commentPreview,
|
||||
]);
|
||||
|
||||
foreach ($employeeIds as $emp) {
|
||||
$employee = Employee::findOrFail($emp);
|
||||
$employee->user->createLog([
|
||||
'title' => 'New Comment Added in Task: "' . $task->title . '"',
|
||||
'data' => 'Comment: ' . $commentPreview,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Comment Store',
|
||||
], 200);
|
||||
|
||||
}
|
||||
|
||||
public function uploadFile(Request $request)
|
||||
{
|
||||
$task = $this->task->getTaskById($request->task_id);
|
||||
$client = $task->product->client;
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$path = 'uploads/task';
|
||||
$fileName = $request->file->getClientOriginalName();
|
||||
$filePath = uploadImage($request->file, $path);
|
||||
$task->documents()->create(['document_name' => $fileName, 'document_path' => $filePath]);
|
||||
}
|
||||
// Storing Logs for Client and Employees
|
||||
$client->createLog([
|
||||
'title' => "Document Uploaded",
|
||||
'data' => "For Task Title '{$task->title}'",
|
||||
]);
|
||||
|
||||
foreach ($task->assignedUser as $employee) {
|
||||
$employee->user->createLog([
|
||||
'title' => "Document Uploaded",
|
||||
'data' => "For Task Title '{$task->title}'",
|
||||
]);
|
||||
}
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'File Upload',
|
||||
], 200);
|
||||
|
||||
}
|
||||
|
||||
public function storeSubTask(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->merge(['status' => 10]);
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'start_date' => 'required',
|
||||
|
||||
]);
|
||||
$task = $this->task->create($request->all());
|
||||
|
||||
// Creating Logs for Client and Employees
|
||||
$employeeIds = $this->task->getTaskById($request->parent_id)->assigned_id['ids'];
|
||||
$taskTitle = $this->task->getTaskById($request->parent_id)->title;
|
||||
$client = $this->product->getProductById($this->task->getTaskById($request->parent_id)->product_id)->Client;
|
||||
$client->createLog([
|
||||
'title' => "Sub-Task Added.",
|
||||
'data' => "For Task Title '{$taskTitle}'",
|
||||
]);
|
||||
|
||||
foreach ($employeeIds as $emp) {
|
||||
$employee = Employee::findOrFail($emp);
|
||||
$employee->user->createLog([
|
||||
'title' => "Sub-Task Added.",
|
||||
'data' => "For Task Title '{$taskTitle}'",
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withSucess('Sub Task Created');
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->back()->withError($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function gantChart()
|
||||
{
|
||||
$data['title'] = 'Gantt Chart';
|
||||
return view('pms::task.gantt.chart', $data);
|
||||
|
||||
}
|
||||
|
||||
public function getGantChartTask(Request $request)
|
||||
{
|
||||
// try {
|
||||
$filters = $request->all();
|
||||
|
||||
$tasks = $this->task->getAllTasks($filters);
|
||||
// dd($tasks->toArray());
|
||||
$finalArr = [];
|
||||
foreach ($tasks as $key => $task) {
|
||||
$finalArr[] = [
|
||||
'taskID' => (string) $task->id,
|
||||
'taskName' => $task->title . ' (' . $task->project?->project_name . ')',
|
||||
'resource' => $task->title,
|
||||
'startDate' => $task->start_date,
|
||||
'endDate' => $task->due_date,
|
||||
'duration' => null,
|
||||
'percentComplete' => null,
|
||||
'dependencies' => null,
|
||||
];
|
||||
if (isset($task['subTask']) && !empty($task['subTask'])) {
|
||||
foreach ($task['subTask'] as $sub_task) {
|
||||
|
||||
array_push($finalArr, [
|
||||
'taskID' => (string) $sub_task->id,
|
||||
'taskName' => $sub_task->title,
|
||||
'resource' => $sub_task->title,
|
||||
'startDate' => $sub_task->start_date,
|
||||
'endDate' => $sub_task->due_date,
|
||||
'duration' => null,
|
||||
'percentComplete' => null,
|
||||
'dependencies' => (string) $task->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $finalArr,
|
||||
'msg' => 'Data fetched',
|
||||
], 200);
|
||||
// } catch (\Throwable $th) {
|
||||
// return response()->json([
|
||||
// 'status' => false,
|
||||
// 'msg' => $th->getMessage(),
|
||||
// ], 400);
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
public function export(Request $request)
|
||||
{
|
||||
return Excel::download(new TaskExport($request), 'tasks.xlsx');
|
||||
}
|
||||
|
||||
public function sendMail(Request $request)
|
||||
{
|
||||
try {
|
||||
$task = $this->task->getTaskById($request->task_id);
|
||||
$message = $request->message;
|
||||
// $message = str_replace('#name', $task->name, $message);
|
||||
// $message = str_replace('#email', $task->email, $message);
|
||||
|
||||
$data = [
|
||||
'subject' => $request->subject,
|
||||
'body' => $message,
|
||||
];
|
||||
|
||||
Mail::to($task->assignedUser)->send(new SendMail($data));
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Mail send successfully',
|
||||
], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
], 500);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
81
Modules/PMS/app/Http/Controllers/TaskTimeController.php
Normal file
81
Modules/PMS/app/Http/Controllers/TaskTimeController.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\PMS\Repositories\TaskInterface;
|
||||
use Modules\PMS\Repositories\TaskTimeInterface;
|
||||
|
||||
class TaskTimeController extends Controller
|
||||
{
|
||||
private $task;
|
||||
private $tasktime;
|
||||
|
||||
public function __construct(
|
||||
TaskInterface $task,
|
||||
TaskTimeInterface $tasktime
|
||||
) {
|
||||
$this->task = $task;
|
||||
$this->tasktime = $tasktime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
// $request->validate([
|
||||
// 'start_time' => 'required',
|
||||
// ]);
|
||||
$taskModel = $this->task->getTaskById($request->task_id);
|
||||
$taskTimeModel = $this->tasktime->getLatestTimeByTaskId($request->task_id);
|
||||
$start_time = is_null($taskTimeModel) ? '00:00:00' : $taskTimeModel->end_time;
|
||||
$taskModel->taskTime()->create(['start_time' => $start_time, 'end_time' => $request->time]);
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Time Store',
|
||||
], 200);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('pms::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('pms::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id): RedirectResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
171
Modules/PMS/app/Http/Controllers/TicketController.php
Normal file
171
Modules/PMS/app/Http/Controllers/TicketController.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Auth;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\PMS\Models\Ticket;
|
||||
use Modules\PMS\Repositories\TicketInterface;
|
||||
use Modules\Admin\Services\AdminService;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
private $ticketRepository;
|
||||
private $adminService;
|
||||
|
||||
public function __construct(TicketInterface $ticketRepository, AdminService $adminService)
|
||||
{
|
||||
$this->adminService = $adminService;
|
||||
$this->ticketRepository = $ticketRepository;
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$data['title'] = 'Ticket List';
|
||||
$data['tickets'] = $this->ticketRepository->findAll();
|
||||
$data['statusList'] = Ticket::STATUS;
|
||||
return view('pms::ticket.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data['title'] = 'Create Ticket';
|
||||
$data['statusList'] = Ticket::STATUS;
|
||||
$data['priority'] = Ticket::PRIORITY;
|
||||
$data['ticketType'] = Ticket::TICKET_TYPE;
|
||||
$data['departmentList'] = $this->adminService->pluckDepartments();
|
||||
|
||||
return view('pms::ticket.create', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$inputData = $request->all();
|
||||
|
||||
$ticket = $this->ticketRepository->create($inputData);
|
||||
if ($request->hasFile('file')) {
|
||||
$path = 'uploads/task';
|
||||
$inputData['file'] = uploadImage($request->file, $path);
|
||||
$ticket->documents()->updateOrCreate([
|
||||
'documentable_id' => $ticket->id,
|
||||
'documentable_type' => 'Modules\PMS\Models\Ticket',
|
||||
], [
|
||||
'document_name' => 'Ticket Files',
|
||||
'document_path' => $inputData['file'],
|
||||
]);
|
||||
}
|
||||
toastr()->success('Ticket Created Succesfully');
|
||||
return redirect()->route('ticket.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$data['title'] = 'View Ticket';
|
||||
$data['tickets'] = $this->ticketRepository->getTicketById($id);
|
||||
$data['status'] = Ticket::STATUS;
|
||||
$data['priority'] = Ticket::PRIORITY;
|
||||
$data['ticketType'] = Ticket::TICKET_TYPE;
|
||||
return view('pms::ticket.show', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$data['title'] = 'Edit Ticket';
|
||||
$data['ticket'] = $this->ticketRepository->getTicketById($id);
|
||||
|
||||
return view('pms::ticket.edit', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id): RedirectResponse
|
||||
{
|
||||
$inputData = $request->except(['_method', '_token']);
|
||||
try {
|
||||
$this->ticketRepository->update($id, $inputData);
|
||||
toastr()->success('Ticket Update Succesfully');
|
||||
} catch (\Throwable $th) {
|
||||
toastr()->error($th->getMessage());
|
||||
}
|
||||
return redirect()->route('ticket.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$this->ticketRepository->delete($id);
|
||||
toastr()->success('Ticket Deleted Succesfully');
|
||||
} catch (\Throwable $th) {
|
||||
toastr()->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function storeComment(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'content' => 'required',
|
||||
]);
|
||||
$ticket = $this->ticketRepository->getTicketById($request->tickets_id);
|
||||
$ticket->comments()->create(['content' => $request->content, 'comment_by' => Auth::id()]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function uploadFile(Request $request)
|
||||
{
|
||||
$task = $this->ticketRepository->getTicketById($request->task_id);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$path = 'uploads/ticket1';
|
||||
$fileName = $request->file->getClientOriginalName();
|
||||
$filePath = uploadImage($request->file, $path);
|
||||
$task->documents()->create(['document_name' => $fileName, 'document_path' => $filePath]);
|
||||
|
||||
}
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'File Upload',
|
||||
], 200);
|
||||
|
||||
}
|
||||
|
||||
public function changeStatus(Request $request)
|
||||
{
|
||||
try {
|
||||
$taskModel = $this->ticketRepository->getTicketById($request->id);
|
||||
$taskModel->status = $request->changeStatus;
|
||||
$taskModel->save();
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Status Changed',
|
||||
], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => $th->getMessage(),
|
||||
], 400);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
0
Modules/PMS/app/Http/Requests/.gitkeep
Normal file
0
Modules/PMS/app/Http/Requests/.gitkeep
Normal file
26
Modules/PMS/app/Http/Requests/ClientRequest.php
Normal file
26
Modules/PMS/app/Http/Requests/ClientRequest.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ClientRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
0
Modules/PMS/app/Models/.gitkeep
Normal file
0
Modules/PMS/app/Models/.gitkeep
Normal file
38
Modules/PMS/app/Models/Comment.php
Normal file
38
Modules/PMS/app/Models/Comment.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Comment extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = ['content', 'comment_by'];
|
||||
|
||||
// protected $casts = [
|
||||
// 'created_at' => 'datetime',
|
||||
// ];
|
||||
|
||||
protected function createdAtFormatted(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn($value, $attributes) => Carbon::parse($attributes['created_at'])->format('d, M Y H:i'),
|
||||
);
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->morphMany(Comment::class, 'commentable');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'comment_by');
|
||||
}
|
||||
}
|
23
Modules/PMS/app/Models/KanbanColumn.php
Normal file
23
Modules/PMS/app/Models/KanbanColumn.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Modules\PMS\Database\Factories\KanbanColumnFactory;
|
||||
|
||||
class KanbanColumn extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public function tasks()
|
||||
{
|
||||
return $this->hasMany(Task::class,'status');
|
||||
}
|
||||
|
||||
}
|
42
Modules/PMS/app/Models/Project.php
Normal file
42
Modules/PMS/app/Models/Project.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
use App\Traits\StatusTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Modules\Admin\Models\Department;
|
||||
use Modules\Employee\Models\Employee;
|
||||
|
||||
class Project extends Model
|
||||
{
|
||||
use StatusTrait, CreatedUpdatedBy;
|
||||
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
|
||||
protected $table = 'tbl_projects';
|
||||
protected $fillable = ['project_code', 'project_name', 'client_id', 'department_id', 'project_category_id', 'members_id', 'start_date', 'end_date', 'summary', 'key_notes', 'status', 'createdBy', 'updatedBy'];
|
||||
protected $appends = ['status_name'];
|
||||
|
||||
protected $casts = [
|
||||
'members_id' => 'json',
|
||||
];
|
||||
const CATEGORY = [
|
||||
10 => 'Vue',
|
||||
11 => 'Laravel',
|
||||
];
|
||||
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(Client::class, 'client_id');
|
||||
}
|
||||
|
||||
public function projectCategory()
|
||||
{
|
||||
return $this->belongsTo(ProjectCategory::class, 'project_category_id');
|
||||
}
|
||||
|
||||
public function members()
|
||||
{
|
||||
return $this->belongsToJson(Employee::class, 'members_id->id');
|
||||
}
|
||||
|
||||
}
|
17
Modules/PMS/app/Models/ProjectCategory.php
Normal file
17
Modules/PMS/app/Models/ProjectCategory.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
use App\Traits\StatusTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ProjectCategory extends Model
|
||||
{
|
||||
use HasFactory, StatusTrait, CreatedUpdatedBy;
|
||||
|
||||
public $appends = ['status_name'];
|
||||
protected $table = 'tbl_project_categories';
|
||||
protected $fillable = ['title', 'desc'];
|
||||
}
|
117
Modules/PMS/app/Models/Task.php
Normal file
117
Modules/PMS/app/Models/Task.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use App\Models\Document;
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Modules\Employee\Models\Employee;
|
||||
use Modules\Product\Models\Product;
|
||||
|
||||
class Task extends Model
|
||||
{
|
||||
use CreatedUpdatedBy;
|
||||
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
|
||||
|
||||
protected $table = 'tbl_tasks';
|
||||
protected $guarded = [];
|
||||
protected $appends = ['status_name', 'priority_status'];
|
||||
|
||||
// const CATEGORY = [
|
||||
// 10 => 'Vue',
|
||||
// 11 => 'Laravel',
|
||||
// ];
|
||||
|
||||
const PRIORITY = [
|
||||
10 => 'High',
|
||||
11 => 'Meduim',
|
||||
12 => 'Low',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'assigned_id' => 'json',
|
||||
];
|
||||
|
||||
protected function statusName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
$kanbanColumn = KanbanColumn::where('id',$attributes['status'])->first();
|
||||
return collect([
|
||||
'status' => $kanbanColumn->name ?? 'N/A',
|
||||
'color' => $kanbanColumn->name ?? '#808080'
|
||||
]);
|
||||
},
|
||||
|
||||
set: fn($value) => $value,
|
||||
);
|
||||
}
|
||||
|
||||
protected function priorityStatus(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
switch ($attributes['priority']) {
|
||||
case '10':
|
||||
return '<span class="badge bg-danger">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
case '11':
|
||||
return '<span class="badge bg-info">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
case '12':
|
||||
return '<span class="badge bg-primary">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
},
|
||||
set: fn($value) => $value,
|
||||
);
|
||||
}
|
||||
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'product_id');
|
||||
}
|
||||
|
||||
public function subTask()
|
||||
{
|
||||
return $this->hasMany(Task::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function taskTime()
|
||||
{
|
||||
return $this->hasMany(TaskTime::class, 'task_id');
|
||||
}
|
||||
|
||||
public function latest_task_time()
|
||||
{
|
||||
return $this->hasOne(TaskTime::class, 'task_id')->latestOfMany();
|
||||
}
|
||||
|
||||
public function assignedUser()
|
||||
{
|
||||
return $this->belongsToJson(Employee::class, 'assigned_id->ids');
|
||||
}
|
||||
|
||||
public function taskCategory()
|
||||
{
|
||||
return $this->belongsTo(TaskCategory::class, 'task_category_id');
|
||||
}
|
||||
|
||||
public function documents(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Document::class, 'documentable');
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->morphMany(Comment::class, 'commentable');
|
||||
}
|
||||
|
||||
public function column()
|
||||
{
|
||||
return $this->belongsTo(KanbanColumn::class, 'status');
|
||||
}
|
||||
|
||||
}
|
25
Modules/PMS/app/Models/TaskCategory.php
Normal file
25
Modules/PMS/app/Models/TaskCategory.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Modules\PMS\Database\Factories\TaskCategoryFactory;
|
||||
use App\Traits\StatusTrait;
|
||||
use App\Traits\CreatedUpdatedBy;
|
||||
|
||||
|
||||
class TaskCategory extends Model
|
||||
{
|
||||
use HasFactory, StatusTrait, CreatedUpdatedBy;
|
||||
|
||||
public $appends = ['status_name'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $table = 'tbl_task_categories';
|
||||
|
||||
protected $fillable = ['title', 'desc'];
|
||||
|
||||
}
|
20
Modules/PMS/app/Models/TaskTime.php
Normal file
20
Modules/PMS/app/Models/TaskTime.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TaskTime extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $table = 'tbl_task_times';
|
||||
protected $fillable = ['task_id', 'start_time', 'end_time'];
|
||||
|
||||
public function task()
|
||||
{
|
||||
return $this->belongsTo(Task::class, 'task_id');
|
||||
}
|
||||
}
|
140
Modules/PMS/app/Models/Ticket.php
Normal file
140
Modules/PMS/app/Models/Ticket.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Models\Document;
|
||||
use Modules\Admin\Models\Department;
|
||||
use Modules\Employee\Models\Employee;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
class Ticket extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $table = 'tbl_tickets';
|
||||
// protected $fillable = ['subject', 'employee_id', 'department_id', 'assign_group_id', 'project_id', 'desc', 'file', 'ticket_type', 'status', 'priority'];
|
||||
protected $guarded = [];
|
||||
|
||||
protected $appends = ['status_name', 'priority_status', 'ticket_type'];
|
||||
|
||||
const STATUS = [
|
||||
10 => 'Pending',
|
||||
11 => 'Approved',
|
||||
12 => 'Rejected',
|
||||
];
|
||||
const PRIORITY = [
|
||||
10 => 'High',
|
||||
11 => 'Meduim',
|
||||
12 => 'Low',
|
||||
];
|
||||
|
||||
const TICKET_TYPE = [
|
||||
11 => 'Management',
|
||||
12 => 'Boxes',
|
||||
13 => 'Assets'
|
||||
];
|
||||
protected function statusName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
switch ($attributes['status']) {
|
||||
case '10':
|
||||
$color = 'danger';
|
||||
break;
|
||||
case '11':
|
||||
$color = 'info';
|
||||
break;
|
||||
case '12':
|
||||
$color = 'primary';
|
||||
break;
|
||||
case '13':
|
||||
$color = 'warning';
|
||||
break;
|
||||
case '14':
|
||||
$color = 'success';
|
||||
break;
|
||||
default:
|
||||
$color = 'light';
|
||||
break;
|
||||
}
|
||||
|
||||
return collect([
|
||||
'status' => self::STATUS[$attributes['status']],
|
||||
'color' => $color]);
|
||||
},
|
||||
set: fn($value) => $value,
|
||||
);
|
||||
}
|
||||
|
||||
protected function priorityStatus(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
switch ($attributes['priority']) {
|
||||
case '10':
|
||||
return '<span class="badge bg-danger">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
break;
|
||||
case '11':
|
||||
return '<span class="badge bg-info">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
break;
|
||||
case '12':
|
||||
return '<span class="badge bg-primary">' . self::PRIORITY[$attributes['priority']] . '</span>';
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
},
|
||||
set: fn($value) => $value,
|
||||
);
|
||||
}
|
||||
|
||||
protected function ticketType(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
switch ($attributes['ticket_type']) {
|
||||
case '11':
|
||||
return '<span class="badge bg-info">' . self::TICKET_TYPE[$attributes['ticket_type']] . '</span>';
|
||||
break;
|
||||
case '12':
|
||||
return '<span class="badge bg-info">' . self::TICKET_TYPE[$attributes['ticket_type']] . '</span>';
|
||||
break;
|
||||
case '13':
|
||||
return '<span class="badge bg-info">' . self::TICKET_TYPE[$attributes['ticket_type']] . '</span>';
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
},
|
||||
set: fn($value) => $value,
|
||||
);
|
||||
}
|
||||
public function project()
|
||||
{
|
||||
return $this->belongsTo(Project::class, 'project_id');
|
||||
}
|
||||
|
||||
public function employee()
|
||||
{
|
||||
return $this->belongsTo(Employee::class, 'employee_id');
|
||||
}
|
||||
public function department()
|
||||
{
|
||||
return $this->belongsTo(Department::class, 'department_id')->withDefault();
|
||||
}
|
||||
public function documents(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Document::class, 'documentable');
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->morphMany(Comment::class, 'commentable');
|
||||
}
|
||||
}
|
0
Modules/PMS/app/Observers/.gitkeep
Normal file
0
Modules/PMS/app/Observers/.gitkeep
Normal file
0
Modules/PMS/app/Providers/.gitkeep
Normal file
0
Modules/PMS/app/Providers/.gitkeep
Normal file
129
Modules/PMS/app/Providers/PMSServiceProvider.php
Normal file
129
Modules/PMS/app/Providers/PMSServiceProvider.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\PMS\Repositories\KanbanColumnInterface;
|
||||
use Modules\PMS\Repositories\KanbanColumnRepository;
|
||||
use Modules\PMS\Repositories\TaskCategoryInterface;
|
||||
use Modules\PMS\Repositories\TaskCategoryRepository;
|
||||
use Modules\PMS\Repositories\TaskInterface;
|
||||
use Modules\PMS\Repositories\TaskRepository;
|
||||
use Modules\PMS\Repositories\TaskTimeInterface;
|
||||
use Modules\PMS\Repositories\TaskTimeRepository;
|
||||
use Modules\PMS\Repositories\TicketInterface;
|
||||
use Modules\PMS\Repositories\TicketRepository;
|
||||
|
||||
class PMSServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected string $moduleName = 'PMS';
|
||||
|
||||
protected string $moduleNameLower = 'pms';
|
||||
|
||||
/**
|
||||
* Boot the application events.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->registerCommands();
|
||||
$this->registerCommandSchedules();
|
||||
$this->registerTranslations();
|
||||
$this->registerConfig();
|
||||
$this->registerViews();
|
||||
$this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(KanbanColumnInterface::class, KanbanColumnRepository::class);
|
||||
$this->app->bind(TaskCategoryInterface::class, TaskCategoryRepository::class);
|
||||
$this->app->bind(TicketInterface::class, TicketRepository::class);
|
||||
$this->app->bind(TaskInterface::class, TaskRepository::class);
|
||||
$this->app->bind(TaskTimeInterface::class, TaskTimeRepository::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->moduleNameLower);
|
||||
|
||||
if (is_dir($langPath)) {
|
||||
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
|
||||
$this->loadJsonTranslationsFrom($langPath);
|
||||
} else {
|
||||
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
|
||||
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register config.
|
||||
*/
|
||||
protected function registerConfig(): void
|
||||
{
|
||||
$this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower . '.php')], 'config');
|
||||
$this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register views.
|
||||
*/
|
||||
public function registerViews(): void
|
||||
{
|
||||
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
|
||||
$sourcePath = module_path($this->moduleName, 'resources/views');
|
||||
|
||||
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower . '-module-views']);
|
||||
|
||||
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
|
||||
|
||||
$componentNamespace = str_replace('/', '\\', config('modules.namespace') . '\\' . $this->moduleName . '\\' . ltrim(config('modules.paths.generator.component-class.path'), config('modules.paths.app_folder', '')));
|
||||
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->moduleNameLower)) {
|
||||
$paths[] = $path . '/modules/' . $this->moduleNameLower;
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
}
|
49
Modules/PMS/app/Providers/RouteServiceProvider.php
Normal file
49
Modules/PMS/app/Providers/RouteServiceProvider.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* 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('PMS', '/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('PMS', '/routes/api.php'));
|
||||
}
|
||||
}
|
0
Modules/PMS/app/Repositories/.gitkeep
Normal file
0
Modules/PMS/app/Repositories/.gitkeep
Normal file
14
Modules/PMS/app/Repositories/KanbanColumnInterface.php
Normal file
14
Modules/PMS/app/Repositories/KanbanColumnInterface.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
interface KanbanColumnInterface
|
||||
{
|
||||
public function findAll();
|
||||
public function getKanbanColumnById($clientId);
|
||||
public function delete($clientId);
|
||||
public function create($clientDetails);
|
||||
public function update($clientId, array $newDetails);
|
||||
public function pluck(callable $query = null);
|
||||
|
||||
}
|
43
Modules/PMS/app/Repositories/KanbanColumnRepository.php
Normal file
43
Modules/PMS/app/Repositories/KanbanColumnRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
use Modules\PMS\Models\KanbanColumn;
|
||||
|
||||
class KanbanColumnRepository implements KanbanColumnInterface
|
||||
{
|
||||
public function findAll()
|
||||
{
|
||||
return KanbanColumn::orderBy('position')->get();
|
||||
}
|
||||
|
||||
public function getKanbanColumnById($TaskCategoryId)
|
||||
{
|
||||
return KanbanColumn::findOrFail($TaskCategoryId);
|
||||
}
|
||||
|
||||
public function delete($TaskCategoryId)
|
||||
{
|
||||
KanbanColumn::destroy($TaskCategoryId);
|
||||
}
|
||||
|
||||
public function create($TaskCategoryDetails)
|
||||
{
|
||||
return KanbanColumn::create($TaskCategoryDetails);
|
||||
}
|
||||
|
||||
public function update($TaskCategoryId, array $newDetails)
|
||||
{
|
||||
return KanbanColumn::whereId($TaskCategoryId)->update($newDetails);
|
||||
}
|
||||
|
||||
public function pluck(callable $query = null)
|
||||
{
|
||||
$baseQuery = KanbanColumn::query();
|
||||
if (is_callable($query)) {
|
||||
$query($baseQuery);
|
||||
}
|
||||
|
||||
return $baseQuery->pluck('name', 'id')->all();
|
||||
}
|
||||
}
|
14
Modules/PMS/app/Repositories/TaskCategoryInterface.php
Normal file
14
Modules/PMS/app/Repositories/TaskCategoryInterface.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
interface TaskCategoryInterface
|
||||
{
|
||||
public function findAll();
|
||||
public function getTaskCategoryById($clientId);
|
||||
public function delete($clientId);
|
||||
public function create($clientDetails);
|
||||
public function update($clientId, array $newDetails);
|
||||
public function pluck();
|
||||
|
||||
}
|
37
Modules/PMS/app/Repositories/TaskCategoryRepository.php
Normal file
37
Modules/PMS/app/Repositories/TaskCategoryRepository.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
use Modules\PMS\Models\TaskCategory;
|
||||
|
||||
class TaskCategoryRepository implements TaskCategoryInterface
|
||||
{
|
||||
public function findAll()
|
||||
{
|
||||
return TaskCategory::get();
|
||||
}
|
||||
|
||||
public function getTaskCategoryById($TaskCategoryId)
|
||||
{
|
||||
return TaskCategory::findOrFail($TaskCategoryId);
|
||||
}
|
||||
|
||||
public function delete($TaskCategoryId)
|
||||
{
|
||||
TaskCategory::destroy($TaskCategoryId);
|
||||
}
|
||||
|
||||
public function create($TaskCategoryDetails)
|
||||
{
|
||||
return TaskCategory::create($TaskCategoryDetails);
|
||||
}
|
||||
|
||||
public function update($TaskCategoryId, array $newDetails)
|
||||
{
|
||||
return TaskCategory::whereId($TaskCategoryId)->update($newDetails);
|
||||
}
|
||||
public function pluck()
|
||||
{
|
||||
return TaskCategory::pluck('title', 'id');
|
||||
}
|
||||
}
|
19
Modules/PMS/app/Repositories/TaskInterface.php
Normal file
19
Modules/PMS/app/Repositories/TaskInterface.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
interface TaskInterface
|
||||
{
|
||||
public function findAll($filters = [], $limit = null, $offset = null);
|
||||
public function getTaskById($clientId);
|
||||
public function delete($clientId);
|
||||
public function create($clientDetails);
|
||||
public function update($clientId, array $newDetails);
|
||||
public function pluck();
|
||||
public function getAllTasks($filters = []);
|
||||
public function findAllWithRelations(array $relations = [], $limit = null);
|
||||
public function getTaskCountsByCategory($userId = null);
|
||||
|
||||
|
||||
// public function getTaskbyMembers($employee_id);
|
||||
}
|
116
Modules/PMS/app/Repositories/TaskRepository.php
Normal file
116
Modules/PMS/app/Repositories/TaskRepository.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\PMS\Models\KanbanColumn;
|
||||
use Modules\PMS\Models\Task;
|
||||
|
||||
class TaskRepository implements TaskInterface
|
||||
{
|
||||
public function findAll($filters = [], $limit = null, $offset = null)
|
||||
{
|
||||
return Task::when(true, function ($query) use ($filters) {
|
||||
$query->whereNull("parent_id");
|
||||
|
||||
if (isset($filters["search"])) {
|
||||
$search = $filters['search'];
|
||||
$query->whereAny(['title'], 'LIKE', "%$search%");
|
||||
}
|
||||
|
||||
if (isset($filters["status"])) {
|
||||
$query->where("status", $filters["status"]);
|
||||
}
|
||||
|
||||
if (isset($filters["priority"])) {
|
||||
$query->where("priority", $filters["priority"]);
|
||||
}
|
||||
|
||||
if (isset($filters["date"])) {
|
||||
$explodeDate = explode("to", $filters['date']);
|
||||
$query->whereBetween("start_date", [$explodeDate[0], preg_replace('/\s+/', '', $explodeDate[1])]);
|
||||
}
|
||||
|
||||
if (isset($filters["assigned_to"])) {
|
||||
$query->whereJsonContains("assigned_id->ids", (string) $filters['assigned_to']);
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('employee')) {
|
||||
$assigned_id = auth()->user()->employee_id;
|
||||
$query->whereJsonContains("assigned_id->ids", (string) $assigned_id);
|
||||
}
|
||||
|
||||
})
|
||||
->with('assignedUser:id,first_name,middle_name,last_name,profile_picture')
|
||||
->latest()
|
||||
->limit($limit)
|
||||
->get();
|
||||
}
|
||||
|
||||
public function getTaskById($TaskId)
|
||||
{
|
||||
return Task::findOrFail($TaskId);
|
||||
}
|
||||
|
||||
public function delete($TaskId)
|
||||
{
|
||||
Task::destroy($TaskId);
|
||||
}
|
||||
|
||||
public function create($TaskDetails)
|
||||
{
|
||||
return Task::create($TaskDetails);
|
||||
}
|
||||
|
||||
public function update($TaskId, array $newDetails)
|
||||
{
|
||||
return Task::whereId($TaskId)->update($newDetails);
|
||||
}
|
||||
|
||||
public function pluck()
|
||||
{
|
||||
return Task::pluck(DB::raw('CONCAT(first_name," ", middle_name , " ",last_name) AS full_name'), 'id');
|
||||
}
|
||||
|
||||
public function getAllTasks($filters = [])
|
||||
{
|
||||
return Task::with('subTask')->when(true, function ($query) use ($filters) {
|
||||
$query->whereNull("parent_id");
|
||||
if (isset($filters["project_id"])) {
|
||||
$query->where("project_id", $filters["project_id"]);
|
||||
}
|
||||
|
||||
if (isset($filters["date"])) {
|
||||
$explodeDate = explode("to", $filters['date']);
|
||||
$query->whereBetween("start_date", [$explodeDate[0], preg_replace('/\s+/', '', $explodeDate[1])]);
|
||||
}
|
||||
|
||||
})
|
||||
// ->latest()
|
||||
->get();
|
||||
}
|
||||
|
||||
public function findAllWithRelations(array $relations = [], $limit = null)
|
||||
{
|
||||
$query = Task::with($relations);
|
||||
if ($limit) {
|
||||
$query->limit($limit);
|
||||
}
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function getTaskCountsByCategory($userId = null)
|
||||
{
|
||||
$query = KanbanColumn::select('category', DB::raw('COUNT(tbl_tasks.id) as task_count'))
|
||||
->leftJoin('tbl_tasks', 'kanban_columns.id', '=', 'tbl_tasks.status');
|
||||
|
||||
// Filter by user ID if provided
|
||||
if ($userId) {
|
||||
$query->whereJsonContains('tbl_tasks.assigned_id->ids', (string) $userId);
|
||||
}
|
||||
|
||||
return $query->groupBy('kanban_columns.category')->get();
|
||||
}
|
||||
|
||||
|
||||
}
|
15
Modules/PMS/app/Repositories/TaskTimeInterface.php
Normal file
15
Modules/PMS/app/Repositories/TaskTimeInterface.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
interface TaskTimeInterface
|
||||
{
|
||||
public function findAll($filters = [], $limit = null, $offset = null);
|
||||
public function getTaskTimeById($clientId);
|
||||
public function delete($clientId);
|
||||
public function create($clientDetails);
|
||||
public function update($clientId, array $newDetails);
|
||||
public function pluck();
|
||||
public function getLatestTimeByTaskId($TaskId);
|
||||
|
||||
}
|
65
Modules/PMS/app/Repositories/TaskTimeRepository.php
Normal file
65
Modules/PMS/app/Repositories/TaskTimeRepository.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\PMS\Models\TaskTime;
|
||||
|
||||
class TaskTimeRepository implements TaskTimeInterface
|
||||
{
|
||||
public function findAll($filters = [], $limit = null, $offset = null)
|
||||
{
|
||||
return TaskTime::when(true, function ($query) use ($filters) {
|
||||
$query->whereNull("parent_id");
|
||||
|
||||
if (isset($filters["search"])) {
|
||||
$search = $filters['search'];
|
||||
$query->whereAny(['title'], 'LIKE', "%$search%");
|
||||
}
|
||||
|
||||
if (isset($filters["status"])) {
|
||||
$query->where("status", $filters["status"]);
|
||||
}
|
||||
|
||||
if (isset($filters["date"])) {
|
||||
$explodeDate = explode("to", $filters['date']);
|
||||
$query->whereBetween("start_date", [$explodeDate[0], preg_replace('/\s+/', '', $explodeDate[1])]);
|
||||
}
|
||||
|
||||
})
|
||||
->latest()
|
||||
->limit(5)
|
||||
->get();
|
||||
}
|
||||
|
||||
public function getTaskTimeById($TaskId)
|
||||
{
|
||||
return TaskTime::findOrFail($TaskId);
|
||||
}
|
||||
|
||||
public function delete($TaskId)
|
||||
{
|
||||
TaskTime::destroy($TaskId);
|
||||
}
|
||||
|
||||
public function create($TaskDetails)
|
||||
{
|
||||
return TaskTime::create($TaskDetails);
|
||||
}
|
||||
|
||||
public function update($TaskId, array $newDetails)
|
||||
{
|
||||
return TaskTime::whereId($TaskId)->update($newDetails);
|
||||
}
|
||||
|
||||
public function pluck()
|
||||
{
|
||||
return TaskTime::pluck(DB::raw('CONCAT(first_name," ", middle_name , " ",last_name) AS full_name'), 'id');
|
||||
}
|
||||
|
||||
public function getLatestTimeByTaskId($TaskId)
|
||||
{
|
||||
return TaskTime::where('task_id', $TaskId)->latest()->first();
|
||||
}
|
||||
|
||||
}
|
17
Modules/PMS/app/Repositories/TicketInterface.php
Normal file
17
Modules/PMS/app/Repositories/TicketInterface.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
|
||||
interface TicketInterface
|
||||
{
|
||||
public function findAll();
|
||||
|
||||
public function getTicketById($clientId);
|
||||
|
||||
public function delete($clientId);
|
||||
public function create($clientDetails);
|
||||
public function update($clientId, array $newDetails);
|
||||
public function pluck();
|
||||
public function count();
|
||||
|
||||
}
|
43
Modules/PMS/app/Repositories/TicketRepository.php
Normal file
43
Modules/PMS/app/Repositories/TicketRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\Repositories;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\PMS\Models\Ticket;
|
||||
|
||||
class TicketRepository implements TicketInterface
|
||||
{
|
||||
public function findAll()
|
||||
{
|
||||
return Ticket::paginate(20);
|
||||
|
||||
}
|
||||
|
||||
public function getTicketById($TicketId)
|
||||
{
|
||||
return Ticket::findOrFail($TicketId);
|
||||
}
|
||||
|
||||
public function delete($TicketId)
|
||||
{
|
||||
Ticket::destroy($TicketId);
|
||||
}
|
||||
|
||||
public function create($TicketDetails)
|
||||
{
|
||||
return Ticket::create($TicketDetails);
|
||||
}
|
||||
|
||||
public function update($TicketId, array $newDetails)
|
||||
{
|
||||
return Ticket::whereId($TicketId)->update($newDetails);
|
||||
}
|
||||
|
||||
public function pluck()
|
||||
{
|
||||
return Ticket::pluck('Ticket_name', 'id');
|
||||
}
|
||||
public function count()
|
||||
{
|
||||
return Ticket::count();
|
||||
}
|
||||
}
|
30
Modules/PMS/composer.json
Normal file
30
Modules/PMS/composer.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "nwidart/pms",
|
||||
"description": "",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Widart",
|
||||
"email": "n.widart@gmail.com"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [],
|
||||
"aliases": {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\PMS\\": "app/",
|
||||
"Modules\\PMS\\Database\\Factories\\": "database/factories/",
|
||||
"Modules\\PMS\\Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Modules\\PMS\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
0
Modules/PMS/config/.gitkeep
Normal file
0
Modules/PMS/config/.gitkeep
Normal file
5
Modules/PMS/config/config.php
Normal file
5
Modules/PMS/config/config.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'PMS',
|
||||
];
|
0
Modules/PMS/database/factories/.gitkeep
Normal file
0
Modules/PMS/database/factories/.gitkeep
Normal file
0
Modules/PMS/database/migrations/.gitkeep
Normal file
0
Modules/PMS/database/migrations/.gitkeep
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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('tbl_tasks', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title')->nullable();
|
||||
$table->unsignedBigInteger('parent_id')->nullable();
|
||||
$table->unsignedBigInteger('task_category_id')->nullable();
|
||||
$table->unsignedBigInteger('product_id')->nullable();
|
||||
$table->date('start_date')->nullable();
|
||||
$table->date('due_date')->nullable();
|
||||
$table->json('assigned_id')->nullable();
|
||||
$table->longText('desc')->nullable();
|
||||
$table->integer('status')->default(1);
|
||||
$table->integer('priority')->nullable();
|
||||
$table->unsignedBigInteger('createdby')->nullable();
|
||||
$table->unsignedBigInteger('updatedby')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tbl_tasks');
|
||||
}
|
||||
};
|
@@ -0,0 +1,37 @@
|
||||
<?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('tbl_tickets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('subject');
|
||||
$table->unsignedBigInteger('department_id')->nullable();
|
||||
$table->unsignedBigInteger('employee_id')->nullable();
|
||||
$table->unsignedBigInteger('assign_group_id')->nullable();
|
||||
$table->unsignedBigInteger('project_id')->nullable();
|
||||
$table->string('priority');
|
||||
$table->text('desc')->nullable();
|
||||
$table->string('file')->nullable();
|
||||
$table->string('ticket_type')->nullable();
|
||||
$table->integer('status')->default(11);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tbl_tickets');
|
||||
}
|
||||
};
|
@@ -0,0 +1,31 @@
|
||||
<?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('comments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->text('content')->nullable();
|
||||
$table->unsignedBigInteger('comment_by')->nullable();
|
||||
$table->unsignedBigInteger('commentable_id')->nullable();
|
||||
$table->string('commentable_type')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('comments');
|
||||
}
|
||||
};
|
@@ -0,0 +1,33 @@
|
||||
<?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('tbl_task_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title')->nullable();
|
||||
$table->string('alias')->nullable();
|
||||
$table->longText('desc')->nullable();
|
||||
$table->integer('status')->default(11);
|
||||
$table->unsignedBigInteger('createdBy')->nullable();
|
||||
$table->unsignedBigInteger('updatedBy')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tbl_task_categories');
|
||||
}
|
||||
};
|
@@ -0,0 +1,30 @@
|
||||
<?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('tbl_task_times', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('task_id')->nullable();
|
||||
$table->time('start_time')->nullable();
|
||||
$table->time('end_time')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tbl_task_times');
|
||||
}
|
||||
};
|
@@ -0,0 +1,30 @@
|
||||
<?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('kanban_columns', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('color')->nullable();
|
||||
$table->integer('position')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('kanban_columns');
|
||||
}
|
||||
};
|
@@ -0,0 +1,28 @@
|
||||
<?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::table('kanban_columns', function (Blueprint $table) {
|
||||
$table->string('category')->default('pending')->after('position');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('kanban_columns', function (Blueprint $table) {
|
||||
$table->dropColumn('category');
|
||||
});
|
||||
}
|
||||
};
|
0
Modules/PMS/database/seeders/.gitkeep
Normal file
0
Modules/PMS/database/seeders/.gitkeep
Normal file
16
Modules/PMS/database/seeders/PMSDatabaseSeeder.php
Normal file
16
Modules/PMS/database/seeders/PMSDatabaseSeeder.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\PMS\database\seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PMSDatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// $this->call([]);
|
||||
}
|
||||
}
|
11
Modules/PMS/module.json
Normal file
11
Modules/PMS/module.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "PMS",
|
||||
"alias": "pms",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
"providers": [
|
||||
"Modules\\PMS\\Providers\\PMSServiceProvider"
|
||||
],
|
||||
"files": []
|
||||
}
|
15
Modules/PMS/package.json
Normal file
15
Modules/PMS/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/PMS/resources/assets/.gitkeep
Normal file
0
Modules/PMS/resources/assets/.gitkeep
Normal file
0
Modules/PMS/resources/assets/js/app.js
Normal file
0
Modules/PMS/resources/assets/js/app.js
Normal file
0
Modules/PMS/resources/assets/sass/app.scss
Normal file
0
Modules/PMS/resources/assets/sass/app.scss
Normal file
0
Modules/PMS/resources/views/.gitkeep
Normal file
0
Modules/PMS/resources/views/.gitkeep
Normal file
17
Modules/PMS/resources/views/client_bak/create.blade.php
Normal file
17
Modules/PMS/resources/views/client_bak/create.blade.php
Normal file
@@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->form('POST')->route('client.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::client.partials.action')
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
21
Modules/PMS/resources/views/client_bak/edit.blade.php
Normal file
21
Modules/PMS/resources/views/client_bak/edit.blade.php
Normal file
@@ -0,0 +1,21 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->modelForm($client, 'PUT')->route('client.update', $client->id)->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
|
||||
@include('pms::client.partials.action')
|
||||
|
||||
{{ html()->closeModelForm() }}
|
||||
<!--end row-->
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
70
Modules/PMS/resources/views/client_bak/index.blade.php
Normal file
70
Modules/PMS/resources/views/client_bak/index.blade.php
Normal file
@@ -0,0 +1,70 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
|
||||
<div class="mb-2 text-end">
|
||||
@can('client.create')
|
||||
<a href="{{ route('client.create') }}" class="btn btn-primary btn-md waves-effect waves-light"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Add</a>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="datatable" class="display table-sm table-bordered table" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>S.N</th>
|
||||
<th>Client Name</th>
|
||||
<th>Email</th>
|
||||
<th>Company</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($clients as $key => $client)
|
||||
<tr>
|
||||
<td>{{ $key + 1 }}</td>
|
||||
<td>{{ $client->client_name }}</td>
|
||||
<td>{{ $client->email }}</td>
|
||||
<td>{{ $client->company_name }}</td>
|
||||
<td>{!! $client->status_name !!}</td>
|
||||
<td>
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
@can('client.show')
|
||||
<a href="{{ route('client.show', $client->id) }}" class="link-info fs-15">
|
||||
<i class="ri-eye-fill"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('client.edit')
|
||||
<a href="{{ route('client.edit', $client->id) }}" class="link-success fs-15 edit-item-btn"><i
|
||||
class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
@can('client.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('client.destroy', $client->id) }}"
|
||||
data-id="{{ $client->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
@endsection
|
108
Modules/PMS/resources/views/client_bak/partials/action.blade.php
Normal file
108
Modules/PMS/resources/views/client_bak/partials/action.blade.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row gy-3">
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Salutation')->class('form-label') }}
|
||||
{{ html()->select('salutation_id', $salutationList)->class('form-control select2')->placeholder('Select Salutation') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Client Name')->class('form-label') }}
|
||||
{{ html()->text('client_name')->class('form-control')->placeholder('Client Name') }}
|
||||
{{ html()->div('Please enter client name')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Email')->class('form-label') }}
|
||||
{{ html()->email('email')->class('form-control')->placeholder('Email Address')->required() }}
|
||||
{{ html()->div('Please enter email')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Gender')->class('form-label') }}
|
||||
{{ html()->select('gender_id', $genderList)->class('form-control select2')->placeholder('Select Gender') }}
|
||||
{{ html()->div('Please select gender')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Country')->class('form-label') }}
|
||||
{{ html()->select('country_id', $countryList)->class('form-control select2')->placeholder('Select Country') }}
|
||||
{{ html()->div('Please enter country')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Phone Number')->class('form-label') }}
|
||||
{{ html()->input($type = 'tel', $name = 'phone', $value = null)->class('form-control')->placeholder('+(977) 9812345678') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Company Name')->class('form-label') }}
|
||||
{{ html()->text('company_name')->class('form-control')->placeholder('Company Name') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Company Adress')->class('form-label') }}
|
||||
{{ html()->text('company_address')->class('form-control')->placeholder('Company Address') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control ckeditor-classic') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card -->
|
||||
<div class="mb-3 text-end">
|
||||
<x-form-buttons :editable="$editable" label="Add" href="{{ route('client.index') }}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
<div class="col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $status)->class('form-control')->required() }}
|
||||
{{ html()->div('Please select status')->class('invalid-feedback') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Profile Picture</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Image')->class('form-label visually-hidden') }}
|
||||
{{ html()->file('profile_pic')->class('form-control dropify')->attributes([
|
||||
'data-default-file' => $editable ? asset('storage/' . $client->profile_pic) : null,
|
||||
'data-height' => 200,
|
||||
]) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
<div class="card-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card -->
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
2091
Modules/PMS/resources/views/client_bak/show.blade.php
Normal file
2091
Modules/PMS/resources/views/client_bak/show.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
44
Modules/PMS/resources/views/export/tasks.blade.php
Normal file
44
Modules/PMS/resources/views/export/tasks.blade.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>S.N</th>
|
||||
<th>Task</th>
|
||||
<th>Product</th>
|
||||
<th>Start Date</th>
|
||||
<th>Deadline</th>
|
||||
<th>Assigned</th>
|
||||
<th>Priority</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($tasks as $key => $task)
|
||||
<tr>
|
||||
<td>{{ $key + 1 }}</td>
|
||||
<td>{{ $task->title }}</td>
|
||||
<td>{{ $task->product?->name }}</td>
|
||||
<td>{{ $task->start_date }}</td>
|
||||
@php
|
||||
$status = $task->status_name['status'];
|
||||
@endphp
|
||||
<td class="{{ $status === 'Completed' ? 'text-success' : ($status === 'Incomplete' ? 'text-danger' : '') }}">
|
||||
{{ $task->due_date }}
|
||||
</td>
|
||||
<td>
|
||||
@isset($task->assignedUser)
|
||||
@foreach ($task->assignedUser as $assignedId)
|
||||
<li>
|
||||
{{ $assignedId->full_name }} ,
|
||||
</li>
|
||||
@endforeach
|
||||
@endisset
|
||||
</td>
|
||||
<td>{!! $task->priority_status !!}</td>
|
||||
<td>
|
||||
{!! $task->status_name['status'] !!}
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
7
Modules/PMS/resources/views/index.blade.php
Normal file
7
Modules/PMS/resources/views/index.blade.php
Normal file
@@ -0,0 +1,7 @@
|
||||
@extends('pms::layouts.master')
|
||||
|
||||
@section('content')
|
||||
<h1>Hello World</h1>
|
||||
|
||||
<p>Module: {!! config('pms.name') !!}</p>
|
||||
@endsection
|
77
Modules/PMS/resources/views/kanbanColumn/index.blade.php
Normal file
77
Modules/PMS/resources/views/kanbanColumn/index.blade.php
Normal file
@@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">{{ isset($kanbanColumn) ? 'Edit' : 'Add' }} Column</h5>
|
||||
</div>
|
||||
|
||||
@include('pms::kanbanColumn.partials.action')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9">
|
||||
<div class="card">
|
||||
<div class="card-header align-items-center d-flex">
|
||||
<h5 class="card-title flex-grow-1 mb-0">{{ $title }}</h5>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{{ route('kanbanColumn.create') }}" class="btn btn-success waves-effect waves-light"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Create</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th class="tb-col"><span class="overline-title">S.N</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Column Name</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Column Color</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Position</span></th>
|
||||
<th class="tb-col" data-sortable="false"><span class="overline-title">Action</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($kanbanColumnLists as $index => $item)
|
||||
<tr>
|
||||
<td class="tb-col">{{ $index + 1 }}</td>
|
||||
<td class="tb-col">{{ $item->name }} </td>
|
||||
<td class="tb-col">
|
||||
<span>{{ $item->color }}</span>
|
||||
<span class="rounded-circle ms-2 border"
|
||||
style="background-color: {{ $item->color }}; width: 15px; height: 15px; display: inline-block;"></span>
|
||||
</td>
|
||||
|
||||
<td class="tb-col">{{ $item->position }}</td>
|
||||
<td class="tb-col">
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('kanbanColumn.show', $item->id) }}" class="link-info fs-15"><i
|
||||
class="ri-eye-fill"></i></a>
|
||||
@can('kanbanColumn.edit')
|
||||
<a href="{{ route('kanbanColumn.edit', $item->id) }}"
|
||||
class="link-success fs-15 edit-item-btn"><i class="ri-edit-2-line"></i></a>
|
||||
@endcan
|
||||
ri-edit-2-fill
|
||||
@can('kanbanColumn.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('kanbanColumn.destroy', $item->id) }}"
|
||||
data-id="{{ $item->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,54 @@
|
||||
{{ html()->modelForm($kanbanColumn ?? null, isset($kanbanColumn) ? 'PUT' : 'POST', isset($kanbanColumn) ? route('kanbanColumn.update', $kanbanColumn->id) : route('kanbanColumn.store'))->class('needs-validation')->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
|
||||
@isset($kanbanColumn)
|
||||
{{ html()->hidden('id', $kanbanColumn->id) }}
|
||||
@endisset
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row gy-3">
|
||||
<div class="col-12">
|
||||
{{ html()->label('Column Name')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('name')->class('form-control')->required() }}
|
||||
{{ html()->div('Please add column name')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
@isset($kanbanColumn)
|
||||
<div class="col-12">
|
||||
{{ html()->label('Board Column Position')->class('form-label') }}
|
||||
{{ html()->text('position')->class('form-control') }}
|
||||
{{ html()->div('Column Position')->class('invalid-feedback') }}
|
||||
</div>
|
||||
@endisset
|
||||
|
||||
<div class="col-12">
|
||||
{{ html()->label('Color')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->input('color', 'color')->class('form-control')->required() }}
|
||||
{{ html()->div('Please add color')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
{{ html()->label('Category')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->select('category', [
|
||||
'pending' => ' Approval pending',
|
||||
'backlog' => 'Backlog',
|
||||
'in_progress' => 'In Progress',
|
||||
'completed' => 'Completed',
|
||||
'on_hold' => 'On Hold',
|
||||
'cancelled' => 'Released'
|
||||
])->class('form-select')->required() }}
|
||||
{{ html()->div('Please select a category')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-12 text-end">
|
||||
{{ html()->a(route('task.index'), 'Cancel')->class('btn btn-danger btn-sm') }}
|
||||
{{ html()->button(isset($kanbanColumn) ? 'Update' : 'Add', 'Submit')->class('btn btn-success btn-sm') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ html()->closeModelForm() }}
|
||||
|
44
Modules/PMS/resources/views/kanbanColumn/show.blade.php
Normal file
44
Modules/PMS/resources/views/kanbanColumn/show.blade.php
Normal file
@@ -0,0 +1,44 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@use('Carbon\Carbon')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-body p-4">
|
||||
<div>
|
||||
<div class="table-responsive">
|
||||
<table class="table-borderless mb-0 table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Column Name</span></th>
|
||||
<td>{{ $kanbanColumn->name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Position</span></th>
|
||||
<td>{{$kanbanColumn->position}}</td>
|
||||
</tr>
|
||||
<th><span class="fw-medium">Color</span></th>
|
||||
<td>{{ $kanbanColumn->color }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('event.index') }}" class="btn btn-secondary w-sm">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
29
Modules/PMS/resources/views/layouts/master.blade.php
Normal file
29
Modules/PMS/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>PMS 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-pms', 'resources/assets/sass/app.scss') }} --}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@yield('content')
|
||||
|
||||
{{-- Vite JS --}}
|
||||
{{-- {{ module_vite('build-pms', 'resources/assets/js/app.js') }} --}}
|
||||
</body>
|
@@ -0,0 +1,6 @@
|
||||
{{ html()->form('POST')->route('projectCategory.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
@include('pms::project-category.partials.action', [
|
||||
'editable' => false,
|
||||
'status' => $projectCategoryStatus,
|
||||
])
|
||||
{{ html()->form()->close() }}
|
@@ -0,0 +1,3 @@
|
||||
{{ html()->modelForm($projectCategory, 'PUT')->route('projectCategory.update', $projectCategory->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
@include('pms::project-category.partials.action')
|
||||
{{ html()->form()->close() }}
|
128
Modules/PMS/resources/views/project-category/modal.blade.php
Normal file
128
Modules/PMS/resources/views/project-category/modal.blade.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<div id="myModal" class="modal fade" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">Project Category</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="hstack d-lfex justify-content-end mb-3 flex-wrap gap-2">
|
||||
@can('projectCategory.create')
|
||||
<a class="btn btn-secondary btn-sm" data-bs-toggle="collapse" href="#collapseExample" role="button"
|
||||
aria-expanded="true" aria-controls="collapseExample">
|
||||
Add
|
||||
</a>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
<div class="collapse" id="collapseExample">
|
||||
<fieldset class="rounded-1 mb-0">
|
||||
<legend>Project Category Form</legend>
|
||||
{{ html()->form('POST')->route('projectCategory.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Project Category Title')->required() }}
|
||||
{{ html()->div('Please enter title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $projectCategoryStatus)->class('form-control select')->placeholder('Select Status') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control')->placeholder('Project Category Description')->attributes(['rows' => 3]) }}
|
||||
</div>
|
||||
|
||||
<div class="justify-content-end d-flex mb-2">
|
||||
<button class="btn btn-sm btn-success waves-effect waves-light mt-2"> Save </button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th class="tb-col"><span class="overline-title">S.N</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Title</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Description</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Status</span></th>
|
||||
<th class="tb-col" data-sortable="false"><span class="overline-title">Action</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($projectCategory as $index => $item)
|
||||
<tr>
|
||||
<td class="tb-col">{{ $index + 1 }}</td>
|
||||
<td class="tb-col">{{ $item->title }}</td>
|
||||
<td class="tb-col">{{ $item->desc }}</td>
|
||||
<td class="tb-col">{!! $item->status_name !!}</td>
|
||||
<td class="tb-col">
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('projectCategory.show', $item->id) }}" class="link-info fs-15"><i
|
||||
class="ri-eye-fill"></i></a>
|
||||
@can('projectCategory.edit')
|
||||
<a href="javascript:void(0)" data-link="{{ route('projectCategory.edit', $item->id) }}"
|
||||
class="link-success fs-15 edit-category-btn"><i class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
|
||||
@can('projectCategory.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('projectCategory.destroy', $item->id) }}"
|
||||
data-id="{{ $item->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
<div id="editCategoryModal" class="modal fade" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">Add Project Category</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{-- @include('pms::project-category.create') --}}
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
$('body').on('click', '.edit-category-btn', function() {
|
||||
link = $(this).data('link');
|
||||
fetch(link)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
$('#editCategoryModal').find('.modal-body').html(html)
|
||||
$('#editCategoryModal').modal('show')
|
||||
console.log(html);
|
||||
// document.querySelector('.comment-box').innerHTML = html;
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@@ -0,0 +1,22 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Project Category Title')->required() }}
|
||||
{{ html()->div('Please enter title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $projectCategoryStatus)->class('form-control select')->placeholder('Select Status') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control')->placeholder('Project Category Description')->attributes(['rows' => 3]) }}
|
||||
</div>
|
||||
|
||||
<div class="justify-content-end d-flex mb-2">
|
||||
<button class="btn btn-sm btn-success waves-effect waves-light mt-2"> Save </button>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,6 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
</div>
|
||||
@endSection
|
17
Modules/PMS/resources/views/project/create.blade.php
Normal file
17
Modules/PMS/resources/views/project/create.blade.php
Normal file
@@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->form('POST')->route('project.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::project.partials.action')
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
19
Modules/PMS/resources/views/project/edit.blade.php
Normal file
19
Modules/PMS/resources/views/project/edit.blade.php
Normal file
@@ -0,0 +1,19 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->modelForm($project, 'PUT')->route('project.update', $project->id)->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::project.partials.action')
|
||||
{{ html()->closeModelForm() }}
|
||||
<!--end row-->
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
97
Modules/PMS/resources/views/project/index.blade.php
Normal file
97
Modules/PMS/resources/views/project/index.blade.php
Normal file
@@ -0,0 +1,97 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
|
||||
<div class="mb-2 text-end">
|
||||
@can('projectCategory.index')
|
||||
<button type="button" class="btn btn-info material-shadow-none" data-bs-toggle="modal" data-bs-target="#myModal"><i
|
||||
class="ri-align-right"></i></button>
|
||||
@endcan
|
||||
|
||||
@can('project.create')
|
||||
<a href="{{ route('project.create') }}" class="btn btn-success btn-md waves-effect waves-light"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Add</a>
|
||||
@endcan
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>S.N</th>
|
||||
<th>Code</th>
|
||||
<th>Project Name</th>
|
||||
<th>Members</th>
|
||||
<th>Start Date</th>
|
||||
<th>Deadline</th>
|
||||
<th>Client</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($projects as $key => $project)
|
||||
<tr>
|
||||
<td>{{ $key + 1 }}</td>
|
||||
<td>{{ $project->project_code }}</td>
|
||||
<td>{{ $project->project_name }}</td>
|
||||
<td>
|
||||
<div class="avatar-group flex-nowrap">
|
||||
@foreach ($project->members as $member)
|
||||
<div class="avatar-group-item">
|
||||
<a href="javascript:void(0);" class="d-inline-block" data-bs-toggle="tooltip"
|
||||
data-bs-trigger="hover" data-bs-placement="top" title="{{ $member->full_name }}">
|
||||
<img src="{{ $member->profile_pic }}" alt="" class="rounded-circle avatar-xxs">
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ $project->start_date }}</td>
|
||||
<td class="text-danger">{{ $project->end_date }}</td>
|
||||
<td>{{ optional($project->client)->client_name }}</td>
|
||||
<td>{!! $project->status_name !!}</td>
|
||||
<td>
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
@can('project.show')
|
||||
<a href="{{ route('project.show', $project->id) }}" class="link-info fs-15">
|
||||
<i class="ri-eye-fill"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('project.edit')
|
||||
<a href="{{ route('project.edit', $project->id) }}"
|
||||
class="link-success fs-15 edit-item-btn"><i class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
@can('project.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('project.destroy', $project->id) }}"
|
||||
data-id="{{ $project->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
|
||||
@include('pms::project-category.modal')
|
||||
@endsection
|
130
Modules/PMS/resources/views/project/partials/action.blade.php
Normal file
130
Modules/PMS/resources/views/project/partials/action.blade.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row gy-1">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Project Code')->class('form-label') }}
|
||||
{{ html()->text('project_code')->class('form-control')->placeholder('Enter Project Code')->required() }}
|
||||
{{ html()->div('Please enter project code')->class('invalid-feedback') }}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Project Name')->class('form-label') }}
|
||||
{{ html()->text('project_name')->class('form-control')->placeholder('Enter Project Name')->required() }}
|
||||
{{ html()->div('Please enter project name')->class('invalid-feedback') }}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Project Category')->class('form-label') }}
|
||||
{{ html()->select('project_category_id', $categoryList)->class('form-control select2')->placeholder('Select Project Category')->required() }}
|
||||
{{ html()->div('Please select project category')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Client')->class('form-label') }}
|
||||
{{ html()->select('client_id', $clientList)->class('form-control select2')->placeholder('Select Client')->required() }}
|
||||
{{ html()->div('Please select client')->class('invalid-feedback') }}
|
||||
|
||||
</div>
|
||||
|
||||
{{-- <div class="col-md-6">
|
||||
{{ html()->label('Department')->class('form-label') }}
|
||||
{{ html()->select('department_id', $departmentList)->class('form-control select2')->placeholder('Select Department') }}
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Summary')->class('form-label') }}
|
||||
{{ html()->textarea('summary')->class('form-control ckeditor-classic') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Key Notes')->class('form-label') }}
|
||||
{{ html()->textarea('key_notes')->class('form-control ckeditor-classic') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
|
||||
<!-- end card -->
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('project.index') }}" class="btn btn-danger w-sm">Cancel</a>
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $status)->class('form-control')->required() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Team Members</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->multiselect('members_id[ids][]', $memberList)->class('form-control select2')->value($project->members_id['ids'] ?? null)->attributes(['multiple']) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Date</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Start Date')->class('form-label') }}
|
||||
{{ html()->date('start_date')->class('form-control')->placeholder('Choose Start Date') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('End Date')->class('form-label') }}
|
||||
{{ html()->date('end_date')->class('form-control')->placeholder('Choose End Date') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
60
Modules/PMS/resources/views/project/show.blade.php
Normal file
60
Modules/PMS/resources/views/project/show.blade.php
Normal file
@@ -0,0 +1,60 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-body p-4">
|
||||
<div>
|
||||
<div class="table-responsive">
|
||||
<table class="table-borderless mb-0 table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Project Name</span></th>
|
||||
<td>{{ $project->project_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Code</span></th>
|
||||
<td>{{ $project->project_code }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Members</span></th>
|
||||
<td>
|
||||
<div class="avatar-group flex-nowrap">
|
||||
@foreach ($project->members as $memberId)
|
||||
<div class="avatar-group-item">
|
||||
<a href="javascript: void(0);" class="d-inline-block">
|
||||
<img src="{{ asset($memberId->profile_pic) }}" alt=""
|
||||
class="rounded-circle avatar-xxs">
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Summary</span></th>
|
||||
<td>{{ $project->summary }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('project.index') }}" class="btn btn-secondary w-sm">Back</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
16
Modules/PMS/resources/views/task-category/create.blade.php
Normal file
16
Modules/PMS/resources/views/task-category/create.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->form('POST')->route('taskCategory.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
|
||||
@include('pms::task-category.partials.action')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
11
Modules/PMS/resources/views/task-category/edit.blade.php
Normal file
11
Modules/PMS/resources/views/task-category/edit.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->modelForm($taskCategory, 'PUT')->route('taskCategory.update', $taskCategory->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
@include('pms::task-category.partials.action')
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
59
Modules/PMS/resources/views/task-category/index.blade.php
Normal file
59
Modules/PMS/resources/views/task-category/index.blade.php
Normal file
@@ -0,0 +1,59 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header align-items-center d-flex">
|
||||
<h5 class="card-title flex-grow-1 mb-0">{{ $title }}</h5>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{{ route('taskCategory.create') }}" class="btn btn-success waves-effect waves-light"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Create Task Category</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th class="tb-col"><span class="overline-title">S.N</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Title</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Description</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Status</span></th>
|
||||
<th class="tb-col" data-sortable="false"><span class="overline-title">Action</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($taskCategoryLists as $index => $item)
|
||||
<tr>
|
||||
<td class="tb-col">{{ $index + 1 }}</td>
|
||||
<td class="tb-col">{{ $item->title }}</td>
|
||||
<td class="tb-col">{{ $item->desc }}</td>
|
||||
<td class="tb-col">{!! $item->status_name !!}</td>
|
||||
<td class="tb-col">
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('taskCategory.show', $item->id) }}" class="link-info fs-15"><i
|
||||
class="ri-eye-fill"></i></a>
|
||||
@can('taskCategory.edit')
|
||||
<a href="{{ route('taskCategory.edit', $item->id) }}" class="link-success fs-15 edit-item-btn"><i
|
||||
class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
|
||||
@can('taskCategory.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('taskCategory.destroy', $item->id) }}"
|
||||
data-id="{{ $item->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
125
Modules/PMS/resources/views/task-category/modal.blade.php
Normal file
125
Modules/PMS/resources/views/task-category/modal.blade.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<div id="myModal" class="modal fade" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">Task Category</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@can('taskCategory.store')
|
||||
<div class="hstack d-lfex justify-content-end mb-3 flex-wrap gap-2">
|
||||
<a class="btn btn-secondary btn-sm" data-bs-toggle="collapse" href="#collapseExample" role="button"
|
||||
aria-expanded="true" aria-controls="collapseExample">
|
||||
Add
|
||||
</a>
|
||||
</div>
|
||||
@endcan
|
||||
|
||||
<div class="collapse" id="collapseExample">
|
||||
<fieldset class="rounded-1 mb-0">
|
||||
<legend>Task Category Form</legend>
|
||||
{{ html()->form('POST')->route('taskCategory.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Task Category Title')->required() }}
|
||||
{{ html()->div('Please enter title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', [])->class('form-control select')->placeholder('Select Status') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control')->placeholder('Task Category Description')->attributes(['rows' => 3]) }}
|
||||
</div>
|
||||
|
||||
<div class="justify-content-end d-flex mb-2">
|
||||
<button class="btn btn-sm btn-success waves-effect waves-light mt-2"> Save </button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th class="tb-col"><span class="overline-title">S.N</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Title</span></th>
|
||||
<th class="tb-col"><span class="overline-title">Status</span></th>
|
||||
<th class="tb-col" data-sortable="false"><span class="overline-title">Action</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($taskCategories as $index => $item)
|
||||
<tr>
|
||||
<td class="tb-col">{{ $index + 1 }}</td>
|
||||
<td class="tb-col">{{ $item->title }}</td>
|
||||
<td class="tb-col">{!! $item->status_name !!}</td>
|
||||
<td class="tb-col">
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
<a href="{{ route('taskCategory.show', $item->id) }}" class="link-info fs-15"><i
|
||||
class="ri-eye-fill"></i></a>
|
||||
@can('taskCategory.edit')
|
||||
<a href="{{ route('taskCategory.edit', $item->id) }}"><i class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
|
||||
@can('taskCategory.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('taskCategory.destroy', $item->id) }}"
|
||||
data-id="{{ $item->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
<div id="editCategoryModal" class="modal fade" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">Add Task Category</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{-- @include('pms::project-category.create') --}}
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
$('body').on('click', '.edit-category-btn', function() {
|
||||
link = $(this).data('link');
|
||||
fetch(link)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
$('#editCategoryModal').find('.modal-body').html(html)
|
||||
$('#editCategoryModal').modal('show')
|
||||
console.log(html);
|
||||
// document.querySelector('.comment-box').innerHTML = html;
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@@ -0,0 +1,48 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row gy-3">
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Task Category Title')->required() }}
|
||||
{{ html()->div('Please select Task Category Title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control')->placeholder('Task Category Description')->attributes(['rows' => 3]) }}
|
||||
</div>
|
||||
|
||||
<x-form-buttons :editable="$editable" label="Add" href="{{ route('taskCategory.index') }}" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $status)->class('form-control select2')->placeholder('Select Status') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
44
Modules/PMS/resources/views/task-category/show.blade.php
Normal file
44
Modules/PMS/resources/views/task-category/show.blade.php
Normal file
@@ -0,0 +1,44 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@use('Carbon\Carbon')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-body p-4">
|
||||
<div>
|
||||
<div class="table-responsive">
|
||||
<table class="table-borderless mb-0 table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Task Category Title</span></th>
|
||||
<td>{{ $taskCategory->title }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr>
|
||||
<th><span class="fw-medium">Status</span></th>
|
||||
<td>{!! $taskCategory->status_name !!}</td>
|
||||
</tr>
|
||||
<th><span class="fw-medium">Description</span></th>
|
||||
<td>{!! $taskCategory->desc !!}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('task.index') }}" class="btn btn-secondary w-sm">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
18
Modules/PMS/resources/views/task/create.blade.php
Normal file
18
Modules/PMS/resources/views/task/create.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->form('POST')->route('task.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::task.partials.action')
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
||||
|
17
Modules/PMS/resources/views/task/edit.blade.php
Normal file
17
Modules/PMS/resources/views/task/edit.blade.php
Normal file
@@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->modelForm($task, 'PUT')->route('task.update', $task->id)->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::task.partials.action')
|
||||
{{ html()->closeModelForm() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
120
Modules/PMS/resources/views/task/gantt/chart.blade.php
Normal file
120
Modules/PMS/resources/views/task/gantt/chart.blade.php
Normal file
@@ -0,0 +1,120 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@push('css')
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/libs/dragula/dragula.min.css') }}" />
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
@include('pms::task.gantt.filter')
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title mb-0">Gantt Chart</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart_div"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@push('js')
|
||||
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
||||
<script type="text/javascript">
|
||||
google.charts.load('current', {
|
||||
'packages': ['gantt']
|
||||
});
|
||||
google.charts.setOnLoadCallback(drawChart);
|
||||
|
||||
async function drawChart(formData) {
|
||||
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Task ID');
|
||||
data.addColumn('string', 'Task Name');
|
||||
data.addColumn('string', 'Resource');
|
||||
data.addColumn('date', 'Start Date');
|
||||
data.addColumn('date', 'End Date');
|
||||
data.addColumn('number', 'Duration');
|
||||
data.addColumn('number', 'Percent Complete');
|
||||
data.addColumn('string', 'Dependencies');
|
||||
|
||||
const fetchData = await getData(formData)
|
||||
|
||||
fetchData.data.forEach(element => {
|
||||
|
||||
const startDateParts = element.startDate.split('-');
|
||||
const endDateParts = element.endDate.split('-');
|
||||
|
||||
const startDate = new Date(startDateParts[0], startDateParts[1] - 1, startDateParts[2]);
|
||||
const endDate = new Date(endDateParts[0], endDateParts[1] - 1, endDateParts[2]);
|
||||
|
||||
data.addRow([
|
||||
element.taskID.toString(),
|
||||
element.taskName,
|
||||
element.resource,
|
||||
startDate,
|
||||
endDate,
|
||||
element.duration,
|
||||
element.percentComplete,
|
||||
element.dependencies
|
||||
]);
|
||||
});
|
||||
|
||||
var options = {
|
||||
height: 400,
|
||||
responsive: true,
|
||||
gantt: {
|
||||
trackHeight: 30
|
||||
}
|
||||
};
|
||||
|
||||
var chart = new google.visualization.Gantt(document.getElementById('chart_div'));
|
||||
|
||||
chart.draw(data, options);
|
||||
}
|
||||
|
||||
const getData = async (formData) => {
|
||||
const queryString = new URLSearchParams(formData).toString();
|
||||
return await fetch(`{{ route('task.getGantChartTask') }}?${queryString}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'url': '/task/get-gant-chart-ajax',
|
||||
"X-CSRF-Token": document.querySelector('input[name=_token]').value
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('There was a problem with the fetch operation:', error);
|
||||
});
|
||||
}
|
||||
|
||||
$('.ganttChartForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
formData = $(this).serialize();
|
||||
drawChart(formData);
|
||||
})
|
||||
|
||||
$('.btn-reset').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$('.ganttChartForm')[0].reset();
|
||||
drawChart();
|
||||
})
|
||||
|
||||
|
||||
$(window).resize(function() {
|
||||
drawChart();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
45
Modules/PMS/resources/views/task/gantt/filter.blade.php
Normal file
45
Modules/PMS/resources/views/task/gantt/filter.blade.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-8">
|
||||
{{ html()->form('GET')->route('task.getGantChartTask')->attributes(['class' => 'ganttChartForm'])->open() }}
|
||||
<div class="row g-3">
|
||||
|
||||
<div class="col-sm-6">
|
||||
<div class="">
|
||||
{{ html()->text('date')->class('form-control')->value(request('date'))->placeholder('Date Range')->attributes([
|
||||
'id' => 'datepicker-range',
|
||||
'data-provider' => 'flatpickr',
|
||||
'data-date-format' => 'Y-m-d',
|
||||
'data-range-date' => 'true',
|
||||
]) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div>
|
||||
{{ html()->select('project_id', $projectList)->placeholder('Select Project')->value(request('project_id'))->class('form-control select2') }}
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="d-flex flex-row gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="ri-equalizer-fill me-2"></i>Filter</button>
|
||||
<a href="javascript:void(0)" class="btn btn-danger btn-reset">
|
||||
<i class="ri-bin-fill me-2"></i>Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--end col-->
|
||||
</div>
|
||||
<!--end row-->
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
<!--end col-->
|
||||
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
</div>
|
99
Modules/PMS/resources/views/task/index.blade.php
Normal file
99
Modules/PMS/resources/views/task/index.blade.php
Normal file
@@ -0,0 +1,99 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
@include('pms::task.partials.filter')
|
||||
|
||||
@include('pms::task.partials.menu')
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="datatable" class="display table-sm table-bordered table" style="width:100%">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>S.N</th>
|
||||
<th>Task</th>
|
||||
<th>Product</th>
|
||||
<th>Start Date</th>
|
||||
<th>Deadline</th>
|
||||
<th>Assigned</th>
|
||||
<th>Priority</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($tasks as $key => $task)
|
||||
<tr>
|
||||
<td>{{ $key + 1 }}</td>
|
||||
<td> <a href="{{ route('task.show', $task->id) }}">
|
||||
{{ $task->title }}
|
||||
</a></td>
|
||||
<td>{{ $task->product?->name }}</td>
|
||||
<td>{{ $task->start_date }}</td>
|
||||
|
||||
<td>
|
||||
{{ $task->due_date }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="avatar-group flex-nowrap">
|
||||
@isset($task->assignedUser)
|
||||
@foreach ($task->assignedUser as $assignedId)
|
||||
<div class="avatar-group-item">
|
||||
<a href="javascript: void(0);" class="d-inline-block" data-bs-toggle="tooltip"
|
||||
data-bs-trigger="hover" data-bs-placement="top" title="{{ $assignedId->full_name }}">
|
||||
<img src="{{ asset($assignedId->profile_pic) }}" alt=""
|
||||
class="rounded-circle avatar-xxs">
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
@endisset
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td>{!! $task->priority_status !!}</td>
|
||||
<td>
|
||||
<span class="badge" style="background-color: {{ $task->column?->color }}">
|
||||
{{ $task->column?->name }} </span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
@can('task.show')
|
||||
<a href="{{ route('task.show', $task->id) }}" class="link-secondary fs-15">
|
||||
<i class="ri-eye-fill"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('task.edit')
|
||||
<a href="{{ route('task.edit', $task->id) }}" class="link-primary fs-15"><i
|
||||
class="ri-edit-2-fill"></i></a>
|
||||
@endcan
|
||||
@can('task.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('task.destroy', $task->id) }}"
|
||||
data-id="{{ $task->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@include('pms::task-category.modal')
|
||||
@include('pms::task.modal.task-status')
|
||||
@endsection
|
151
Modules/PMS/resources/views/task/kanban.blade.php
Normal file
151
Modules/PMS/resources/views/task/kanban.blade.php
Normal file
@@ -0,0 +1,151 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
@push('css')
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/libs/dragula/dragula.min.css') }}" />
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
@include('pms::task.partials.filter')
|
||||
|
||||
@include('pms::task.partials.menu')
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="tasks-board mb-3" id="kanbanboard">
|
||||
@foreach ($columnsWithTasks as $column)
|
||||
<div class="tasks-list border-end pe-3" data-status-key="{{ $column->id }}">
|
||||
<div class="d-flex border-bottom mb-2">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="fs-12 text-uppercase fw-semibold mb-0">{{ $column->name }} <small
|
||||
class="badge totaltask-badge ms-1 align-bottom"
|
||||
style="background: {{ $column->color }}">{{ (int) $column->tasks->count() }}</small>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="javascript:void(0);" class="text-muted" id="dropdownMenuLink12" data-bs-toggle="dropdown"
|
||||
aria-expanded="false"><i class="ri-more-fill"></i></a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink12">
|
||||
|
||||
@can('kanbanColumn.edit')
|
||||
<li><a class="dropdown-item edit-item-btn" href="javascript:void(0);"
|
||||
data-link="{{ route('kanbanColumn.edit', $column->id) }}"><i
|
||||
class="ri-edit-2-fill text-muted me-2 align-bottom"></i>
|
||||
Edit</a></li>
|
||||
@endcan
|
||||
|
||||
@can('kanbanColumn.destroy')
|
||||
<li><a class="dropdown-item remove-item-btn" href="javascript:void(0);"
|
||||
data-link="{{ route('kanbanColumn.destroy', $column->id) }}" data-id="{{ $column->id }}"><i
|
||||
class="ri-delete-bin-5-line text-muted me-2 align-bottom"></i>
|
||||
Delete</a></li>
|
||||
@endcan
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-simplebar class="tasks-wrapper mx-n3 px-3">
|
||||
<div id="{{ str()->slug($column->name) }}-task" @class(['tasks', 'noTask' => !$column->tasks()->exists()])>
|
||||
@foreach ($column->tasks as $task)
|
||||
<div class="card tasks-box" data-id="{{ $task->id }}">
|
||||
<div class="card-body">
|
||||
<div class="d-flex border-bottom mb-3">
|
||||
<div class="flex-grow-1 flex-wrap">
|
||||
<h6 class="fs-15 text-truncate task-title mb-0"><a
|
||||
href="{{ route('task.show', $task->id) }}" class="d-block">{{ $task->title }}</a>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="javascript:void(0);" class="text-muted" id="dropdownMenuLink12"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"><i class="ri-more-fill"></i></a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink12">
|
||||
@can('task.show')
|
||||
<li><a class="dropdown-item" href="{{ route('task.show', $task->id) }}"><i
|
||||
class="ri-eye-fill text-muted me-2 align-bottom"></i>
|
||||
View</a></li>
|
||||
@endcan
|
||||
@can('task.edit')
|
||||
<li><a class="dropdown-item" href="{{ route('task.edit', $task->id) }}"><i
|
||||
class="ri-edit-2-fill text-muted me-2 align-bottom"></i>
|
||||
Edit</a></li>
|
||||
@endcan
|
||||
@can('task.destroy')
|
||||
<li><a class="dropdown-item remove-item-btn" href="javascript:void(0);"
|
||||
data-link="{{ route('task.destroy', $task->id) }}" data-id="{{ $task->id }}"><i
|
||||
class="ri-delete-bin-5-line text-muted me-2 align-bottom"></i>
|
||||
Delete</a></li>
|
||||
@endcan
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@if ($task->desc)
|
||||
<span class="fs-14 mb-0">
|
||||
{!! Str::limit($task->desc, 150) !!}
|
||||
</span>
|
||||
@endif
|
||||
<p class="fs-14 mb-0"><i class="ri-stack-line"></i>{{ $task->product?->name }}</p>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-grow-1">
|
||||
<span
|
||||
class="badge bg-secondary-subtle text-dark fs-12"><em>{{ $task->taskCategory?->title }}</em></span>
|
||||
</div>
|
||||
|
||||
<div class="flex-shrink-0">
|
||||
<div class="avatar-group">
|
||||
@foreach ($task->assignedUser as $assignedId)
|
||||
<a href="javascript: void(0);" class="avatar-group-item" data-bs-toggle="tooltip"
|
||||
data-bs-trigger="hover" data-bs-placement="top" title="{{ $assignedId->full_name }}">
|
||||
<img src="{{ $assignedId->profile_pic }}" alt=""
|
||||
class="rounded-circle avatar-xxs">
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer border-top-dashed">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<span class="fs-12"><i class="ri-time-line text-success align-bottom"></i>
|
||||
{{ date('d M, Y', strtotime($task->start_date)) }}</span>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
{!! $task->priority_status !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="progress progress-sm">
|
||||
<div class="progress-bar"
|
||||
style="background-color: {{ $column->color }}; --vz-bg-opacity: 1; width: 100%;"
|
||||
role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@include('pms::task-category.modal')
|
||||
@include('pms::task.modal.task-status')
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
var columnLists = @json($columnLists);
|
||||
</script>
|
||||
<script src="{{ asset('assets/libs/dragula/dragula.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/libs/dom-autoscroller/dom-autoscroller.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/pages/tasks-kanban.init.js') }}"></script>
|
||||
@endpush
|
50
Modules/PMS/resources/views/task/modal/task-status.blade.php
Normal file
50
Modules/PMS/resources/views/task/modal/task-status.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<div id="taskStatusModal" class="modal fade" tabindex="-1" aria-labelledby="taskStatusModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="taskStatusModalLabel">Add Status Column</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ html()->form('POST')->route('kanbanColumn.store')->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
|
||||
@include('pms::kanbanColumn.partials.action')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="editTaskStatusModal" tabindex="-1" aria-labelledby="editTaskStatusModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-light p-3">
|
||||
<h5 class="modal-title" id="editTaskStatusModalLabel">Edit Status Column</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"
|
||||
id="close-modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
$(document).on('click', '.edit-item-btn', function() {
|
||||
const url = $(this).attr('data-link');
|
||||
const myModal = new bootstrap.Modal(document.getElementById("editTaskStatusModal"));
|
||||
$("#editTaskStatusModal .modal-body").html(
|
||||
'<div class="text-center my-5"><i class="spinner-border text-primary" role="status"></i></div>'
|
||||
);
|
||||
myModal.show();
|
||||
$.get(url, function(res, status) {
|
||||
$("#editTaskStatusModal .modal-body").html(res);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
127
Modules/PMS/resources/views/task/partials/action.blade.php
Normal file
127
Modules/PMS/resources/views/task/partials/action.blade.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row gy-1">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Enter Title')->required() }}
|
||||
{{ html()->div('Please enter title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Task Category')->class('form-label') }}
|
||||
{{ html()->select('task_category_id', $categoryList)->class('form-select select2')->placeholder('Select Task Category')->required() }}
|
||||
{{ html()->div('Please select task category')->class('invalid-feedback') }}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Product')->class('form-label') }}
|
||||
{{ html()->select('product_id', $product)->class('form-select select2')->placeholder('Select Product')->required() }}
|
||||
{{ html()->div('Please select product')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Team Members</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->multiselect('assigned_id[ids][]', $memberList)->class('form-select select2')->value($task->assigned_id['ids'] ?? null)->attributes(['multiple', 'id' => 'assigned_id'])->required() }}
|
||||
{{ html()->div('Please select team members')->class('invalid-feedback') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control ckeditor-classic')->placeholder('..') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('task.index') }}" class="btn btn-danger w-sm">Cancel</a>
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $status)->class('form-select')->placeholder('Select') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Date</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Priority')->class('form-label') }}
|
||||
{{ html()->select('priority', $priority)->class('form-select')->required() }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Start Date')->class('form-label') }}
|
||||
{{ html()->date('start_date')->class('form-control')->placeholder('Choose Start Date') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Due Date')->class('form-label') }}
|
||||
{{ html()->date('due_date')->class('form-control')->placeholder('Choose Due Date') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Upload File</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('File')->class('form-label visually-hidden') }}
|
||||
{{ html()->file('file')->class('form-control dropify')->attributes([
|
||||
// 'data-default-file' => $editable ? asset('storage/' . $task?->documents?->document_path) : null,
|
||||
'data-height' => 200,
|
||||
]) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card -->
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
16
Modules/PMS/resources/views/task/partials/comment.blade.php
Normal file
16
Modules/PMS/resources/views/task/partials/comment.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<div data-simplebar style="height: 200px;" class="mx-n3 mb-2 px-3">
|
||||
@forelse ($task->comments as $comment)
|
||||
<div class="d-flex mb-4">
|
||||
<div class="flex-shrink-0">
|
||||
<img src="{{ asset('assets/images/user.png') }}" alt="" class="avatar-xs rounded-circle material-shadow" />
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h5 class="fs-13"><a href="#">{{ $comment->user?->name }}</a> <small
|
||||
class="text-muted">{{ $comment->created_at_formatted }}</small></h5>
|
||||
<p class="text-muted">{!! $comment->content !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-danger"> No Comment Found.. </p>
|
||||
@endforelse
|
||||
</div>
|
62
Modules/PMS/resources/views/task/partials/filter.blade.php
Normal file
62
Modules/PMS/resources/views/task/partials/filter.blade.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<div class="card bg-light">
|
||||
<div class="card-header border-bottom-dashed">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="card-title mb-0">Advance Filter</h6>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<ul class="list-inline card-toolbar-menu d-flex align-items-center mb-0">
|
||||
|
||||
<li class="list-inline-item">
|
||||
<a class="minimize-card align-middle" data-bs-toggle="collapse" href="#collapseExample2" role="button"
|
||||
aria-expanded="false" aria-controls="collapseExample2">
|
||||
<i class="mdi mdi-plus plus align-middle"></i>
|
||||
<i class="mdi mdi-minus minus align-middle"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body show collapse" id="collapseExample2">
|
||||
{{ html()->form('GET')->open() }}
|
||||
<div class="row">
|
||||
<div class="col-sm-3 mb-1">
|
||||
{{ html()->label('Search')->class('form-label') }}
|
||||
<div class="search-box">
|
||||
{{ html()->text('search')->class('form-control form-control-sm')->placeholder('Search...') }}
|
||||
<i class="ri-search-line search-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mb-1">
|
||||
{{ html()->label('Date')->class('form-label') }}
|
||||
{{ html()->text('date')->class('form-control form-control-sm daterange-custom-picker')->value(request('date'))->placeholder('Date Range') }}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mb-1">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $statusList)->placeholder('Select Status')->value(request('status'))->class('form-control form-control-sm') }}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mb-1">
|
||||
{{ html()->label('Assigned to')->class('form-label') }}
|
||||
{{ html()->select('assigned_to', $memberList)->placeholder('Select Assignee')->value(request('assigned_to'))->class('form-control form-control-sm') }}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mb-1">
|
||||
{{ html()->label('Priority')->class('form-label') }}
|
||||
{{ html()->select('priority', Modules\PMS\Models\Task::PRIORITY)->placeholder('Select Priority')->value(request('priority'))->class('form-control form-control-sm') }}
|
||||
</div>
|
||||
<!--end col-->
|
||||
</div>
|
||||
|
||||
<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(Route::currentRouteName()) }}" class="btn btn-danger btn-sm reset-filter">Reset</a>
|
||||
</div>
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
</div>
|
40
Modules/PMS/resources/views/task/partials/menu.blade.php
Normal file
40
Modules/PMS/resources/views/task/partials/menu.blade.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<div class="row justify-content-between my-2">
|
||||
<div class="col-sm-auto">
|
||||
<div class="list-grid-nav hstack gap-1">
|
||||
@can('task.create')
|
||||
<a href="{{ route('task.create') }}" class="btn btn-sm btn-primary btn-md waves-effect waves-light"><i
|
||||
class="ri-add-fill align-bottom"></i> Add</a>
|
||||
@endcan
|
||||
@can('kanbanColumn.index')
|
||||
<button href="javascript:void(0)" class="btn btn-sm btn-secondary waves-effect waves-light fs-14 text-white"
|
||||
data-bs-toggle="modal" data-bs-target="#taskStatusModal"><i class="ri-add-line"></i> <span class="">Status
|
||||
Column</span></button>
|
||||
@endcan
|
||||
@can('taskCategory.index')
|
||||
<button href="javascript:void(0)" class="btn btn-sm btn-success waves-effect waves-light fs-14"
|
||||
data-bs-toggle="modal" data-bs-target="#myModal"><i class="ri-book-3-line"></i> <span class="">Add
|
||||
Category</span></button>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-auto">
|
||||
<div class="btn-group material-shadow mt-2" role="group" aria-label="Basic example">
|
||||
@can('task.index')
|
||||
<a href="{{ route('task.index') }}" id="list-view-button"
|
||||
class="btn btn-sm btn-{{ Route::is('task.index') ? 'primary' : 'secondary' }} btn-icon material-shadow-none fs-14"><i
|
||||
class="ri-list-unordered"></i></a>
|
||||
@endcan
|
||||
|
||||
@can('task.kanban')
|
||||
<a href="{{ route('task.kanban') }}" id="grid-view-button"
|
||||
class="btn btn-sm btn-{{ Route::is('task.kanban') ? 'primary' : 'secondary' }} btn-icon material-shadow-none fs-14"><i
|
||||
class="ri-grid-fill"></i></a>
|
||||
@endcan
|
||||
@can('task.export')
|
||||
<a href="{{ route('task.export', request()->all()) }}" id=""
|
||||
class="btn btn-sm btn-secondary btn-icon material-shadow-none fs-14"><i class="ri-download-2-line"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
</div>
|
679
Modules/PMS/resources/views/task/show.blade.php
Normal file
679
Modules/PMS/resources/views/task/show.blade.php
Normal file
@@ -0,0 +1,679 @@
|
||||
@extends('layouts.app')
|
||||
@section('css')
|
||||
{{-- <link rel="stylesheet" type="text/css" href="{{ asset('assets/libs/glightbox/css/glightbox.min.css') }}" /> --}}
|
||||
{{-- <link rel="stylesheet" type="text/css" href="{{ asset('assets/libs/fancybox/jquery.fancybox.css') }}" /> --}}
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="page-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xxl-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md">
|
||||
<div class="row align-items-center g-3">
|
||||
<div class="col-md d-flex justify-content-between">
|
||||
<h4 class="fw-bold">{{ $task->title }}</h4>
|
||||
<h4 class="fw-bold text-end">{{ $clientName }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<div class="hstack flex-wrap gap-1">
|
||||
<span class="badge bg-{{ $task->status_name['color'] }} fs-12"> {!! $task->status_name['status'] !!} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-muted">
|
||||
<h6 class="fw-semibold text-uppercase mb-3">Description</h6>
|
||||
<p>{!! $task->desc !!}</p>
|
||||
</div>
|
||||
|
||||
@if ($task->subTask->count() > 0)
|
||||
<div class="text-muted">
|
||||
<h6 class="fw-semibold text-uppercase mb-2">Sub Task</h6>
|
||||
<div class="acitivity-timeline">
|
||||
@foreach ($task->subTask as $subTask)
|
||||
<div class="acitivity-item d-flex">
|
||||
<div class="flex-shrink-0">
|
||||
<i class="mdi mdi-checkbox-blank-circle text-info me-2"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h6 class="mb-1">{{ $subTask->title }}
|
||||
<span class="text-danger ms-1 align-middle"><em>
|
||||
{{ $subTask->start_date }}</em></span>
|
||||
</h6>
|
||||
<p class="text-muted mb-2">{!! $subTask->desc !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="border-top border-top-dashed mt-4 pt-3">
|
||||
<div class="row gy-2">
|
||||
<div class="col-lg-3 col-sm-4">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Product :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $task->product?->name }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-4">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Category :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $task->taskCategory?->title }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-4">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Create Date :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $task->start_date }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-4">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Due Date :</p>
|
||||
<h5 class="fs-15 mb-0">{{ $task->due_date }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-4">
|
||||
<div>
|
||||
<p class="text-uppercase fw-medium mb-2">Priority :</p>
|
||||
{!! $task->priority_status !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<ul class="nav nav-tabs-custom card-header-tabs border-bottom-0 rounded" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-bs-toggle="tab" href="#home-1" role="tab">
|
||||
Comments ({{ $task->comments->count() }})
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#messages-1" role="tab">
|
||||
File ({{ $task->documents->count() }})
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#sub-task-1" role="tab">
|
||||
Sub Task
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!--end nav-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="home-1" role="tabpanel">
|
||||
<h5 class="card-title mb-4">Comments</h5>
|
||||
<div class="comment-box">
|
||||
|
||||
</div>
|
||||
{{ html()->form('POST')->route('task.storeComment')->class(['needs-validation commentForm'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-12">
|
||||
<label for="exampleFormControlTextarea1" class="form-label">Leave a Comments</label>
|
||||
<textarea class="form-control bg-light border-light" id="exampleFormControlTextarea1" name="content" rows="3"
|
||||
placeholder="Enter comments"></textarea>
|
||||
{{ html()->hidden('task_id', $task->id) }}
|
||||
</div>
|
||||
<!--end col-->
|
||||
<div class="col-12 text-end">
|
||||
|
||||
<input type="submit" class="btn btn-success submit-btn" value="Add Comment" />
|
||||
</div>
|
||||
</div>
|
||||
<!--end row-->
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
<!--end tab-pane-->
|
||||
<div class="tab-pane" id="messages-1" role="tabpanel">
|
||||
<div class="drop-content">
|
||||
|
||||
<div class="dropzone">
|
||||
<div class="fallback">
|
||||
<input name="file" type="file" multiple="multiple">
|
||||
</div>
|
||||
<div class="dz-message needsclick">
|
||||
<div class="mb-3">
|
||||
<i class="display-4 text-muted ri-upload-cloud-2-fill"></i>
|
||||
</div>
|
||||
<h4>Drop files here or click to upload.</h4>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-unstyled mb-0" id="dropzone-preview">
|
||||
<li class="mt-2" id="dropzone-preview-list">
|
||||
<div class="rounded border">
|
||||
<div class="d-flex p-2">
|
||||
<div class="me-3 flex-shrink-0">
|
||||
<div class="avatar-sm bg-light rounded">
|
||||
<img data-dz-thumbnail class="img-fluid d-block rounded"
|
||||
src="assets/images/new-document.png" alt="Dropzone-Image" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="pt-1">
|
||||
<h5 class="fs-14 mb-1" data-dz-name> </h5>
|
||||
<p class="fs-13 text-muted mb-0" data-dz-size></p>
|
||||
<strong class="error text-danger" data-dz-errormessage></strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-3 flex-shrink-0">
|
||||
<button data-dz-remove class="btn btn-sm btn-danger">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="row gx-2 gy-2 rounded border border-dashed p-2">
|
||||
@foreach ($task->documents as $document)
|
||||
<div class="col-3">
|
||||
<a href="{{ asset('storage/' . $document->document_path) }}" data-fancybox="images"
|
||||
target="_blank">
|
||||
<img src="{{ asset('storage/' . $document->document_path) }}" alt=""
|
||||
class="img-fluid material-shadow-none1 rounded" style="width: 100%;height: 150px;object-fit: cover;">
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<!--end tab-pane-->
|
||||
<div class="tab-pane" id="sub-task-1" role="tabpanel">
|
||||
{{-- <h5 class="card-title mb-4">Sub Task</h5> --}}
|
||||
{{ html()->form('POST')->route('task.storeSubTask')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::task.subTask.create')
|
||||
{{ html()->form()->close() }}
|
||||
</div>
|
||||
<!--end tab-pane-->
|
||||
</div>
|
||||
<!--end tab-content-->
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
</div>
|
||||
<!--end col-->
|
||||
<div class="col-xxl-3">
|
||||
<div class="mb-2 text-end">
|
||||
<a href="javascript:void(0)" class="btn btn-sm btn-warning" data-bs-toggle="modal"
|
||||
data-bs-target="#emailModal">
|
||||
<i class="ri-mail-fill me-2 align-middle"></i>Send Reminder
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h6 class="card-title flex-grow-1 mb-3 text-start">Time Tracking</h6>
|
||||
<div class="mb-0">
|
||||
<lord-icon id="time-icon" src="https://cdn.lordicon.com/kbtmbyzy.json"
|
||||
colors="primary:#405189,secondary:#02a8b5" style="width:90px;height:90px"></lord-icon>
|
||||
</div>
|
||||
<div class="stopwatch fs-20"></div>
|
||||
<ul class="results"></ul>
|
||||
<div class="hstack justify-content-center control gap-2">
|
||||
<button class="btn btn-success btn-sm start">
|
||||
<i class="ri-play-circle-line me-1 align-bottom"></i> Start
|
||||
</button>
|
||||
<button class="btn btn-info btn-sm stop">
|
||||
<i class="ri-stop-circle-line me-1 align-bottom"></i> Stop
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<div class="mb-4">
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
{{ html()->select('status', $status, $task->status)->class('form-control')->required() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<div class="d-flex mb-3">
|
||||
<h6 class="card-title flex-grow-1 mb-0">Assigned To</h6>
|
||||
</div>
|
||||
<ul class="list-unstyled vstack mb-0 gap-3">
|
||||
@foreach ($task->assignedUser as $assignedUser)
|
||||
<li>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<img src="{{ $assignedUser->profile_pic }}" alt=""
|
||||
class="avatar-xs rounded-circle material-shadow">
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-2">
|
||||
<h6 class="mb-1"><a href="#">{{ $assignedUser->full_name }}</a></h6>
|
||||
<p class="text-muted mb-0">{{ $assignedUser->email }}</p>
|
||||
</div>
|
||||
{{-- <div class="flex-shrink-0">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-icon btn-sm fs-16 text-muted dropdown material-shadow-none"
|
||||
type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="ri-more-fill"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="ri-eye-fill text-muted me-2 align-bottom"></i>View</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-3">Attachments</h5>
|
||||
<div class="vstack gap-2">
|
||||
@foreach ($task->documents as $document)
|
||||
<div class="rounded border border-dashed p-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="me-3 flex-shrink-0">
|
||||
<div class="avatar-xs">
|
||||
|
||||
<img src="{{ asset('storage/' . $document->document_path) }}" alt=""
|
||||
class="avatar-xs material-shadow rounded">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 overflow-hidden">
|
||||
<h5 class="fs-13 mb-1"><a href="javascript:void(0);"
|
||||
class="text-body text-truncate d-block">{{ $document->document_name }}</a></h5>
|
||||
</div>
|
||||
{{-- <div class="ms-2 flex-shrink-0">
|
||||
<div class="d-flex gap-1">
|
||||
<button type="button" class="btn btn-icon text-muted btn-sm fs-18 material-shadow-none"><i
|
||||
class="ri-download-2-line"></i></button>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-icon text-muted btn-sm fs-18 dropdown material-shadow-none"
|
||||
type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="ri-more-fill"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item remove-item-btn" href="javascript:void(0);"
|
||||
data-link="{{ route('document.destroy', $document->id) }}"
|
||||
data-id="{{ $document->id }}"><i
|
||||
class="ri-delete-bin-fill text-muted me-2 align-bottom"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end card-->
|
||||
</div>
|
||||
<!---end col-->
|
||||
</div>
|
||||
<!--end row-->
|
||||
|
||||
</div>
|
||||
<!-- container-fluid -->
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="emailModal" tabindex="-1" aria-labelledby="emailModalLabel" aria-hidden="true"
|
||||
style="display: none;">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-0">
|
||||
<h5 class="modal-title" id="emailModalLabel">Send Email</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ html()->form('POST', route('task.sendMail'))->class(['needs-validation sendMailForm'])->attributes(['novalidate'])->open() }}
|
||||
{{ html()->hidden('task_id', $task->id) }}
|
||||
|
||||
<ul class="list-inline d-flex flex-column flex-wrap gap-2">
|
||||
<li class="list-inline-item">
|
||||
<span class="fw-bold">To:</span>
|
||||
<span class="selected-names">
|
||||
@foreach ($task->assignedUser as $assignedUser)
|
||||
{{ $assignedUser->email }},
|
||||
{{-- {{ html()->hidden('email[]')->value($assignedUser->email) }} --}}
|
||||
@endforeach
|
||||
</span>
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<span class="fw-bold">From:</span> {{ setting('email') }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="card card-body bg-white">
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Select Template')->class('form-label') }}
|
||||
{{ html()->select('template', @$template['email'])->class('form-control change-template')->placeholder('Select Template')->attributes(['data-type' => 'email']) }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Subject')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('subject')->class('form-control subject')->required() }}
|
||||
{{ html()->div('Subject is required!')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
{{ html()->label('Message')->class('form-label') }}
|
||||
{{ html()->textarea('message')->class('form-control message ckeditor-classic')->id('email-editor') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hstack justify-content-end mt-2 gap-2">
|
||||
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-success">Send</button>
|
||||
</div>
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/pages/plugins/lord-icon-2.1.0.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/pages/timer.js') }}"></script>
|
||||
<script src="{{ asset('assets/libs/dropzone/dropzone-min.js') }}"></script>
|
||||
{{-- <script src="{{ asset('assets/libs/fancybox/jquery.fancybox.js') }}"></script> --}}
|
||||
{{-- <script src="{{ asset('assets/libs/glightbox/js/glightbox.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/libs/isotope-layout/isotope.pkgd.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/pages/gallery.init.js') }}"></script> --}}
|
||||
|
||||
<script>
|
||||
var previewTemplate, dropzone, dropzonePreviewNode = document
|
||||
.querySelector("#dropzone-preview-list");
|
||||
var task_id = "{{ $task->id }}";
|
||||
dropzonePreviewNode.id = "";
|
||||
|
||||
if (dropzonePreviewNode) {
|
||||
previewTemplate = dropzonePreviewNode.parentNode.innerHTML;
|
||||
dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode);
|
||||
|
||||
dropzone = new Dropzone(".dropzone", {
|
||||
url: "uploadFile",
|
||||
method: "post",
|
||||
previewTemplate: previewTemplate,
|
||||
previewsContainer: "#dropzone-preview",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
|
||||
}
|
||||
});
|
||||
|
||||
dropzone.on("sending", function(file, xhr, formData) {
|
||||
formData.append("task_id", '{{ $task->id }}');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
fetchComment();
|
||||
|
||||
let time = '{{ $task->latest_task_time?->end_time }}';
|
||||
let timeArray = [0, 0, 0];
|
||||
if (time) {
|
||||
timeArray = time.split(':').map(numStr => parseInt(numStr, 10));
|
||||
}
|
||||
|
||||
let stopwatch = new Stopwatch(
|
||||
$('.stopwatch'),
|
||||
$('.results'),
|
||||
timeArray
|
||||
);
|
||||
|
||||
$('.start').click(function() {
|
||||
console.log('time start vayo');
|
||||
stopwatch.start();
|
||||
});
|
||||
|
||||
$('.lap').click(function() {
|
||||
stopwatch.lap();
|
||||
});
|
||||
|
||||
$('.stop').click(function() {
|
||||
stopwatch.stop();
|
||||
let formData = {
|
||||
task_id: task_id,
|
||||
time: $('.stopwatch').text()
|
||||
};
|
||||
storeTime(formData)
|
||||
});
|
||||
|
||||
$('.restart').click(function() {
|
||||
stopwatch.restart();
|
||||
});
|
||||
|
||||
$('.clear').click(function() {
|
||||
stopwatch.clear();
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('change', '#status', function() {
|
||||
status = $(this).val();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '{{ route('task.changeStatus') }}',
|
||||
data: {
|
||||
id: task_id,
|
||||
changeStatus: status
|
||||
},
|
||||
success: function(data) {
|
||||
flasher.success('Status Changed');
|
||||
location.reload()
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
$('body').on('submit', '.commentForm', function(event) {
|
||||
|
||||
event.preventDefault();
|
||||
const url = $(this).attr('action');
|
||||
const method = $(this).attr('method');
|
||||
|
||||
let formData = new FormData($(this)[0]);
|
||||
|
||||
let button = $(this).find('.submit-btn');
|
||||
|
||||
// button.prop('disabled', true);
|
||||
// $('.loader').removeClass('d-none');
|
||||
// $('.icon').addClass('d-none');
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: method,
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $("meta[name='csrf-token']").attr('content'),
|
||||
},
|
||||
}).done(function(response) {
|
||||
if (response.status == true) {
|
||||
flasher.success(response.msg);
|
||||
$('.commentForm')[0].reset();
|
||||
fetchComment();
|
||||
}
|
||||
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
flasher.error("Failed to send message!");
|
||||
})
|
||||
});
|
||||
|
||||
const fetchComment = () => {
|
||||
fetch(base_url + `/admin/task/fetchComment/${task_id}`)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
document.querySelector('.comment-box').innerHTML = html;
|
||||
})
|
||||
}
|
||||
|
||||
const storeTime = (formData) => {
|
||||
$.ajax({
|
||||
url: '{{ route('taskTime.store') }}',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $("meta[name='csrf-token']").attr('content'),
|
||||
},
|
||||
}).done(function(response) {
|
||||
if (response.status == true) {
|
||||
flasher.success(response.msg);
|
||||
}
|
||||
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
flasher.error("Failed to send message!");
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
const icon = $('#time-icon');
|
||||
|
||||
$('.start').on('click', function() {
|
||||
icon.attr('trigger', 'loop');
|
||||
});
|
||||
|
||||
$('.stop').on('click', function() {
|
||||
icon.attr('trigger', '');
|
||||
});
|
||||
|
||||
$('body').on('change', '.change-template', function() {
|
||||
id = $(this).val();
|
||||
that = $(this)
|
||||
|
||||
if (id == '') {
|
||||
toastr.error('Choose Template First');
|
||||
return false;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '{{ route('template.findByAjax') }}',
|
||||
data: {
|
||||
id: id,
|
||||
},
|
||||
success: function(res) {
|
||||
result = res.data;
|
||||
if (result.status) {
|
||||
that.parents('.card').find('.subject').val(result.subject);
|
||||
|
||||
let messageFieldId = that.parents('.card').find('.message').attr('id');
|
||||
let editor = CKEDITOR.instances[messageFieldId];
|
||||
if (editor) {
|
||||
let currentContent = editor.getData();
|
||||
editor.setData(result.message);
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
$(document).on('submit', '.sendMailForm', function(event) {
|
||||
event.preventDefault();
|
||||
const url = $(this).attr('action');
|
||||
const method = $(this).attr('method');
|
||||
let form = $(this);
|
||||
let formData = new FormData(form[0]);
|
||||
|
||||
let myModalEl = $(this).closest('.modal').attr('id');
|
||||
var emailModal = bootstrap.Modal.getOrCreateInstance($('#' + myModalEl))
|
||||
const button = $(this).find('button[type="submit"]');
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: method,
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $("meta[name='csrf-token']").attr('content'),
|
||||
},
|
||||
beforeSend: () => {
|
||||
button.text('Sending...');
|
||||
button.prop('disabled', true);
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.status == true) {
|
||||
emailModal.hide()
|
||||
|
||||
button.text('Send');
|
||||
button.prop('disabled', false);
|
||||
|
||||
let messageFieldId = form.find('.message').attr('id');
|
||||
let editor = CKEDITOR.instances[messageFieldId];
|
||||
|
||||
if (editor) {
|
||||
editor.setData('');
|
||||
}
|
||||
|
||||
form[0].reset();
|
||||
toastr.success(response.msg);
|
||||
|
||||
}
|
||||
|
||||
$('#student-table').DataTable().ajax.reload();
|
||||
var statusModal = bootstrap.Modal.getInstance($('#bulkStatusModal'));
|
||||
statusModal.hide();
|
||||
|
||||
|
||||
},
|
||||
|
||||
error: function(xhr) {
|
||||
if (xhr.status == 422) {
|
||||
let errors = xhr.responseJSON.errors;
|
||||
$('.error-message').remove();
|
||||
$.each(errors, function(key, value) {
|
||||
let errorMessage = $(
|
||||
'<span class="error-message text-danger mt-2"></span>'
|
||||
)
|
||||
.text(
|
||||
value[0]);
|
||||
$('#' + key).after(errorMessage);
|
||||
});
|
||||
} else {
|
||||
console.log(xhr);
|
||||
}
|
||||
},
|
||||
complete: () => {
|
||||
button.text('Save');
|
||||
button.prop('disabled', false);
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
@endpush
|
33
Modules/PMS/resources/views/task/subTask/create.blade.php
Normal file
33
Modules/PMS/resources/views/task/subTask/create.blade.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<div class="row gy-1">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Title')->class('form-label') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Enter Title')->required() }}
|
||||
{{ html()->div('Please enter title')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Start Date')->class('form-label') }}
|
||||
{{ html()->date('start_date')->class('form-control')->placeholder('Choose Start Date')->required() }}
|
||||
{{ html()->div('Please choose start date')->class('invalid-feedback') }}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Due Date')->class('form-label') }}
|
||||
{{ html()->date('due_date')->class('form-control')->placeholder('Choose Due Date') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control ckeditor-classic')->placeholder('..') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-3 text-end">
|
||||
{{ html()->hidden('parent_id', $task->id) }}
|
||||
<a href="{{ route('task.index') }}" class="btn btn-danger w-sm">Cancel</a>
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
|
||||
</div>
|
16
Modules/PMS/resources/views/ticket/create.blade.php
Normal file
16
Modules/PMS/resources/views/ticket/create.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->form('POST')->route('ticket.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::ticket.partials.action')
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
18
Modules/PMS/resources/views/ticket/edit.blade.php
Normal file
18
Modules/PMS/resources/views/ticket/edit.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
{{ html()->modelForm($ticket, 'PUT')->route('ticket.update', $ticket->id)->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data'])->open() }}
|
||||
@include('pms::ticket.partials.action')
|
||||
{{ html()->closeModelForm() }}
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('assets/js/pages/form-validation.init.js') }}"></script>
|
||||
@endpush
|
71
Modules/PMS/resources/views/ticket/index.blade.php
Normal file
71
Modules/PMS/resources/views/ticket/index.blade.php
Normal file
@@ -0,0 +1,71 @@
|
||||
@extends('layouts.app')
|
||||
@inject('employeeRepository', 'Modules\Employee\Repositories\EmployeeRepository')
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
|
||||
@include('pms::ticket.partials.menu')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="buttons-datatables" class="display table-sm table-bordered table" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>S.N</th>
|
||||
<th>Ticket</th>
|
||||
<th>Assigned</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($tickets as $key => $ticket)
|
||||
<tr>
|
||||
<td>{{ $key + 1 }}</td>
|
||||
<td>{{ $ticket->subject }}</td>
|
||||
<td>
|
||||
<div class="avatar-group flex-nowrap">
|
||||
<div class="avatar-group-item">
|
||||
Assigned
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{-- <span class="badge bg-{{ $task->status_name['color'] }}"> {!! $task->status_name['status'] !!} </span> --}}Status
|
||||
</td>
|
||||
<td>
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
@can('ticket.show')
|
||||
<a href="{{ route('ticket.show', $ticket->id) }}" class="link-info fs-15">
|
||||
<i class="ri-eye-fill"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('ticket.edit')
|
||||
<a href="{{ route('ticket.edit', $ticket->id) }}" class="link-success fs-15 edit-item-btn"><i
|
||||
classri-edit-2-fillne"></i></a>
|
||||
@endcan
|
||||
@can('ticket.destroy')
|
||||
<a href="javascript:void(0);" data-link="{{ route('ticket.destroy', $ticket->id) }}"
|
||||
data-id="{{ $ticket->id }}" class="link-danger fs-15 remove-item-btn"><i
|
||||
class="ri-delete-bin-fill"></i></a>
|
||||
@endcan
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
@endsection
|
74
Modules/PMS/resources/views/ticket/partials/action.blade.php
Normal file
74
Modules/PMS/resources/views/ticket/partials/action.blade.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row gy-1">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Subject')->class('form-label') }}
|
||||
{{ html()->text('subject')->class('form-control')->placeholder('Enter Subject')->required() }}
|
||||
{{ html()->div('Please enter subject')->class('invalid-feedback') }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 py-3">
|
||||
{{ html()->label('Department')->class('form-label') }}
|
||||
{{ html()->select('department_id',$departmentList)->class('form-select')->placeholder('Select Department')->required() }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 py-3">
|
||||
{{ html()->label('Priority')->class('form-label') }}
|
||||
{{ html()->select('priority', $priority)->class('form-select')->placeholder('Select Priority')->required() }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 py-3">
|
||||
{{ html()->label('Ticket Type')->class('form-label') }}
|
||||
{{ html()->select('ticket_type', $ticketType)->class('form-select')->placeholder('Select Ticket Type')->required() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->label('Description')->class('form-label') }}
|
||||
{{ html()->textarea('desc')->class('form-control ckeditor-classic')->placeholder('..') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
{{-- <div class="mb-3 text-end">
|
||||
<a href="{{ route('ticket.index') }}" class="btn btn-danger w-sm">Cancel</a>
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
|
||||
</div> --}}
|
||||
</div>
|
||||
<!-- end col -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
{{ html()->label('Status')->class('form-label') }}
|
||||
@if(auth()->user()->getRoleNames()->contains('admin'))
|
||||
{{ html()->select('status', $statusList)->class('form-control') }}
|
||||
@else
|
||||
{{ html()->select('status', $statusList['10'])->class('form-control') }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
<div class="mb-3 text-end">
|
||||
<a href="{{ route('ticket.index') }}" class="btn btn-danger w-sm">Cancel</a>
|
||||
<button type="submit" class="btn btn-success w-sm">Save</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
52
Modules/PMS/resources/views/ticket/partials/menu.blade.php
Normal file
52
Modules/PMS/resources/views/ticket/partials/menu.blade.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-sm-8">
|
||||
{{ html()->form('GET')->route('ticket.index')->open() }}
|
||||
<div class="row g-3">
|
||||
<div class="col-xl-3">
|
||||
<div class="search-box">
|
||||
{{ html()->text('search')->class('form-control search')->value(request('search'))->placeholder('Search...') }}
|
||||
<i class="ri-search-line search-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="">
|
||||
{{ html()->text('date')->class('form-control')->value(request('date'))->placeholder('Date Range')->attributes([
|
||||
'id' => 'datepicker-range',
|
||||
'data-provider' => 'flatpickr',
|
||||
'data-date-format' => 'Y-m-d',
|
||||
'data-range-date' => 'true',
|
||||
]) }}
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="ri-equalizer-fill me-2"></i>Filters</button>
|
||||
{{-- <a href="{{ route('task.index') }}" class="btn btn-danger">
|
||||
<i class="ri-bin-fill me-2"></i>Reset</a> --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--end col-->
|
||||
</div>
|
||||
<!--end row-->
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
<!--end col-->
|
||||
<div class="col-sm-auto ms-auto">
|
||||
<div class="list-grid-nav hstack gap-1">
|
||||
<a href="{{ route('ticket.create') }}" class="btn btn-success btn-md waves-effect waves-light"><i
|
||||
class="ri-add-fill me-1 align-bottom"></i> Add</a>
|
||||
</div>
|
||||
</div>
|
||||
<!--end col-->
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user