Bug 33547: Add missing action button for non-table view
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / vue / components / Preservation / TrainsShow.vue
1 <template>
2     <transition name="modal">
3         <div v-if="show_modal" class="modal">
4             <h2>{{ $__("Copy item to the following train") }}</h2>
5             <form @submit="copyItem($event)">
6                 <div class="page-section">
7                     <fieldset class="rows">
8                         <ol>
9                             <li>
10                                 <label class="required" for="train_list"
11                                     >{{ $__("Select a train") }}:</label
12                                 >
13                                 <v-select
14                                     v-model="train_id_selected_for_copy"
15                                     label="name"
16                                     :options="train_list"
17                                     :reduce="t => t.train_id"
18                                 >
19                                     <template #search="{ attributes, events }">
20                                         <input
21                                             :required="
22                                                 !train_id_selected_for_copy
23                                             "
24                                             class="vs__search"
25                                             v-bind="attributes"
26                                             v-on="events"
27                                         />
28                                     </template>
29                                 </v-select>
30                                 <span class="required">{{
31                                     $__("Required")
32                                 }}</span>
33                             </li>
34                         </ol>
35                     </fieldset>
36                     <fieldset class="action">
37                         <input type="submit" value="Copy" />
38                         <input
39                             type="button"
40                             @click="show_modal = false"
41                             :value="$__('Close')"
42                         />
43                     </fieldset>
44                 </div>
45             </form>
46         </div>
47     </transition>
48     <div v-if="!initialized">{{ $__("Loading") }}</div>
49     <div v-else id="trains_show">
50         <Toolbar>
51             <ToolbarButton
52                 v-if="train.closed_on == null"
53                 :to="{
54                     name: 'TrainsFormAddItem',
55                     params: { train_id: train.train_id },
56                 }"
57                 class="btn btn-default"
58                 icon="plus"
59                 :title="$__('Add items')"
60             />
61             <span
62                 v-else
63                 class="btn btn-default"
64                 disabled="disabled"
65                 :title="$__('Cannot add items to a closed train')"
66             >
67                 <font-awesome-icon icon="plus" /> {{ $__("Add items") }}
68             </span>
69             <ToolbarButton
70                 :to="{
71                     name: 'TrainsFormEdit',
72                     params: { train_id: train.train_id },
73                 }"
74                 class="btn btn-default"
75                 icon="pencil"
76                 :title="$__('Edit')"
77             />
78             <a @click="deleteTrain(train)" class="btn btn-default"
79                 ><font-awesome-icon icon="trash" /> {{ $__("Delete") }}</a
80             >
81             <a
82                 v-if="!train.closed_on"
83                 class="btn btn-default"
84                 @click="closeTrain"
85                 ><font-awesome-icon icon="remove" /> {{ $__("Close") }}</a
86             >
87             <a
88                 v-else-if="!train.sent_on"
89                 class="btn btn-default"
90                 @click="sendTrain"
91                 ><font-awesome-icon icon="paper-plane" /> {{ $__("Send") }}</a
92             >
93             <a
94                 v-else-if="!train.received_on"
95                 class="btn btn-default"
96                 @click="receiveTrain"
97                 ><font-awesome-icon icon="inbox" /> {{ $__("Receive") }}</a
98             >
99         </Toolbar>
100         <h2>
101             {{ $__("Train #%s").format(train.train_id) }}
102         </h2>
103         <div>
104             <fieldset class="rows">
105                 <ol>
106                     <li>
107                         <label>{{ $__("Name") }}:</label>
108                         <span>
109                             {{ train.name }}
110                         </span>
111                     </li>
112                     <li>
113                         <label>{{ $__("Description") }}:</label>
114                         <span>
115                             {{ train.description }}
116                         </span>
117                     </li>
118                     <li v-if="train.closed_on">
119                         <label>{{ $__("Closed on") }}:</label>
120                         <span>
121                             {{ format_date(train.closed_on) }}
122                         </span>
123                     </li>
124                     <li v-if="train.sent_on">
125                         <label>{{ $__("Sent on") }}:</label>
126                         <span>
127                             {{ format_date(train.sent_on) }}
128                         </span>
129                     </li>
130                     <li v-if="train.received_on">
131                         <label>{{ $__("Received on") }}:</label>
132                         <span>
133                             {{ format_date(train.received_on) }}
134                         </span>
135                     </li>
136                     <li>
137                         <label
138                             >{{
139                                 $__("Status for item added to this train")
140                             }}:</label
141                         >
142                         <span>{{
143                             get_lib_from_av("av_notforloan", train.not_for_loan)
144                         }}</span>
145                     </li>
146                     <li>
147                         <label>{{ $__("Default processing") }}:</label>
148                         <span>
149                             {{ train.default_processing.name }}
150                         </span>
151                     </li>
152                 </ol>
153             </fieldset>
154             <fieldset v-if="train.items.length" class="rows">
155                 <legend>{{ $__("Items") }}</legend>
156                 <table v-if="item_table.display" :id="table_id"></table>
157                 <ol v-else>
158                     <li
159                         :id="`item_${counter}`"
160                         class="rows"
161                         v-for="(item, counter) in train.items"
162                         v-bind:key="counter"
163                     >
164                         <label
165                             >{{ item.user_train_item_id }}
166                             <span class="action_links">
167                                 <a
168                                     role="button"
169                                     @click="editItem(item.train_item_id)"
170                                     :title="$__('Edit')"
171                                     ><i class="fa fa-pencil"></i
172                                 ></a>
173                                 <a
174                                     role="button"
175                                     @click="removeItem(item.train_item_id)"
176                                     :title="$__('Remove')"
177                                     ><i class="fa fa-trash"></i
178                                 ></a>
179                                 <a
180                                     v-if="train.received_on !== null"
181                                     role="button"
182                                     @click="
183                                         selectTrainForCopy(item.train_item_id)
184                                     "
185                                     :title="$__('Copy')"
186                                     ><i class="fa fa-copy"></i
187                                 ></a>
188                                 <a
189                                     v-if="item.processing.letter_code !== null"
190                                     role="button"
191                                     @click="printSlip(item.train_item_id)"
192                                     :title="$__('Print')"
193                                     ><i class="fa fa-print"></i></a
194                             ></span>
195                         </label>
196                         <div class="attributes_values">
197                             <span
198                                 :id="`attribute_${counter_attribute}`"
199                                 class="attribute_value"
200                                 v-for="(
201                                     attribute, counter_attribute
202                                 ) in item.attributes"
203                                 v-bind:key="counter_attribute"
204                             >
205                                 {{ attribute.processing_attribute.name }}={{
206                                     attribute._strings.value.str
207                                 }}
208                             </span>
209                         </div>
210                     </li>
211                 </ol>
212             </fieldset>
213             <fieldset class="action">
214                 <router-link
215                     :to="{ name: 'TrainsList' }"
216                     role="button"
217                     class="cancel"
218                     >{{ $__("Close") }}</router-link
219                 >
220             </fieldset>
221         </div>
222     </div>
223 </template>
224
225 <script>
226 import { inject, createVNode, render } from "vue"
227 import { APIClient } from "../../fetch/api-client"
228 import { useDataTable } from "../../composables/datatables"
229 import Toolbar from "../Toolbar.vue"
230 import ToolbarButton from "../ToolbarButton.vue"
231
232 export default {
233     setup() {
234         const format_date = $date
235
236         const AVStore = inject("AVStore")
237         const { get_lib_from_av } = AVStore
238
239         const { setConfirmationDialog, setMessage, setWarning } =
240             inject("mainStore")
241
242         const table_id = "item_list"
243         useDataTable(table_id)
244
245         return {
246             format_date,
247             get_lib_from_av,
248             table_id,
249             setConfirmationDialog,
250             setMessage,
251             setWarning,
252         }
253     },
254     data() {
255         return {
256             train: {
257                 train_id: null,
258                 name: "",
259                 description: "",
260             },
261             initialized: false,
262             show_modal: false,
263             item_table: {
264                 display: false,
265                 data: [],
266                 columns: [],
267             },
268             train_list: [],
269             train_id_selected_for_copy: null,
270             train_item_id_to_copy: null,
271             av_options: {},
272         }
273     },
274     beforeRouteEnter(to, from, next) {
275         next(vm => {
276             vm.getTrain(to.params.train_id).then(() => vm.build_datatable())
277             vm.getTrainList()
278         })
279     },
280     methods: {
281         async getTrain(train_id) {
282             const client = APIClient.preservation
283             await client.trains.get(train_id).then(
284                 train => {
285                     this.train = train
286                     let display_table = this.train.items.every(
287                         item =>
288                             item.processing_id ==
289                             this.train.default_processing_id
290                     )
291                     if (display_table) {
292                         this.item_table.data = []
293                         this.train.items.forEach(item => {
294                             let item_row = {}
295                             this.train.default_processing.attributes.forEach(
296                                 attribute => {
297                                     item_row[
298                                         attribute.processing_attribute_id
299                                     ] = item.attributes
300                                         .filter(
301                                             a =>
302                                                 a.processing_attribute_id ==
303                                                 attribute.processing_attribute_id
304                                         )
305                                         .map(a => a._strings.value.str)
306                                 }
307                             )
308                             item_row.item = item
309                             this.item_table.data.push(item_row)
310                         })
311                         this.item_table.columns = []
312                         this.item_table.columns.push({
313                             name: "",
314                             title: this.$__("ID"),
315                             data: "item.user_train_item_id",
316                         })
317                         train.default_processing.attributes.forEach(a =>
318                             this.item_table.columns.push({
319                                 name: a.name,
320                                 title: a.name,
321                                 data: a.processing_attribute_id,
322                                 render: (data, type, row) => {
323                                     return data.join("<br/>")
324                                 },
325                             })
326                         )
327                         this.item_table.columns.push({
328                             name: "actions",
329                             className: "actions noExport",
330                             title: this.$__("Actions"),
331                             searchable: false,
332                             orderable: false,
333                             render: (data, type, row) => {
334                                 return ""
335                             },
336                         })
337                     }
338                     this.initialized = true
339                     this.item_table.display = display_table
340                 },
341                 error => {}
342             )
343         },
344         getTrainList: function () {
345             const client = APIClient.preservation
346             let q = { "me.closed_on": null }
347             client.trains.getAll(q).then(
348                 trains => (this.train_list = trains),
349                 error => {}
350             )
351         },
352         deleteTrain: function (train) {
353             this.setConfirmationDialog(
354                 {
355                     title: this.$__(
356                         "Are you sure you want to remove this train?"
357                     ),
358                     message: train.name,
359                     accept_label: this.$__("Yes, delete"),
360                     cancel_label: this.$__("No, do not delete"),
361                 },
362                 () => {
363                     const client = APIClient.preservation
364                     client.trains.delete(train.train_id).then(
365                         success => {
366                             this.setMessage(
367                                 this.$__("Train %s deleted").format(train.name),
368                                 true
369                             )
370                             this.$router.push({ name: "TrainsList" })
371                         },
372                         error => {}
373                     )
374                 }
375             )
376         },
377         async updateTrainDate(attribute) {
378             let train = JSON.parse(JSON.stringify(this.train))
379             let train_id = train.train_id
380             delete train.train_id
381             delete train.items
382             delete train.default_processing
383             train[attribute] = new Date()
384             const client = APIClient.preservation
385             if (train_id) {
386                 return client.trains
387                     .update(train, train_id)
388                     .then(() => this.getTrain(this.train.train_id))
389             } else {
390                 return client.trains
391                     .create(train)
392                     .then(() => this.getTrain(this.train.train_id))
393             }
394         },
395         closeTrain() {
396             this.updateTrainDate("closed_on")
397         },
398         sendTrain() {
399             this.updateTrainDate("sent_on")
400         },
401         receiveTrain() {
402             this.updateTrainDate("received_on").then(
403                 success => {
404                     // Rebuild the table to show the "copy" button
405                     $("#" + this.table_id)
406                         .DataTable()
407                         .destroy()
408                     this.build_datatable()
409                 },
410                 error => {}
411             )
412         },
413         editItem(train_item_id) {
414             this.$router.push({
415                 name: "TrainsFormEditItem",
416                 params: { train_id: this.train.train_id, train_item_id },
417             })
418         },
419         removeItem(train_item_id) {
420             this.setConfirmationDialog(
421                 {
422                     title: this.$__(
423                         "Are you sure you want to remove this item?"
424                     ),
425                     accept_label: this.$__("Yes, remove"),
426                     cancel_label: this.$__("No, do not remove"),
427                 },
428                 () => {
429                     const client = APIClient.preservation
430                     client.train_items
431                         .delete(this.train.train_id, train_item_id)
432                         .then(
433                             success => {
434                                 this.setMessage(this.$__("Item removed"), true)
435                                 this.getTrain(this.train.train_id).then(() => {
436                                     $("#" + this.table_id)
437                                         .DataTable()
438                                         .destroy()
439                                     this.build_datatable()
440                                 })
441                             },
442                             error => {}
443                         )
444                 }
445             )
446         },
447         printSlip(train_item_id) {
448             window.open(
449                 "/cgi-bin/koha/preservation/print_slip.pl?train_item_id=" +
450                     train_item_id,
451                 "_blank"
452             )
453         },
454         selectTrainForCopy(train_item_id) {
455             this.show_modal = true
456             this.train_item_id_to_copy = train_item_id
457         },
458         copyItem(event) {
459             event.preventDefault()
460             const client = APIClient.preservation
461             client.train_items
462                 .copy(
463                     this.train_id_selected_for_copy,
464                     this.train.train_id,
465                     this.train_item_id_to_copy
466                 )
467                 .then(
468                     success => {
469                         this.setMessage(this.$__("Item copied successfully."))
470                         this.show_modal = false
471                     },
472                     error => {
473                         this.setWarning(
474                             this.$__(
475                                 "Item cannot be copied to a train, it is already in a non-received train."
476                             )
477                         )
478                     }
479                 )
480         },
481         build_datatable: function () {
482             let table_id = this.table_id
483             let item_table = this.item_table
484             let removeItem = this.removeItem
485             let editItem = this.editItem
486             let printSlip = this.printSlip
487             let selectTrainForCopy = this.selectTrainForCopy
488             let train = this.train
489
490             let table = KohaTable(table_id, {
491                 data: item_table.data,
492                 ordering: false,
493                 autoWidth: false,
494                 columns: item_table.columns,
495                 drawCallback: function (settings) {
496                     var api = new $.fn.dataTable.Api(settings)
497                     $.each($(this).find("td.actions"), function (index, e) {
498                         let tr = $(this).parent()
499                         let train_item = api.row(tr).data().item
500                         let train_item_id = train_item.train_item_id
501
502                         let editButton = createVNode(
503                             "a",
504                             {
505                                 class: "btn btn-default btn-xs",
506                                 role: "button",
507                                 onClick: () => {
508                                     editItem(train_item_id)
509                                 },
510                             },
511                             [
512                                 createVNode("i", {
513                                     class: "fa fa-pencil",
514                                     "aria-hidden": "true",
515                                 }),
516                                 " ",
517                                 __("Edit"),
518                             ]
519                         )
520
521                         let removeButton = createVNode(
522                             "a",
523                             {
524                                 class: "btn btn-default btn-xs",
525                                 role: "button",
526                                 onClick: () => {
527                                     removeItem(train_item_id)
528                                 },
529                             },
530                             [
531                                 createVNode("i", {
532                                     class: "fa fa-trash",
533                                     "aria-hidden": "true",
534                                 }),
535                                 " ",
536                                 __("Remove"),
537                             ]
538                         )
539                         let buttons = [editButton, " ", removeButton]
540
541                         if (train.received_on !== null) {
542                             buttons.push(" ")
543                             buttons.push(
544                                 createVNode(
545                                     "a",
546                                     {
547                                         class: "btn btn-default btn-xs",
548                                         role: "button",
549                                         onClick: () => {
550                                             selectTrainForCopy(train_item_id)
551                                         },
552                                     },
553                                     [
554                                         createVNode("i", {
555                                             class: "fa fa-copy",
556                                             "aria-hidden": "true",
557                                         }),
558                                         " ",
559                                         __("Copy"),
560                                     ]
561                                 )
562                             )
563                         }
564
565                         if (train_item.processing.letter_code !== null) {
566                             let printButton = createVNode(
567                                 "a",
568                                 {
569                                     class: "btn btn-default btn-xs",
570                                     role: "button",
571                                     onClick: () => {
572                                         printSlip(train_item_id)
573                                     },
574                                 },
575                                 [
576                                     createVNode("i", {
577                                         class: "fa fa-print",
578                                         "aria-hidden": "true",
579                                     }),
580                                     __("Print slip"),
581                                 ]
582                             )
583                             buttons.push(" ")
584                             buttons.push(printButton)
585                         }
586
587                         let n = createVNode("span", {}, buttons)
588                         render(n, e)
589                     })
590                 },
591             })
592         },
593     },
594     components: { Toolbar, ToolbarButton },
595     name: "TrainsShow",
596 }
597 </script>
598 <style scoped>
599 .action_links a {
600     padding-left: 0.2em;
601     font-size: 11px;
602 }
603 .attributes_values {
604     float: left;
605 }
606 .attribute_value {
607     display: block;
608 }
609 .modal {
610     position: fixed;
611     z-index: 9998;
612     overflow-y: inherit !important;
613     top: 0;
614     left: 0;
615     width: 35%;
616     height: 30%;
617     background-color: rgba(0, 0, 0, 0.5);
618     display: table;
619     transition: opacity 0.3s ease;
620     margin: auto;
621     padding: 20px 30px;
622     background-color: #fff;
623     border-radius: 2px;
624     box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
625     transition: all 0.3s ease;
626 }
627 </style>