Optimized avatars and added avatar auto-fixer when cache is old.

This commit is contained in:
zenodeapp 2023-12-01 14:26:49 +01:00
parent aa17be0839
commit 727979bf20
2 changed files with 93 additions and 47 deletions

View File

@ -79,6 +79,7 @@ const selfRate = computed(() => {
} }
return '-'; return '-';
}); });
const logo = (identity?: string) => { const logo = (identity?: string) => {
if (!identity) return ''; if (!identity) return '';
const url = avatars.value[identity] || ''; const url = avatars.value[identity] || '';
@ -86,25 +87,43 @@ const logo = (identity?: string) => {
? url ? url
: `https://s3.amazonaws.com/keybase_processed_uploads/${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 = () => {
fetchAvatar(identity.value).then(() => {
localStorage.setItem('avatars', JSON.stringify(avatars.value));
});
};
onMounted(() => { onMounted(() => {
if (validator) { if (validator) {
staking.fetchValidator(validator).then((res) => { staking.fetchValidator(validator).then((res) => {
v.value = res.validator; v.value = res.validator;
identity.value = res.validator?.description?.identity || ''; identity.value = res.validator?.description?.identity || '';
if (identity.value && !avatars.value[identity.value]) { if (identity.value && !avatars.value[identity.value]) loadAvatar();
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));
}
}
});
}
const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>'; const prefix = valoperToPrefix(v.value.operator_address) || '<Invalid>';
addresses.value.hex = consensusPubkeyToHexAddress( addresses.value.hex = consensusPubkeyToHexAddress(
v.value.consensus_pubkey v.value.consensus_pubkey
@ -187,6 +206,13 @@ function pageload(p: number) {
v-if="avatars[identity] !== 'undefined'" v-if="avatars[identity] !== 'undefined'"
v-lazy="logo(identity)" v-lazy="logo(identity)"
class="object-contain" class="object-contain"
@error="
(e) => {
if (identity) {
loadAvatar();
}
}
"
/> />
<Icon <Icon
v-else v-else

View File

@ -141,39 +141,54 @@ const list = computed(() => {
return unbondList.value.map((x, i) => ({v: x, rank: 'primary', logo: logo(x.description.identity)})); return unbondList.value.map((x, i) => ({v: x, rank: 'primary', logo: logo(x.description.identity)}));
}); });
const loadAvatars = () => { const fetchAvatar = (identity: string) => {
// fetch avatar from keybase // fetch avatar from keybase
let promise = Promise.resolve(); return new Promise<void>((resolve) => {
staking.validators.forEach((item) => { staking
promise = promise.then( .keybase(identity)
() => .then((d) => {
new Promise((resolve) => { if (Array.isArray(d.them) && d.them.length > 0) {
const identity = item.description?.identity; const uri = String(d.them[0]?.pictures?.primary?.url).replace(
if (identity && !avatars.value[identity]) { 'https://s3.amazonaws.com/keybase_processed_uploads/',
staking.keybase(identity).then((d) => { ''
if (Array.isArray(d.them) && d.them.length > 0) { );
const uri = String(
d.them[0]?.pictures?.primary?.url avatars.value[identity] = uri;
).replace( resolve();
'https://s3.amazonaws.com/keybase_processed_uploads/', } else throw new Error(`failed to fetch avatar for ${identity}`);
'' })
); .catch((error) => {
if (uri) { // console.error(error); // uncomment this if you want the user to see which avatars failed to load.
avatars.value[identity] = uri; resolve();
localStorage.setItem( });
'avatars', });
JSON.stringify(avatars.value) };
);
} const loadAvatar = (validator: Validator) => {
} const identity = validator.description?.identity;
resolve();
}); if (identity) {
} else { fetchAvatar(identity).then(() => {
resolve(); localStorage.setItem('avatars', JSON.stringify(avatars.value));
}
})
);
}); });
}
};
const loadAvatars = () => {
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) => { const logo = (identity?: string) => {
@ -313,7 +328,7 @@ loadAvatars();
style="max-width: 300px" style="max-width: 300px"
> >
<div <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 <div
class="w-8 h-8 rounded-full bg-gray-400 absolute opacity-10" class="w-8 h-8 rounded-full bg-gray-400 absolute opacity-10"
@ -323,6 +338,11 @@ loadAvatars();
v-if="logo" v-if="logo"
:src="logo" :src="logo"
class="object-contain" class="object-contain"
@error="
(e) => {
loadAvatar(v);
}
"
/> />
<Icon <Icon
v-else v-else