Browse Source

feat: migrate all clipboard operations from useClipboard to ClipboardService

- Replace useClipboard with platform-agnostic ClipboardService across 13 files
- Add proper error handling with user notifications for all clipboard operations
- Fix naming conflicts between method names and imported function names
- Ensure consistent async/await patterns throughout the codebase
- Add notification system to HelpView.vue for user feedback on clipboard errors
- Remove unnecessary wrapper methods for cleaner code

Files migrated:
- View components: UserProfileView, QuickActionBvcEndView, ProjectViewView,
  InviteOneView, SeedBackupView, HelpView, AccountViewView, DatabaseMigration,
  ConfirmGiftView, ClaimView, OnboardMeetingSetupView
- Utility functions: libs/util.ts (doCopyTwoSecRedo)
- Components: HiddenDidDialog

Naming conflicts resolved:
- DatabaseMigration: copyToClipboard() → copyExportedDataToClipboard()
- ShareMyContactInfoView: copyToClipboard() → copyContactMessageToClipboard() → removed
- HiddenDidDialog: copyToClipboard() → copyTextToClipboard()
- ClaimView: copyToClipboard() → copyTextToClipboard()
- ConfirmGiftView: copyToClipboard() → copyTextToClipboard()

This migration ensures reliable clipboard functionality across iOS, Android,
and web platforms with proper error handling and user feedback.

Closes: Platform-specific clipboard issues on mobile devices
pull/199/head
Jose Olarte III 4 days ago
parent
commit
4c218c4786
  1. 29
      src/components/HiddenDidDialog.vue
  2. 18
      src/libs/util.ts
  3. 14
      src/views/AccountViewView.vue
  4. 31
      src/views/ClaimView.vue
  5. 43
      src/views/ConfirmGiftView.vue
  6. 3
      src/views/ContactQRScanFullView.vue
  7. 3
      src/views/ContactQRScanShowView.vue
  8. 12
      src/views/DatabaseMigration.vue
  9. 26
      src/views/HelpView.vue
  10. 30
      src/views/InviteOneView.vue
  11. 19
      src/views/OnboardMeetingSetupView.vue
  12. 16
      src/views/ProjectViewView.vue
  13. 32
      src/views/QuickActionBvcEndView.vue
  14. 14
      src/views/SeedBackupView.vue
  15. 11
      src/views/ShareMyContactInfoView.vue
  16. 16
      src/views/UserProfileView.vue

29
src/components/HiddenDidDialog.vue

