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