@ -174,13 +174,15 @@
: aria - busy = "loadingProfile || savingProfile"
: aria - busy = "loadingProfile || savingProfile"
> < / textarea >
> < / textarea >
< div class = "flex items-center mb-4" @click ="toggleUserProfileLocation" >
< div class = "flex items-center mb-4" >
< input
< input
v - model = "includeUserProfileLocation"
v - model = "includeUserProfileLocation"
type = "checkbox"
type = "checkbox"
class = "mr-2"
class = "mr-2"
@ change = "onLocationCheckboxChange"
/ >
/ >
< label for = "includeUserProfileLocation" > Include Location < / label >
< label for = "includeUserProfileLocation" > Include Location < / label >
< span class = "text-xs text-slate-400 ml-2" > ( Debug : { { isMapReady ? 'Map Ready' : 'Map Loading' } } ) < / span >
< / div >
< / div >
< div v-if ="includeUserProfileLocation" class="mb-4 aspect-video" >
< div v-if ="includeUserProfileLocation" class="mb-4 aspect-video" >
< p class = "text-sm mb-2 text-slate-500" >
< p class = "text-sm mb-2 text-slate-500" >
@ -194,6 +196,7 @@
class = "!z-40 rounded-md"
class = "!z-40 rounded-md"
@ click = "onProfileMapClick"
@ click = "onProfileMapClick"
@ ready = "onMapReady"
@ ready = "onMapReady"
@ mounted = "onMapMounted"
>
>
< l -tile -layer
< l -tile -layer
url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
@ -751,6 +754,7 @@ import "dexie-export-import";
/ / @ t s - e x p e c t - e r r o r - t h e y a r e n ' t e x p o r t i n g i t b u t i t ' s t h e r e
/ / @ t s - e x p e c t - e r r o r - t h e y a r e n ' t e x p o r t i n g i t b u t i t ' s t h e r e
import { ImportProgress } from "dexie-export-import" ;
import { ImportProgress } from "dexie-export-import" ;
import { LeafletMouseEvent } from "leaflet" ;
import { LeafletMouseEvent } from "leaflet" ;
import * as L from "leaflet" ;
import * as R from "ramda" ;
import * as R from "ramda" ;
import { IIdentifier } from "@veramo/core" ;
import { IIdentifier } from "@veramo/core" ;
import { ref } from "vue" ;
import { ref } from "vue" ;
@ -902,6 +906,7 @@ export default class AccountViewView extends Vue {
warnIfProdServer : boolean = false ;
warnIfProdServer : boolean = false ;
warnIfTestServer : boolean = false ;
warnIfTestServer : boolean = false ;
zoom : number = 2 ;
zoom : number = 2 ;
isMapReady : boolean = false ;
/ / L i m i t s a n d v a l i d a t i o n p r o p e r t i e s
/ / L i m i t s a n d v a l i d a t i o n p r o p e r t i e s
endorserLimits : EndorserRateLimits | null = null ;
endorserLimits : EndorserRateLimits | null = null ;
@ -913,6 +918,17 @@ export default class AccountViewView extends Vue {
created ( ) {
created ( ) {
this . notify = createNotifyHelpers ( this . $notify ) ;
this . notify = createNotifyHelpers ( this . $notify ) ;
/ / F i x L e a f l e t i c o n i s s u e s i n m o d e r n b u n d l e r s
/ / T h i s p r e v e n t s t h e " C a n n o t r e a d p r o p e r t i e s o f u n d e f i n e d ( r e a d i n g ' D e f a u l t ' ) " e r r o r
if ( L . Icon . Default ) {
delete ( L . Icon . Default . prototype as any ) . _getIconUrl ;
L . Icon . Default . mergeOptions ( {
iconRetinaUrl : 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png' ,
iconUrl : 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png' ,
shadowUrl : 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png' ,
} ) ;
}
}
}
/ * *
/ * *
@ -939,10 +955,16 @@ export default class AccountViewView extends Vue {
this . userProfileLatitude = profile . latitude ;
this . userProfileLatitude = profile . latitude ;
this . userProfileLongitude = profile . longitude ;
this . userProfileLongitude = profile . longitude ;
this . includeUserProfileLocation = profile . includeLocation ;
this . includeUserProfileLocation = profile . includeLocation ;
/ / I n i t i a l i z e m a p r e a d y s t a t e i f l o c a t i o n i s i n c l u d e d
if ( profile . includeLocation ) {
this . isMapReady = false ; / / W i l l b e s e t t o t r u e w h e n m a p i s r e a d y
}
} else {
} else {
/ / P r o f i l e n o t c r e a t e d y e t ; l e a v e d e f a u l t s
/ / P r o f i l e n o t c r e a t e d y e t ; l e a v e d e f a u l t s
}
}
} catch ( error ) {
} catch ( error ) {
logger . error ( "Error loading profile:" , error ) ;
this . notify . error (
this . notify . error (
ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_NOT_AVAILABLE ,
ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_NOT_AVAILABLE ,
) ;
) ;
@ -1518,9 +1540,45 @@ export default class AccountViewView extends Vue {
}
}
onMapReady ( map : L . Map ) : void {
onMapReady ( map : L . Map ) : void {
try {
logger . debug ( "Map ready event fired, map object:" , map ) ;
/ / d o i n g t h i s h e r e i n s t e a d o f o n t h e l - m a p e l e m e n t a v o i d s a r e c e n t e r i n g a f t e r a d r a g t h e n z o o m a t s t a r t u p
/ / d o i n g t h i s h e r e i n s t e a d o f o n t h e l - m a p e l e m e n t a v o i d s a r e c e n t e r i n g a f t e r a d r a g t h e n z o o m a t s t a r t u p
const zoom = this . userProfileLatitude && this . userProfileLongitude ? 12 : 2 ;
const zoom = this . userProfileLatitude && this . userProfileLongitude ? 12 : 2 ;
map . setView ( [ this . userProfileLatitude , this . userProfileLongitude ] , zoom ) ;
const lat = this . userProfileLatitude || 0 ;
const lng = this . userProfileLongitude || 0 ;
map . setView ( [ lat , lng ] , zoom ) ;
this . isMapReady = true ;
logger . debug ( "Map ready state set to true, coordinates:" , [ lat , lng ] , "zoom:" , zoom ) ;
} catch ( error ) {
logger . error ( "Error in onMapReady:" , error ) ;
this . isMapReady = true ; / / S e t t o t r u e e v e n o n e r r o r t o p r e v e n t i n f i n i t e l o a d i n g
}
}
onMapMounted ( ) : void {
logger . debug ( "Map component mounted" ) ;
/ / C h e c k i f m a p r e f i s a v a i l a b l e
const mapRef = this . $refs . profileMap ;
logger . debug ( "Map ref:" , mapRef ) ;
/ / T r y t o s e t m a p r e a d y a f t e r c o m p o n e n t i s m o u n t e d
setTimeout ( ( ) => {
this . isMapReady = true ;
logger . debug ( "Map ready set to true after mounted" ) ;
} , 500 ) ;
}
/ / F a l l b a c k m e t h o d t o h a n d l e m a p i n i t i a l i z a t i o n f a i l u r e s
private handleMapInitFailure ( ) : void {
logger . debug ( "Starting map initialization timeout (5 seconds)" ) ;
setTimeout ( ( ) => {
if ( ! this . isMapReady ) {
logger . warn ( "Map failed to initialize, forcing ready state" ) ;
this . isMapReady = true ;
} else {
logger . debug ( "Map initialized successfully, timeout not needed" ) ;
}
} , 5000 ) ; / / 5 s e c o n d t i m e o u t
}
}
showProfileInfo ( ) : void {
showProfileInfo ( ) : void {
@ -1532,13 +1590,16 @@ export default class AccountViewView extends Vue {
async saveProfile ( ) : Promise < void > {
async saveProfile ( ) : Promise < void > {
this . savingProfile = true ;
this . savingProfile = true ;
try {
const profileData : ProfileData = {
const profileData : ProfileData = {
description : this . userProfileDesc ,
description : this . userProfileDesc ,
latitude : this . userProfileLatitude ,
latitude : this . userProfileLatitude ,
longitude : this . userProfileLongitude ,
longitude : this . userProfileLongitude ,
includeLocation : this . includeUserProfileLocation ,
includeLocation : this . includeUserProfileLocation ,
} ;
} ;
try {
logger . debug ( "Saving profile data:" , profileData ) ;
const success = await this . profileService . saveProfile (
const success = await this . profileService . saveProfile (
this . activeDid ,
this . activeDid ,
profileData ,
profileData ,
@ -1549,6 +1610,7 @@ export default class AccountViewView extends Vue {
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_SAVE_ERROR ) ;
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_SAVE_ERROR ) ;
}
}
} catch ( error ) {
} catch ( error ) {
logger . error ( "Error saving profile:" , error ) ;
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_SAVE_ERROR ) ;
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_SAVE_ERROR ) ;
} finally {
} finally {
this . savingProfile = false ;
this . savingProfile = false ;
@ -1556,6 +1618,7 @@ export default class AccountViewView extends Vue {
}
}
toggleUserProfileLocation ( ) : void {
toggleUserProfileLocation ( ) : void {
try {
const updated = this . profileService . toggleProfileLocation ( {
const updated = this . profileService . toggleProfileLocation ( {
description : this . userProfileDesc ,
description : this . userProfileDesc ,
latitude : this . userProfileLatitude ,
latitude : this . userProfileLatitude ,
@ -1565,6 +1628,15 @@ export default class AccountViewView extends Vue {
this . userProfileLatitude = updated . latitude ;
this . userProfileLatitude = updated . latitude ;
this . userProfileLongitude = updated . longitude ;
this . userProfileLongitude = updated . longitude ;
this . includeUserProfileLocation = updated . includeLocation ;
this . includeUserProfileLocation = updated . includeLocation ;
/ / R e s e t m a p r e a d y s t a t e w h e n t o g g l i n g l o c a t i o n
if ( ! updated . includeLocation ) {
this . isMapReady = false ;
}
} catch ( error ) {
logger . error ( "Error in toggleUserProfileLocation:" , error ) ;
this . notify . error ( "Failed to toggle location setting" ) ;
}
}
}
confirmEraseLatLong ( ) : void {
confirmEraseLatLong ( ) : void {
@ -1592,6 +1664,7 @@ export default class AccountViewView extends Vue {
async deleteProfile ( ) : Promise < void > {
async deleteProfile ( ) : Promise < void > {
try {
try {
logger . debug ( "Attempting to delete profile for DID:" , this . activeDid ) ;
const success = await this . profileService . deleteProfile ( this . activeDid ) ;
const success = await this . profileService . deleteProfile ( this . activeDid ) ;
if ( success ) {
if ( success ) {
this . notify . success ( ACCOUNT_VIEW_CONSTANTS . SUCCESS . PROFILE_DELETED ) ;
this . notify . success ( ACCOUNT_VIEW_CONSTANTS . SUCCESS . PROFILE_DELETED ) ;
@ -1599,13 +1672,22 @@ export default class AccountViewView extends Vue {
this . userProfileLatitude = 0 ;
this . userProfileLatitude = 0 ;
this . userProfileLongitude = 0 ;
this . userProfileLongitude = 0 ;
this . includeUserProfileLocation = false ;
this . includeUserProfileLocation = false ;
this . isMapReady = false ; / / R e s e t m a p s t a t e
logger . debug ( "Profile deleted successfully, UI state reset" ) ;
} else {
} else {
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_DELETE_ERROR ) ;
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_DELETE_ERROR ) ;
}
}
} catch ( error ) {
} catch ( error ) {
logger . error ( "Error in deleteProfile component method:" , error ) ;
/ / S h o w m o r e s p e c i f i c e r r o r m e s s a g e i f a v a i l a b l e
if ( error instanceof Error ) {
this . notify . error ( error . message ) ;
} else {
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_DELETE_ERROR ) ;
this . notify . error ( ACCOUNT_VIEW_CONSTANTS . ERRORS . PROFILE_DELETE_ERROR ) ;
}
}
}
}
}
private handleQRCodeClick ( ) {
private handleQRCodeClick ( ) {
if ( Capacitor . isNativePlatform ( ) ) {
if ( Capacitor . isNativePlatform ( ) ) {
@ -1616,9 +1698,44 @@ export default class AccountViewView extends Vue {
}
}
onProfileMapClick ( event : LeafletMouseEvent ) {
onProfileMapClick ( event : LeafletMouseEvent ) {
try {
if ( event && event . latlng ) {
this . userProfileLatitude = event . latlng . lat ;
this . userProfileLatitude = event . latlng . lat ;
this . userProfileLongitude = event . latlng . lng ;
this . userProfileLongitude = event . latlng . lng ;
}
}
} catch ( error ) {
logger . error ( "Error in onProfileMapClick:" , error ) ;
}
}
onLocationCheckboxChange ( ) : void {
try {
logger . debug ( "Location checkbox changed, new value:" , this . includeUserProfileLocation ) ;
if ( ! this . includeUserProfileLocation ) {
/ / L o c a t i o n c h e c k b o x w a s u n c h e c k e d , c l e a n u p m a p s t a t e
this . isMapReady = false ;
this . userProfileLatitude = 0 ;
this . userProfileLongitude = 0 ;
logger . debug ( "Location unchecked, map state reset" ) ;
} else {
/ / L o c a t i o n c h e c k b o x w a s c h e c k e d , s t a r t m a p i n i t i a l i z a t i o n t i m e o u t
this . isMapReady = false ;
logger . debug ( "Location checked, starting map initialization timeout" ) ;
/ / T r y t o s e t m a p r e a d y a f t e r a s h o r t d e l a y t o a l l o w V u e t o r e n d e r
setTimeout ( ( ) => {
if ( ! this . isMapReady ) {
logger . debug ( "Setting map ready after timeout" ) ;
this . isMapReady = true ;
}
} , 1000 ) ; / / 1 s e c o n d d e l a y
this . handleMapInitFailure ( ) ;
}
} catch ( error ) {
logger . error ( "Error in onLocationCheckboxChange:" , error ) ;
}
}
/ / I d e n t i t y S e c t i o n e v e n t h a n d l e r s
/ / I d e n t i t y S e c t i o n e v e n t h a n d l e r s
onEditName ( ) {
onEditName ( ) {