@ -74,7 +74,7 @@
If you'd like an introduction,
<a
class="text-blue-500"
@click="copyToClipboard('A link to this page', deepLinkUrl)"
@click="copyTextToClipboard('A link to this page', deepLinkUrl)"
>click here to copy this page, paste it into a message, and ask if
they'll tell you more about the {{ roleName }}.</a
>
@ -110,7 +110,7 @@
* @since 2024-12-19
*/
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import * as R from "ramda";
import * as serverUtil from "../libs/endorserServer";
import { Contact } from "../db/tables/contacts";
@ -197,19 +197,24 @@ export default class HiddenDidDialog extends Vue {
);
}
copyToClipboard(name: string, text: string) {
useClipboard()
.copy(text)
.then(() => {
this.notify.success(
NOTIFY_COPIED_TO_CLIPBOARD.message(name || "That"),
TIMEOUTS.SHORT,
);
});
async copyTextToClipboard(name: string, text: string) {
try {
await copyToClipboard(text);
this.notify.success(
NOTIFY_COPIED_TO_CLIPBOARD.message(name || "That"),
TIMEOUTS.SHORT,
);
} catch (error) {
this.$logAndConsole(
`Error copying ${name || "content"} to clipboard: ${error}`,
true,
);
this.notify.error(`Failed to copy ${name || "content"} to clipboard.`);
}
}
onClickShareClaim() {
this.copyToClipboard("A link to this page", this.deepLinkUrl);
this.copyTextToClipboard("A link to this page", this.deepLinkUrl);
window.navigator.share({
title: "Help Connect Me",
text: "I'm trying to find the people who recorded this. Can you help me?",

18
src/libs/util.ts

@ -3,7 +3,7 @@
import axios, { AxiosResponse } from "axios";
import { Buffer } from "buffer";
import * as R from "ramda";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { DEFAULT_PUSH_SERVER, NotificationIface } from "../constants/app";
import { Account, AccountEncrypted } from "../db/tables/accounts";
@ -232,11 +232,19 @@ export const nameForContact = (
);
};
export const doCopyTwoSecRedo = (text: string, fn: () => void) => {
export const doCopyTwoSecRedo = async (
text: string,
fn: () => void,
): Promise<void> => {
fn();
useClipboard()
.copy(text)
.then(() => setTimeout(fn, 2000));
try {
await copyToClipboard(text);
setTimeout(fn, 2000);
} catch (error) {
// Note: This utility function doesn't have access to notification system
// The calling component should handle error notifications
// Error is silently caught to avoid breaking the 2-second redo pattern
}
};
export interface ConfirmerData {

14
src/views/AccountViewView.vue

@ -764,7 +764,7 @@ import { IIdentifier } from "@veramo/core";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { LMap, LMarker, LTileLayer } from "@vue-leaflet/vue-leaflet";
import { Capacitor } from "@capacitor/core";
@ -1084,11 +1084,15 @@ export default class AccountViewView extends Vue {
}
// call fn, copy text to the clipboard, then redo fn after 2 seconds
doCopyTwoSecRedo(text: string, fn: () => void): void {
async doCopyTwoSecRedo(text: string, fn: () => void): Promise<void> {
fn();
useClipboard()
.copy(text)
.then(() => setTimeout(fn, 2000));
try {
await copyToClipboard(text);
setTimeout(fn, 2000);
} catch (error) {
this.$logAndConsole(`Error copying to clipboard: ${error}`, true);
this.notify.error("Failed to copy to clipboard.");
}
}
async toggleShowContactAmounts(): Promise<void> {

31
src/views/ClaimView.vue

@ -58,7 +58,7 @@
title="Copy Printable Certificate Link"
aria-label="Copy printable certificate link"
@click="
copyToClipboard(
copyTextToClipboard(
'A link to the certificate page',
`${APP_SERVER}/deep-link/claim-cert/${veriClaim.id}`,
)
@ -72,7 +72,9 @@
<button
title="Copy Link"
aria-label="Copy page link"
@click="copyToClipboard('A link to this page', windowDeepLink)"
@click="
copyTextToClipboard('A link to this page', windowDeepLink)
"
>
<font-awesome icon="link" class="text-slate-500" />
</button>
@ -399,7 +401,7 @@
contacts can see more details:
<a
class="text-blue-500"
@click="copyToClipboard('A link to this page', windowDeepLink)"
@click="copyTextToClipboard('A link to this page', windowDeepLink)"
>click to copy this page info</a
>
and see if they can make an introduction. Someone is connected to
@ -422,7 +424,7 @@
If you'd like an introduction,
<a
class="text-blue-500"
@click="copyToClipboard('A link to this page', windowDeepLink)"
@click="copyTextToClipboard('A link to this page', windowDeepLink)"
>share this page with them and ask if they'll tell you more about
about the participants.</a
>
@ -532,7 +534,7 @@ import * as yaml from "js-yaml";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { Router, RouteLocationNormalizedLoaded } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { GenericVerifiableCredential } from "../interfaces";
import GiftedDialog from "../components/GiftedDialog.vue";
import QuickNav from "../components/QuickNav.vue";
@ -1129,16 +1131,21 @@ export default class ClaimView extends Vue {
);
}
copyToClipboard(name: string, text: string) {
useClipboard()
.copy(text)
.then(() => {
this.notify.copied(name || "That");
});
async copyTextToClipboard(name: string, text: string) {
try {
await copyToClipboard(text);
this.notify.copied(name || "That");
} catch (error) {
this.$logAndConsole(
`Error copying ${name || "content"} to clipboard: ${error}`,
true,
);
this.notify.error(`Failed to copy ${name || "content"} to clipboard.`);
}
}
onClickShareClaim() {
this.copyToClipboard("A link to this page", this.windowDeepLink);
this.copyTextToClipboard("A link to this page", this.windowDeepLink);
window.navigator.share({
title: "Help Connect Me",
text: "I'm trying to find the people who recorded this. Can you help me?",

43
src/views/ConfirmGiftView.vue

@ -192,7 +192,7 @@
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
<button
@click="
copyToClipboard(
copyTextToClipboard(
'The DID of ' + confirmerId,
confirmerId,
)
@ -238,7 +238,7 @@
>
<button
@click="
copyToClipboard(
copyTextToClipboard(
'The DID of ' + confsVisibleTo,
confsVisibleTo,
)
@ -309,7 +309,9 @@
contacts can see more details:
<a
class="text-blue-500"
@click="copyToClipboard('A link to this page', windowLocation)"
@click="
copyTextToClipboard('A link to this page', windowLocation)
"
>click to copy this page info</a
>
and see if they can make an introduction. Someone is connected to
@ -332,7 +334,9 @@
If you'd like an introduction,
<a
class="text-blue-500"
@click="copyToClipboard('A link to this page', windowLocation)"
@click="
copyTextToClipboard('A link to this page', windowLocation)
"
>share this page with them and ask if they'll tell you more about
about the participants.</a
>
@ -360,7 +364,7 @@
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
<button
@click="
copyToClipboard('The DID of ' + visDid, visDid)
copyTextToClipboard('The DID of ' + visDid, visDid)
"
>
<font-awesome
@ -433,7 +437,7 @@
import * as yaml from "js-yaml";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
@ -779,16 +783,21 @@ export default class ConfirmGiftView extends Vue {
* @param description - Description of copied content
* @param text - Text to copy
*/
copyToClipboard(description: string, text: string): void {
useClipboard()
.copy(text)
.then(() => {
this.notify.toast(
NOTIFY_COPIED_TO_CLIPBOARD.title,
NOTIFY_COPIED_TO_CLIPBOARD.message(description),
TIMEOUTS.SHORT,
);
});
async copyTextToClipboard(description: string, text: string): Promise<void> {
try {
await copyToClipboard(text);
this.notify.toast(
NOTIFY_COPIED_TO_CLIPBOARD.title,
NOTIFY_COPIED_TO_CLIPBOARD.message(description),
TIMEOUTS.SHORT,
);
} catch (error) {
this.$logAndConsole(
`Error copying ${description} to clipboard: ${error}`,
true,
);
this.notify.error(`Failed to copy ${description} to clipboard.`);
}
}
/**
@ -870,7 +879,7 @@ export default class ConfirmGiftView extends Vue {
* Handles share functionality based on platform capabilities
*/
async onClickShareClaim(): Promise<void> {
this.copyToClipboard("A link to this page", this.windowLocation);
this.copyTextToClipboard("A link to this page", this.windowLocation);
window.navigator.share({
title: "Help Connect Me",
text: "I'm trying to find the full details of this claim. Can you help me?",

3
src/views/ContactQRScanFullView.vue

@ -104,6 +104,7 @@ import { Buffer } from "buffer/";
import QRCodeVue3 from "qr-code-generator-vue3";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { copyToClipboard } from "../services/ClipboardService";
import { logger } from "../utils/logger";
import { QRScannerFactory } from "../services/QRScanner/QRScannerFactory";
@ -661,7 +662,6 @@ export default class ContactQRScanFull extends Vue {
);
// Use the platform-specific ClipboardService for reliable iOS support
const { copyToClipboard } = await import("../services/ClipboardService");
await copyToClipboard(jwtUrl);
this.notify.toast(
@ -684,7 +684,6 @@ export default class ContactQRScanFull extends Vue {
async onCopyDidToClipboard() {
try {
// Use the platform-specific ClipboardService for reliable iOS support
const { copyToClipboard } = await import("../services/ClipboardService");
await copyToClipboard(this.activeDid);
this.notify.info(NOTIFY_QR_DID_COPIED.message, QR_TIMEOUT_LONG);

3
src/views/ContactQRScanShowView.vue

@ -140,6 +140,7 @@ import { AxiosError } from "axios";
import { Buffer } from "buffer/";
import QRCodeVue3 from "qr-code-generator-vue3";
import { Component, Vue } from "vue-facing-decorator";
import { copyToClipboard } from "../services/ClipboardService";
import { QrcodeStream } from "vue-qrcode-reader";
@ -628,7 +629,6 @@ export default class ContactQRScanShow extends Vue {
);
// Copy the URL to clipboard
const { copyToClipboard } = await import("../services/ClipboardService");
await copyToClipboard(jwtUrl);
this.notify.toast(
NOTIFY_QR_URL_COPIED.title,
@ -647,7 +647,6 @@ export default class ContactQRScanShow extends Vue {
async onCopyDidToClipboard() {
//this.onScanDetect([{ rawValue: this.qrValue }]); // good for testing
try {
const { copyToClipboard } = await import("../services/ClipboardService");
await copyToClipboard(this.activeDid);
this.notify.info(NOTIFY_QR_DID_COPIED.message, QR_TIMEOUT_LONG);
} catch (error) {

12
src/views/DatabaseMigration.vue

@ -1003,7 +1003,7 @@
<h2>Exported Data</h2>
<span
class="text-blue-500 cursor-pointer hover:text-blue-700"
@click="copyToClipboard"
@click="copyExportedDataToClipboard"
>
Copy to Clipboard
</span>
@ -1014,7 +1014,7 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { Router } from "vue-router";
import {
@ -1072,8 +1072,6 @@ export default class DatabaseMigration extends Vue {
private exportedData: Record<string, any> | null = null;
private successMessage = "";
useClipboard = useClipboard;
/**
* Computed property to get the display name for a setting
* Handles both live comparison data and exported JSON format
@ -1133,13 +1131,11 @@ export default class DatabaseMigration extends Vue {
/**
* Copies exported data to clipboard and shows success message
*/
async copyToClipboard(): Promise<void> {
async copyExportedDataToClipboard(): Promise<void> {
if (!this.exportedData) return;
try {
await this.useClipboard().copy(
JSON.stringify(this.exportedData, null, 2),
);
await copyToClipboard(JSON.stringify(this.exportedData, null, 2));
// Use global window object properly
if (typeof window !== "undefined") {
window.alert("Copied to clipboard!");

26
src/views/HelpView.vue

@ -584,15 +584,16 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
// 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 { APP_SERVER, NotificationIface } from "../constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { QRNavigationService } from "@/services/QRNavigationService";
import { UNNAMED_ENTITY_NAME } from "@/constants/entities";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
/**
* HelpView.vue - Comprehensive Help System Component
@ -626,8 +627,10 @@ import { UNNAMED_ENTITY_NAME } from "@/constants/entities";
})
export default class HelpView extends Vue {
$router!: Router;
$notify!: (notification: NotificationIface, timeout?: number) => void;
package = Package;
notify!: ReturnType<typeof createNotifyHelpers>;
commitHash = import.meta.env.VITE_GIT_HASH;
showAlpha = false;
showBasics = false;
@ -640,6 +643,13 @@ export default class HelpView extends Vue {
APP_SERVER = APP_SERVER;
// Capacitor reference removed - using QRNavigationService instead
/**
* Initialize notification helpers
*/
created() {
this.notify = createNotifyHelpers(this.$notify);
}
/**
* Get the unnamed entity name constant
*/
@ -660,11 +670,15 @@ export default class HelpView extends Vue {
* @param {string} text - The text to copy to clipboard
* @param {Function} fn - Callback function to execute before and after copying
*/
doCopyTwoSecRedo(text: string, fn: () => void): void {
async doCopyTwoSecRedo(text: string, fn: () => void): Promise<void> {
fn();
useClipboard()
.copy(text)
.then(() => setTimeout(fn, 2000));
try {
await copyToClipboard(text);
setTimeout(fn, 2000);
} catch (error) {
this.$logAndConsole(`Error copying to clipboard: ${error}`, true);
this.notify.error("Failed to copy to clipboard.", TIMEOUTS.SHORT);
}
}
/**

30
src/views/InviteOneView.vue

@ -128,7 +128,7 @@
<script lang="ts">
import axios from "axios";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { Router } from "vue-router";
import ContactNameDialog from "../components/ContactNameDialog.vue";
@ -333,17 +333,27 @@ export default class InviteOneView extends Vue {
return `${APP_SERVER}/deep-link/invite-one-accept/${jwt}`;
}
copyInviteAndNotify(inviteId: string, jwt: string) {
useClipboard().copy(this.inviteLink(jwt));
this.notify.success(createInviteLinkCopyMessage(inviteId), TIMEOUTS.LONG);
async copyInviteAndNotify(inviteId: string, jwt: string) {
try {
await copyToClipboard(this.inviteLink(jwt));
this.notify.success(createInviteLinkCopyMessage(inviteId), TIMEOUTS.LONG);
} catch (error) {
this.$logAndConsole(`Error copying invite link: ${error}`, true);
this.notify.error("Failed to copy invite link.");
}
}
showInvite(inviteId: string, redeemed: boolean, expired: boolean) {
useClipboard().copy(inviteId);
this.notify.success(
createInviteIdCopyMessage(inviteId, redeemed, expired),
TIMEOUTS.LONG,
);
async showInvite(inviteId: string, redeemed: boolean, expired: boolean) {
try {
await copyToClipboard(inviteId);
this.notify.success(
createInviteIdCopyMessage(inviteId, redeemed, expired),
TIMEOUTS.LONG,
);
} catch (error) {
this.$logAndConsole(`Error copying invite ID: ${error}`, true);
this.notify.error("Failed to copy invite ID.");
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any

19
src/views/OnboardMeetingSetupView.vue

@ -270,7 +270,7 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
@ -676,12 +676,17 @@ export default class OnboardMeetingView extends Vue {
this.notify.error(message, TIMEOUTS.LONG);
}
copyMembersLinkToClipboard() {
useClipboard()
.copy(this.onboardMeetingMembersLink())
.then(() => {
this.notify.info(NOTIFY_MEETING_LINK_COPIED.message, TIMEOUTS.LONG);
});
async copyMembersLinkToClipboard() {
try {
await copyToClipboard(this.onboardMeetingMembersLink());
this.notify.info(NOTIFY_MEETING_LINK_COPIED.message, TIMEOUTS.LONG);
} catch (error) {
this.$logAndConsole(
`Error copying meeting link to clipboard: ${error}`,
true,
);
this.notify.error("Failed to copy meeting link to clipboard.");
}
}
}
</script>

16
src/views/ProjectViewView.vue

@ -616,7 +616,7 @@ import * as serverUtil from "../libs/endorserServer";
import { retrieveAccountDids } from "../libs/util";
import HiddenDidDialog from "../components/HiddenDidDialog.vue";
import { logger } from "../utils/logger";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { NOTIFY_CONFIRM_CLAIM } from "@/constants/notifications";
@ -817,7 +817,7 @@ export default class ProjectViewView extends Vue {
});
}
onCopyLinkClick() {
async onCopyLinkClick() {
const shortestProjectId = this.projectId.startsWith(
serverUtil.ENDORSER_CH_HANDLE_PREFIX,
)
@ -825,11 +825,13 @@ export default class ProjectViewView extends Vue {
: this.projectId;
// Use production URL for sharing to avoid localhost issues in development
const deepLink = `${APP_SERVER}/deep-link/project/${shortestProjectId}`;
useClipboard()
.copy(deepLink)
.then(() => {
this.notify.copied("link to this project", TIMEOUTS.SHORT);
});
try {
await copyToClipboard(deepLink);
this.notify.copied("link to this project", TIMEOUTS.SHORT);
} catch (error) {
this.$logAndConsole(`Error copying project link: ${error}`, true);
this.notify.error("Failed to copy project link.");
}
}
// Isn't there a better way to make this available to the template?

32
src/views/QuickActionBvcEndView.vue

@ -127,7 +127,7 @@ import { DateTime } from "luxon";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
@ -305,23 +305,21 @@ export default class QuickActionBvcEndView extends Vue {
(this.$router as Router).push(route);
}
copyContactsLinkToClipboard() {
async copyContactsLinkToClipboard() {
const deepLinkUrl = `${APP_SERVER}/deep-link/did/${this.activeDid}`;
useClipboard()
.copy(deepLinkUrl)
.then(() => {
this.notify.success(
NOTIFY_COPIED_TO_CLIPBOARD.message("Your info link"),
TIMEOUTS.SHORT,
);
})
.catch((error) => {
logger.error("Failed to copy to clipboard:", error);
this.notify.error(
"Failed to copy link to clipboard. Please try again.",
TIMEOUTS.SHORT,
);
});
try {
await copyToClipboard(deepLinkUrl);
this.notify.success(
NOTIFY_COPIED_TO_CLIPBOARD.message("Your info link"),
TIMEOUTS.SHORT,
);
} catch (error) {
logger.error("Failed to copy to clipboard:", error);
this.notify.error(
"Failed to copy link to clipboard. Please try again.",
TIMEOUTS.SHORT,
);
}
}
async record() {

14
src/views/SeedBackupView.vue

@ -106,7 +106,7 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
@ -279,11 +279,15 @@ export default class SeedBackupView extends Vue {
* @param text - The text to copy to clipboard
* @param fn - Callback function to execute for feedback (called twice - immediately and after 2 seconds)
*/
doCopyTwoSecRedo(text: string, fn: () => void) {
async doCopyTwoSecRedo(text: string, fn: () => void) {
fn();
useClipboard()
.copy(text)
.then(() => setTimeout(fn, 2000));
try {
await copyToClipboard(text);
setTimeout(fn, 2000);
} catch (error) {
this.$logAndConsole(`Error copying to clipboard: ${error}`, true);
this.notify.error("Failed to copy to clipboard.");
}
}
}
</script>

11
src/views/ShareMyContactInfoView.vue

@ -54,6 +54,7 @@ import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { Settings } from "@/db/tables/settings";
import { Account } from "@/db/tables/accounts";
import { copyToClipboard } from "../services/ClipboardService";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
// Constants for magic numbers
@ -99,7 +100,7 @@ export default class ShareMyContactInfoView extends Vue {
}
const message = await this.generateContactMessage(settings, account);
await this.copyToClipboard(message);
await copyToClipboard(message);
await this.showSuccessNotifications();
this.navigateToContacts();
} catch (error) {
@ -140,14 +141,6 @@ export default class ShareMyContactInfoView extends Vue {
);
}
/**
* Copy the contact message to clipboard
*/
private async copyToClipboard(message: string): Promise<void> {
const { copyToClipboard } = await import("../services/ClipboardService");
await copyToClipboard(message);
}
/**
* Show success notifications after copying
*/

16
src/views/UserProfileView.vue

@ -108,7 +108,7 @@ import { didInfo, getHeaders } from "../libs/endorserServer";
import { UserProfile } from "../libs/partnerServer";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { useClipboard } from "@vueuse/core";
import { copyToClipboard } from "../services/ClipboardService";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { NOTIFY_PROFILE_LOAD_ERROR } from "@/constants/notifications";
@ -240,14 +240,16 @@ export default class UserProfileView extends Vue {
* Creates a deep link to the profile and copies it to the clipboard
* Shows success notification when completed
*/
onCopyLinkClick() {
async onCopyLinkClick() {
// Use production URL for sharing to avoid localhost issues in development
const deepLink = `${APP_SERVER}/deep-link/user-profile/${this.profile?.rowId}`;
useClipboard()
.copy(deepLink)
.then(() => {
this.notify.copied("profile link", TIMEOUTS.STANDARD);
});
try {
await copyToClipboard(deepLink);
this.notify.copied("profile link", TIMEOUTS.STANDARD);
} catch (error) {
this.$logAndConsole(`Error copying profile link: ${error}`, true);
this.notify.error("Failed to copy profile link.");
}
}
/**

Loading…
Cancel
Save