From c4590e1000e1844db4def1f94683a9e79dc94f47 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Tue, 13 Sep 2016 16:08:07 +0000 Subject: [PATCH] Bug 17297 - Add React based item message editor Signed-off-by: Josef Moravec --- catalogue/moredetail.pl | 9 +- koha-tmpl/intranet-tmpl/prog/css/staff-global.css | 96 +++++++------ .../prog/en/modules/catalogue/moredetail.tt | 11 ++ .../intranet-tmpl/prog/js/public/moredetail.js | 150 +++++++++++++++++++++ 4 files changed, 220 insertions(+), 46 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/js/public/moredetail.js diff --git a/catalogue/moredetail.pl b/catalogue/moredetail.pl index 125b103..b443b20 100755 --- a/catalogue/moredetail.pl +++ b/catalogue/moredetail.pl @@ -30,14 +30,15 @@ use C4::Acquisition; use C4::Output; use C4::Auth; use C4::Serials; -use C4::Members; # to use GetMember -use C4::Search; # enabled_staff_search_views +use C4::Members; # to use GetMember +use C4::Search; # enabled_staff_search_views use C4::Reserves qw(GetReservesFromBiblionumber); use Koha::Acquisition::Booksellers; use Koha::AuthorisedValues; use Koha::DateUtils; use Koha::Items; +use Koha::Item::Messages; use Koha::Patrons; my $query=new CGI; @@ -133,8 +134,10 @@ foreach ( keys %{$data} ) { } ($itemnumber) and @items = (grep {$_->{'itemnumber'} == $itemnumber} @items); +my $item_messages; foreach my $item (@items){ $item->{object} = Koha::Items->find( $item->{itemnumber} ); + $item_messages->{ $item->{itemnumber} } = ( Koha::Item::Messages->search( { itemnumber => $item->{itemnumber} } )->unblessed ); $item->{'collection'} = $ccodes->{ $item->{ccode} } if ($ccodes); $item->{'itype'} = $itemtypes->{ $item->{'itype'} }->{'translated_description'}; $item->{'replacementprice'} = sprintf( "%.2f", $item->{'replacementprice'} ); @@ -226,6 +229,7 @@ $template->param( z3950_search_params => C4::Search::z3950_search_args(GetBiblioData($biblionumber)), subtitle => $subtitle, hidepatronname => $hidepatronname, + item_messages => $item_messages, ); $template->param(ONLY_ONE => 1) if ( $itemnumber && $showncount != @items ); $template->{'VARS'}->{'searchid'} = $query->param('searchid'); @@ -261,6 +265,7 @@ $template->param (countdeletedorders => $count_deletedorders_using_biblio); my $holds = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 }); my $holdcount = scalar( @$holds ); $template->param( holdcount => scalar ( @$holds ) ); +warn Data::Dumper::Dumper( $item_messages ); output_html_with_http_headers $query, $cookie, $template->output; diff --git a/koha-tmpl/intranet-tmpl/prog/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/css/staff-global.css index 6b22201..2dd6f47 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/staff-global.css +++ b/koha-tmpl/intranet-tmpl/prog/css/staff-global.css @@ -75,12 +75,12 @@ h3 { } h4 { - font-size : 116%; + font-size : 116%; font-weight : bold; } h5 { - font-size : 100%; + font-size : 100%; font-weight : bold; } @@ -614,7 +614,7 @@ div.yui-b fieldset.brief fieldset legend { margin-left: 20px; } -fieldset.rows { +fieldset.rows { border-width : 1px; border:2px solid #b9d8d9; float : left; @@ -622,7 +622,7 @@ font-size : 90%; clear : left; margin: .9em 0 0 0; padding: 0; -width: 100%; +width: 100%; } fieldset.rows.unselected { @@ -631,17 +631,17 @@ fieldset.rows.unselected { border: 0; } -fieldset.rows legend { +fieldset.rows legend { margin-left: 1em; font-weight: bold; font-size : 110%; } -fieldset.rows label, fieldset.rows span.label { - float: left; +fieldset.rows label, fieldset.rows span.label { + float: left; font-weight : bold; - width: 6em; - margin-right: 1em; + width: 6em; + margin-right: 1em; text-align: right; } @@ -652,8 +652,8 @@ fieldset.rows fieldset { padding : .3em; } -.yui-b fieldset.rows label, .yui-b fieldset.rows span.label { - width: 9em; +.yui-b fieldset.rows label, .yui-b fieldset.rows span.label { + width: 9em; } .yui-b fieldset.rows td label, .yui-b fieldset.rows td span.label { @@ -664,8 +664,8 @@ fieldset.rows fieldset { margin-left : 10.5em; } -.yui-u fieldset.rows label, .yui-u fieldset.rows span.label { - width: 10em; +.yui-u fieldset.rows label, .yui-u fieldset.rows span.label { + width: 10em; } .yui-u fieldset.rows div.hint { @@ -674,20 +674,20 @@ fieldset.rows fieldset { fieldset.rows.left label, fieldset.rows.left span.label { width : 8em; - text-align : left; + text-align : left; } -fieldset.rows ol { -padding: 1em 1em 0 1em; +fieldset.rows ol { +padding: 1em 1em 0 1em; list-style-type: none; } -fieldset.rows li { +fieldset.rows li { float : left; clear : left; padding-bottom: 1em; list-style-type: none; -width: 100%; +width: 100%; } fieldset.rows.left li { @@ -783,17 +783,17 @@ div.rows+div.rows { div.rows { float : left; clear : left; -margin: 0 0 0 0; +margin: 0 0 0 0; padding: 0; -width: 100%; +width: 100%; } -div.rows span.label { - float: left; +div.rows span.label { + float: left; font-weight : bold; width: 9em; - margin-right: 1em; + margin-right: 1em; text-align: left; padding-top: 0; } @@ -802,8 +802,8 @@ div.rows span.label { white-space: normal; } -div.rows ol { -padding: .5em 1em 0 0; +div.rows ol { +padding: .5em 1em 0 0; list-style-type: none; } @@ -818,7 +818,7 @@ clear : left; padding-bottom: .2em; padding-top: .1em; list-style-type: none; -width: 100%; +width: 100%; } a.cancel { @@ -946,8 +946,8 @@ ol.bibliodetails span.label { border-right : 1px solid #E8E8E8; float : left; font-weight: bold; - width: 12em; - margin-right: 1em; + width: 12em; + margin-right: 1em; } div.listgroup { @@ -966,6 +966,14 @@ div.listgroup input { font-size: 80%; } +div.listgroup ol li span.label i { + margin-right : .5em; +} + +div.listgroup ol li button,a { + margin-left : .5em; +} + div.sysprefs h3 { margin : .2em 0 .2em .4em; } @@ -1035,7 +1043,7 @@ span.expired { } div.help { - margin: .9em 0 0 0; + margin: .9em 0 0 0; } .blocker { @@ -1092,12 +1100,12 @@ div.first fieldset { .dialog table td { text-align : left; } - + .dialog h2, .dialog h3, .dialog h4 { margin : auto; text-align : center; } - + .dialog input { background-color : #FFF; border : 1px solid #bcbcbc; @@ -1252,11 +1260,11 @@ div.note i.fa-exclamation { div.results { padding : .7em 0; } - + .accesskey { text-decoration : underline; } - + label.required, span.required { color : #C00; @@ -1388,7 +1396,7 @@ h1#logo a { } #closewindow a { - font-weight : bold; + font-weight : bold; } .patroninfo+#menu { @@ -1421,10 +1429,10 @@ li.email { } .clearfix:after { - content: "."; - display: block; - height: 0; - clear: both; + content: "."; + display: block; + height: 0; + clear: both; visibility: hidden; } @@ -1664,7 +1672,7 @@ input.warning { } #displayexample { - padding: 5px; + padding: 5px; margin-bottom: 10px; background-color: #CCCCCC; } @@ -1781,7 +1789,7 @@ span.permissiondesc { .results_summary { display: block; - font-size : 85%; + font-size : 85%; color: #707070; padding : 0 0 .5em 0; } @@ -1886,10 +1894,10 @@ fieldset.rows+h3 {clear:both;padding-top:.5em;} } .m880 { - display:block; - text-align:right; - float:right; - width:50%; + display:block; + text-align:right; + float:right; + width:50%; padding-left:20px } diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt index b04fd39..4b4df45 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt @@ -1,5 +1,7 @@ +[% USE To %] [% USE Koha %] [% USE Branches %] +[% USE AuthorisedValues %] [% INCLUDE 'doc-head-open.inc' %] Koha › Catalog › Item details for [% title | html %] [% FOREACH subtitl IN subtitle %] [% subtitl.subfield | html %][% END %] [% INCLUDE 'doc-head-close.inc' %] @@ -13,8 +15,16 @@ // + [% USE KohaDates %] @@ -199,6 +209,7 @@ [% END %] +

