7 changed files with 356 additions and 76 deletions
			
			
		| @ -0,0 +1,151 @@ | |||
| <template> | |||
|   <QuickNav selected="Discover" /> | |||
|   <TopMessage /> | |||
| 
 | |||
|   <!-- CONTENT --> | |||
|   <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> | |||
|     <h1 id="ViewHeading" class="text-4xl text-center font-light"> | |||
|       Individual Profile | |||
|     </h1> | |||
| 
 | |||
|     <!-- Loading Animation --> | |||
|     <div | |||
|       class="fixed left-6 mt-16 text-center text-4xl leading-none bg-slate-400 text-white w-14 py-2.5 rounded-full" | |||
|       v-if="isLoading" | |||
|     > | |||
|       <fa icon="spinner" class="fa-spin-pulse"></fa> | |||
|     </div> | |||
| 
 | |||
|     <div v-else-if="profile"> | |||
|       <!-- Profile Info --> | |||
|       <div class="mt-8"> | |||
|         <div class="text-sm"> | |||
|           <fa icon="user" class="fa-fw text-slate-400"></fa> | |||
|           {{ didInfo(profile.issuerDid, activeDid, allMyDids, allContacts) }} | |||
|         </div> | |||
|         <p v-if="profile.description" class="mt-4 text-slate-600"> | |||
|           {{ profile.description }} | |||
|         </p> | |||
|       </div> | |||
| 
 | |||
|       <!-- Map --> | |||
|       <div v-if="profile?.locLat && profile?.locLon" class="mt-4"> | |||
|         <h2 class="text-lg font-semibold">Location</h2> | |||
|         <div class="h-96 mt-2 w-full"> | |||
|           <l-map | |||
|             ref="profileMap" | |||
|             :center="[profile.locLat, profile.locLon]" | |||
|             :zoom="12" | |||
|           > | |||
|             <l-tile-layer | |||
|               url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" | |||
|               layer-type="base" | |||
|               name="OpenStreetMap" | |||
|             /> | |||
|             <l-marker :lat-lng="[profile.locLat, profile.locLon]"> | |||
|               <l-popup>{{ | |||
|                 didInfo(profile.issuerDid, activeDid, allMyDids, allContacts) | |||
|               }}</l-popup> | |||
|             </l-marker> | |||
|           </l-map> | |||
|         </div> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|     <div v-else class="text-center mt-8"> | |||
|       <p class="text-lg text-slate-500">Profile not found.</p> | |||
|     </div> | |||
|   </section> | |||
| </template> | |||
| 
 | |||
| <script lang="ts"> | |||
| import "leaflet/dist/leaflet.css"; | |||
| import { Component, Vue } from "vue-facing-decorator"; | |||
| import { LMap, LTileLayer, LMarker, LPopup } from "@vue-leaflet/vue-leaflet"; | |||
| import { Router, RouteLocationNormalizedLoaded } from "vue-router"; | |||
| 
 | |||
| import QuickNav from "@/components/QuickNav.vue"; | |||
| import TopMessage from "@/components/TopMessage.vue"; | |||
| import { DEFAULT_PARTNER_API_SERVER, NotificationIface } from "@/constants/app"; | |||
| import { db } from "@/db/index"; | |||
| import { Contact } from "@/db/tables/contacts"; | |||
| import { didInfo, getHeaders } from "@/libs/endorserServer"; | |||
| import { UserProfile } from "@/libs/partnerServer"; | |||
| import { retrieveAccountDids } from "@/libs/util"; | |||
| 
 | |||
| @Component({ | |||
|   components: { | |||
|     LMap, | |||
|     LMarker, | |||
|     LPopup, | |||
|     LTileLayer, | |||
|     QuickNav, | |||
|     TopMessage, | |||
|   }, | |||
| }) | |||
| export default class UserProfileView extends Vue { | |||
|   $notify!: (notification: NotificationIface, timeout?: number) => void; | |||
|   $router!: Router; | |||
|   $route!: RouteLocationNormalizedLoaded; | |||
| 
 | |||
|   activeDid = ""; | |||
|   allContacts: Array<Contact> = []; | |||
|   allMyDids: Array<string> = []; | |||
|   isLoading = true; | |||
|   partnerApiServer = DEFAULT_PARTNER_API_SERVER; | |||
|   profile: UserProfile | null = null; | |||
| 
 | |||
|   // make this function available to the Vue template | |||
|   didInfo = didInfo; | |||
| 
 | |||
|   async mounted() { | |||
|     const settings = await db.settings.toArray(); | |||
|     this.activeDid = settings[0]?.activeDid || ""; | |||
|     this.partnerApiServer = | |||
|       settings[0]?.partnerApiServer || this.partnerApiServer; | |||
| 
 | |||
|     this.allContacts = await db.contacts.toArray(); | |||
|     this.allMyDids = await retrieveAccountDids(); | |||
| 
 | |||
|     await this.loadProfile(); | |||
|   } | |||
| 
 | |||
|   async loadProfile() { | |||
|     const profileId: string = this.$route.params.id as string; | |||
|     if (!profileId) { | |||
|       this.isLoading = false; | |||
|       return; | |||
|     } | |||
| 
 | |||
|     try { | |||
|       const response = await fetch( | |||
|         `${this.partnerApiServer}/api/partner/userProfile/${encodeURIComponent(profileId)}`, | |||
|         { | |||
|           method: "GET", | |||
|           headers: await getHeaders(this.activeDid), | |||
|         }, | |||
|       ); | |||
| 
 | |||
|       if (response.status === 200) { | |||
|         const result = await response.json(); | |||
|         this.profile = result.data; | |||
|       } else { | |||
|         throw new Error("Failed to load profile"); | |||
|       } | |||
|     } catch (error) { | |||
|       console.error("Error loading profile:", error); | |||
|       this.$notify( | |||
|         { | |||
|           group: "alert", | |||
|           type: "danger", | |||
|           title: "Error", | |||
|           text: "There was a problem loading the profile.", | |||
|         }, | |||
|         5000, | |||
|       ); | |||
|     } finally { | |||
|       this.isLoading = false; | |||
|     } | |||
|   } | |||
| } | |||
| </script> | |||
					Loading…
					
					
				
		Reference in new issue