forked from trent_larson/crowd-funder-for-time-pwa
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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user