You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

215 lines
5.7 KiB

<template>
<QuickNav />
<TopMessage />
<!-- CONTENT -->
<section id="Content" class="p-2 pb-24 max-w-3xl mx-auto">
<!-- Breadcrumb -->
<div>
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<button
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
aria-label="Go back"
@click="$router.back()"
>
<font-awesome icon="chevron-left" class="fa-fw" />
</button>
</div>
<!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light">
Share Your Contact Info
</h1>
</div>
<div class="flex justify-center mt-8">
<button
class="block w-fit text-center text-lg font-bold 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-2 py-3 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
:disabled="isLoading"
aria-label="Copy contact information to clipboard"
@click="onClickShare()"
>
{{ isLoading ? "Copying..." : "Copy to Clipboard" }}
</button>
</div>
<div class="ml-12">
<div class="mt-8">Click to copy your info, then send it to them.</div>
<div>
They will paste it in the input box on the Contacts
<font-awesome icon="users" /> screen.
</div>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app";
import { retrieveFullyDecryptedAccount } from "../libs/util";
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { Settings } from "@/db/tables/settings";
import { Account } from "@/db/tables/accounts";
// Constants for magic numbers
const NOTIFICATION_TIMEOUTS = {
COPY_SUCCESS: 5000,
SHARE_CONTACTS: 10000,
ERROR: 5000,
} as const;
const DELAYS = {
SHARE_CONTACTS_DELAY: 3000,
} as const;
@Component({
mixins: [PlatformServiceMixin],
components: { QuickNav, TopMessage },
})
export default class ShareMyContactInfoView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
$router!: Router;
// Component state
isLoading = false;
/**
* Main share functionality - orchestrates the contact sharing process
*/
async onClickShare(): Promise<void> {
this.isLoading = true;
try {
const settings = await this.$settings();
const account = await this.retrieveAccount(settings);
if (!account) {
this.showAccountError();
return;
}
const message = await this.generateContactMessage(settings, account);
await this.copyToClipboard(message);
await this.showSuccessNotifications();
this.navigateToContacts();
} catch (error) {
await this.$logError(`Error sharing contact info: ${error}`);
this.showGenericError();
} finally {
this.isLoading = false;
}
}
/**
* Retrieve the fully decrypted account for the active DID
*/
private async retrieveAccount(
settings: Settings,
): Promise<Account | undefined> {
const activeDid = settings.activeDid || "";
if (!activeDid) {
return undefined;
}
return await retrieveFullyDecryptedAccount(activeDid);
}
/**
* Generate the contact message URL for sharing
*/
private async generateContactMessage(
settings: Settings,
account: Account,
): Promise<string> {
const givenName = settings.firstName || "";
const isRegistered = !!settings.isRegistered;
const profileImageUrl = settings.profileImageUrl || "";
return await generateEndorserJwtUrlForAccount(
account,
isRegistered,
givenName,
profileImageUrl,
true,
);
}
/**
* Copy the contact message to clipboard
*/
private async copyToClipboard(message: string): Promise<void> {
const { useClipboard } = await import("@vueuse/core");
await useClipboard().copy(message);
}
/**
* Show success notifications after copying
*/
private async showSuccessNotifications(): Promise<void> {
this.$notify(
{
group: "alert",
type: "info",
title: "Copied",
text: "Your contact info was copied to the clipboard. Have them click on it, or paste it in the box on their 'Contacts' screen.",
},
NOTIFICATION_TIMEOUTS.COPY_SUCCESS,
);
const numContacts = await this.$contactCount();
if (numContacts > 0) {
setTimeout(() => {
this.$notify(
{
group: "alert",
type: "success",
title: "Share Other Contacts",
text: "You may want to share some of your contacts with them. Select them below to copy and send.",
},
NOTIFICATION_TIMEOUTS.SHARE_CONTACTS,
);
}, DELAYS.SHARE_CONTACTS_DELAY);
}
}
/**
* Navigate to contacts page
*/
private navigateToContacts(): void {
this.$router.push({ name: "contacts" });
}
/**
* Show account not found error
*/
private showAccountError(): void {
this.$notify(
{
group: "alert",
type: "error",
title: "Error",
text: "No account was found for the active DID.",
},
NOTIFICATION_TIMEOUTS.ERROR,
);
}
/**
* Show generic error notification
*/
private showGenericError(): void {
this.$notify(
{
group: "alert",
type: "error",
title: "Error",
text: "There was a problem sharing your contact information. Please try again.",
},
NOTIFICATION_TIMEOUTS.ERROR,
);
}
}
</script>