Browse Source

fix: Resolve contact export errors in DataExportSection

- Fix ref timing issue by always rendering download link element
- Convert notify helper to getter to ensure $notify availability
- Add proper error handling and resource cleanup for blob URLs
- Improve user feedback with better error messages
- Add comprehensive documentation and security considerations

Resolves: TypeError on downloadLink.click() and notify function errors
pull/142/head
Matthew Raymer 14 hours ago
parent
commit
400748b9a1
  1. 46
      src/components/DataExportSection.vue

46
src/components/DataExportSection.vue

@ -1,9 +1,12 @@
/** * Data Export Section Component * * Provides UI and functionality for
exporting user data and backing up identifier seeds. * Includes buttons for seed
backup and database export, with platform-specific download instructions. * *
@component * @displayName DataExportSection * @example * ```vue *
Features: * - Platform-specific export handling (web vs. native) * - Proper
resource cleanup for blob URLs * - Robust error handling with user-friendly
messages * - Conditional UI based on platform capabilities * * @component *
@displayName DataExportSection * @example * ```vue *
<DataExportSection :active-did="currentDid" />
* ``` */
* ``` * * @author Matthew Raymer * @since 2025-01-25 * @version 1.1.0 */
<template>
<div
@ -26,11 +29,14 @@ backup and database export, with platform-specific download instructions. * *
>
Download Contacts
</button>
<!-- Hidden download link for web platform - always rendered for ref access -->
<a
v-if="isWebPlatform && downloadUrl"
v-if="isWebPlatform"
ref="downloadLink"
:href="downloadUrl"
:download="fileName"
:class="{ hidden: !downloadUrl }"
class="block w-full text-center text-md bg-gradient-to-b from-green-500 to-green-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6"
>
If no download happened yet, click again here to download now.
@ -97,8 +103,11 @@ export default class DataExportSection extends Vue {
/**
* Notification helper for consistent notification patterns
* Created as a getter to ensure $notify is available when called
*/
notify = createNotifyHelpers(this.$notify);
get notify() {
return createNotifyHelpers(this.$notify);
}
/**
* NOTE: PlatformServiceMixin provides both concise helpers (e.g. $contacts, capabilities)
@ -135,6 +144,7 @@ export default class DataExportSection extends Vue {
beforeUnmount() {
if (this.downloadUrl && this.isWebPlatform) {
URL.revokeObjectURL(this.downloadUrl);
this.downloadUrl = "";
}
}
@ -183,9 +193,31 @@ export default class DataExportSection extends Vue {
*/
private async handleWebExport(blob: Blob): Promise<void> {
this.downloadUrl = URL.createObjectURL(blob);
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
downloadAnchor.click();
setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
try {
// Wait for next tick to ensure DOM is updated
await this.$nextTick();
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
if (!downloadAnchor) {
throw new Error("Download link element not found. Please try again.");
}
downloadAnchor.click();
// Clean up the URL after a delay
setTimeout(() => {
URL.revokeObjectURL(this.downloadUrl);
this.downloadUrl = "";
}, 1000);
} catch (error) {
// Clean up the URL on error
if (this.downloadUrl) {
URL.revokeObjectURL(this.downloadUrl);
this.downloadUrl = "";
}
throw error;
}
}
/**

Loading…
Cancel
Save