diff --git a/app/DataTables/WorklistDataTable.php b/app/DataTables/WorklistDataTable.php index 6cf8bb5..9086b4a 100644 --- a/app/DataTables/WorklistDataTable.php +++ b/app/DataTables/WorklistDataTable.php @@ -337,6 +337,11 @@ private function filterStatus(QueryBuilder $query, ?string $status): void case 'orphan': $query->whereNull('assigned_at'); break; + case 'bookmark': + $query->whereHas('bookmarkedByUsers', function ($q) { + $q->where('user_id', auth()->id()); + }); + break; } } @@ -609,6 +614,27 @@ private function generateActionButtons(Study $study): string case WorklistButton::Audit: $btns[] = $this->renderImageLink($study->hash, 'audit.png', 'show-audit', 'Audit Trail'); break; + case WorklistButton::Bookmark: + if ($study->isBookmarkedBy()) { + $btns[] = Blade::render('staff.worklist.partials.bookmarks._delete', + [ + 'study_id' => $study->id, + 'user_id' => me()->id, + 'url' => route('staff.bookmark.delete'), + 'img' => asset('imgs/bookmark-delete.png'), + 'tip' => 'Remove bookmark', + ]); + } else { + $btns[] = Blade::render('staff.worklist.partials.bookmarks._create', + [ + 'study_id' => $study->id, + 'user_id' => me()->id, + 'url' => route('staff.bookmark.create'), + 'img' => asset('imgs/bookmark.png'), + 'tip' => 'Bookmark study', + ]); + } + break; } } diff --git a/app/Domain/ACL/Permission.php b/app/Domain/ACL/Permission.php index 81853a4..70f4d71 100644 --- a/app/Domain/ACL/Permission.php +++ b/app/Domain/ACL/Permission.php @@ -26,4 +26,5 @@ enum Permission: string case UnassignRadiologist = 'unassign_radiologist'; case AccessAllWorklists = 'access_all_worklists'; case AuditLogView = 'audit_log_view'; + case BookmarkCreate = 'bookmark_create'; } diff --git a/app/Http/Controllers/Staff/BookmarkController.php b/app/Http/Controllers/Staff/BookmarkController.php new file mode 100644 index 0000000..cffa248 --- /dev/null +++ b/app/Http/Controllers/Staff/BookmarkController.php @@ -0,0 +1,30 @@ +validated()); + + audit()->did(Activity::Study_Bookmark)->on($request->study_id)->log(); + + return redirect()->route('staff.worklist.index'); + } + + public function delete(BookmarkCrudRequest $request) + { + $studyBookmark = StudyBookmark::where($request->validated())->firstOrFail(); + $studyBookmark->delete(); + + audit()->did(Activity::Study_Unmark)->on($request->study_id)->log(); + + return redirect()->route('staff.worklist.index'); + } +} diff --git a/app/Http/Controllers/StudyBookmarkController.php b/app/Http/Controllers/StudyBookmarkController.php deleted file mode 100644 index 3f0ea02..0000000 --- a/app/Http/Controllers/StudyBookmarkController.php +++ /dev/null @@ -1,38 +0,0 @@ -validated()); - } - - public function show(StudyBookmark $studyBookmark) - { - return $studyBookmark; - } - - public function update(BookmarkCrudRequest $request, StudyBookmark $studyBookmark) - { - $studyBookmark->update($request->validated()); - - return $studyBookmark; - } - - public function destroy(StudyBookmark $studyBookmark) - { - $studyBookmark->delete(); - - return response()->json(); - } -} diff --git a/app/Http/Requests/BookmarkCrudRequest.php b/app/Http/Requests/BookmarkCrudRequest.php index 1369beb..1a658ae 100644 --- a/app/Http/Requests/BookmarkCrudRequest.php +++ b/app/Http/Requests/BookmarkCrudRequest.php @@ -9,8 +9,8 @@ class BookmarkCrudRequest extends FormRequest public function rules(): array { return [ - 'study_id' => ['required', 'exists:studies'], - 'user_id' => ['required', 'exists:users'], + 'study_id' => ['required', 'exists:studies,id'], + 'user_id' => ['required', 'exists:users,id'], ]; } diff --git a/app/Models/Study.php b/app/Models/Study.php index f61fb8e..6b45321 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -443,6 +443,11 @@ public function isReadBy(User|int|null $user = null): bool return $this->reading_physician_id === me($user)->id; } + public function isBookmarkedBy(User|int|null $user = null): bool + { + return $this->bookmarkedByUsers()->where('user_id', me($user)->id)->exists(); + } + /** * Returns true if study has been locked by the given user or is unlocked. Returns false if the study was locked by another user. */ diff --git a/app/Services/ACL/WorklistButton.php b/app/Services/ACL/WorklistButton.php index 0825814..2066456 100644 --- a/app/Services/ACL/WorklistButton.php +++ b/app/Services/ACL/WorklistButton.php @@ -11,4 +11,5 @@ enum WorklistButton: string case Assign = 'assign'; case Report = 'report'; case Audit = 'audit'; + case Bookmark = 'bookmark'; } diff --git a/app/Services/ACL/WorklistGuard.php b/app/Services/ACL/WorklistGuard.php index ccfdbab..16b923f 100644 --- a/app/Services/ACL/WorklistGuard.php +++ b/app/Services/ACL/WorklistGuard.php @@ -58,6 +58,7 @@ public static function worklistButtons(Study $study, User|int|null $usr = null): WorklistButton::StudyMetadata, WorklistButton::Notes, // WorklistButton::Audit, + WorklistButton::Bookmark, ]); } @@ -75,6 +76,10 @@ public static function worklistButtons(Study $study, User|int|null $usr = null): $buttons->push(WorklistButton::Audit); } + if (may(Permission::BookmarkCreate)) { + $buttons->push(WorklistButton::Bookmark); + } + return $buttons; } } diff --git a/app/Services/AuditTrail/Activity.php b/app/Services/AuditTrail/Activity.php index c76e0dc..88a057b 100644 --- a/app/Services/AuditTrail/Activity.php +++ b/app/Services/AuditTrail/Activity.php @@ -28,6 +28,8 @@ enum Activity: int case Attachment_Upload = 112; case Attachment_Download = 113; case Attachment_Delete = 114; + case Study_Bookmark = 115; + case Study_Unmark = 116; // image case Image_Download = 150; diff --git a/database/migrations/2025_01_25_114600_create_study_bookmarks_table.php b/database/migrations/2025_01_25_114600_create_study_bookmarks_table.php index d79d654..6c7f5f7 100644 --- a/database/migrations/2025_01_25_114600_create_study_bookmarks_table.php +++ b/database/migrations/2025_01_25_114600_create_study_bookmarks_table.php @@ -2,6 +2,8 @@ use App\Models\Study; use App\Models\User; +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; return new class extends Migration { diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index df693c9..1a90702 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -34,6 +34,7 @@ public function run(): void Permission::StudyNotesCreate, Permission::StudyNotesView, Permission::AttachmentDownload, + Permission::BookmarkCreate, ]); $tech->givePermissionTo([ @@ -49,6 +50,7 @@ public function run(): void Permission::StudyArchive, Permission::ReportDownload, Permission::AuditLogView, + Permission::BookmarkCreate, ]); $adm->givePermissionTo(SpatiePermission::all()); diff --git a/resources/imgs/bookmark-delete.png b/resources/imgs/bookmark-delete.png new file mode 100644 index 0000000..a18504a Binary files /dev/null and b/resources/imgs/bookmark-delete.png differ diff --git a/resources/imgs/bookmark.png b/resources/imgs/bookmark.png new file mode 100644 index 0000000..a6d79fb Binary files /dev/null and b/resources/imgs/bookmark.png differ diff --git a/resources/views/staff/worklist/partials/_nav-top.blade.php b/resources/views/staff/worklist/partials/_nav-top.blade.php index f64ceab..e3b1908 100644 --- a/resources/views/staff/worklist/partials/_nav-top.blade.php +++ b/resources/views/staff/worklist/partials/_nav-top.blade.php @@ -7,6 +7,7 @@ @include('staff.worklist.partials._nav-item', ['id' => 'nav__orphan', 'text' => 'Unassigned', 'active' => '', 'icon' => 'price-tag-3-line', 'tip' => 'Unassigned studies']) @include('staff.worklist.partials._nav-item', ['id' => 'nav__assigned', 'text' => 'Assigned', 'active' => '', 'icon' => 'team-line', 'tip' => 'Studies assigned to radiologists']) @endif + @include('staff.worklist.partials._nav-item', ['id' => 'nav__bookmark', 'text' => 'Bookmarked', 'active' => '', 'icon' => 'bookmark-line', 'tip' => 'Bookmarked studies']) @include('staff.worklist.partials._nav-item', ['id' => 'nav__all', 'text' => 'All', 'active' => '', 'icon' => 'stack-line', 'tip' => 'All studies']) diff --git a/resources/views/staff/worklist/partials/bookmarks/_create.blade.php b/resources/views/staff/worklist/partials/bookmarks/_create.blade.php new file mode 100644 index 0000000..3bd2b0a --- /dev/null +++ b/resources/views/staff/worklist/partials/bookmarks/_create.blade.php @@ -0,0 +1,7 @@ +@php + $form_id = 'bm-creat-' . $study_id; +@endphp + + @include('_partials._img-tooltip', ['src' => $img, 'class' => $class ?? 'msg-icon', 'tip' => $tip]) + @include('staff.worklist.partials.bookmarks._form', ['form_id' => $form_id, 'url' => $url, 'study_id' => $study_id, 'user_id' => $user_id, 'delete' => false]) + diff --git a/resources/views/staff/worklist/partials/bookmarks/_delete.blade.php b/resources/views/staff/worklist/partials/bookmarks/_delete.blade.php new file mode 100644 index 0000000..e25defa --- /dev/null +++ b/resources/views/staff/worklist/partials/bookmarks/_delete.blade.php @@ -0,0 +1,7 @@ +@php + $form_id = 'bm-del_' . $study_id; +@endphp + + @include('_partials._img-tooltip', ['src' => $img, 'class' => $class ?? 'msg-icon', 'tip' => $tip]) + @include('staff.worklist.partials.bookmarks._form', ['form_id' => $form_id, 'url' => $url, 'study_id' => $study_id, 'user_id' => $user_id, 'delete' => true]) + diff --git a/resources/views/staff/worklist/partials/bookmarks/_form.blade.php b/resources/views/staff/worklist/partials/bookmarks/_form.blade.php new file mode 100644 index 0000000..e8028f7 --- /dev/null +++ b/resources/views/staff/worklist/partials/bookmarks/_form.blade.php @@ -0,0 +1,8 @@ +
diff --git a/routes/web.php b/routes/web.php index 81f93d1..75abe74 100644 --- a/routes/web.php +++ b/routes/web.php @@ -6,6 +6,7 @@ use App\Http\Controllers\Staff\AssignmentController; use App\Http\Controllers\Staff\AttachmentController; use App\Http\Controllers\Staff\AuditLogController; +use App\Http\Controllers\Staff\BookmarkController; use App\Http\Controllers\Staff\DicomViewerController; use App\Http\Controllers\Staff\HistoryController; use App\Http\Controllers\Staff\MetadataController; @@ -85,6 +86,11 @@ Route::group(['prefix' => 'audit', 'as' => 'audit.'], function () { Route::get('popup', [AuditLogController::class, 'popup'])->name('popup'); }); + + Route::group(['prefix' => 'bookmark', 'as' => 'bookmark.'], function () { + Route::post('/', [BookmarkController::class, 'create'])->name('create'); + Route::delete('/', [BookmarkController::class, 'delete'])->name('delete'); + }); }); });