Bug 32181: ERM - Fix 'filter by expired' when adding an agreement to EBSCO's package
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / vue / components / ERM / AgreementsList.vue
1 <template>
2     <div v-if="!initialized">{{ $__("Loading") }}</div>
3     <div v-else-if="agreements" id="agreements_list">
4         <Toolbar v-if="before_route_entered" />
5         <fieldset v-if="agreements.length" class="filters">
6             <label for="expired_filter">{{ $__("Filter by expired") }}:</label>
7             <input
8                 type="checkbox"
9                 id="expired_filter"
10                 v-model="filters.by_expired"
11                 @keyup.enter="filter_table"
12             />
13             {{ $__("on") }}
14             <flat-pickr
15                 id="max_expiration_date_filter"
16                 v-model="filters.max_expiration_date"
17                 :config="fp_config"
18             />
19
20             <input
21                 @click="filter_table"
22                 id="filter_table"
23                 type="button"
24                 :value="$__('Filter')"
25             />
26         </fieldset>
27         <div v-if="agreements.length" class="page-section">
28             <table :id="table_id"></table>
29         </div>
30         <div v-else-if="initialized" class="dialog message">
31             {{ $__("There are no agreements defined") }}
32         </div>
33     </div>
34 </template>
35
36 <script>
37 import flatPickr from "vue-flatpickr-component"
38 import Toolbar from "./AgreementsToolbar.vue"
39 import { inject, createVNode, render } from "vue"
40 import { storeToRefs } from "pinia"
41 import { fetchAgreements } from "../../fetch"
42 import { useDataTable, build_url } from "../../composables/datatables"
43
44 export default {
45     setup() {
46         const vendorStore = inject("vendorStore")
47         const { vendors } = storeToRefs(vendorStore)
48
49         const AVStore = inject("AVStore")
50         const { get_lib_from_av, map_av_dt_filter } = AVStore
51
52         const table_id = "agreement_list"
53         useDataTable(table_id)
54
55         return {
56             vendors,
57             get_lib_from_av,
58             map_av_dt_filter,
59             table_id,
60         }
61     },
62     data: function () {
63         return {
64             fp_config: flatpickr_defaults,
65             agreements: [],
66             initialized: false,
67             filters: {
68                 by_expired: this.$route.query.by_expired || false,
69                 max_expiration_date:
70                     this.$route.query.max_expiration_date || "",
71             },
72             before_route_entered: false,
73             building_table: false,
74         }
75     },
76     beforeRouteEnter(to, from, next) {
77         next(vm => {
78             vm.before_route_entered = true // FIXME This is ugly, but we need to distinguish when it's used as main component or child component (from EHoldingsEBSCOPAckagesShow for instance)
79             if (!vm.building_table) {
80                 vm.building_table = true
81                 vm.getAgreements().then(() => vm.build_datatable())
82             }
83         })
84     },
85     computed: {
86         datatable_url() {
87             let url = "/api/v1/erm/agreements"
88             if (this.filters.by_expired)
89                 url +=
90                     "?max_expiration_date=" + this.filters.max_expiration_date
91             return url
92         },
93     },
94     methods: {
95         async getAgreements() {
96             const agreements = await fetchAgreements()
97             this.agreements = agreements
98             this.initialized = true
99         },
100         show_agreement: function (agreement_id) {
101             this.$router.push("/cgi-bin/koha/erm/agreements/" + agreement_id)
102         },
103         edit_agreement: function (agreement_id) {
104             this.$router.push(
105                 "/cgi-bin/koha/erm/agreements/edit/" + agreement_id
106             )
107         },
108         delete_agreement: function (agreement_id) {
109             this.$router.push(
110                 "/cgi-bin/koha/erm/agreements/delete/" + agreement_id
111             )
112         },
113         select_agreement: function (agreement_id) {
114             this.$emit("select-agreement", agreement_id)
115             this.$emit("close")
116         },
117         filter_table: async function () {
118             if (this.before_route_entered) {
119                 let new_route = build_url(
120                     "/cgi-bin/koha/erm/agreements",
121                     this.filters
122                 )
123                 this.$router.push(new_route)
124             }
125             if (this.filters.by_expired) {
126                 if (!this.filters.max_expiration_date)
127                     this.filters.max_expiration_date = new Date()
128                         .toISOString()
129                         .substring(0, 10)
130             }
131             $("#" + this.table_id)
132                 .DataTable()
133                 .ajax.url(this.datatable_url)
134                 .draw()
135         },
136         table_url: function () {},
137         build_datatable: function () {
138             let show_agreement = this.show_agreement
139             let edit_agreement = this.edit_agreement
140             let delete_agreement = this.delete_agreement
141             let select_agreement = this.select_agreement
142             let get_lib_from_av = this.get_lib_from_av
143             let map_av_dt_filter = this.map_av_dt_filter
144             let datatable_url = this.datatable_url
145             let default_search = this.$route.query.q
146             let actions = this.before_route_entered ? "edit_delete" : "select"
147             let table_id = this.table_id
148
149             window["vendors"] = this.vendors.map(e => {
150                 e["_id"] = e["id"]
151                 e["_str"] = e["name"]
152                 return e
153             })
154             let vendors_map = this.vendors.reduce((map, e) => {
155                 map[e.id] = e
156                 return map
157             }, {})
158             let avs = [
159                 "av_agreement_statuses",
160                 "av_agreement_closure_reasons",
161                 "av_agreement_renewal_priorities",
162             ]
163             avs.forEach(function (av_cat) {
164                 window[av_cat] = map_av_dt_filter(av_cat)
165             })
166
167             window["av_agreement_is_perpetual"] = [
168                 { _id: 0, _str: _("No") },
169                 { _id: 1, _str: _("Yes") },
170             ]
171
172             const table = $("#" + table_id).kohaTable(
173                 {
174                     ajax: {
175                         url: datatable_url,
176                     },
177                     order: [[0, "asc"]],
178                     autoWidth: false,
179                     search: { search: default_search },
180                     columnDefs: [
181                         {
182                             targets: [0, 2],
183                             render: function (data, type, row, meta) {
184                                 if (type == "display") {
185                                     return escape_str(data)
186                                 }
187                                 return data
188                             },
189                         },
190                     ],
191                     columns: [
192                         {
193                             title: __("Name"),
194                             data: "me.agreement_id:me.name",
195                             searchable: true,
196                             orderable: true,
197                             render: function (data, type, row, meta) {
198                                 // Rendering done in drawCallback
199                                 return ""
200                             },
201                         },
202                         {
203                             title: __("Vendor"),
204                             data: "vendor_id",
205                             searchable: true,
206                             orderable: true,
207                             render: function (data, type, row, meta) {
208                                 return row.vendor_id != undefined
209                                     ? escape_str(
210                                           vendors_map[row.vendor_id].name
211                                       )
212                                     : ""
213                             },
214                         },
215                         {
216                             title: __("Description"),
217                             data: "description",
218                             searchable: true,
219                             orderable: true,
220                         },
221                         {
222                             title: __("Status"),
223                             data: "status",
224                             searchable: true,
225                             orderable: true,
226                             render: function (data, type, row, meta) {
227                                 return escape_str(
228                                     get_lib_from_av(
229                                         "av_agreement_statuses",
230                                         row.status
231                                     )
232                                 )
233                             },
234                         },
235                         {
236                             title: __("Closure reason"),
237                             data: "closure_reason",
238                             searchable: true,
239                             orderable: true,
240                             render: function (data, type, row, meta) {
241                                 return escape_str(
242                                     get_lib_from_av(
243                                         "av_agreement_closure_reasons",
244                                         row.closure_reason
245                                     )
246                                 )
247                             },
248                         },
249                         {
250                             title: __("Is perpetual"),
251                             data: "is_perpetual",
252                             searchable: true,
253                             orderable: true,
254                             render: function (data, type, row, meta) {
255                                 return escape_str(
256                                     row.is_perpetual ? _("Yes") : _("No")
257                                 )
258                             },
259                         },
260                         {
261                             title: __("Renewal priority"),
262                             data: "renewal_priority",
263                             searchable: true,
264                             orderable: true,
265                             render: function (data, type, row, meta) {
266                                 return escape_str(
267                                     get_lib_from_av(
268                                         "av_agreement_renewal_priorities",
269                                         row.renewal_priority
270                                     )
271                                 )
272                             },
273                         },
274                         {
275                             title: __("Actions"),
276                             data: function (row, type, val, meta) {
277                                 return '<div class="actions"></div>'
278                             },
279                             className: "actions noExport",
280                             searchable: false,
281                             orderable: false,
282                         },
283                     ],
284                     drawCallback: function (settings) {
285                         var api = new $.fn.dataTable.Api(settings)
286
287                         if (actions == "edit_delete") {
288                             $.each(
289                                 $(this).find("td .actions"),
290                                 function (index, e) {
291                                     let tr = $(this).parent().parent()
292                                     let agreement_id = api
293                                         .row(tr)
294                                         .data().agreement_id
295                                     let editButton = createVNode(
296                                         "a",
297                                         {
298                                             class: "btn btn-default btn-xs",
299                                             role: "button",
300                                             onClick: () => {
301                                                 edit_agreement(agreement_id)
302                                             },
303                                         },
304                                         [
305                                             createVNode("i", {
306                                                 class: "fa fa-pencil",
307                                                 "aria-hidden": "true",
308                                             }),
309                                             __("Edit"),
310                                         ]
311                                     )
312
313                                     let deleteButton = createVNode(
314                                         "a",
315                                         {
316                                             class: "btn btn-default btn-xs",
317                                             role: "button",
318                                             onClick: () => {
319                                                 delete_agreement(agreement_id)
320                                             },
321                                         },
322                                         [
323                                             createVNode("i", {
324                                                 class: "fa fa-trash",
325                                                 "aria-hidden": "true",
326                                             }),
327                                             __("Delete"),
328                                         ]
329                                     )
330
331                                     let n = createVNode("span", {}, [
332                                         editButton,
333                                         " ",
334                                         deleteButton,
335                                     ])
336                                     render(n, e)
337                                 }
338                             )
339                         } else {
340                             $.each(
341                                 $(this).find("td .actions"),
342                                 function (index, e) {
343                                     let tr = $(this).parent().parent()
344                                     let agreement_id = api
345                                         .row(tr)
346                                         .data().agreement_id
347                                     let selectButton = createVNode(
348                                         "a",
349                                         {
350                                             class: "btn btn-default btn-xs",
351                                             role: "button",
352                                             onClick: () => {
353                                                 select_agreement(agreement_id)
354                                             },
355                                         },
356                                         [
357                                             createVNode("i", {
358                                                 class: "fa fa-check",
359                                                 "aria-hidden": "true",
360                                             }),
361                                             __("Select"),
362                                         ]
363                                     )
364
365                                     let n = createVNode("span", {}, [
366                                         selectButton,
367                                     ])
368                                     render(n, e)
369                                 }
370                             )
371                         }
372
373                         $.each(
374                             $(this).find("tbody tr td:first-child"),
375                             function (index, e) {
376                                 let tr = $(this).parent()
377                                 let row = api.row(tr).data()
378                                 if (!row) return // Happen if the table is empty
379                                 let n = createVNode(
380                                     "a",
381                                     {
382                                         role: "button",
383                                         onClick: () => {
384                                             show_agreement(row.agreement_id)
385                                         },
386                                     },
387                                     `${row.name} (#${row.agreement_id})`
388                                 )
389                                 render(n, e)
390                             }
391                         )
392                     },
393                     preDrawCallback: function (settings) {
394                         $("#" + table_id)
395                             .find("thead th")
396                             .eq(1)
397                             .attr("data-filter", "vendors")
398                         $("#" + table_id)
399                             .find("thead th")
400                             .eq(3)
401                             .attr("data-filter", "av_agreement_statuses")
402                         $("#" + table_id)
403                             .find("thead th")
404                             .eq(4)
405                             .attr("data-filter", "av_agreement_closure_reasons")
406                         $("#" + table_id)
407                             .find("thead th")
408                             .eq(5)
409                             .attr("data-filter", "av_agreement_is_perpetual")
410                         $("#" + table_id)
411                             .find("thead th")
412                             .eq(6)
413                             .attr(
414                                 "data-filter",
415                                 "av_agreement_renewal_priorities"
416                             )
417                     },
418                 },
419                 agreement_table_settings,
420                 1
421             )
422         },
423     },
424     mounted() {
425         if (!this.building_table) {
426             this.building_table = true
427             this.getAgreements().then(() => this.build_datatable())
428         }
429     },
430     components: { flatPickr, Toolbar },
431     name: "AgreementsList",
432     emits: ["select-agreement", "close"],
433 }
434 </script>
435
436 <style scoped>
437 #agreement_list {
438     display: table;
439 }
440 .filters > input[type="checkbox"],
441 .filters > input[type="button"] {
442     margin-left: 1rem;
443 }
444 </style>