diff --git a/components/CredentialCompactBundle.vue b/components/CredentialCompactBundle.vue index 0f478e7..6248a55 100644 --- a/components/CredentialCompactBundle.vue +++ b/components/CredentialCompactBundle.vue @@ -9,6 +9,8 @@ :credential="credential"> @@ -91,6 +93,7 @@ async function createCompactBundledCredentials({credentials}) { } credentialsList.push(credential); } + console.log(credentialsList); return credentialsList; } diff --git a/components/CredentialDashboard.vue b/components/CredentialDashboard.vue index 2c1e3d3..b5884b3 100644 --- a/components/CredentialDashboard.vue +++ b/components/CredentialDashboard.vue @@ -16,8 +16,16 @@ size="sm" color="primary" class="q-mr-sm" - icon="fas fa-barcode" + icon="fas fa-camera" @click="openBarcodeDialog" /> + + @@ -52,6 +63,7 @@ import {config} from '@bedrock/web'; import {createEmitExtendable} from '@digitalbazaar/vue-extendable-event'; import CredentialsList from './CredentialsList.vue'; import SearchBox from './SearchBox.vue'; +import ShowInteractionQrModal from './ShowInteractionQrModal.vue'; import ShowScannerModal from './ShowScannerModal.vue'; export default { @@ -59,6 +71,7 @@ export default { components: { CredentialsList, SearchBox, + ShowInteractionQrModal, ShowScannerModal }, props: { @@ -96,6 +109,7 @@ export default { const search = ref(''); const filteredProfiles = ref([]); const showBarcodeDialog = ref(false); + const showInteractionQrDialog = ref(false); const credentials = toRef(props, 'credentials'); // Credentials filtered by search term match @@ -132,6 +146,10 @@ export default { showBarcodeDialog.value = true; }; + const openInteractionQrDialog = () => { + showInteractionQrDialog.value = true; + }; + // Pass delete-credential event up component chain const deleteCredential = async ({profileId, credentialId}) => { return emitExtendable('delete-credential', {profileId, credentialId}); @@ -139,7 +157,7 @@ export default { // Watchers watch(() => filteredProfiles, () => { - return emit('filtered-profiles', filteredProfiles); + return emit('filtered-profiles', filteredProfiles.value); }, {immediate: true}); // Get each credential title and subtitle overrides @@ -181,6 +199,8 @@ export default { search, openBarcodeDialog, showBarcodeDialog, + openInteractionQrDialog, + showInteractionQrDialog, }; } }; diff --git a/components/CredentialsList.vue b/components/CredentialsList.vue index 3bc554a..067773b 100644 --- a/components/CredentialsList.vue +++ b/components/CredentialsList.vue @@ -13,6 +13,8 @@ diff --git a/components/ShareCredentials.vue b/components/ShareCredentials.vue index 1cc9fda..d765471 100644 --- a/components/ShareCredentials.vue +++ b/components/ShareCredentials.vue @@ -16,7 +16,9 @@ style="overflow: auto" :style="$q.screen.lt.sm ? 'max-height: calc(100% - 67px)' : 'max-height: calc(100vh - 102px)'"> -
+
@@ -124,6 +126,10 @@ export default { return []; }, [], profilesUpdating); + const accountHasOnlyOneProfile = computed(() => { + return profiles.value.length === 1; + }); + const verifiablePresentationRequest = toRef( props, 'verifiablePresentationRequest'); @@ -197,6 +203,7 @@ export default { sharing.value); return { + accountHasOnlyOneProfile, displayableCredentials, selectedCredentials, loading, diff --git a/components/ShowInteractionQrModal.vue b/components/ShowInteractionQrModal.vue new file mode 100644 index 0000000..49eca66 --- /dev/null +++ b/components/ShowInteractionQrModal.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/components/StoreCredentials.vue b/components/StoreCredentials.vue index 21753f0..3fc6321 100644 --- a/components/StoreCredentials.vue +++ b/components/StoreCredentials.vue @@ -17,11 +17,13 @@ 'max-height: calc(100vh - 102px)'">
- Would you like to store these credentials? + Would you like to store these credential(s)?
-
+
profileManager.getProfiles({useCache: true}), [], profilesUpdating); - + const accountHasOnlyOneProfile = computed(() => { + return profiles.value.length === 1; + }); const storing = ref(false); const loading = computed( () => profilesUpdating.value || storing.value); - return {loading, profiles, profilesUpdating, storing}; + return { + accountHasOnlyOneProfile, loading, profiles, profilesUpdating, storing + }; }, data() { return { diff --git a/components/wallet-interaction.js b/components/wallet-interaction.js new file mode 100644 index 0000000..27c81a6 --- /dev/null +++ b/components/wallet-interaction.js @@ -0,0 +1,49 @@ +/*! + * Copyright (c) 2025 Digital Bazaar, Inc. All rights reserved. + */ + +import {httpClient} from '@digitalbazaar/http-client'; +import QRCode from 'qrcode'; + +export async function create() { + const {data: {id}} = await httpClient.post('/mock-interactions'); + return `${window.location.origin}/mock-interactions/${id}`; +} + +export function poll({url, interval = 1000, timeout = 60000}) { + const start = Date.now(); + return new Promise((resolve, reject) => { + (async function tick() { + if(Date.now() - start >= timeout) { + return reject(new Error('timeout')); + } + try { + const {data} = await httpClient.get(url); + if(data?.protocols?.website) { + const {website} = data.protocols; + return resolve(website); + } + + setTimeout(tick, interval); + } catch(e) { + console.error(e); + setTimeout(tick, interval); + } + })(); + }); +} + +export function toQrCode({text}) { + if(!text || text.length === 0) { + return; + } + + return QRCode.toDataURL(text, { + type: 'image/png', + width: 800, + }); +} + +export function toQrText(obj) { + return window.btoa(JSON.stringify(obj)); +} diff --git a/lib/index.js b/lib/index.js index cc162ef..448fc34 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ * Copyright (c) 2022-2023 Digital Bazaar, Inc. All rights reserved. */ import * as brQuasar from '@bedrock/quasar'; -import {Loading, Notify, Quasar} from 'quasar'; +import {Dialog, Loading, Notify, Quasar} from 'quasar'; import {session, sessionDataRef} from './session.js'; import {config} from '@bedrock/web'; import {configureRouter} from './router.js'; @@ -55,7 +55,8 @@ export async function initialize({app, router, features, quasarOptions} = {}) { plugins: { // known plugins in use Loading, - Notify + Notify, + Dialog, }, config: {} }; diff --git a/package.json b/package.json index 850ae36..da2a341 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,14 @@ "@digitalbazaar/web-app-manifest-utils": "^2.0.0", "html5-qrcode": "^2.3.8", "mustache": "^4.2.0", - "qrcode": "^1.5.3", + "qrcode": "^1.5.4", "randomcolor": "^0.6.2", "web-credential-handler": "^3.0.0" }, "peerDependencies": { "@bedrock/quasar": "^10.0.0", "@bedrock/quasar-components": "^5.0.0", - "@bedrock/vue-vc": "^5.0.0", + "@bedrock/vue-vc": "digitalbazaar/bedrock-vue-vc#dwiwg", "@bedrock/web": "^3.1.0", "@bedrock/web-account": "^6.1.0", "@bedrock/web-authn-token": "^7.0.0",