import React from "react" ;
import { Menu , MenuList , MenuButton , MenuItem } from "@reach/menu-button" ;
import "./PublicationSearchResult.css" ;
import { PublicationSearchResult2 } from "./PublicationSearchResult2.js" ;
import { gAppRef } from "./index.js" ;
import { pluralString , applyUpdatedVals , removeSpecialFields } from "./utils.js" ;
const axios = require ( "axios" ) ;
// --------------------------------------------------------------------
export class PublicationSearchResult extends React . Component
{
render ( ) {
const display _description = this . props . data [ "pub_description!" ] || this . props . data . pub _description ;
const publ = gAppRef . caches . publishers [ this . props . data . publ _id ] ;
const image _url = gAppRef . makeFlaskImageUrl ( "publication" , this . props . data . pub _image _id , true ) ;
let tags = [ ] ;
if ( this . props . data [ "tags!" ] ) {
// the backend has provided us with a list of tags (possibly highlighted) - use them directly
// NOTE: We don't normally show HTML in tags, but in this case we need to, in order to be able to highlight
// matching search terms. This will have the side-effect of rendering any HTML that may be in the tag,
// but we can live with that.
this . props . data [ "tags!" ] . map (
t => tags . push ( < div key = { t } className = "tag" dangerouslySetInnerHTML = { { _ _html : t } } / > )
) ;
} else {
if ( this . props . data . pub _tags ) {
this . props . data . pub _tags . map (
t => tags . push ( < div key = { t } className = "tag" > { t } < / d i v > )
) ;
}
}
const menu = ( < Menu >
< MenuButton className = "sr-menu" / >
< MenuList >
< MenuItem className = "edit"
onSelect = { this . onEditPublication . bind ( this ) }
> Edit < / M e n u I t e m >
< MenuItem className = "delete"
onSelect = { this . onDeletePublication . bind ( this ) }
> Delete < / M e n u I t e m >
< / M e n u L i s t >
< / M e n u > ) ;
return ( < div className = "search-result publication"
ref = { r => gAppRef . setTestAttribute ( r , "pub_id" , this . props . data . pub _id ) }
>
< div className = "header" >
{ menu }
{ publ && < span className = "publisher" > { publ . publ _name } < / s p a n > }
< span className = "name" dangerouslySetInnerHTML = { { _ _html : this . _makeDisplayName ( true ) } } / >
{ this . props . data . pub _url && < a href = { this . props . data . pub _url } className = "open-link" target = "_blank" rel = "noopener noreferrer" > < img src = "/images/open-link.png" alt = "Open publication." title = "Open this publication." / > < / a > }
< / d i v >
< div className = "content" >
{ image _url && < img src = { image _url } className = "image" alt = "Publication." / > }
< div className = "description" dangerouslySetInnerHTML = { { _ _html : display _description } } / >
< / d i v >
< div className = "footer" >
{ this . props . data . pub _date && < div > < label > Published : < / l a b e l > < s p a n c l a s s N a m e = " p u b _ d a t e " > { t h i s . p r o p s . d a t a . p u b _ d a t e } < / s p a n > < / d i v > }
{ tags . length > 0 && < div className = "tags" > < label > Tags : < / l a b e l > { t a g s } < / d i v > }
< / d i v >
< / d i v > ) ;
}
static onNewPublication ( notify ) {
PublicationSearchResult2 . _doEditPublication ( { } , null , ( newVals , refs ) => {
axios . post ( gAppRef . makeFlaskUrl ( "/publication/create" , { list : 1 } ) , newVals )
. then ( resp => {
// update the caches
gAppRef . caches . publications = resp . data . publications ;
gAppRef . caches . tags = resp . data . tags ;
// unload any updated values
applyUpdatedVals ( newVals , newVals , resp . data . updated , refs ) ;
// update the UI with the new details
notify ( resp . data . pub _id , newVals ) ;
if ( resp . data . warnings )
gAppRef . showWarnings ( "The new publication was created OK." , resp . data . warnings ) ;
else
gAppRef . showInfoToast ( < div > The new publication was created OK . < / d i v > ) ;
gAppRef . closeModalForm ( ) ;
} )
. catch ( err => {
gAppRef . showErrorMsg ( < div > Couldn ' t create the publication : < div className = "monospace" > { err . toString ( ) } < / d i v > < / d i v > ) ;
} ) ;
} ) ;
}
onEditPublication ( ) {
// get the articles for this publication
axios . get ( gAppRef . makeFlaskUrl ( "/publication/" + this . props . data . pub _id + "/articles" ) )
. then ( resp => {
let articles = resp . data ; // nb: _doEditPublication() might modify this list
PublicationSearchResult2 . _doEditPublication ( this . props . data , articles , ( newVals , refs ) => {
// send the updated details to the server
newVals . pub _id = this . props . data . pub _id ;
newVals . article _order = articles . map ( a => a . article _id ) ;
axios . post ( gAppRef . makeFlaskUrl ( "/publication/update" , { list : 1 } ) , newVals )
. then ( resp => {
// update the caches
gAppRef . caches . publications = resp . data . publications ;
gAppRef . caches . tags = resp . data . tags ;
// update the UI with the new details
applyUpdatedVals ( this . props . data , newVals , resp . data . updated , refs ) ;
removeSpecialFields ( this . props . data ) ;
this . forceUpdate ( ) ;
if ( resp . data . warnings )
gAppRef . showWarnings ( "The publication was updated OK." , resp . data . warnings ) ;
else
gAppRef . showInfoToast ( < div > The publication was updated OK . < / d i v > ) ;
gAppRef . closeModalForm ( ) ;
} )
. catch ( err => {
gAppRef . showErrorMsg ( < div > Couldn ' t update the publication : < div className = "monospace" > { err . toString ( ) } < / d i v > < / d i v > ) ;
} ) ;
} ) ;
} )
. catch ( err => {
gAppRef . showErrorMsg ( < div > Couldn ' t load the articles : < div className = "monospace" > { err . toString ( ) } < / d i v > < / d i v > ) ;
} ) ;
}
onDeletePublication ( ) {
let doDelete = ( nArticles ) => {
// confirm the operation
let warning ;
if ( typeof nArticles === "number" ) {
if ( nArticles === 0 )
warning = < div > No articles will be deleted . < / d i v > ;
else
warning = < div > { pluralString ( nArticles , "associated article" ) + " will also be deleted." } < / d i v > ;
} else {
warning = ( < div > < img className = "icon" src = "/images/error.png" alt = "Error." / >
WARNING : Couldn ' t check if any associated articles will be deleted :
< div className = "monospace" > { nArticles . toString ( ) } < / d i v >
< / d i v > ) ;
}
const content = ( < div >
Delete this publication ?
< div style = { { margin : "0.5em 0 0.5em 2em" , fontStyle : "italic" } } dangerouslySetInnerHTML = { { _ _html : this . _makeDisplayName ( false ) } } / >
{ warning }
< / d i v > ) ;
gAppRef . ask ( content , "ask" , {
"OK" : ( ) => {
// delete the publication on the server
axios . get ( gAppRef . makeFlaskUrl ( "/publication/delete/" + this . props . data . pub _id , { list : 1 } ) )
. then ( resp => {
// update the caches
gAppRef . caches . publications = resp . data . publications ;
gAppRef . caches . tags = resp . data . tags ;
// update the UI
this . props . onDelete ( "pub_id" , this . props . data . pub _id ) ;
resp . data . deleteArticles . forEach ( article _id => {
this . props . onDelete ( "article_id" , article _id ) ;
} ) ;
if ( resp . data . warnings )
gAppRef . showWarnings ( "The publication was deleted." , resp . data . warnings ) ;
else
gAppRef . showInfoToast ( < div > The publication was deleted . < / d i v > ) ;
} )
. catch ( err => {
gAppRef . showErrorToast ( < div > Couldn ' t delete the publication : < div className = "monospace" > { err . toString ( ) } < / d i v > < / d i v > ) ;
} ) ;
} ,
"Cancel" : null ,
} ) ;
}
// get the publication details
axios . get ( gAppRef . makeFlaskUrl ( "/publication/" + this . props . data . pub _id ) )
. then ( resp => {
doDelete ( resp . data . nArticles ) ;
} )
. catch ( err => {
doDelete ( err ) ;
} ) ;
}
static makeDisplayName ( vals , allowAlternateContent ) {
let pub _name = null ;
if ( allowAlternateContent && vals [ "pub_name!" ] )
pub _name = vals [ "pub_name!" ] ;
if ( ! pub _name )
pub _name = vals . pub _name ;
if ( vals . pub _edition )
return pub _name + " (" + vals . pub _edition + ")" ;
else
return pub _name ;
}
_makeDisplayName ( allowAlternateContent ) { return PublicationSearchResult . makeDisplayName ( this . props . data , allowAlternateContent ) ; }
}