Fixed loading of invalid recommendation icons and feature images (#18011)

fixes https://github.com/TryGhost/Product/issues/3811 
fixes https://github.com/TryGhost/Product/issues/3829
This commit is contained in:
Simon Backx 2023-09-07 12:30:59 +02:00 committed by GitHub
parent 1366296330
commit 6e7089e58a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 5 deletions

View File

@ -1,5 +1,6 @@
import NoValueLabel from '../../../../admin-x-ds/global/NoValueLabel';
import React from 'react';
import RecommendationIcon from './RecommendationIcon';
import Table from '../../../../admin-x-ds/global/Table';
import TableCell from '../../../../admin-x-ds/global/TableCell';
import TableRow from '../../../../admin-x-ds/global/TableRow';
@ -23,7 +24,7 @@ const IncomingRecommendationItem: React.FC<{mention: Mention}> = ({mention}) =>
<div className='group flex items-center gap-3 hover:cursor-pointer'>
<div className={`flex grow flex-col`}>
<div className="mb-1 flex items-center gap-2">
{mention.source_favicon && <img alt={mention.source_title || mention.source_site_title || cleanedSource} className="h-5 w-5 rounded-sm" src={mention.source_favicon} />}
<RecommendationIcon favicon={mention.source_favicon} featured_image={mention.source_featured_image} title={mention.source_title || mention.source_site_title || cleanedSource} />
<span className='line-clamp-1'>{mention.source_title || mention.source_site_title || cleanedSource}</span>
</div>
<span className='line-clamp-1 text-xs leading-snug text-grey-700'>{mention.source_excerpt || cleanedSource}</span>

View File

@ -0,0 +1,24 @@
/* eslint-disable camelcase */
import React, {useState} from 'react';
interface Props {
title: string,
favicon?: string | null,
featured_image?: string | null
}
const RecommendationIcon: React.FC<Props> = ({title, favicon, featured_image}) => {
const [icon, setIcon] = useState(favicon || featured_image || null);
const clearIcon = () => {
setIcon(null);
};
if (!icon) {
return null;
}
return (<img alt={title} className="h-5 w-5 rounded-sm" src={icon} onError={clearIcon} />);
};
export default RecommendationIcon;

View File

@ -3,6 +3,7 @@ import ConfirmationModal from '../../../../admin-x-ds/global/modal/ConfirmationM
import NiceModal from '@ebay/nice-modal-react';
import NoValueLabel from '../../../../admin-x-ds/global/NoValueLabel';
import React from 'react';
import RecommendationIcon from './RecommendationIcon';
import Table from '../../../../admin-x-ds/global/Table';
import TableCell from '../../../../admin-x-ds/global/TableCell';
import TableRow from '../../../../admin-x-ds/global/TableRow';
@ -43,7 +44,7 @@ const RecommendationItem: React.FC<{recommendation: Recommendation}> = ({recomme
<div className='group flex items-center gap-3 hover:cursor-pointer'>
<div className={`flex grow flex-col`}>
<div className="mb-1 flex items-center gap-2">
{recommendation.favicon && <img alt={recommendation.title} className="h-5 w-5 rounded-sm" src={recommendation.favicon} />}
<RecommendationIcon {...recommendation} />
<span className='line-clamp-1'>{recommendation.title}</span>
</div>
<span className='line-clamp-1 text-xs leading-snug text-grey-700'>{recommendation.reason || 'No reason added'}</span>

View File

@ -1,6 +1,7 @@
import Form from '../../../../admin-x-ds/global/form/Form';
import Heading from '../../../../admin-x-ds/global/Heading';
import React from 'react';
import RecommendationIcon from './RecommendationIcon';
import TextArea from '../../../../admin-x-ds/global/form/TextArea';
import TextField from '../../../../admin-x-ds/global/form/TextField';
import {EditOrAddRecommendation, Recommendation} from '../../../../api/recommendations';
@ -21,7 +22,7 @@ const RecommendationReasonForm: React.FC<Props<EditOrAddRecommendation | Recomme
<Heading className='mb-2 block text-2xs font-semibold uppercase tracking-wider text-grey-700'>Preview</Heading>
<a className='flex flex-col rounded-sm border border-grey-300 p-3' href={formState.url} rel="noopener noreferrer" target="_blank">
<div className="mb-1 flex items-center gap-2">
{(formState.favicon || formState.featured_image) && <img alt={formState.title} className="h-5 w-5 rounded-sm" src={formState.favicon ?? formState.featured_image!} />}
<RecommendationIcon {...formState} />
<span className='line-clamp-1 font-medium'>{formState.title}</span>
</div>
<span className='line-clamp-1 text-xs leading-snug text-grey-700'>{formState.url}</span>

View File

@ -49,15 +49,29 @@ const shuffleRecommendations = (array) => {
return array;
};
const RecommendationIcon = ({title, favicon, featuredImage}) => {
const [icon, setIcon] = useState(favicon || featuredImage);
const hideIcon = () => {
setIcon(null);
};
if (!icon) {
return null;
}
return (<img className="gh-portal-recommendation-item-favicon" src={icon} alt={title} onError={hideIcon} />);
};
const RecommendationItem = (recommendation) => {
const {t} = useContext(AppContext);
const {title, url, reason, favicon, one_click_subscribe: oneClickSubscribe} = recommendation;
const {title, url, reason, favicon, one_click_subscribe: oneClickSubscribe, featured_image: featuredImage} = recommendation;
return (
<section className="gh-portal-recommendation-item">
<div className="gh-portal-list-detail gh-portal-list-big">
<div className="gh-portal-recommendation-item-header">
{favicon && <img className="gh-portal-recommendation-item-favicon" src={favicon} alt={title}/>}
<RecommendationIcon title={title} favicon={favicon} featuredImage={featuredImage} />
<h3>{title}</h3>
</div>
{reason && <p>{reason}</p>}