Skip to content

Commit

Permalink
enhancement: add error toast if media doesnt load (#5436)
Browse files Browse the repository at this point in the history
* enhancement: add error toast if media doesnt load

* enhancement: add error field to nft details

* enhancement: add warning if max filesize is succeeded

* chore: remove redndant code

* enhancement: add loading error tooltip icon to gallery item

* fix: fix color

* fix localization string typo

* chore: fix pr review issues

* enhancement: add different translations for small and big image

* chore: update translations

Co-authored-by: Jason Kraft <developer.kraft@gmail.com>
  • Loading branch information
MarkNerdi996 and kraftjs committed Dec 20, 2022
1 parent f8fd8fd commit 381be56
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 31 deletions.
Expand Up @@ -29,9 +29,12 @@
Pane,
Text,
TextType,
Alert,
} from 'shared/components'
let modal: Modal
let error: string
let warning: string
const explorerUrl = getOfficialExplorerUrl($activeProfile?.networkProtocol, $activeProfile?.networkType)
const nft: INft = getNftByIdFromAllAccountNfts($selectedAccountIndex, $selectedNftId)
Expand Down Expand Up @@ -122,12 +125,21 @@
<div class="relative w-full h-full flex rounded-2xl overflow-hidden">
<NftMedia
nftId={id}
bind:error
bind:warning
classes="rounded-2xl overflow-hidden flex-1 w-auto h-auto max-w-full max-h-full object-contain absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
autoplay
controls
loop
muted
/>
<div class="absolute right-6 bottom-6 w-auto">
{#if error}
<Alert type="error" message={error} />
{:else if warning}
<Alert type="warning" message={warning} />
{/if}
</div>
</div>
</div>
<Pane classes="flex flex-col p-6 space-y-3 w-full h-full max-w-lg">
Expand Down
26 changes: 15 additions & 11 deletions packages/shared/components/atoms/MediaDisplay.svelte
@@ -1,23 +1,24 @@
<script lang="typescript">
import { MimeType, ParentMimeType } from '@core/nfts'
export let Media: HTMLImageElement | HTMLVideoElement
export let Media: HTMLImageElement | HTMLVideoElement = undefined
export let src: string
export let expectedType: MimeType
export let classes: string = ''
export let alt = ''
export let onError: () => unknown
export let onError: (a?: string) => unknown
export let onWarning: (a?: string) => unknown
export let onLoad: () => unknown
export let autoplay: boolean = false
export let controls: boolean = false
export let muted: boolean = false
export let loop: boolean = false
let type: string
const type: string = convertMimeTypeToHtmlTag(expectedType)
let safeToLoad = false
let isLoaded = false
const MAX_FILE_SIZE_IN_MB = 30000000
$: type = convertMimeTypeToHtmlTag(expectedType)
$: src && void checkContentIsSafeToLoad()
$: isLoaded && muteVideo()
Expand Down Expand Up @@ -47,7 +48,7 @@
case ParentMimeType.Video:
return 'video'
default:
onError()
onWarning('error.nft.unsupportedFileType.')
return undefined
}
}
Expand All @@ -66,18 +67,21 @@
async function checkContentIsSafeToLoad() {
try {
if (src && typeof src === 'string') {
if (type && src && typeof src === 'string') {
const response = await fetch(src, { method: 'HEAD', cache: 'force-cache' })
if (response.headers.get('Content-Type') === expectedType) {
safeToLoad = true
} else {
if (response.headers.get('Content-Type') !== expectedType) {
safeToLoad = false
onError('error.nft.notMatchingFileTypes.')
} else if (Number(response.headers.get('Content-Length')) > MAX_FILE_SIZE_IN_MB) {
safeToLoad = false
onError()
onWarning('error.nft.tooLargeFile.')
} else {
safeToLoad = true
}
}
} catch (error) {
safeToLoad = false
onError()
onError('error.nft.unsafeToLoad.')
}
}
</script>
Expand Down
31 changes: 14 additions & 17 deletions packages/shared/components/atoms/buttons/TooltipIcon.svelte
@@ -1,7 +1,6 @@
<script lang="typescript">
import { Icon, Text, Tooltip, FontWeight, TextType } from 'shared/components'
import { Icon, Text, Tooltip, FontWeight, TextType, Position } from 'shared/components'
import { Icon as IconEnum } from '@lib/auxiliary/icon'
import { Position } from 'shared/components/enums'
export let title: string = ''
export let text: string = ''
Expand All @@ -11,6 +10,8 @@
export let classes: string = ''
export let iconClasses: string = ''
export let position: Position = Position.Right
export let primaryColor: string = undefined
export let secondaryColor: string = undefined
let tooltipAnchor: HTMLElement
let isTooltipVisible = false
Expand All @@ -27,24 +28,20 @@
bind:this={tooltipAnchor}
class="text-gray-600"
>
<Icon {width} {height} {icon} classes={iconClasses} />
<Icon {width} {height} {icon} classes={iconClasses} {primaryColor} {secondaryColor} />
</icon-container>
{#if isTooltipVisible}
<Tooltip anchor={tooltipAnchor} {position} {...$$restProps}>
{#if title}
<Text
bigger
type={TextType.h5}
fontWeight={FontWeight.medium}
classes="text-left mb-2"
color="gray-900"
>
{title}
</Text>
{/if}
{#if text}
<Text smaller classes="text-left" color="gray-700" lineHeight="leading-140">{text}</Text>
{/if}
<div class="flex flex-col space-y-2">
{#if title}
<Text bigger type={TextType.h5} fontWeight={FontWeight.medium} classes="text-left" color="gray-900">
{title}
</Text>
{/if}
{#if text}
<Text smaller classes="text-left" color="gray-700" lineHeight="leading-140">{text}</Text>
{/if}
</div>
<slot />
</Tooltip>
{/if}
Expand Down
38 changes: 36 additions & 2 deletions packages/shared/components/molecules/NftGalleryItem.svelte
@@ -1,32 +1,66 @@
<script lang="typescript">
import { INft } from '@core/nfts'
import { Text, FontWeight, NftMedia } from 'shared/components'
import { Text, FontWeight, NftMedia, TooltipIcon, Position } from 'shared/components'
import { CollectiblesRoute, collectiblesRouter } from '@core/router'
import { selectedNftId } from '@core/nfts/stores'
export let nft: INft
let nftWrapperClientWidth: number
let error: string
let warning: string
function openCollectiblesDetailsView(): void {
$selectedNftId = nft.id
$collectiblesRouter.goTo(CollectiblesRoute.Details)
}
let tooltipContent
$: if (error) {
tooltipContent = {
icon: 'error-filled',
iconClasses: 'fill-current text-red-700',
text: error,
}
} else if (warning) {
tooltipContent = {
icon: 'exclamation-filled',
iconClasses: 'fill-current text-yellow-700',
text: warning,
}
}
</script>

<button on:click={openCollectiblesDetailsView} class="flex flex-col items-center justify-center">
<div class="w-full rounded-2xl overflow-hidden flex flex-col shadow-elevation-1">
<div
class="w-full overflow-hidden flex"
class="w-full flex relative"
bind:clientWidth={nftWrapperClientWidth}
style="height: {nftWrapperClientWidth}px; "
>
<NftMedia
nftId={nft.id}
bind:error
bind:warning
classes="bg-gray-200 dark:bg-gray-700 min-w-full min-h-full object-cover"
translationSuffix="short"
loop
muted
/>
{#if error || warning}
<div class="absolute right-3 top-3">
<TooltipIcon
height={24}
width={24}
icon={tooltipContent.icon}
iconClasses={tooltipContent.iconClasses}
text={tooltipContent.text}
size="small"
primaryColor="white"
position={Position.Left}
/>
</div>
{/if}
</div>
<div class="w-full flex flex-col justify-center p-3.5 bg-white dark:bg-gray-800">
<Text fontWeight={FontWeight.semibold} fontSize="12" classes="text-left truncate">{nft.name}</Text>
Expand Down
15 changes: 14 additions & 1 deletion packages/shared/components/molecules/NftMedia.svelte
@@ -1,5 +1,6 @@
<script lang="typescript">
import { selectedAccountIndex } from '@core/account'
import { localize } from '@core/i18n'
import { getNftByIdFromAllAccountNfts, rewriteIpfsUri } from '@core/nfts'
import { MediaDisplay } from 'shared/components'
import MediaPlaceholder from './MediaPlaceholder.svelte'
Expand All @@ -10,6 +11,9 @@
export let loop: boolean = false
export let muted: boolean = false
export let classes: string = ''
export let error: string = ''
export let warning: string = ''
export let translationSuffix: string = 'long'
const bgColor = 'gray-200'
const darkBgColor = 'gray-700'
Expand Down Expand Up @@ -46,6 +50,7 @@
newUrl = rewriteIpfsUri(targetUrl)
break
default:
error = localize('error.nft.unsupportedUrl.' + translationSuffix)
return undefined
}
Expand All @@ -56,8 +61,14 @@
}
}
function handleLoadingError(): void {
function handleLoadingError(err): void {
hasError = true
error = localize(err + translationSuffix)
}
function handleWarning(warn): void {
hasError = true
warning = localize(warn + translationSuffix)
}
function handleOnLoad(): void {
Expand All @@ -77,6 +88,7 @@
classes="hidden {classes}"
onLoad={handleOnLoad}
onError={handleLoadingError}
onWarning={handleWarning}
/>

{#if !isLoaded}
Expand All @@ -94,6 +106,7 @@
{muted}
{classes}
onError={handleLoadingError}
onWarning={handleWarning}
/>
{/if}
{/if}
30 changes: 30 additions & 0 deletions packages/shared/locales/en.json
Expand Up @@ -1809,6 +1809,36 @@
"eventId": {
"doesNotStartWith0x": "Event ID should start with '0x'",
"insufficientLength": "Event ID should be 66 characters long"
},
"nft": {
"unsupportedUrl": {
"short": "Url not supported",
"long": "Url schema not supported"
},
"unsupportedFileType": {
"short": "Unsupported media type",
"long": "The media type is not currently supported"
},
"notMatchingFileTypes": {
"short": "Loading blocked",
"long": "NFT file type does not match the expected media type"
},
"tooLargeFile": {
"short": "File is too large",
"long": "Loading NFT blocked because the file is too large"
},
"corsError": {
"short": "Loading blocked",
"long": "Loading NFT blocked by CORS policy"
},
"unsafeToLoad": {
"short": "Unsafe to load",
"long": "An error occurred while checking if the NFT was safe to load"
},
"loadingError": {
"short": "Unable to load",
"long": "An error occurred while loading the NFT"
}
}
},
"warning": {
Expand Down

0 comments on commit 381be56

Please sign in to comment.