From c92c7ad5d733ad3ad8277f4c4b2ab14d1d122376 Mon Sep 17 00:00:00 2001 From: mtyszczak <mateusz.tyszczak@gmail.com> Date: Tue, 18 Mar 2025 15:25:14 +0100 Subject: [PATCH] Add account details card --- src/App.vue | 1 + src/components/navigation/AppHeader.vue | 2 +- src/components/utilcards/AccountDetails.vue | 56 +++++++++++++ src/components/utilcards/AuthorityCard.vue | 80 ------------------- .../utilcards/ConfirmAccountUpdateCard.vue | 2 +- .../utilcards/ConfirmCreateAccountCard.vue | 2 +- src/components/utilcards/MemoEncryptCard.vue | 2 +- .../utilcards/SignTransactionCard.vue | 2 +- src/pages/index.vue | 6 +- src/stores/user.store.ts | 6 +- 10 files changed, 69 insertions(+), 90 deletions(-) create mode 100644 src/components/utilcards/AccountDetails.vue delete mode 100644 src/components/utilcards/AuthorityCard.vue diff --git a/src/App.vue b/src/App.vue index c01a156..6c11479 100644 --- a/src/App.vue +++ b/src/App.vue @@ -36,6 +36,7 @@ const complete = async(data: { account: string; wallet: UsedWallet }) => { const wax = await getWax(); const { accounts: [ account ] } = await wax.api.database_api.find_accounts({ accounts: [ settingsStore.settings.account! ], delayed_votes_active: false }); void userStore.setUserData(account); + walletStore.closeWalletSelectModal(); }; </script> diff --git a/src/components/navigation/AppHeader.vue b/src/components/navigation/AppHeader.vue index 04cccd8..fcb24b2 100644 --- a/src/components/navigation/AppHeader.vue +++ b/src/components/navigation/AppHeader.vue @@ -27,7 +27,7 @@ const userStore = useUserStore(); <div class="fixed top-0 z-10 bg-background/60 backdrop-blur-sm px-4 h-[60px] border-b w-full md:w-[calc(100%-var(--sidebar-width))] flex items-center justify-between"> <ToggleSidebar /> <div v-if="settingsStore.isLoaded && hasUser" class="ml-2 inline-flex items-center"> - <Avatar class="w-8 h-8 mr-2"> + <Avatar class="w-8 h-8 mr-2 border"> <AvatarImage v-if="userStore.profileImage" :src="userStore.profileImage" /> <AvatarFallback v-if="settingsStore.isLoaded && hasUser">{{ settingsStore.settings.account?.slice(0, 2) }}</AvatarFallback> </Avatar> diff --git a/src/components/utilcards/AccountDetails.vue b/src/components/utilcards/AccountDetails.vue new file mode 100644 index 0000000..8f0fa75 --- /dev/null +++ b/src/components/utilcards/AccountDetails.vue @@ -0,0 +1,56 @@ +<script setup lang="ts"> +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { Skeleton } from '@/components/ui/skeleton'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { mdiAccountBadgeOutline, mdiOpenInNew } from '@mdi/js'; +import { useSettingsStore } from '@/stores/settings.store'; +import { computed } from 'vue'; +import { useUserStore } from '@/stores/user.store'; + +const settingsStore = useSettingsStore(); +const hasUser = computed(() => settingsStore.settings.account !== undefined); + +const userStore = useUserStore(); +</script> + +<template> + <Card class="w-full"> + <CardHeader> + <CardTitle class="inline-flex items-center justify-between"> + <span>Account details</span> + <svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path style="fill: hsla(var(--foreground) / 80%)" :d="mdiAccountBadgeOutline"/></svg> + </CardTitle> + <CardDescription class="mr-8">Account description parsed from the metadata</CardDescription> + </CardHeader> + <CardContent> + <div class="space-y-4" v-if="hasUser"> + <div class="flex space-x-1"> + <div> + <Avatar v-if="userStore.isReady" shape="square" class="border rounded-xl w-20 h-20 mr-2"> + <AvatarImage v-if="userStore.profileImage" :src="userStore.profileImage" /> + <AvatarFallback>{{ settingsStore.settings.account?.slice(0, 12) }}</AvatarFallback> + </Avatar> + <Skeleton v-else class="rounded-xl w-20 h-20 mr-2" /> + </div> + <div class="flex flex-col space-y-1 w-full mt-1"> + <div v-if="userStore.isReady" class="inline-flex items-center text-lg/3 font-bold"> + <span>{{ userStore.name }}</span> + <a v-if="userStore.website" :href="userStore.website" target="_blank" class=""> + <svg class="ml-2 inline" width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path style="fill: hsla(var(--foreground) / 80%)" :d="mdiOpenInNew"/></svg> + </a> + </div> + <Skeleton v-else class="w-40 h-6" /> + <span v-if="userStore.isReady" class="text-xs font-bold top-[-5px]">@{{ settingsStore.settings.account }}</span> + <Skeleton v-else class="w-40 h-6" /> + <span v-if="userStore.isReady" class="text-sm">{{ userStore.about }}</span> + <span v-else class="space-y-1"> + <Skeleton class="w-full h-4" /> + <Skeleton class="w-full h-4" /> + <Skeleton class="w-full h-4" /> + </span> + </div> + </div> + </div> + </CardContent> + </Card> +</template> \ No newline at end of file diff --git a/src/components/utilcards/AuthorityCard.vue b/src/components/utilcards/AuthorityCard.vue deleted file mode 100644 index 365abd4..0000000 --- a/src/components/utilcards/AuthorityCard.vue +++ /dev/null @@ -1,80 +0,0 @@ -<script setup lang="ts"> -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Skeleton } from '@/components/ui/skeleton'; -import { mdiAccountKeyOutline } from '@mdi/js'; -import { useSettingsStore } from '@/stores/settings.store'; -import { computed, onMounted, ref, watch } from 'vue'; -import type { authority } from '@hiveio/wax/vite'; -import { getWax } from '@/stores/wax.store'; -import PublicKey from '@/components/hive/PublicKey.vue'; - -const settingsStore = useSettingsStore(); -const hasUser = computed(() => settingsStore.settings.account !== undefined); - -const memoKey = ref<null | string>(null); -const activeAuthority = ref<null | authority>(null); -const postingAuthority = ref<null | authority>(null); -const ownerAuthority = ref<null | authority>(null); - -const retrieveAuthority = async() => { - try { - const wax = await getWax(); - - const { AccountAuthorityUpdateOperation } = await import("@hiveio/wax/vite"); - const op = await AccountAuthorityUpdateOperation.createFor(wax, settingsStore.settings.account!); - memoKey.value = op.role("memo").value; - postingAuthority.value = op.role("posting").value; - activeAuthority.value = op.role("active").value; - ownerAuthority.value = op.role("owner").value; - } catch(error) { - console.error(error); // TODO: Handle error - toast - } -}; -watch(hasUser, value => { - if(value) - void retrieveAuthority(); -}); -onMounted(() => { - if(hasUser.value) - void retrieveAuthority(); -}); -</script> - -<template> - <Card class="w-full max-w-[600px] backdrop-blur-sm"> - <CardHeader> - <CardTitle class="inline-flex items-center justify-between"> - <span>Authority info</span> - <svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path style="fill: hsla(var(--foreground) / 80%)" :d="mdiAccountKeyOutline"/></svg> - </CardTitle> - <CardDescription class="mr-8">Use this module to gather information about your Hive on-chain authorities</CardDescription> - </CardHeader> - <CardContent> - <div class="space-y-4" v-if="hasUser"> - <div class="flex flex-col"> - <h4>Memo</h4> - <PublicKey v-if="memoKey" :value="memoKey" /> - <Skeleton v-if="!memoKey" class="ml-2 h-[40px] w-full rounded-xl" /> - </div> - <div class="flex flex-col"> - <h4>Posting</h4> - <PublicKey v-if="postingAuthority" v-for="(key, val) in postingAuthority.key_auths" :key="key" :value="val" :after-value="`(${key}/${postingAuthority.weight_threshold})`" /> - <PublicKey :context="0" v-if="postingAuthority" v-for="(key, val) in postingAuthority.account_auths" :key="key" :value="val" :after-value="`(${key}/${postingAuthority.weight_threshold})`"/> - <Skeleton v-if="!postingAuthority" class="ml-2 h-[40px] w-full rounded-xl" /> - </div> - <div class="flex flex-col"> - <h4>Active</h4> - <PublicKey v-if="activeAuthority" v-for="(key, val) in activeAuthority.key_auths" :key="key" :value="val" :after-value="`(${key}/${activeAuthority.weight_threshold})`" /> - <PublicKey :context="0" v-if="activeAuthority" v-for="(key, val) in activeAuthority.account_auths" :key="key" :value="val" :after-value="`(${key}/${activeAuthority.weight_threshold})`"/> - <Skeleton v-if="!activeAuthority" class="ml-2 h-[40px] w-full rounded-xl" /> - </div> - <div class="flex flex-col"> - <h4>Owner</h4> - <PublicKey v-if="ownerAuthority" v-for="(key, val) in ownerAuthority.key_auths" :key="key" :value="val" :after-value="`(${key}/${ownerAuthority.weight_threshold})`" /> - <PublicKey :context="0" v-if="ownerAuthority" v-for="(key, val) in ownerAuthority.account_auths" :key="key" :value="val" :after-value="`(${key}/${ownerAuthority.weight_threshold})`"/> - <Skeleton v-if="!ownerAuthority" class="ml-2 h-[40px] w-full rounded-xl" /> - </div> - </div> - </CardContent> - </Card> -</template> \ No newline at end of file diff --git a/src/components/utilcards/ConfirmAccountUpdateCard.vue b/src/components/utilcards/ConfirmAccountUpdateCard.vue index 0fef627..8e0273d 100644 --- a/src/components/utilcards/ConfirmAccountUpdateCard.vue +++ b/src/components/utilcards/ConfirmAccountUpdateCard.vue @@ -64,7 +64,7 @@ const updateAuthority = async() => { </script> <template> - <Card class="w-full max-w-[600px] backdrop-blur-sm"> + <Card class="w-full max-w-[600px]"> <CardHeader> <CardTitle class="inline-flex items-center justify-between"> <span>Process Authority Update</span> diff --git a/src/components/utilcards/ConfirmCreateAccountCard.vue b/src/components/utilcards/ConfirmCreateAccountCard.vue index 6a7be44..038d904 100644 --- a/src/components/utilcards/ConfirmCreateAccountCard.vue +++ b/src/components/utilcards/ConfirmCreateAccountCard.vue @@ -116,7 +116,7 @@ const createAccount = async() => { </script> <template> - <Card class="w-full max-w-[600px] backdrop-blur-sm"> + <Card class="w-full max-w-[600px]"> <CardHeader> <CardTitle class="inline-flex items-center justify-between"> <span>Process Account Creation</span> diff --git a/src/components/utilcards/MemoEncryptCard.vue b/src/components/utilcards/MemoEncryptCard.vue index 2ca7c54..8c03ca0 100644 --- a/src/components/utilcards/MemoEncryptCard.vue +++ b/src/components/utilcards/MemoEncryptCard.vue @@ -76,7 +76,7 @@ const encryptOrDecrypt = async () => { </script> <template> - <Card class="w-full max-w-[600px] backdrop-blur-sm"> + <Card class="w-full max-w-[600px]"> <CardHeader> <CardTitle class="inline-flex items-center justify-between"> <span>Memo encryption</span> diff --git a/src/components/utilcards/SignTransactionCard.vue b/src/components/utilcards/SignTransactionCard.vue index 004e4ad..30158ff 100644 --- a/src/components/utilcards/SignTransactionCard.vue +++ b/src/components/utilcards/SignTransactionCard.vue @@ -87,7 +87,7 @@ onMounted(() => { </script> <template> - <Card class="w-full max-w-[600px] backdrop-blur-sm"> + <Card class="w-full max-w-[600px]"> <CardHeader> <CardTitle class="inline-flex items-center justify-between"> <span>Transaction signing</span> diff --git a/src/pages/index.vue b/src/pages/index.vue index 452df94..d944bda 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,9 +1,9 @@ <script setup lang="ts"> -import AuthorityCard from '@/components/utilcards/AuthorityCard.vue'; +import AccountDetails from '@/components/utilcards/AccountDetails.vue'; </script> <template> - <div class="flex p-8"> - <AuthorityCard /> + <div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 p-8"> + <AccountDetails /> </div> </template> diff --git a/src/stores/user.store.ts b/src/stores/user.store.ts index 306afb2..59e1bda 100644 --- a/src/stores/user.store.ts +++ b/src/stores/user.store.ts @@ -9,7 +9,7 @@ export const useUserStore = defineStore('user', { }), getters: { profileImage: (ctx): undefined | string => ctx.isReady ? ctx.parsedJsonMetadata?.profile?.profile_image : undefined, - name: (ctx): undefined | string => ctx.isReady ? ctx.parsedJsonMetadata?.profile?.name : undefined, + name: (ctx): undefined | string => ctx.isReady ? ctx.parsedJsonMetadata?.profile?.name || ctx.userData?.name : undefined, about: (ctx): undefined | string => ctx.isReady ? ctx.parsedJsonMetadata?.profile?.about : undefined, website: (ctx): undefined | string => ctx.isReady ? ctx.parsedJsonMetadata?.profile?.website : undefined }, @@ -22,7 +22,9 @@ export const useUserStore = defineStore('user', { }, setUserData(data: ApiAccount) { this.userData = data; - this.parsedJsonMetadata = JSON.parse(data.posting_json_metadata); + try { + this.parsedJsonMetadata = JSON.parse(data.posting_json_metadata); + } catch {} this.isReady = true; } } -- GitLab