Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#645 | IPFS NFTs #665

Merged
merged 40 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1dc08c8
add owners table
ezra-sg Nov 3, 2023
d88f84e
add address search
ezra-sg Nov 3, 2023
e211ad8
WIP refator transfer form to own component
ezra-sg Nov 3, 2023
73ab5e4
Merge branch '499-erc1155-inventory-updates' into 658-erc1155-transfe…
ezra-sg Nov 6, 2023
ec2ee00
WIP add integer input
ezra-sg Nov 7, 2023
e34347a
move constants to helpers file
ezra-sg Nov 8, 2023
94e84fa
finish and integrate integer input
ezra-sg Nov 8, 2023
d61d14d
extract common input styles
ezra-sg Nov 8, 2023
ea8179a
add focusinput method
ezra-sg Nov 8, 2023
c1adc78
improve aria for inputs
ezra-sg Nov 8, 2023
7c22e84
improve currency input keyboard a11y
ezra-sg Nov 8, 2023
2b73211
update snaps
ezra-sg Nov 8, 2023
9bc8bb1
fix back navigation on nft detail page
ezra-sg Nov 8, 2023
593014f
fix vmodel, enable transfers for 1155
ezra-sg Nov 8, 2023
b66f0e5
fix owners tab
ezra-sg Nov 8, 2023
d8cb203
update coverage
ezra-sg Nov 8, 2023
465caa4
fix owners tab logic
ezra-sg Nov 8, 2023
5030648
add name to owners table addy search
ezra-sg Nov 8, 2023
7ca6a21
Merge branch 'develop' of https://github.com/telosnetwork/telos-walle…
donnyquixotic Nov 10, 2023
11f9631
attempt to fix nft not loading
ezra-sg Nov 10, 2023
1c9f3f5
Merge branch '658-erc1155-transfers-and-owners' of github.com:telosne…
ezra-sg Nov 10, 2023
cb1c90e
attempt to fix infiniload 2
ezra-sg Nov 10, 2023
64c6044
show total owners when logged out
ezra-sg Nov 10, 2023
03ca227
fix loading state after xfer, fix tab order
ezra-sg Nov 10, 2023
d03f03c
Merge branch 'develop' of github.com:telosnetwork/telos-wallet into 6…
ezra-sg Nov 11, 2023
e3e8e64
Merge branch 'develop' of github.com:telosnetwork/telos-wallet into 6…
ezra-sg Nov 13, 2023
4912f5c
fix nft icon video hover, support ipfs
ezra-sg Nov 13, 2023
f297e0d
jsdoc
ezra-sg Nov 13, 2023
c2d5b79
fix stacking issue
ezra-sg Nov 13, 2023
b122397
fix stacking issue 2
ezra-sg Nov 13, 2023
d817970
coverage
ezra-sg Nov 13, 2023
a4fc6e2
adding global web3Provider for all cases
Viterbo Nov 14, 2023
8ad8162
typo
ezra-sg Nov 14, 2023
2bad251
Merge branch '666-we-need-a-provider-to-read-data-when-the-user-os-no…
ezra-sg Nov 14, 2023
63faf57
attempt to fix broken NFT detail page when logged out
ezra-sg Nov 14, 2023
79e370f
covfefe
ezra-sg Nov 14, 2023
5129867
replace magic string with const
ezra-sg Nov 14, 2023
e0a6c65
Merge branch 'develop' of https://github.com/telosnetwork/telos-walle…
donnyquixotic Nov 14, 2023
850820a
revert type changes
ezra-sg Nov 14, 2023
6aba824
Merge branch '645-ipfs-nfts' of github.com:telosnetwork/telos-wallet …
ezra-sg Nov 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/antelope/chains/EVMChainSettings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RpcEndpoint } from 'universal-authenticator-library';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, Method } from 'axios';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from 'axios';
import {
AbiSignature,
ChainSettings,
Expand Down Expand Up @@ -92,7 +92,7 @@ export default abstract class EVMChainSettings implements ChainSettings {

// Interceptor handlers -- these handlers are used to limit the number of concurrent requests
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const requestHandler = (value: InternalAxiosRequestConfig) => new Promise<InternalAxiosRequestConfig<any>>((resolve) => {
const requestHandler = (value: any) => new Promise<any>((resolve) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix new error saying InternalAxiosRequestConfig does not exist

const interval = setInterval(() => {
if (pendingRequests < MAX_REQUESTS_COUNT) {
pendingRequests++;
Expand Down
4 changes: 2 additions & 2 deletions src/antelope/chains/NativeChainSettings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { RpcEndpoint } from 'universal-authenticator-library';
import {
Name,
Expand Down Expand Up @@ -77,7 +77,7 @@ export default abstract class NativeChainSettings implements ChainSettings {

// Interceptor handlers -- these handlers are used to limit the number of concurrent requests
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const requestHandler = (value: InternalAxiosRequestConfig) => new Promise<InternalAxiosRequestConfig<any>>((resolve) => {
const requestHandler = (value: any) => new Promise<any>((resolve) => {
const interval = setInterval(() => {
if (pendingRequests < MAX_REQUESTS_COUNT) {
pendingRequests++;
Expand Down
30 changes: 30 additions & 0 deletions src/antelope/stores/utils/nft-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,35 @@ export async function extractNftMetadata(
}
}

if (metadata?.image?.includes('https://cloudflare-ipfs.com/ipfs/')) {
mediaType = await determineIpfsMediaType(metadata?.image);

if (mediaType === NFTSourceTypes.IMAGE) {
image = metadata?.image;
}
mediaSource = metadata?.image;
}

return { image, mediaType, mediaSource };
}


// eztodo docs
export async function determineIpfsMediaType(url: string): Promise<NftSourceType> {
try {
const response = await fetch(url);
const contentType = response.headers.get('Content-Type') ?? '';

if (contentType.startsWith('image/')) {
return NFTSourceTypes.IMAGE;
} else if (contentType.startsWith('video/')) {
return NFTSourceTypes.VIDEO;
} else if (contentType.startsWith('audio/')) {
return NFTSourceTypes.AUDIO;
} else {
return NFTSourceTypes.UNKNOWN;
}
} catch (error) {
throw new Error('Error determining IPFS media type');
}
}
4 changes: 3 additions & 1 deletion src/antelope/types/NFTClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export async function constructNft(
console.error('Error parsing metadata', `"${indexerData.metadata}"`, e);
}
if (!indexerData.metadata || typeof indexerData.metadata !== 'object') {
// we create a new metadata object with the actual string atributes of the item
// we create a new metadata object with the actual string attributes of the item
const list = indexerData as unknown as { [key: string]: unknown };
indexerData.metadata =
Object.keys(indexerData)
Expand All @@ -129,6 +129,8 @@ export async function constructNft(
}, {} as { [key: string]: string });
}

indexerData.metadata.image = ((indexerData.metadata.image as string) ?? '').replace('ipfs://', 'https://cloudflare-ipfs.com/ipfs/');

const { image, mediaType, mediaSource } = await extractNftMetadata(indexerData.imageCache ?? '', indexerData.tokenUri ?? '', indexerData.metadata ?? {});
const commonData: NftPrecursorData = {
name: (indexerData.metadata?.name ?? '') as string,
Expand Down
237 changes: 110 additions & 127 deletions src/pages/evm/nfts/NftDetailsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,35 @@ function removeTab(tab: Tab){
:class="{
'c-nft-details__header-container': true,
'c-nft-details__header-container--grid': nft !== null || loading,
'row': true,
}"
>
<template v-if="loading">
<div
v-for="index in 5"
:key="`nft-details-page-${index}`"
class="c-nft-details__header-card c-nft-details__header-card--placeholder"
>
<q-skeleton type="rect" class="c-nft-details__header-skeleton" />
<div class="col-12">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-6">
<q-skeleton type="rect" class="c-nft-details__header-skeleton--large" />
</div>

<div class="col-12 col-md-6">
<div class="row q-col-gutter-sm">
<div class="col-12">
<q-skeleton type="rect" class="c-nft-details__header-skeleton" />
</div>
<div class="col-6">
<q-skeleton type="rect" class="c-nft-details__header-skeleton" />
</div>
<div class="col-6">
<q-skeleton type="rect" class="c-nft-details__header-skeleton" />
</div>
<div class="col-12">
<q-skeleton type="rect" class="c-nft-details__header-skeleton" />
</div>
</div>
</div>
</div>
</div>

</template>

<template v-else-if="nft === null">
Expand All @@ -252,71 +271,84 @@ function removeTab(tab: Tab){
:nft="nft"
:previewMode="false"
:tileMode="true"
class="c-nft-details__viewer"
class="col-12 col-md-6 q-mb-md q-pr-md"
/>
<NftDetailsCard :title="$t('global.collection')" class="c-nft-details__header-card">
<ExternalLink :text="nft.contractPrettyName || nft.contractAddress" :url="contractLink" />
</NftDetailsCard>

<NftDetailsCard :title="$t('global.id')" class="c-nft-details__header-card">
{{ nft.id }}
</NftDetailsCard>

<NftDetailsCard
v-if="isErc721"
:title="$t('global.owner')"
class="c-nft-details__header-card"
>
<ExternalLink :text="nftAsErc721.owner" :url="ownerLink" />
</NftDetailsCard>

<NftDetailsCard
v-else
:title="$t('global.owners')"
class="c-nft-details__header-card"
>
<ToolTip
:text="Object.keys(nftAsErc1155.owners).length.toLocaleString()"
:hideIcon="true"
>
{{ nftOwnersText }}
</ToolTip>
</NftDetailsCard>

<NftDetailsCard
v-if="nft.description"
:title="$t('global.description')"
class="c-nft-details__header-card"
>
{{ nft.description }}
</NftDetailsCard>


<NftDetailsCard
v-if="isErc1155 && userAddress"
:title="$t('global.owned_by_you')"
class="c-nft-details__header-card"
>
<ToolTip
:text="(nftAsErc1155.owners[userAddress] ?? 0).toLocaleString()"
:hideIcon="true"
>
{{ nftQuantityText }}
</ToolTip>
</NftDetailsCard>

<NftDetailsCard
v-if="isErc1155"
:title="$t('global.total')"
class="c-nft-details__header-card"
>
<ToolTip
:text="nftSupplyText"
:hideIcon="true"
>
{{ nftSupplyTextAbbreviated }}
</ToolTip>
</NftDetailsCard>

<div class="col-12 col-md-6">
<div class="row q-col-gutter-sm">
<div class="col-12">
<NftDetailsCard :title="$t('global.collection')" class="c-nft-details__header-card">
<ExternalLink :text="nft.contractPrettyName || nft.contractAddress" :url="contractLink" />
</NftDetailsCard>
</div>

<div class="col-6">
<NftDetailsCard :title="$t('global.id')" class="c-nft-details__header-card col-6">
{{ nft.id }}
</NftDetailsCard>
</div>

<div class="col-6">
<NftDetailsCard
v-if="isErc721"
:title="$t('global.owner')"
class="c-nft-details__header-card"
>
<ExternalLink :text="nftAsErc721.owner" :url="ownerLink" />
</NftDetailsCard>

<NftDetailsCard
v-else
:title="$t('global.owners')"
class="c-nft-details__header-card"
>
<ToolTip
:text="Object.keys(nftAsErc1155.owners).length.toLocaleString()"
:hideIcon="true"
>
{{ nftOwnersText }}
</ToolTip>
</NftDetailsCard>
</div>

<div v-if="nft.description" class="col-12">
<NftDetailsCard
:title="$t('global.description')"
class="c-nft-details__header-card"
>
{{ nft.description }}
</NftDetailsCard>
</div>

<div v-if="isErc1155 && userAddress" class="col-6">
<NftDetailsCard
:title="$t('global.owned_by_you')"
class="c-nft-details__header-card"
>
<ToolTip
:text="(nftAsErc1155.owners[userAddress] ?? 0).toLocaleString()"
:hideIcon="true"
>
{{ nftQuantityText }}
</ToolTip>
</NftDetailsCard>
</div>

<div v-if="isErc1155" class="col-6">
<NftDetailsCard
:title="$t('global.total')"
class="c-nft-details__header-card col-6"
>
<ToolTip
:text="nftSupplyText"
:hideIcon="true"
>
{{ nftSupplyTextAbbreviated }}
</ToolTip>
</NftDetailsCard>
</div>
</div>
</div>
</template>
</div>
</template>
Expand Down Expand Up @@ -421,34 +453,14 @@ function removeTab(tab: Tab){

&__header-container {
&--grid {
display: grid;
grid-template-areas:
'a'
'b'
'c'
'd'
'e';
gap: 8px;
width: 100%;

@include sm-and-up {
grid-template-areas:
'a a'
'b b'
'c d'
'e e';
max-width: 432px;
}

@include md-and-up {
grid-template-areas:
'a a a b b'
'a a a c d'
'a a a e e'
'a a a . .';
max-width: 1000px;
width: max-content;
grid-template-columns: repeat(5, 1fr);
}
}
}
Expand All @@ -458,48 +470,19 @@ function removeTab(tab: Tab){
max-width: 1000px;
}

&__viewer {
grid-area: a;
}

&__header-card {
&:nth-of-type(2) {
grid-area: b;
}

&:nth-of-type(3) {
grid-area: c;
}

&:nth-of-type(4) {
grid-area: d;
}

&:nth-of-type(5) {
grid-area: e;
}

&--placeholder {
margin: auto;
height: 80px;
width: 100%;

&:first-of-type {
grid-area: a;
width: 270px;
height: 270px;

@include md-and-up {
width: 432px;
height: 432px;
}
}
}
min-height: 88px;
}

&__header-skeleton {
height: 100%;
height: 88px;
width: 100%;

&--large {
margin: auto;
height: 270px;
max-width: 270px;
}
}

&__attributes-container {
Expand Down
6 changes: 3 additions & 3 deletions src/pages/evm/nfts/NftInventoryPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, ref, watch, onMounted, onUnmounted, toRaw } from 'vue';
import { computed, ref, watch, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';

Expand All @@ -18,7 +19,6 @@ import { truncateText } from 'src/antelope/stores/utils/text-utils';
import EVMChainSettings from 'src/antelope/chains/EVMChainSettings';
import TableControls from 'components/evm/TableControls.vue';
import { truncateAddress } from 'src/antelope/stores/utils/text-utils';
import { storeToRefs } from 'pinia';


const nftStore = useNftsStore();
Expand Down Expand Up @@ -447,7 +447,7 @@ onUnmounted(() => {
@click="goToDetailPage(props.row)"
@keydown.space.enter.prevent="goToDetailPage(props.row)"
>
<template v-if="props.row.image">
<template v-if="props.row.image || props.row.isVideo">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix the issue where the hover preview for NFT tile icons would not show for video NFTs

<NftViewer
:nft="getNftForViewer(props.row)"
:previewMode="false"
Expand Down
Loading