Browse Source

feat: switch ContactQRScanShowView to URL-based contact sharing

- Replace CSV QR value copying with URL generation for better UX
- Add generateEndorserJwtUrlForAccount import and Account type
- Implement proper error handling for URL generation failures
- Maintain consistency with ContactQRScanFullView behavior
- Add documentation for the URL solution implementation

Recipients can now click shared URLs to add contacts directly instead of
manually pasting CSV data into input fields.

addresses:  https://app.clickup.com/t/86b63xhz4
get-get-hash
Matthew Raymer 6 days ago
parent
commit
6868a322f1
  1. 84
      docs/contact-sharing-url-solution.md
  2. 6
      src/utils/PlatformServiceMixin.ts
  3. 39
      src/views/ContactQRScanShowView.vue

84
docs/contact-sharing-url-solution.md

@ -0,0 +1,84 @@
# Contact Sharing - URL Solution
## Overview
Simple implementation to switch ContactQRScanShowView from copying QR value (CSV) to copying a URL for better user experience.
## Problem
The ContactQRScanShowView was copying QR value (CSV content) to clipboard instead of a URL, making contact sharing less user-friendly.
## Solution
Updated the `onCopyUrlToClipboard()` method in ContactQRScanShowView.vue to generate and copy a URL instead of the QR value.
## Changes Made
### ContactQRScanShowView.vue
**Added Imports:**
```typescript
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { Account } from "@/db/tables/accounts";
```
**Updated Method:**
```typescript
async onCopyUrlToClipboard() {
try {
// Generate URL for sharing
const account = (await libsUtil.retrieveFullyDecryptedAccount(
this.activeDid,
)) as Account;
const jwtUrl = await generateEndorserJwtUrlForAccount(
account,
this.isRegistered,
this.givenName,
this.profileImageUrl,
true,
);
// Copy the URL to clipboard
useClipboard()
.copy(jwtUrl)
.then(() => {
this.notify.toast(
"Copied",
NOTIFY_QR_URL_COPIED.message,
QR_TIMEOUT_MEDIUM,
);
});
} catch (error) {
logger.error("Failed to generate contact URL:", error);
this.notify.error("Failed to generate contact URL. Please try again.");
}
}
```
## Benefits
1. **Better UX**: Recipients can click the URL to add contact directly
2. **Consistency**: Both ContactQRScanShowView and ContactQRScanFullView now use URL format
3. **Error Handling**: Graceful fallback if URL generation fails
4. **Simple**: Minimal changes, no new components needed
## User Experience
**Before:**
- Click QR code → Copy CSV data to clipboard
- Recipient must paste CSV into input field
**After:**
- Click QR code → Copy URL to clipboard
- Recipient clicks URL → Contact added automatically
## Testing
- ✅ Linting passes
- ✅ Error handling implemented
- ✅ Consistent with ContactQRScanFullView behavior
- ✅ Maintains existing notification system
## Deployment
Ready for deployment. No breaking changes, maintains backward compatibility.

6
src/utils/PlatformServiceMixin.ts

@ -1062,9 +1062,9 @@ export const PlatformServiceMixin = {
: null,
contactMethods:
contact.contactMethods !== undefined
? (Array.isArray(contact.contactMethods)
? JSON.stringify(contact.contactMethods)
: contact.contactMethods)
? Array.isArray(contact.contactMethods)
? JSON.stringify(contact.contactMethods)
: contact.contactMethods
: null,
};

39
src/views/ContactQRScanShowView.vue

@ -153,6 +153,7 @@ import {
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
register,
setVisibilityUtil,
generateEndorserJwtUrlForAccount,
} from "../libs/endorserServer";
import { decodeEndorserJwt, ETHR_DID_PREFIX } from "../libs/crypto/vc";
import * as libsUtil from "../libs/util";
@ -187,6 +188,7 @@ import {
QR_TIMEOUT_STANDARD,
QR_TIMEOUT_LONG,
} from "@/constants/notifications";
import { Account } from "@/db/tables/accounts";
interface QRScanResult {
rawValue?: string;
@ -610,16 +612,33 @@ export default class ContactQRScanShow extends Vue {
}
async onCopyUrlToClipboard() {
// Copy the CSV format QR code value instead of generating a deep link
useClipboard()
.copy(this.qrValue)
.then(() => {
this.notify.toast(
"Copied",
NOTIFY_QR_URL_COPIED.message,
QR_TIMEOUT_MEDIUM,
);
});
try {
// Generate URL for sharing
const account = (await libsUtil.retrieveFullyDecryptedAccount(
this.activeDid,
)) as Account;
const jwtUrl = await generateEndorserJwtUrlForAccount(
account,
this.isRegistered,
this.givenName,
this.profileImageUrl,
true,
);
// Copy the URL to clipboard
useClipboard()
.copy(jwtUrl)
.then(() => {
this.notify.toast(
"Copied",
NOTIFY_QR_URL_COPIED.message,
QR_TIMEOUT_MEDIUM,
);
});
} catch (error) {
logger.error("Failed to generate contact URL:", error);
this.notify.error("Failed to generate contact URL. Please try again.");
}
}
toastQRCodeHelp() {

Loading…
Cancel
Save