Merge pull request #517 from zenodeapp/master

Optimized avatars and added avatar auto-fixer when cache is old.
This commit is contained in:
ping 2023-12-02 08:19:05 +08:00 committed by GitHub
commit 1aee5ac969
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 50 deletions

View File

@ -79,6 +79,7 @@ const selfRate = computed(() => {
}
return '-';
});
const logo = (identity?: string) => {
if (!identity) return '';
const url = avatars.value[identity] || '';
@ -86,25 +87,44 @@ const logo = (identity?: string) => {
? url
: `https://s3.amazonaws.com/keybase_processed_uploads/${url}`;
};
const fetchAvatar = (identity: string) => {
// fetch avatar from keybase
return new Promise<void>((resolve) => {
staking
.keybase(identity)
.then((d) => {
if (Array.isArray(d.them) && d.them.length > 0) {
const uri = String(d.them[0]?.pictures?.primary?.url).replace(
'https://s3.amazonaws.com/keybase_processed_uploads/',
''
);
avatars.value[identity] = uri;
resolve();
} else throw new Error(`failed to fetch avatar for ${identity}.`);
})
.catch((error) => {
// console.error(error); // uncomment this if you want the user to see if the avatar failed to load.
resolve();
});
});
};
const loadAvatar = (identity: string) => {
// fetches avatar from keybase and stores it in localStorage
fetchAvatar(identity).then(() => {
localStorage.setItem('avatars', JSON.stringify(avatars.value));
});
};
onMounted(() => {
if (validator) {
staking.fetchValidator(validator).then((res) => {
v.value = res.validator;
identity.value = res.validator?.description?.identity || '';
if (identity.value && !avatars.value[identity.value]) {
staking.keybase(identity.value).then((d) => {
if (Array.isArray(d.them) && d.them.length > 0) {
const uri = String(d.them[0]?.pictures?.primary?.url).replace(
'https://s3.amazonaws.com/keybase_processed_uploads/',
''
);
if (uri) {
avatars.value[identity.value] = uri;
localStorage.setItem('avatars', JSON.stringify(avatars.value));
}
}
});
}
if (identity.value && !avatars.value[identity.value]) loadAvatar(identity.value);
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>';
addresses.value.hex = consensusPubkeyToHexAddress(
v.value.consensus_pubkey
@ -184,13 +204,18 @@ function pageload(p: number) {
<div class="w-24 rounded-lg absolute opacity-10"></div>
<div class="w-24 rounded-lg">
<img
v-if="avatars[identity] !== 'undefined'"
v-if="identity && avatars[identity] !== 'undefined'"
v-lazy="logo(identity)"
class="object-contain"
@error="
(e) => {
loadAvatar(identity);
}
"
/>
<Icon
v-else
class="text-4xl"
class="text-8xl"
:icon="`mdi-help-circle-outline`"
/>
</div>

View File

@ -141,39 +141,52 @@ const list = computed(() => {
return unbondList.value.map((x, i) => ({v: x, rank: 'primary', logo: logo(x.description.identity)}));
});
const fetchAvatar = (identity: string) => {
// fetch avatar from keybase
return new Promise<void>((resolve) => {
staking
.keybase(identity)
.then((d) => {
if (Array.isArray(d.them) && d.them.length > 0) {
const uri = String(d.them[0]?.pictures?.primary?.url).replace(
'https://s3.amazonaws.com/keybase_processed_uploads/',
''
);
avatars.value[identity] = uri;
resolve();
} else throw new Error(`failed to fetch avatar for ${identity}`);
})
.catch((error) => {
// console.error(error); // uncomment this if you want the user to see which avatars failed to load.
resolve();
});
});
};
const loadAvatar = (identity: string) => {
// fetches avatar from keybase and stores it in localStorage
fetchAvatar(identity).then(() => {
localStorage.setItem('avatars', JSON.stringify(avatars.value));
});
};
const loadAvatars = () => {
// fetch avatar from keybase
let promise = Promise.resolve();
staking.validators.forEach((item) => {
promise = promise.then(
() =>
new Promise((resolve) => {
const identity = item.description?.identity;
if (identity && !avatars.value[identity]) {
staking.keybase(identity).then((d) => {
if (Array.isArray(d.them) && d.them.length > 0) {
const uri = String(
d.them[0]?.pictures?.primary?.url
).replace(
'https://s3.amazonaws.com/keybase_processed_uploads/',
''
);
if (uri) {
avatars.value[identity] = uri;
localStorage.setItem(
'avatars',
JSON.stringify(avatars.value)
);
}
}
resolve();
});
} else {
resolve();
}
})
);
});
// fetches all avatars from keybase and stores it in localStorage
const promises = staking.validators.map((validator) => {
const identity = validator.description?.identity;
// Here we also check whether we haven't already fetched the avatar
if (identity && !avatars.value[identity]) {
return fetchAvatar(identity);
} else {
return Promise.resolve();
}
});
Promise.all(promises).then(() =>
localStorage.setItem('avatars', JSON.stringify(avatars.value))
);
};
const logo = (identity?: string) => {
@ -313,7 +326,7 @@ loadAvatars();
style="max-width: 300px"
>
<div
class="avatar mr-4 relative w-8 h-8 rounded-full overflow-hidden"
class="avatar mr-4 relative w-8 h-8 rounded-full"
>
<div
class="w-8 h-8 rounded-full bg-gray-400 absolute opacity-10"
@ -323,10 +336,16 @@ loadAvatars();
v-if="logo"
:src="logo"
class="object-contain"
@error="
(e) => {
const identity = v.description?.identity;
if (identity) loadAvatar(identity);
}
"
/>
<Icon
v-else
class="text-4xl"
class="text-3xl"
:icon="`mdi-help-circle-outline`"
/>