diff --git a/ProcessMaker/Http/Controllers/Api/UserConfigurationController.php b/ProcessMaker/Http/Controllers/Api/UserConfigurationController.php index 64ea095fd1..d325c1636b 100644 --- a/ProcessMaker/Http/Controllers/Api/UserConfigurationController.php +++ b/ProcessMaker/Http/Controllers/Api/UserConfigurationController.php @@ -25,6 +25,9 @@ class UserConfigurationController extends Controller 'tasks' => [ 'isMenuCollapse' => true, ], + 'tasks_inbox' => [ + 'isMenuCollapse' => false, + ], ]; public function index() @@ -54,6 +57,7 @@ public function store(Request $request) 'ui_configuration.cases' => 'required|array', 'ui_configuration.requests' => 'required|array', 'ui_configuration.tasks' => 'required|array', + 'ui_configuration.tasks_inbox' => 'required|array', ]); $uiConfiguration = json_encode($request->input('ui_configuration')); diff --git a/ProcessMaker/Http/Controllers/TaskController.php b/ProcessMaker/Http/Controllers/TaskController.php index fa4c945454..63c2fb474b 100755 --- a/ProcessMaker/Http/Controllers/TaskController.php +++ b/ProcessMaker/Http/Controllers/TaskController.php @@ -58,7 +58,9 @@ public function index() $taskDraftsEnabled = TaskDraft::draftsEnabled(); - return view('tasks.index', compact('title', 'userFilter', 'defaultColumns', 'taskDraftsEnabled')); + $userConfiguration = (new UserConfigurationController())->index()['ui_configuration'] ?? []; + + return view('tasks.index', compact('title', 'userFilter', 'defaultColumns', 'taskDraftsEnabled', 'userConfiguration')); } public function edit(ProcessRequestToken $task, string $preview = '') diff --git a/resources/js/tasks/components/ParticipantHomeScreen.vue b/resources/js/tasks/components/ParticipantHomeScreen.vue new file mode 100644 index 0000000000..cc12f71978 --- /dev/null +++ b/resources/js/tasks/components/ParticipantHomeScreen.vue @@ -0,0 +1,533 @@ + + + + + diff --git a/resources/js/tasks/index.js b/resources/js/tasks/index.js index 41ad99016b..ecea920a86 100644 --- a/resources/js/tasks/index.js +++ b/resources/js/tasks/index.js @@ -2,12 +2,18 @@ import Vue from "vue"; import TasksList from "./components/TasksList"; import TasksListCounter from "./components/TasksListCounter.vue"; import setDefaultAdvancedFilterStatus from "../common/setDefaultAdvancedFilterStatus"; +import ParticipantHomeScreen from './components/ParticipantHomeScreen.vue'; Vue.component("TasksList", TasksList); +Vue.component('participant-home-screen', ParticipantHomeScreen); new Vue({ el: "#tasks", data: { + showOldTaskScreen: false, + userConfiguration: window.ProcessMaker.userConfiguration, + urlConfiguration: "users/configuration", + showMenu: true, columns: window.Processmaker.defaultColumns || null, filter: "", pmql: "", @@ -62,7 +68,9 @@ new Vue({ if (!window.location.search.includes("filter_user_recommendation")) { this.$nextTick(() => { - this.$refs.taskList.fetch(); + if (this.$refs.taskList) { + this.$refs.taskList.fetch(); + } }); } }, diff --git a/resources/js/tasks/mixins/TasksMixin.js b/resources/js/tasks/mixins/TasksMixin.js new file mode 100644 index 0000000000..ad96cc0a3e --- /dev/null +++ b/resources/js/tasks/mixins/TasksMixin.js @@ -0,0 +1,191 @@ +export default { + data() { + return { + showOldTaskScreen: false, + urlConfiguration: "users/configuration", + showMenu: false, + columns: window.Processmaker.defaultColumns || null, + filter: "", + pmql: "", + urlPmql: "", + filtersPmql: "", + fullPmql: "", + status: [], + inOverdueMessage: "", + additions: [], + priorityField: "is_priority", + draftField: "draft", + isDataLoading: false, + inbox: true, + priority: false, + draft: false, + tab: "inbox", + inboxCount: null, + draftCount: null, + priorityCount: null, + priorityFilter: [ + { + subject: { + type: "Field", + value: "is_priority", + }, + operator: "=", + value: true, + _column_field: "is_priority", + _column_label: "Priority", + _hide_badge: true, + }, + ], + draftFilter: [ + { + subject: { + type: "Relationship", + value: "draft.id", + }, + operator: ">", + value: 0, + _column_field: "draft", + _column_label: "Draft", + _hide_badge: true, + }, + ], + }; + }, + computed: { + effectiveSavedsearchDefaultsEditRoute() { + return ( + this.savedsearchDefaultsEditRoute || + window.ProcessMaker.savedsearchDefaultsEditRoute + ); + }, + }, + methods: { + defineUserConfiguration() { + this.localUserConfiguration = JSON.parse( + window.ProcessMaker.userConfiguration || "{}" + ); + if (this.localUserConfiguration.tasks_inbox) { + this.showMenu = this.localUserConfiguration.tasks_inbox.isMenuCollapse; + } else { + this.showMenu = false; + this.localUserConfiguration.tasks_inbox = { + isMenuCollapse: false, + }; + } + }, + hideMenu() { + this.showMenu = !this.showMenu; + this.updateUserConfiguration(); + }, + updateUserConfiguration() { + this.localUserConfiguration.tasks_inbox.isMenuCollapse = this.showMenu; + ProcessMaker.apiClient + .put(this.urlConfiguration, { + ui_configuration: this.localUserConfiguration, + }) + .catch((error) => { + console.error("Error", error); + }); + }, + switchTab(tab) { + this.tab = tab; + const taskListComponent = this.$refs.taskList; + taskListComponent.advancedFilter[this.priorityField] = []; + taskListComponent.advancedFilter[this.draftField] = []; + switch (tab) { + case "priority": + taskListComponent.advancedFilter["is_priority"] = this.priorityFilter; + break; + case "draft": + taskListComponent.advancedFilter["draft"] = this.draftFilter; + break; + } + taskListComponent.markStyleWhenColumnSetAFilter(); + taskListComponent.storeFilterConfiguration(); + taskListComponent.fetch(true); + }, + dataLoading(value) { + this.isDataLoading = value; + }, + onFetchTask() { + this.inbox = true; + this.priority = this.draft = false; + let filters = window.ProcessMaker.advanced_filter?.filters; + if (!Array.isArray(filters)) { + filters = []; + } + filters.forEach((item) => { + if (item._column_field === "is_priority") { + this.priority = true; + this.inbox = this.draft = false; + } + if (item._column_field === "draft") { + this.draft = true; + this.inbox = this.priority = false; + } + }); + }, + handleTabCount(value) { + if (this.tab === "inbox") { + this.inboxCount = value; + } + if (this.tab === "draft") { + this.draftCount = value; + } + if (this.tab === "priority") { + this.priorityCount = value; + } + }, + onFiltersPmqlChange(value) { + this.filtersPmql = value[0]; + this.fullPmql = this.getFullPmql(); + }, + onNLQConversion(query) { + this.onChange(query); + this.onSearch(); + }, + onChange(query) { + this.pmql = query; + this.fullPmql = this.getFullPmql(); + }, + onSearch() { + if (this.$refs.taskList) { + this.$refs.taskList.fetch(true); + } + }, + onInboxRules() { + window.location.href = "/tasks/rules"; + }, + setInOverdueMessage(inOverdue) { + let inOverdueMessage = ""; + if (inOverdue) { + const taskText = + inOverdue > 1 + ? this.$t("Tasks").toLowerCase() + : this.$t("Task").toLowerCase(); + inOverdueMessage = this.$t( + "You have {{ inOverDue }} overdue {{ taskText }} pending", + { inOverDue: inOverdue, taskText } + ); + } + this.inOverdueMessage = inOverdueMessage; + }, + getFullPmql() { + let fullPmqlString = ""; + + if (this.filtersPmql && this.filtersPmql !== "") { + fullPmqlString = this.filtersPmql; + } + + if (fullPmqlString !== "" && this.pmql && this.pmql !== "") { + fullPmqlString = `${fullPmqlString} AND ${this.pmql}`; + } + + if (fullPmqlString === "" && this.pmql && this.pmql !== "") { + fullPmqlString = this.pmql; + } + + return fullPmqlString; + }, + }, +}; diff --git a/resources/views/tasks/index.blade.php b/resources/views/tasks/index.blade.php index cc3082c845..41cb76000e 100644 --- a/resources/views/tasks/index.blade.php +++ b/resources/views/tasks/index.blade.php @@ -1,7 +1,7 @@ @extends('layouts.layout') @section('title') - {{__($title)}} + {{ __($title) }} @endsection @section('sidebar') @@ -9,175 +9,157 @@ @endsection @section('breadcrumbs') - @include('shared.breadcrumbs', ['routes' => [ - __('Tasks') => route('tasks.index'), - __($title) => null, - ]]) + @include('shared.breadcrumbs', [ + 'routes' => [ + __('Tasks') => route('tasks.index'), + __($title) => null, + ], + ]) @endsection + @section('content') -
-
-
- - @{{ inOverdueMessage }} - -
-
+
+
+
+
+
+ + @{{ inOverdueMessage }} + +
+
-
-
- - -
-
-
-
-
-
- -
- -
+
+ +
-
@endsection @section('js') - + @endsection @section('css') @@ -222,14 +204,17 @@ class="ml-md-2" min-height: 25px; border-radius: 50%; } + .task-nav { border-bottom: 0 !important; } + .task-nav-link.active { color: #1572C2 !important; font-weight: 700; font-size: 15px; } + .task-nav-link { color: #556271; font-weight: 400; @@ -237,25 +222,231 @@ class="ml-md-2" border-top-left-radius: 5px !important; border-top-right-radius: 5px !important; } + .task-list-body { border-radius: 5px; } + .task-inbox-rules { - width: max-content; + width: max-content; } + .task-inbox-rules-content { - display: flex; - justify-content: space-between; - padding: 15px; + display: flex; + justify-content: space-between; + padding: 15px; } + .task-inbox-rules-content-text { - width: 310px; - padding-left: 10px; + width: 310px; + padding-left: 10px; } + @endsection diff --git a/tests/Feature/Api/UserConfigurationTest.php b/tests/Feature/Api/UserConfigurationTest.php index 0a2b4a0c8d..95fdce0acc 100644 --- a/tests/Feature/Api/UserConfigurationTest.php +++ b/tests/Feature/Api/UserConfigurationTest.php @@ -55,6 +55,9 @@ public function testStoreUserConfigurationAndGetNewValues() 'tasks' => [ 'isMenuCollapse' => false, ], + 'tasks_inbox' => [ + 'isMenuCollapse' => false, + ], ]; $response = $this->apiCall('PUT', self::API_TEST_URL, ['ui_configuration' => $values]); @@ -74,6 +77,7 @@ public function testStoreUserConfigurationAndGetNewValues() $this->assertEquals($uiConfig->cases->isMenuCollapse, $values['cases']['isMenuCollapse']); $this->assertEquals($uiConfig->requests->isMenuCollapse, $values['requests']['isMenuCollapse']); $this->assertEquals($uiConfig->tasks->isMenuCollapse, $values['tasks']['isMenuCollapse']); + $this->assertEquals($uiConfig->tasks_inbox->isMenuCollapse, $values['tasks_inbox']['isMenuCollapse']); } /** @@ -86,7 +90,7 @@ public function testStoreUserConfigurationWithInvalidValues() // Validate the header status code $response->assertStatus(422); - $this->assertEquals('The Ui configuration field is required. (and 4 more errors)', $response->json()['message']); + $this->assertEquals('The Ui configuration field is required. (and 5 more errors)', $response->json()['message']); // An incomplete ui_configuration $values = [ @@ -99,6 +103,9 @@ public function testStoreUserConfigurationWithInvalidValues() 'tasks' => [ 'isMenuCollapse' => false, ], + 'tasks_inbox' => [ + 'isMenuCollapse' => false, + ], ]; $response = $this->apiCall('PUT', self::API_TEST_URL, ['ui_configuration' => $values]); // Validate the header status code