diff --git a/src/components/DataExportSection.vue b/src/components/DataExportSection.vue
index e9f37649..b34b3430 100644
--- a/src/components/DataExportSection.vue
+++ b/src/components/DataExportSection.vue
@@ -20,34 +20,33 @@ backup and database export, with platform-specific download instructions. * *
If no download happened yet, click again here to download now.
-
+
After the download, you can save the file in your preferred storage
location.
-
+
On iOS: You will be prompted to choose a location to save your backup
file.
On Android: You will be prompted to choose a location to save your
@@ -62,23 +61,19 @@ backup and database export, with platform-specific download instructions. * *
import { Component, Prop, Vue } from "vue-facing-decorator";
import { AppString, NotificationIface } from "../constants/app";
-import { Contact } from "../db/tables/contacts";
-import * as databaseUtil from "../db/databaseUtil";
-
import { logger } from "../utils/logger";
-import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
-import {
- PlatformService,
- PlatformCapabilities,
-} from "../services/PlatformService";
import { contactsToExportJson } from "../libs/util";
+import { createNotifyHelpers } from "@/utils/notify";
+import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
/**
* @vue-component
* Data Export Section Component
* Handles database export and seed backup functionality with platform-specific behavior
*/
-@Component
+@Component({
+ mixins: [PlatformServiceMixin],
+})
export default class DataExportSection extends Vue {
/**
* Notification function injected by Vue
@@ -101,16 +96,29 @@ export default class DataExportSection extends Vue {
downloadUrl = "";
/**
- * Platform service instance for platform-specific operations
+ * Notification helper for consistent notification patterns
*/
- private platformService: PlatformService =
- PlatformServiceFactory.getInstance();
+ notify = createNotifyHelpers(this.$notify);
/**
- * Platform capabilities for the current platform
+ * Computed property to check if we're on web platform
*/
- private get platformCapabilities(): PlatformCapabilities {
- return this.platformService.getCapabilities();
+ private get isWebPlatform(): boolean {
+ return this.capabilities.hasFileDownload;
+ }
+
+ /**
+ * Computed property to check if download is in progress
+ */
+ private get isDownloadInProgress(): boolean {
+ return Boolean(this.downloadUrl && this.isWebPlatform);
+ }
+
+ /**
+ * Computed property for the export file name
+ */
+ private get fileName(): string {
+ return `${AppString.APP_NAME_NO_SPACES}-backup-contacts.json`;
}
/**
@@ -118,7 +126,7 @@ export default class DataExportSection extends Vue {
* Revokes object URL when component is unmounted (web platform only)
*/
beforeUnmount() {
- if (this.downloadUrl && this.platformCapabilities.hasFileDownload) {
+ if (this.downloadUrl && this.isWebPlatform) {
URL.revokeObjectURL(this.downloadUrl);
}
}
@@ -129,84 +137,56 @@ export default class DataExportSection extends Vue {
* Shows success/error notifications to user
*
* @throws {Error} If export fails
- * @emits {Notification} Success or error notification
*/
- public async exportDatabase() {
+ public async exportDatabase(): Promise {
try {
- let allContacts: Contact[] = [];
- const platformService = PlatformServiceFactory.getInstance();
- const result = await platformService.dbQuery(`SELECT * FROM contacts`);
- if (result) {
- allContacts = databaseUtil.mapQueryResultToValues(
- result,
- ) as unknown as Contact[];
- }
+ // Fetch contacts from database using mixin's cached method
+ const allContacts = await this.$contacts();
// Convert contacts to export format
const exportData = contactsToExportJson(allContacts);
const jsonStr = JSON.stringify(exportData, null, 2);
const blob = new Blob([jsonStr], { type: "application/json" });
- const fileName = `${AppString.APP_NAME_NO_SPACES}-backup-contacts.json`;
-
- if (this.platformCapabilities.hasFileDownload) {
- // Web platform: Use download link
- this.downloadUrl = URL.createObjectURL(blob);
- const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
- downloadAnchor.href = this.downloadUrl;
- downloadAnchor.download = fileName;
- downloadAnchor.click();
- setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
- } else if (this.platformCapabilities.hasFileSystem) {
- // Native platform: Write to app directory
- await this.platformService.writeAndShareFile(fileName, jsonStr);
+ // Handle export based on platform capabilities
+ if (this.isWebPlatform) {
+ await this.handleWebExport(blob);
+ } else if (this.capabilities.hasFileSystem) {
+ await this.handleNativeExport(jsonStr);
} else {
throw new Error("This platform does not support file downloads.");
}
- this.$notify(
- {
- group: "alert",
- type: "success",
- title: "Export Successful",
- text: this.platformCapabilities.hasFileDownload
- ? "See your downloads directory for the backup."
- : "The backup file has been saved.",
- },
- 3000,
+ this.notify.success(
+ this.isWebPlatform
+ ? "See your downloads directory for the backup."
+ : "The backup file has been saved.",
);
} catch (error) {
logger.error("Export Error:", error);
- this.$notify(
- {
- group: "alert",
- type: "danger",
- title: "Export Error",
- text: "There was an error exporting the data.",
- },
- 3000,
+ this.notify.error(
+ `There was an error exporting the data: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
}
/**
- * Computes class names for the initial download button
- * @returns Object with 'hidden' class when download is in progress (web platform only)
+ * Handles export for web platform using download link
+ * @param blob The blob to download
*/
- public computedStartDownloadLinkClassNames() {
- return {
- hidden: this.downloadUrl && this.platformCapabilities.hasFileDownload,
- };
+ private async handleWebExport(blob: Blob): Promise {
+ this.downloadUrl = URL.createObjectURL(blob);
+ const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
+ downloadAnchor.click();
+ setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
}
/**
- * Computes class names for the secondary download link
- * @returns Object with 'hidden' class when no download is available or not on web platform
+ * Handles export for native platforms using file system
+ * @param jsonStr The JSON string to save
*/
- public computedDownloadLinkClassNames() {
- return {
- hidden: !this.downloadUrl || !this.platformCapabilities.hasFileDownload,
- };
+ private async handleNativeExport(jsonStr: string): Promise {
+ await this.platformService.writeAndShareFile(this.fileName, jsonStr);
}
}
diff --git a/src/components/LocationSearchSection.vue b/src/components/LocationSearchSection.vue
index 8bf41ce4..a91e52c4 100644
--- a/src/components/LocationSearchSection.vue
+++ b/src/components/LocationSearchSection.vue
@@ -1,7 +1,7 @@
Location for Searches
-
+
Current Area: {{ searchAreaLabel }}
@@ -15,14 +15,14 @@
\ No newline at end of file
+
diff --git a/src/components/RegistrationNotice.vue b/src/components/RegistrationNotice.vue
index fb977f14..c9faffea 100644
--- a/src/components/RegistrationNotice.vue
+++ b/src/components/RegistrationNotice.vue
@@ -7,7 +7,8 @@
aria-live="polite"
>
- Before you can publicly announce a new project or time commitment, a friend needs to register you.
+ Before you can publicly announce a new project or time commitment, a
+ friend needs to register you.