History

    diff --git a/koha-tmpl/intranet-tmpl/prog/js/public/moredetail.js b/koha-tmpl/intranet-tmpl/prog/js/public/moredetail.js new file mode 100644 index 0000000..80ab376 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/public/moredetail.js @@ -0,0 +1,150 @@ +var React = require('react'); +var ReactDOM = require('react-dom'); + +var av_descriptions = []; +$( document ).ready(function() { + for (var i = 0; i < authorised_values.length; i++) { + var av = authorised_values[i]; + av_descriptions[av.authorised_value] = av.lib; + } + + $('.item-messages').each(function() { + var itemnumber = parseInt( $(this).attr('id').split('item-messages-')[1] ); + ReactDOM.render( + , + this + ); + }); +}); + +var ItemMessages = React.createClass({ + propTypes: { + messages: React.PropTypes.array.isRequired, + itemnumber: React.PropTypes.number.isRequired, + }, + getInitialState: function() { + return { messages: this.props.messages }; + }, + addMessage: function(message) { + this.setState(function(state) { + var newData = state.messages.slice(); + newData.push( message ); + return {messages: newData}; + }); + }, + removeMessage: function(index) { + var message = this.state.messages[index]; + var itemMessage = this; + $.ajax({ + url: '/api/v1/items/' + message.itemnumber + '/messages/' + message.item_message_id, + type: 'DELETE', + success: function( result ) { + itemMessage.setState(function(state) { + var newData = state.messages.slice(); + newData.splice(index, 1); + return {messages: newData}; + }); + } + }); + }, + render: function () { + var item_messages = this; + return
    +

    Messages

    +
      + {this.state.messages.map(function(message, index) { + return + })} + +
    +
    ; + } +}); + +var ItemMessage = React.createClass({ + propTypes: { + message: React.PropTypes.object.isRequired, + index: React.PropTypes.number.isRequired, + onRemove: React.PropTypes.func.isRequired, + }, + removeMessage: function() { + if ( confirm( ARE_YOU_SURE + this.props.message.message ) ) { + this.props.onRemove(this.props.index); + } + }, + render: function () { + return
  1. + + + {av_descriptions[this.props.message.type]} + + {this.props.message.message} +
  2. + } +}); + +var ItemMessageCreator = React.createClass({ + propTypes: { + itemnumber: React.PropTypes.number.isRequired, + onAdd: React.PropTypes.func.isRequired, + }, + getInitialState: function () { + return { + message: "", + type: authorised_values[0].authorised_value, + }; + }, + addMessage: function() { + var self = this; + var item_message = { + type: this.state.type, + message: this.state.message, + }; + $.ajax({ + type: 'POST', + url: '/api/v1/items/' + this.props.itemnumber + '/messages', + data: JSON.stringify(item_message), + success: function(data) { + self.cancelMessage(); + self.props.onAdd(data); + }, + error: function (xhr, ajaxOptions, thrownError) { + console.log(xhr.responseText); + console.log(thrownError); + }, + }); + }, + cancelMessage: function() { + this.setState( this.getInitialState ); + return false; + }, + handleTypeChange: function(e) { + this.setState({ type: e.target.value }); + }, + handleContentChange: function(e) { + this.setState({ message: e.target.value }); + }, + render: function () { + var options = []; + for (var i = 0; i < authorised_values.length; i++) { + var av = authorised_values[i]; + options.push( + + ); + } + + return
  3. + + + + + + {CANCEL} +
  4. + } +}); -- 2.1.4