import React from "react" ;
import { Link } from "react-router-dom" ;
import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button" ;
import "./PublicationSearchResult.css" ;
import { PublicationSearchResult2 } from "./PublicationSearchResult2.js" ;
import { PreviewableImage } from "./PreviewableImage.js" ;
import { PUBLICATION_EXCESS_ARTICLE_THRESHOLD } from "./constants.js" ;
import { gAppRef } from "./App.js" ;
import { makeCollapsibleList, pluralString, applyUpdatedVals, removeSpecialFields, isLink } from "./utils.js" ;
const axios = require( "axios" ) ;
// --------------------------------------------------------------------
export class PublicationSearchResult extends React.Component
{
render() {
// prepare the basic details
const display_description = PreviewableImage.adjustHtmlForPreviewableImages(
this.props.data[ "pub_description!" ] || this.props.data.pub_description
) ;
const publ = gAppRef.caches.publishers[ this.props.data.publ_id ] ;
const image_url = PublicationSearchResult.makeImageUrl( this.props.data ) ;
// prepare the publication's URL
let pub_url = this.props.data.pub_url ;
if ( pub_url && ! isLink(pub_url) )
pub_url = gAppRef.makeExternalDocUrl( pub_url ) ;
// prepare the tags
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.
for ( let i=0 ; i < this.props.data["tags!"].length ; ++i ) {
const tag = this.props.data.pub_tags[ i ] ; // nb: this is the actual tag (without highlights)
tags.push( ) ;
}
} else {
if ( this.props.data.pub_tags ) {
this.props.data.pub_tags.map(
tag => tags.push( {tag} )
) ;
}
}
// prepare the articles
let articles = [] ;
if ( this.props.data.articles ) {
for ( let i=0 ; i < this.props.data.articles.length ; ++i ) {
const article = this.props.data.articles[ i ] ;
if ( this.props.onArticleClick ) {
// forward clicks on the article to the parent
articles.push(
this.props.onArticleClick( article.article_id ) }
style = {{ cursor: "pointer" }}
title = "Go to this article."
/> ) ;
} else {
// handle clicks on the article normally
articles.push( ) ;
}
}
}
// prepare the menu
const menu = ( ) ;
return (
) ;
}
componentDidMount() {
PreviewableImage.activatePreviewableImages( this ) ;
}
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(
The new publication was created OK.
) ;
gAppRef.closeModalForm() ;
// NOTE: The parent publisher will update itself in the UI to show this new publication,
// since we've just received an updated copy of the publications.
} )
.catch( err => {
gAppRef.showErrorMsg(
Couldn't create the publication:
{err.toString()}
) ;
} ) ;
} ) ;
}
onEditPublication() {
// get the articles for this publication
let articles = this.props.data.articles ; // nb: _doEditPublication() might change the order of 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 ;
if ( articles )
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 ) ;
if ( newVals.imageData )
gAppRef.forceFlaskImageReload( "publication", newVals.pub_id ) ;
this.forceUpdate() ;
PreviewableImage.activatePreviewableImages( this ) ;
if ( resp.data.warnings )
gAppRef.showWarnings( "The publication was updated OK.", resp.data.warnings ) ;
else
gAppRef.showInfoToast(
The publication was updated OK.
) ;
gAppRef.closeModalForm() ;
// NOTE: The parent publisher will update itself in the UI to show this updated publication,
// since we've just received an updated copy of the publications.
} )
.catch( err => {
gAppRef.showErrorMsg(
Couldn't update the publication:
{err.toString()}
) ;
} ) ;
} ) ;
}
onDeletePublication() {
let doDelete = ( nArticles ) => {
// confirm the operation
let warning ;
if ( typeof nArticles === "number" ) {
if ( nArticles === 0 )
warning =
No articles will be deleted.
;
else
warning =
{ pluralString(nArticles,"associated article") + " will also be deleted." }
;
} else {
warning = (
WARNING: Couldn't check if any associated articles will be deleted:
{nArticles.toString()}
) ;
}
const content = (
Delete this publication?
{warning}
) ;
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(