forked from jsnbuchanan/crowd-funder-for-time-pwa
- Add PlatformCapabilities interface to define available features - Remove isWeb(), isCapacitor(), isElectron(), isPyWebView() methods - Update platform services to implement getCapabilities() - Refactor DataExportSection to use capability checks instead of platform checks - Improve platform abstraction and separation of concerns - Make platform-specific logic more maintainable and extensible This change decouples components from specific platform implementations, making the codebase more maintainable and easier to extend with new platforms.
195 lines
6.2 KiB
Vue
195 lines
6.2 KiB
Vue
/**
|
|
* 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
|
|
* <DataExportSection :active-did="currentDid" />
|
|
* ```
|
|
*/
|
|
|
|
<template>
|
|
<div
|
|
id="sectionDataExport"
|
|
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
|
|
>
|
|
<div class="mb-2 font-bold">Data Export</div>
|
|
<router-link
|
|
v-if="activeDid"
|
|
:to="{ name: 'seed-backup' }"
|
|
class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
|
|
>
|
|
Backup Identifier Seed
|
|
</router-link>
|
|
|
|
<button
|
|
:class="computedStartDownloadLinkClassNames()"
|
|
class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md"
|
|
@click="exportDatabase()"
|
|
>
|
|
Download Settings & Contacts
|
|
<br />
|
|
(excluding Identifier Data)
|
|
</button>
|
|
<a
|
|
ref="downloadLink"
|
|
:class="computedDownloadLinkClassNames()"
|
|
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.
|
|
</a>
|
|
<div class="mt-4" v-if="platformCapabilities.needsFileHandlingInstructions">
|
|
<p>
|
|
After the download, you can save the file in your preferred storage
|
|
location.
|
|
</p>
|
|
<ul>
|
|
<li v-if="platformCapabilities.isIOS" class="list-disc list-outside ml-4">
|
|
On iOS: Choose "More..." and select a place in iCloud, or go "Back"
|
|
and save to another location.
|
|
</li>
|
|
<li v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS" class="list-disc list-outside ml-4">
|
|
On Android: Choose "Open" and then share
|
|
<font-awesome icon="share-nodes" class="fa-fw" />
|
|
to your prefered place.
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Prop, Vue } from "vue-facing-decorator";
|
|
import { NotificationIface } from "../constants/app";
|
|
import { db } from "../db/index";
|
|
import { logger } from "../utils/logger";
|
|
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
|
|
import { PlatformService, PlatformCapabilities } from "../services/PlatformService";
|
|
|
|
/**
|
|
* @vue-component
|
|
* Data Export Section Component
|
|
* Handles database export and seed backup functionality with platform-specific behavior
|
|
*/
|
|
@Component
|
|
export default class DataExportSection extends Vue {
|
|
/**
|
|
* Notification function injected by Vue
|
|
* Used to show success/error messages to the user
|
|
*/
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
|
|
|
/**
|
|
* Active DID (Decentralized Identifier) of the user
|
|
* Controls visibility of seed backup option
|
|
* @required
|
|
*/
|
|
@Prop({ required: true }) readonly activeDid!: string;
|
|
|
|
/**
|
|
* URL for the database export download
|
|
* Created and revoked dynamically during export process
|
|
* Only used in web platform
|
|
*/
|
|
downloadUrl = "";
|
|
|
|
/**
|
|
* Platform service instance for platform-specific operations
|
|
*/
|
|
private platformService: PlatformService = PlatformServiceFactory.getInstance();
|
|
|
|
/**
|
|
* Platform capabilities for the current platform
|
|
*/
|
|
private get platformCapabilities(): PlatformCapabilities {
|
|
return this.platformService.getCapabilities();
|
|
}
|
|
|
|
/**
|
|
* Lifecycle hook to clean up resources
|
|
* Revokes object URL when component is unmounted (web platform only)
|
|
*/
|
|
beforeUnmount() {
|
|
if (this.downloadUrl && this.platformCapabilities.hasFileDownload) {
|
|
URL.revokeObjectURL(this.downloadUrl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Exports the database to a JSON file
|
|
* Uses platform-specific methods for saving the exported data
|
|
* Shows success/error notifications to user
|
|
*
|
|
* @throws {Error} If export fails
|
|
* @emits {Notification} Success or error notification
|
|
*/
|
|
public async exportDatabase() {
|
|
try {
|
|
const blob = await db.export({ prettyJson: true });
|
|
const fileName = `${db.name}-backup.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
|
|
const content = await blob.text();
|
|
await this.platformService.writeFile(fileName, content);
|
|
}
|
|
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "success",
|
|
title: "Export Successful",
|
|
text: this.platformCapabilities.hasFileDownload
|
|
? "See your downloads directory for the backup. It is in the Dexie format."
|
|
: "The backup has been saved to your device.",
|
|
},
|
|
-1,
|
|
);
|
|
} 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,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes class names for the initial download button
|
|
* @returns Object with 'hidden' class when download is in progress (web platform only)
|
|
*/
|
|
public computedStartDownloadLinkClassNames() {
|
|
return {
|
|
hidden: this.downloadUrl && this.platformCapabilities.hasFileDownload,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Computes class names for the secondary download link
|
|
* @returns Object with 'hidden' class when no download is available or not on web platform
|
|
*/
|
|
public computedDownloadLinkClassNames() {
|
|
return {
|
|
hidden: !this.downloadUrl || !this.platformCapabilities.hasFileDownload,
|
|
};
|
|
}
|
|
}
|
|
</script>
|