forked from trent_larson/crowd-funder-for-time-pwa
Merge branch 'master' into nearby-filter
This commit is contained in:
@@ -174,14 +174,16 @@
|
||||
:aria-busy="loadingProfile || savingProfile"
|
||||
></textarea>
|
||||
|
||||
<div class="flex items-center mb-4" @click="toggleUserProfileLocation">
|
||||
<input
|
||||
v-model="includeUserProfileLocation"
|
||||
type="checkbox"
|
||||
class="mr-2"
|
||||
/>
|
||||
<label for="includeUserProfileLocation">Include Location</label>
|
||||
</div>
|
||||
<div class="flex items-center mb-4">
|
||||
<input
|
||||
v-model="includeUserProfileLocation"
|
||||
type="checkbox"
|
||||
class="mr-2"
|
||||
@change="onLocationCheckboxChange"
|
||||
/>
|
||||
<label for="includeUserProfileLocation">Include Location</label>
|
||||
<span class="text-xs text-slate-400 ml-2">(Debug: {{ isMapReady ? 'Map Ready' : 'Map Loading' }})</span>
|
||||
</div>
|
||||
<div v-if="includeUserProfileLocation" class="mb-4 aspect-video">
|
||||
<p class="text-sm mb-2 text-slate-500">
|
||||
The location you choose will be shared with the world until you remove
|
||||
@@ -194,6 +196,7 @@
|
||||
class="!z-40 rounded-md"
|
||||
@click="onProfileMapClick"
|
||||
@ready="onMapReady"
|
||||
@mounted="onMapMounted"
|
||||
>
|
||||
<l-tile-layer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
@@ -751,6 +754,7 @@ import "dexie-export-import";
|
||||
// @ts-expect-error - they aren't exporting it but it's there
|
||||
import { ImportProgress } from "dexie-export-import";
|
||||
import { LeafletMouseEvent } from "leaflet";
|
||||
import * as L from "leaflet";
|
||||
import * as R from "ramda";
|
||||
import { IIdentifier } from "@veramo/core";
|
||||
import { ref } from "vue";
|
||||
@@ -902,6 +906,7 @@ export default class AccountViewView extends Vue {
|
||||
warnIfProdServer: boolean = false;
|
||||
warnIfTestServer: boolean = false;
|
||||
zoom: number = 2;
|
||||
isMapReady: boolean = false;
|
||||
|
||||
// Limits and validation properties
|
||||
endorserLimits: EndorserRateLimits | null = null;
|
||||
@@ -913,6 +918,17 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
created() {
|
||||
this.notify = createNotifyHelpers(this.$notify);
|
||||
|
||||
// Fix Leaflet icon issues in modern bundlers
|
||||
// This prevents the "Cannot read properties of undefined (reading 'Default')" error
|
||||
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.userProfileLongitude = profile.longitude;
|
||||
this.includeUserProfileLocation = profile.includeLocation;
|
||||
|
||||
// Initialize map ready state if location is included
|
||||
if (profile.includeLocation) {
|
||||
this.isMapReady = false; // Will be set to true when map is ready
|
||||
}
|
||||
} else {
|
||||
// Profile not created yet; leave defaults
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error loading profile:", error);
|
||||
this.notify.error(
|
||||
ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_AVAILABLE,
|
||||
);
|
||||
@@ -1518,9 +1540,45 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
onMapReady(map: L.Map): void {
|
||||
// doing this here instead of on the l-map element avoids a recentering after a drag then zoom at startup
|
||||
const zoom = this.userProfileLatitude && this.userProfileLongitude ? 12 : 2;
|
||||
map.setView([this.userProfileLatitude, this.userProfileLongitude], zoom);
|
||||
try {
|
||||
logger.debug("Map ready event fired, map object:", map);
|
||||
// doing this here instead of on the l-map element avoids a recentering after a drag then zoom at startup
|
||||
const zoom = this.userProfileLatitude && this.userProfileLongitude ? 12 : 2;
|
||||
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; // Set to true even on error to prevent infinite loading
|
||||
}
|
||||
}
|
||||
|
||||
onMapMounted(): void {
|
||||
logger.debug("Map component mounted");
|
||||
// Check if map ref is available
|
||||
const mapRef = this.$refs.profileMap;
|
||||
logger.debug("Map ref:", mapRef);
|
||||
|
||||
// Try to set map ready after component is mounted
|
||||
setTimeout(() => {
|
||||
this.isMapReady = true;
|
||||
logger.debug("Map ready set to true after mounted");
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Fallback method to handle map initialization failures
|
||||
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 second timeout
|
||||
}
|
||||
|
||||
showProfileInfo(): void {
|
||||
@@ -1532,13 +1590,16 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async saveProfile(): Promise<void> {
|
||||
this.savingProfile = true;
|
||||
const profileData: ProfileData = {
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
};
|
||||
try {
|
||||
const profileData: ProfileData = {
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
};
|
||||
|
||||
logger.debug("Saving profile data:", profileData);
|
||||
|
||||
const success = await this.profileService.saveProfile(
|
||||
this.activeDid,
|
||||
profileData,
|
||||
@@ -1549,6 +1610,7 @@ export default class AccountViewView extends Vue {
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_SAVE_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error saving profile:", error);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_SAVE_ERROR);
|
||||
} finally {
|
||||
this.savingProfile = false;
|
||||
@@ -1556,15 +1618,25 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
toggleUserProfileLocation(): void {
|
||||
const updated = this.profileService.toggleProfileLocation({
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
});
|
||||
this.userProfileLatitude = updated.latitude;
|
||||
this.userProfileLongitude = updated.longitude;
|
||||
this.includeUserProfileLocation = updated.includeLocation;
|
||||
try {
|
||||
const updated = this.profileService.toggleProfileLocation({
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
});
|
||||
this.userProfileLatitude = updated.latitude;
|
||||
this.userProfileLongitude = updated.longitude;
|
||||
this.includeUserProfileLocation = updated.includeLocation;
|
||||
|
||||
// Reset map ready state when toggling location
|
||||
if (!updated.includeLocation) {
|
||||
this.isMapReady = false;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error in toggleUserProfileLocation:", error);
|
||||
this.notify.error("Failed to toggle location setting");
|
||||
}
|
||||
}
|
||||
|
||||
confirmEraseLatLong(): void {
|
||||
@@ -1592,6 +1664,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async deleteProfile(): Promise<void> {
|
||||
try {
|
||||
logger.debug("Attempting to delete profile for DID:", this.activeDid);
|
||||
const success = await this.profileService.deleteProfile(this.activeDid);
|
||||
if (success) {
|
||||
this.notify.success(ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_DELETED);
|
||||
@@ -1599,11 +1672,20 @@ export default class AccountViewView extends Vue {
|
||||
this.userProfileLatitude = 0;
|
||||
this.userProfileLongitude = 0;
|
||||
this.includeUserProfileLocation = false;
|
||||
this.isMapReady = false; // Reset map state
|
||||
logger.debug("Profile deleted successfully, UI state reset");
|
||||
} else {
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
logger.error("Error in deleteProfile component method:", error);
|
||||
|
||||
// Show more specific error message if available
|
||||
if (error instanceof Error) {
|
||||
this.notify.error(error.message);
|
||||
} else {
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1616,8 +1698,43 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
onProfileMapClick(event: LeafletMouseEvent) {
|
||||
this.userProfileLatitude = event.latlng.lat;
|
||||
this.userProfileLongitude = event.latlng.lng;
|
||||
try {
|
||||
if (event && event.latlng) {
|
||||
this.userProfileLatitude = event.latlng.lat;
|
||||
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) {
|
||||
// Location checkbox was unchecked, clean up map state
|
||||
this.isMapReady = false;
|
||||
this.userProfileLatitude = 0;
|
||||
this.userProfileLongitude = 0;
|
||||
logger.debug("Location unchecked, map state reset");
|
||||
} else {
|
||||
// Location checkbox was checked, start map initialization timeout
|
||||
this.isMapReady = false;
|
||||
logger.debug("Location checked, starting map initialization timeout");
|
||||
|
||||
// Try to set map ready after a short delay to allow Vue to render
|
||||
setTimeout(() => {
|
||||
if (!this.isMapReady) {
|
||||
logger.debug("Setting map ready after timeout");
|
||||
this.isMapReady = true;
|
||||
}
|
||||
}, 1000); // 1 second delay
|
||||
|
||||
this.handleMapInitFailure();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error in onLocationCheckboxChange:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// IdentitySection event handlers
|
||||
|
||||
@@ -714,8 +714,16 @@ export default class ContactQRScanShow extends Vue {
|
||||
|
||||
// Add new contact
|
||||
// @ts-expect-error because we're just using the value to store to the DB
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
contact.contactMethods = JSON.stringify(
|
||||
(this as any)._parseJsonField(contact.contactMethods, []),
|
||||
(
|
||||
this as {
|
||||
_parseJsonField: (
|
||||
value: unknown,
|
||||
defaultValue: unknown[],
|
||||
) => unknown[];
|
||||
}
|
||||
)._parseJsonField(contact.contactMethods, []),
|
||||
);
|
||||
await this.$insertContact(contact);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ import * as R from "ramda";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
// Capacitor import removed - using PlatformService instead
|
||||
|
||||
import QuickNav from "../components/QuickNav.vue";
|
||||
import EntityIcon from "../components/EntityIcon.vue";
|
||||
@@ -165,13 +165,18 @@ import { GiveSummaryRecord } from "@/interfaces/records";
|
||||
import { UserInfo } from "@/interfaces/common";
|
||||
import { VerifiableCredential } from "@/interfaces/claims-result";
|
||||
import * as libsUtil from "../libs/util";
|
||||
import { generateSaveAndActivateIdentity } from "../libs/util";
|
||||
import {
|
||||
generateSaveAndActivateIdentity,
|
||||
contactsToExportJson,
|
||||
} from "../libs/util";
|
||||
import { logger } from "../utils/logger";
|
||||
// No longer needed - using PlatformServiceMixin methods
|
||||
// import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { isDatabaseError } from "@/interfaces/common";
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import { APP_SERVER } from "@/constants/app";
|
||||
import { QRNavigationService } from "@/services/QRNavigationService";
|
||||
import {
|
||||
NOTIFY_CONTACT_NO_INFO,
|
||||
NOTIFY_CONTACTS_ADD_ERROR,
|
||||
@@ -197,6 +202,7 @@ import {
|
||||
NOTIFY_REGISTRATION_ERROR_FALLBACK,
|
||||
NOTIFY_REGISTRATION_ERROR_GENERIC,
|
||||
NOTIFY_VISIBILITY_ERROR_FALLBACK,
|
||||
NOTIFY_EXPORT_DATA_PROMPT,
|
||||
getRegisterPersonSuccessMessage,
|
||||
getVisibilitySuccessMessage,
|
||||
getGivesRetrievalErrorMessage,
|
||||
@@ -376,7 +382,11 @@ export default class ContactsView extends Vue {
|
||||
"",
|
||||
async (name) => {
|
||||
await this.addContact({
|
||||
did: (registration.vc.credentialSubject.agent as any).identifier,
|
||||
did: (
|
||||
registration.vc.credentialSubject.agent as {
|
||||
identifier: string;
|
||||
}
|
||||
).identifier,
|
||||
name: name,
|
||||
registered: true,
|
||||
});
|
||||
@@ -387,7 +397,11 @@ export default class ContactsView extends Vue {
|
||||
async () => {
|
||||
// on cancel, will still add the contact
|
||||
await this.addContact({
|
||||
did: (registration.vc.credentialSubject.agent as any).identifier,
|
||||
did: (
|
||||
registration.vc.credentialSubject.agent as {
|
||||
identifier: string;
|
||||
}
|
||||
).identifier,
|
||||
name: "(person who invited you)",
|
||||
registered: true,
|
||||
});
|
||||
@@ -396,8 +410,7 @@ export default class ContactsView extends Vue {
|
||||
this.showOnboardingInfo();
|
||||
},
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
const fullError = "Error redeeming invite: " + errorStringForLog(error);
|
||||
this.$logAndConsole(fullError, true);
|
||||
let message = "Got an error sending the invite.";
|
||||
@@ -784,6 +797,9 @@ export default class ContactsView extends Vue {
|
||||
|
||||
// Show success notification
|
||||
this.notify.success(addedMessage);
|
||||
|
||||
// Show export data prompt after successful contact addition
|
||||
await this.showExportDataPrompt();
|
||||
} catch (err) {
|
||||
this.handleContactAddError(err);
|
||||
}
|
||||
@@ -881,20 +897,21 @@ export default class ContactsView extends Vue {
|
||||
/**
|
||||
* Handle errors during contact addition
|
||||
*/
|
||||
private handleContactAddError(err: any): void {
|
||||
private handleContactAddError(err: unknown): void {
|
||||
const fullError =
|
||||
"Error when adding contact to storage: " + errorStringForLog(err);
|
||||
this.$logAndConsole(fullError, true);
|
||||
|
||||
let message = NOTIFY_CONTACT_IMPORT_ERROR.message;
|
||||
if (
|
||||
(err as any).message?.indexOf("Key already exists in the object store.") >
|
||||
-1
|
||||
) {
|
||||
message = NOTIFY_CONTACT_IMPORT_CONFLICT.message;
|
||||
}
|
||||
if ((err as any).name === "ConstraintError") {
|
||||
message += " " + NOTIFY_CONTACT_IMPORT_CONSTRAINT.message;
|
||||
|
||||
// Use type-safe error checking with our new type guards
|
||||
if (isDatabaseError(err)) {
|
||||
if (err.message.includes("Key already exists in the object store")) {
|
||||
message = NOTIFY_CONTACT_IMPORT_CONFLICT.message;
|
||||
}
|
||||
if (err.name === "ConstraintError") {
|
||||
message += " " + NOTIFY_CONTACT_IMPORT_CONSTRAINT.message;
|
||||
}
|
||||
}
|
||||
|
||||
this.notify.error(message, TIMEOUTS.LONG);
|
||||
@@ -1246,19 +1263,76 @@ export default class ContactsView extends Vue {
|
||||
|
||||
/**
|
||||
* Handle QR code button click - route to appropriate scanner
|
||||
* Uses native scanner on mobile platforms, web scanner otherwise
|
||||
* Uses QRNavigationService to determine scanner type and route
|
||||
*/
|
||||
|
||||
public handleQRCodeClick() {
|
||||
this.$logAndConsole(
|
||||
"[ContactsView] handleQRCodeClick method called",
|
||||
false,
|
||||
);
|
||||
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
this.$router.push({ name: "contact-qr-scan-full" });
|
||||
} else {
|
||||
this.$router.push({ name: "contact-qr" });
|
||||
const qrNavigationService = QRNavigationService.getInstance();
|
||||
const route = qrNavigationService.getQRScannerRoute();
|
||||
|
||||
this.$router.push(route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show export data prompt after adding a contact
|
||||
* Prompts user to export their contact data as a backup
|
||||
*/
|
||||
private async showExportDataPrompt(): Promise<void> {
|
||||
setTimeout(() => {
|
||||
this.$notify(
|
||||
{
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: NOTIFY_EXPORT_DATA_PROMPT.title,
|
||||
text: NOTIFY_EXPORT_DATA_PROMPT.message,
|
||||
onYes: async () => {
|
||||
await this.exportContactData();
|
||||
},
|
||||
yesText: "Export Data",
|
||||
onNo: async () => {
|
||||
// User chose not to export - no action needed
|
||||
},
|
||||
noText: "Not Now",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}, 1000); // Small delay to ensure success notification is shown first
|
||||
}
|
||||
|
||||
/**
|
||||
* Export contact data to JSON file
|
||||
* Uses platform service to handle platform-specific export logic
|
||||
*/
|
||||
private async exportContactData(): Promise<void> {
|
||||
// Note that similar code is in DataExportSection.vue exportDatabase()
|
||||
try {
|
||||
// Fetch all contacts from database
|
||||
const allContacts = await this.$contacts();
|
||||
|
||||
// Convert contacts to export format
|
||||
const exportData = contactsToExportJson(allContacts);
|
||||
const jsonStr = JSON.stringify(exportData, null, 2);
|
||||
|
||||
// Generate filename with current date
|
||||
const today = new Date();
|
||||
const dateString = today.toISOString().split("T")[0]; // YYYY-MM-DD format
|
||||
const fileName = `timesafari-backup-contacts-${dateString}.json`;
|
||||
|
||||
// Use platform service to handle export
|
||||
await this.platformService.writeAndShareFile(fileName, jsonStr);
|
||||
|
||||
this.notify.success(
|
||||
"Contact export completed successfully. Check your downloads or share dialog.",
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error("Export Error:", error);
|
||||
this.notify.error(
|
||||
`There was an error exporting the data: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,6 +490,8 @@ export default class DIDView extends Vue {
|
||||
message +=
|
||||
" Note that they can see your activity, so if you want to hide your activity from them then you should do that first.";
|
||||
}
|
||||
message +=
|
||||
" Note that this will also remove anyone with the same DID underneath.";
|
||||
this.notify.confirm(message, async () => {
|
||||
await this.deleteContact(contact);
|
||||
});
|
||||
|
||||
@@ -91,17 +91,12 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="downloadAccount"
|
||||
>
|
||||
<IconRenderer
|
||||
<font-awesome
|
||||
v-if="isLoading"
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<IconRenderer
|
||||
v-else
|
||||
icon-name="chart"
|
||||
svg-class="-ml-1 mr-3 h-5 w-5"
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
<font-awesome v-else icon="chart-line" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Show Account Seed
|
||||
</button>
|
||||
|
||||
@@ -110,17 +105,12 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="downloadSettingsContacts"
|
||||
>
|
||||
<IconRenderer
|
||||
<font-awesome
|
||||
v-if="isLoading"
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<IconRenderer
|
||||
v-else
|
||||
icon-name="chart"
|
||||
svg-class="-ml-1 mr-3 h-5 w-5"
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
<font-awesome v-else icon="chart-line" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Download Settings & Contacts
|
||||
</button>
|
||||
|
||||
@@ -143,17 +133,12 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="compareDatabases"
|
||||
>
|
||||
<IconRenderer
|
||||
<font-awesome
|
||||
v-if="isLoading"
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<IconRenderer
|
||||
v-else
|
||||
icon-name="chart"
|
||||
svg-class="-ml-1 mr-3 h-5 w-5"
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
<font-awesome v-else icon="chart-line" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Compare Databases
|
||||
</button>
|
||||
|
||||
@@ -162,17 +147,12 @@
|
||||
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="migrateAll"
|
||||
>
|
||||
<IconRenderer
|
||||
<font-awesome
|
||||
v-if="isLoading"
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<IconRenderer
|
||||
v-else
|
||||
icon-name="check"
|
||||
svg-class="-ml-1 mr-3 h-5 w-5"
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
<font-awesome v-else icon="check" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Migrate All
|
||||
</button>
|
||||
|
||||
@@ -185,10 +165,9 @@
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="warning"
|
||||
svg-class="h-5 w-5 text-red-400"
|
||||
fill="currentColor"
|
||||
<font-awesome
|
||||
icon="triangle-exclamation"
|
||||
class="h-5 w-5 text-red-400"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
@@ -207,10 +186,9 @@
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="warning"
|
||||
svg-class="h-5 w-5 text-red-400"
|
||||
fill="currentColor"
|
||||
<font-awesome
|
||||
icon="triangle-exclamation"
|
||||
class="h-5 w-5 text-red-400"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
@@ -229,10 +207,7 @@
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-green-400"
|
||||
/>
|
||||
<font-awesome icon="check" class="h-5 w-5 text-green-400" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-green-800">Success</h3>
|
||||
@@ -249,7 +224,7 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="exportComparison"
|
||||
>
|
||||
<IconRenderer icon-name="download" svg-class="-ml-1 mr-3 h-5 w-5" />
|
||||
<font-awesome icon="download" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Export Comparison
|
||||
</button>
|
||||
|
||||
@@ -258,17 +233,12 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="displayDatabases"
|
||||
>
|
||||
<IconRenderer
|
||||
<font-awesome
|
||||
v-if="isLoading"
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<IconRenderer
|
||||
v-else
|
||||
icon-name="chart"
|
||||
svg-class="-ml-1 mr-3 h-5 w-5"
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
<font-awesome v-else icon="chart-line" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Show Previous Data
|
||||
</button>
|
||||
|
||||
@@ -277,7 +247,7 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-orange-600 hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-orange-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="migrateAccounts"
|
||||
>
|
||||
<IconRenderer icon-name="lock" svg-class="-ml-1 mr-3 h-5 w-5" />
|
||||
<font-awesome icon="lock" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Migrate Accounts
|
||||
</button>
|
||||
|
||||
@@ -286,7 +256,7 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="migrateSettings"
|
||||
>
|
||||
<IconRenderer icon-name="settings" svg-class="-ml-1 mr-3 h-5 w-5" />
|
||||
<font-awesome icon="gear" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Migrate Settings
|
||||
</button>
|
||||
|
||||
@@ -295,7 +265,7 @@
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
@click="migrateContacts"
|
||||
>
|
||||
<IconRenderer icon-name="plus" svg-class="-ml-1 mr-3 h-5 w-5" />
|
||||
<font-awesome icon="plus" class="-ml-1 mr-3 h-5 w-5" />
|
||||
Migrate Contacts
|
||||
</button>
|
||||
</div>
|
||||
@@ -316,11 +286,7 @@
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="info"
|
||||
svg-class="h-5 w-5 text-blue-400"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<font-awesome icon="info" class="h-5 w-5 text-blue-400" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800">
|
||||
@@ -357,10 +323,9 @@
|
||||
<div
|
||||
class="inline-flex items-center px-4 py-2 font-semibold leading-6 text-sm shadow rounded-md text-white bg-blue-500 hover:bg-blue-400 transition ease-in-out duration-150 cursor-not-allowed"
|
||||
>
|
||||
<IconRenderer
|
||||
icon-name="spinner"
|
||||
svg-class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
fill="currentColor"
|
||||
<font-awesome
|
||||
icon="spinner"
|
||||
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||
/>
|
||||
{{ loadingMessage }}
|
||||
</div>
|
||||
@@ -375,10 +340,7 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="lock"
|
||||
svg-class="h-6 w-6 text-orange-600"
|
||||
/>
|
||||
<font-awesome icon="lock" class="h-6 w-6 text-orange-600" />
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
<dl>
|
||||
@@ -398,10 +360,7 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-6 w-6 text-teal-600"
|
||||
/>
|
||||
<font-awesome icon="check" class="h-6 w-6 text-teal-600" />
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
<dl>
|
||||
@@ -422,10 +381,7 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="settings"
|
||||
svg-class="h-6 w-6 text-purple-600"
|
||||
/>
|
||||
<font-awesome icon="gear" class="h-6 w-6 text-purple-600" />
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
<dl>
|
||||
@@ -445,10 +401,7 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-6 w-6 text-indigo-600"
|
||||
/>
|
||||
<font-awesome icon="check" class="h-6 w-6 text-indigo-600" />
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
<dl>
|
||||
@@ -469,9 +422,9 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="chart"
|
||||
svg-class="h-6 w-6 text-blue-600"
|
||||
<font-awesome
|
||||
icon="chart-line"
|
||||
class="h-6 w-6 text-blue-600"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
@@ -492,10 +445,7 @@
|
||||
<div class="p-5">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-6 w-6 text-green-600"
|
||||
/>
|
||||
<font-awesome icon="check" class="h-6 w-6 text-green-600" />
|
||||
</div>
|
||||
<div class="ml-5 w-0 flex-1">
|
||||
<dl>
|
||||
@@ -526,9 +476,9 @@
|
||||
class="flex items-center justify-between p-3 bg-blue-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="plusCircle"
|
||||
svg-class="h-5 w-5 text-blue-600 mr-2"
|
||||
<font-awesome
|
||||
icon="circle-plus"
|
||||
class="h-5 w-5 text-blue-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-blue-900">Add</span>
|
||||
</div>
|
||||
@@ -541,9 +491,9 @@
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
<font-awesome
|
||||
icon="check"
|
||||
class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Unmodified</span
|
||||
@@ -558,9 +508,9 @@
|
||||
class="flex items-center justify-between p-3 bg-red-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="trash"
|
||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||
<font-awesome
|
||||
icon="trash-can"
|
||||
class="h-5 w-5 text-red-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||
</div>
|
||||
@@ -677,9 +627,9 @@
|
||||
class="flex items-center justify-between p-3 bg-blue-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="plusCircle"
|
||||
svg-class="h-5 w-5 text-blue-600 mr-2"
|
||||
<font-awesome
|
||||
icon="circle-plus"
|
||||
class="h-5 w-5 text-blue-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-blue-900">Add</span>
|
||||
</div>
|
||||
@@ -692,9 +642,9 @@
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="edit"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
<font-awesome
|
||||
icon="pen"
|
||||
class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Modify</span
|
||||
@@ -709,9 +659,9 @@
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
<font-awesome
|
||||
icon="check"
|
||||
class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Unmodified</span
|
||||
@@ -726,9 +676,9 @@
|
||||
class="flex items-center justify-between p-3 bg-red-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="trash"
|
||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||
<font-awesome
|
||||
icon="trash-can"
|
||||
class="h-5 w-5 text-red-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||
</div>
|
||||
@@ -868,9 +818,9 @@
|
||||
class="flex items-center justify-between p-3 bg-blue-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="plusCircle"
|
||||
svg-class="h-5 w-5 text-blue-600 mr-2"
|
||||
<font-awesome
|
||||
icon="circle-plus"
|
||||
class="h-5 w-5 text-blue-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-blue-900">Add</span>
|
||||
</div>
|
||||
@@ -883,9 +833,9 @@
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="edit"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
<font-awesome
|
||||
icon="pen"
|
||||
class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Modify</span
|
||||
@@ -900,9 +850,9 @@
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
<font-awesome
|
||||
icon="check"
|
||||
class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Unmodified</span
|
||||
@@ -917,9 +867,9 @@
|
||||
class="flex items-center justify-between p-3 bg-red-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="trash"
|
||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||
<font-awesome
|
||||
icon="trash-can"
|
||||
class="h-5 w-5 text-red-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||
</div>
|
||||
@@ -1067,7 +1017,6 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import IconRenderer from "../components/IconRenderer.vue";
|
||||
import {
|
||||
compareDatabases,
|
||||
migrateSettings,
|
||||
@@ -1104,9 +1053,6 @@ import { logger } from "../utils/logger";
|
||||
*/
|
||||
@Component({
|
||||
name: "DatabaseMigration",
|
||||
components: {
|
||||
IconRenderer,
|
||||
},
|
||||
})
|
||||
export default class DatabaseMigration extends Vue {
|
||||
$router!: Router;
|
||||
|
||||
@@ -458,7 +458,9 @@ export default class DiscoverView extends Vue {
|
||||
if (this.isLocalActive) {
|
||||
await this.searchLocal();
|
||||
} else if (this.isMappedActive) {
|
||||
const mapRef = this.$refs.projectMap as any;
|
||||
const mapRef = this.$refs.projectMap as {
|
||||
leafletObject: L.Map;
|
||||
};
|
||||
this.requestTiles(mapRef.leafletObject); // not ideal because I found this from experimentation, not documentation
|
||||
} else {
|
||||
await this.searchAll();
|
||||
@@ -518,11 +520,11 @@ export default class DiscoverView extends Vue {
|
||||
throw JSON.stringify(results);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
} catch (e: unknown) {
|
||||
logger.error("Error with search all: " + errorStringForLog(e));
|
||||
this.notify.error(
|
||||
e.userMessage || NOTIFY_DISCOVER_SEARCH_ERROR.message,
|
||||
(e as { userMessage?: string })?.userMessage ||
|
||||
NOTIFY_DISCOVER_SEARCH_ERROR.message,
|
||||
TIMEOUTS.LONG,
|
||||
);
|
||||
} finally {
|
||||
|
||||
@@ -565,22 +565,22 @@
|
||||
<h2 class="text-xl font-semibold">What app version is this?</h2>
|
||||
<p>{{ package.version }} ({{ commitHash }})</p>
|
||||
|
||||
<div v-if="Capacitor.isNativePlatform()">
|
||||
<div v-if="isCapacitor">
|
||||
<h2 class="text-xl font-semibold">
|
||||
Do I have the latest version?
|
||||
</h2>
|
||||
<p v-if="Capacitor.getPlatform() === 'ios'">
|
||||
<p v-if="capabilities.isIOS">
|
||||
<a href="https://apps.apple.com/us/app/time-safari/id6742664907" target="_blank" class="text-blue-500">
|
||||
Check the App Store.
|
||||
</a>
|
||||
</p>
|
||||
<p v-else-if="Capacitor.getPlatform() === 'android'">
|
||||
<p v-else-if="!capabilities.isIOS && capabilities.isMobile">
|
||||
<a href="https://play.google.com/store/apps/details?id=app.timesafari.app" target="_blank" class="text-blue-500">
|
||||
Check the Play Store.
|
||||
</a>
|
||||
</p>
|
||||
<p v-else>
|
||||
Sorry, your platform of '{{ Capacitor.getPlatform() }}' is not recognized.
|
||||
Sorry, your platform is not recognized.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -592,12 +592,13 @@
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
// Capacitor import removed - using QRNavigationService instead
|
||||
|
||||
import * as Package from "../../package.json";
|
||||
import QuickNav from "../components/QuickNav.vue";
|
||||
import { APP_SERVER } from "../constants/app";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { QRNavigationService } from "@/services/QRNavigationService";
|
||||
|
||||
/**
|
||||
* HelpView.vue - Comprehensive Help System Component
|
||||
@@ -643,7 +644,7 @@ export default class HelpView extends Vue {
|
||||
showVerifiable = false;
|
||||
|
||||
APP_SERVER = APP_SERVER;
|
||||
Capacitor = Capacitor;
|
||||
// Capacitor reference removed - using QRNavigationService instead
|
||||
|
||||
// Ideally, we put no functionality in here, especially in the setup,
|
||||
// because we never want this page to have a chance of throwing an error.
|
||||
@@ -711,11 +712,10 @@ export default class HelpView extends Vue {
|
||||
* @private
|
||||
*/
|
||||
private handleQRCodeClick(): void {
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
this.$router.push({ name: "contact-qr-scan-full" });
|
||||
} else {
|
||||
this.$router.push({ name: "contact-qr" });
|
||||
}
|
||||
const qrNavigationService = QRNavigationService.getInstance();
|
||||
const route = qrNavigationService.getQRScannerRoute();
|
||||
|
||||
this.$router.push(route);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,7 +234,9 @@ export default class IdentitySwitcherView extends Vue {
|
||||
{
|
||||
did,
|
||||
settingsKeys: Object.keys(newSettings).filter(
|
||||
(k) => (newSettings as any)[k] !== undefined,
|
||||
(k) =>
|
||||
k in newSettings &&
|
||||
newSettings[k as keyof typeof newSettings] !== undefined,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -221,10 +221,11 @@ export default class ImportAccountView extends Vue {
|
||||
|
||||
this.notify.success("Account imported successfully!", TIMEOUTS.STANDARD);
|
||||
this.$router.push({ name: "account" });
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
this.$logError("Import failed: " + error);
|
||||
this.notify.error(
|
||||
error.message || "Failed to import account.",
|
||||
(error instanceof Error ? error.message : String(error)) ||
|
||||
"Failed to import account.",
|
||||
TIMEOUTS.LONG,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ export default class OnboardMeetingListView extends Vue {
|
||||
if (response2.data?.data) {
|
||||
this.meetings = response2.data.data;
|
||||
}
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
this.$logAndConsole(
|
||||
"Error fetching meetings: " + errorStringForLog(error),
|
||||
true,
|
||||
|
||||
@@ -345,7 +345,9 @@ export default class OnboardMeetingView extends Vue {
|
||||
}
|
||||
|
||||
async created() {
|
||||
this.notify = createNotifyHelpers(this.$notify as any);
|
||||
this.notify = createNotifyHelpers(
|
||||
this.$notify as Parameters<typeof createNotifyHelpers>[0],
|
||||
);
|
||||
const settings = await this.$accountSettings();
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
@@ -419,7 +421,7 @@ export default class OnboardMeetingView extends Vue {
|
||||
} else {
|
||||
this.newOrUpdatedMeetingInputs = this.blankMeeting();
|
||||
}
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
this.newOrUpdatedMeetingInputs = this.blankMeeting();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
// Capacitor import removed - using QRNavigationService instead
|
||||
|
||||
import { NotificationIface } from "../constants/app";
|
||||
import EntityIcon from "../components/EntityIcon.vue";
|
||||
@@ -281,6 +281,7 @@ import { OnboardPage, iconForUnitCode } from "../libs/util";
|
||||
import { logger } from "../utils/logger";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import { QRNavigationService } from "@/services/QRNavigationService";
|
||||
import {
|
||||
NOTIFY_NO_ACCOUNT_ERROR,
|
||||
NOTIFY_PROJECT_LOAD_ERROR,
|
||||
@@ -464,8 +465,10 @@ export default class ProjectsView extends Vue {
|
||||
);
|
||||
this.notify.error(NOTIFY_PROJECT_LOAD_ERROR.message, TIMEOUTS.LONG);
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error("Got error loading plans:", error.message || error);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
logger.error("Got error loading plans:", errorMessage);
|
||||
this.notify.error(NOTIFY_PROJECT_LOAD_ERROR.message, TIMEOUTS.LONG);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
@@ -578,8 +581,10 @@ export default class ProjectsView extends Vue {
|
||||
);
|
||||
this.notify.error(NOTIFY_OFFERS_LOAD_ERROR.message, TIMEOUTS.LONG);
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error("Got error loading offers:", error.message || error);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
logger.error("Got error loading offers:", errorMessage);
|
||||
this.notify.error(NOTIFY_OFFERS_FETCH_ERROR.message, TIMEOUTS.LONG);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
@@ -757,11 +762,10 @@ export default class ProjectsView extends Vue {
|
||||
* - Web-based QR interface for browser environments
|
||||
*/
|
||||
private handleQRCodeClick() {
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
this.$router.push({ name: "contact-qr-scan-full" });
|
||||
} else {
|
||||
this.$router.push({ name: "contact-qr" });
|
||||
}
|
||||
const qrNavigationService = QRNavigationService.getInstance();
|
||||
const route = qrNavigationService.getQRScannerRoute();
|
||||
|
||||
this.$router.push(route);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user