Adds error states to story images

This commit is contained in:
Josh Perez 2022-08-03 20:38:41 -04:00 committed by GitHub
parent 782838c591
commit fcf7406dd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 158 additions and 21 deletions

View file

@ -92,7 +92,9 @@ export const MyStories = ({
>
<StoryImage
attachment={story.attachment}
firstName={i18n('you')}
i18n={i18n}
isMe
isThumbnail
label={i18n('MyStories__story')}
moduleClassName="MyStories__story__preview"

View file

@ -83,7 +83,9 @@ export const MyStoriesButton = ({
{newestStory ? (
<StoryImage
attachment={newestStory.attachment}
firstName={i18n('you')}
i18n={i18n}
isMe
isThumbnail
label=""
moduleClassName="StoryListItem__previews--image"

View file

@ -27,6 +27,7 @@ function getDefaultProps(): PropsType {
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
thumbnail: fakeThumbnail('/fixtures/nathan-anderson-316188-unsplash.jpg'),
}),
firstName: 'Charlie',
i18n,
label: 'A story',
queueStoryDownload: action('queueStoryDownload'),
@ -129,3 +130,39 @@ export const Video = (): JSX.Element => (
})}
/>
);
export const ErrorImage = (): JSX.Element => (
<StoryImage
{...getDefaultProps()}
attachment={fakeAttachment({
error: true,
url: '/this/path/does/not/exist.jpg',
})}
/>
);
export const ErrorImageThumbnail = (): JSX.Element => (
<StoryImage
{...getDefaultProps()}
attachment={fakeAttachment({
error: true,
url: '/this/path/does/not/exist.jpg',
})}
isThumbnail
/>
);
ErrorImageThumbnail.story = {
name: 'Error Image (thumbnail)',
};
export const ErrorImageYou = (): JSX.Element => (
<StoryImage
{...getDefaultProps()}
isMe
attachment={fakeAttachment({
error: true,
url: '/this/path/does/not/exist.jpg',
})}
/>
);

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReactNode } from 'react';
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { Blurhash } from 'react-blurhash';
@ -13,6 +13,7 @@ import { TextAttachment } from './TextAttachment';
import { ThemeType } from '../types/Util';
import {
defaultBlurHash,
hasFailed,
hasNotResolved,
isDownloaded,
isDownloading,
@ -24,7 +25,9 @@ import { isVideoTypeSupported } from '../util/GoogleChrome';
export type PropsType = {
readonly attachment?: AttachmentType;
readonly children?: ReactNode;
readonly firstName: string;
readonly i18n: LocalizerType;
readonly isMe?: boolean;
readonly isMuted?: boolean;
readonly isPaused?: boolean;
readonly isThumbnail?: boolean;
@ -37,7 +40,9 @@ export type PropsType = {
export const StoryImage = ({
attachment,
children,
firstName,
i18n,
isMe,
isMuted,
isPaused,
isThumbnail,
@ -50,6 +55,7 @@ export const StoryImage = ({
(!isDownloaded(attachment) && !isDownloading(attachment)) ||
hasNotResolved(attachment);
const [hasImgError, setHasImgError] = useState(false);
const videoRef = useRef<HTMLVideoElement | null>(null);
useEffect(() => {
@ -74,8 +80,10 @@ export const StoryImage = ({
return null;
}
const isPending = Boolean(attachment.pending) && !attachment.textAttachment;
const isNotReadyToShow = hasNotResolved(attachment) || isPending;
const hasError = hasImgError || hasFailed(attachment);
const isPending =
Boolean(attachment.pending) && !attachment.textAttachment && !hasError;
const isNotReadyToShow = hasNotResolved(attachment) || isPending || hasError;
const isSupportedVideo = isVideoTypeSupported(attachment.contentType);
const getClassName = getClassNamesFor('StoryImage', moduleClassName);
@ -118,6 +126,7 @@ export const StoryImage = ({
<img
alt={label}
className={getClassName('__image')}
onError={() => setHasImgError(true)}
src={
isThumbnail && attachment.thumbnail
? attachment.thumbnail.url
@ -136,6 +145,17 @@ export const StoryImage = ({
</div>
</div>
);
} else if (hasError) {
let content = <div className="StoryImage__error" />;
if (!isThumbnail) {
if (isMe) {
content = <>{i18n('StoryImage__error--you')}</>;
} else {
content = <>{i18n('StoryImage__error2', [firstName])}</>;
}
}
overlay = <div className="StoryImage__overlay-container">{content}</div>;
}
return (

View file

@ -179,6 +179,7 @@ export const StoryListItem = ({
<div className="StoryListItem__previews">
<StoryImage
attachment={attachment}
firstName={firstName || title}
i18n={i18n}
isThumbnail
label=""

View file

@ -471,6 +471,7 @@ export const StoryViewer = ({
<div className="StoryViewer__container">
<StoryImage
attachment={attachment}
firstName={firstName || title}
i18n={i18n}
isPaused={shouldPauseViewing}
isMuted={isStoryMuted}