From 47feaf07f59f556b8bf2bd22d7a33fc82a684127 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Sat, 23 Sep 2023 14:29:54 +0000 Subject: [PATCH 01/50] refactor: CredentialsLanding component: add heading card Signed-off-by: Akiff Manji --- .../DigitalCredentials/CredentialsLanding.vue | 78 ++++++++----------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/src/components/DigitalCredentials/CredentialsLanding.vue b/src/components/DigitalCredentials/CredentialsLanding.vue index 499b7485c..955c803da 100644 --- a/src/components/DigitalCredentials/CredentialsLanding.vue +++ b/src/components/DigitalCredentials/CredentialsLanding.vue @@ -1,47 +1,35 @@ From bbd85b7903feebf2330ba18586c9f516d86abad6 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 28 Sep 2023 15:14:46 +0000 Subject: [PATCH 10/50] refactor: DigitalCredentials component: update types and imports Signed-off-by: Akiff Manji --- .../CredentialsDashboard.vue | 10 +-- .../DigitalCredentials/CredentialsLanding.vue | 2 +- .../DigitalCredentials/CredentialsMenu.vue | 75 +++++++++++++++++++ .../DigitalCredentials/CredentialsStepper.vue | 11 ++- .../DigitalCredentials/CredentialsTable.vue | 30 +++++--- .../CredentialsWebSocket.vue | 5 +- src/components/DigitalCredentials/index.ts | 1 + .../digitalCredentials-interface.ts | 10 ++- 8 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 src/components/DigitalCredentials/CredentialsMenu.vue diff --git a/src/components/DigitalCredentials/CredentialsDashboard.vue b/src/components/DigitalCredentials/CredentialsDashboard.vue index e3595b6de..817950352 100644 --- a/src/components/DigitalCredentials/CredentialsDashboard.vue +++ b/src/components/DigitalCredentials/CredentialsDashboard.vue @@ -23,13 +23,13 @@ diff --git a/src/components/DigitalCredentials/CredentialsStepper.vue b/src/components/DigitalCredentials/CredentialsStepper.vue index 4f7b30e51..618b5e337 100644 --- a/src/components/DigitalCredentials/CredentialsStepper.vue +++ b/src/components/DigitalCredentials/CredentialsStepper.vue @@ -137,6 +137,7 @@ import { useBusinessStore } from '@/stores' import { Getter } from 'pinia-class' import { Component, Vue } from 'vue-property-decorator' import QrcodeVue from 'qrcode.vue' +import { DigitalCredentialIF, WalletConnectionIF } from '@/interfaces' import CredentialsWebSocket from '@/components/DigitalCredentials/CredentialsWebSocket.vue' Component.registerHooks([ @@ -149,10 +150,8 @@ export default class CredentialsStepper extends Vue { @Getter(useBusinessStore) getIdentifier!: string; credentialTypes = DigitalCredentialTypes; - // TODO: Create the correct type for a Connection - credentialConnection: any = null; - // TODO: Create the correct type for a Credential - issuedCredential: any = null; + credentialConnection: WalletConnectionIF = null; + issuedCredential: DigitalCredentialIF = null; steps = [ { id: 1, @@ -218,12 +217,12 @@ export default class CredentialsStepper extends Vue { await LegalServices.sendCredentialOffer(this.getIdentifier, credentialType) } - async handleConnection (connection: any) { + async handleConnection (connection: WalletConnectionIF) { this.credentialConnection = connection await this.issueCredential(this.credentialTypes.BUSINESS) } - async handleIssuedCredential (issuedCredential: any) { + async handleIssuedCredential (issuedCredential: DigitalCredentialIF) { this.issuedCredential = issuedCredential } } diff --git a/src/components/DigitalCredentials/CredentialsTable.vue b/src/components/DigitalCredentials/CredentialsTable.vue index 7036ee1c5..f6397415d 100644 --- a/src/components/DigitalCredentials/CredentialsTable.vue +++ b/src/components/DigitalCredentials/CredentialsTable.vue @@ -22,13 +22,13 @@ {{ formatCredentialType(item.credentialType) }} @@ -37,13 +37,18 @@ diff --git a/src/components/DigitalCredentials/CredentialsTable.vue b/src/components/DigitalCredentials/CredentialsTable.vue index f6397415d..01b8f122e 100644 --- a/src/components/DigitalCredentials/CredentialsTable.vue +++ b/src/components/DigitalCredentials/CredentialsTable.vue @@ -27,8 +27,11 @@ - @@ -103,7 +112,6 @@ export default class CredentialsTable extends Mixins(DateMixin) { // Vuetify overrides for Table Headers and Cells :deep() { - .v-data-table>.v-data-table__wrapper>table>thead>tr>th, td { color: $gray7; diff --git a/src/components/dialogs/ConfirmRevokeCredentialDialog.vue b/src/components/dialogs/ConfirmRevokeCredentialDialog.vue new file mode 100644 index 000000000..02f2ea5cf --- /dev/null +++ b/src/components/dialogs/ConfirmRevokeCredentialDialog.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/components/dialogs/CredentialRevokedDialog.vue b/src/components/dialogs/CredentialRevokedDialog.vue new file mode 100644 index 000000000..4e94f03e0 --- /dev/null +++ b/src/components/dialogs/CredentialRevokedDialog.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/components/dialogs/RevokeCredentialErrorDialog.vue b/src/components/dialogs/RevokeCredentialErrorDialog.vue new file mode 100644 index 000000000..b68f34822 --- /dev/null +++ b/src/components/dialogs/RevokeCredentialErrorDialog.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/components/dialogs/index.ts b/src/components/dialogs/index.ts index b7c38efab..357661fcb 100644 --- a/src/components/dialogs/index.ts +++ b/src/components/dialogs/index.ts @@ -5,6 +5,8 @@ import CancelPaymentErrorDialog from './CancelPaymentErrorDialog.vue' import CoaWarningDialog from './CoaWarningDialog.vue' import { ConfirmDialog } from '@bcrs-shared-components/confirm-dialog' import ConfirmDissolutionDialog from './ConfirmDissolutionDialog.vue' +import ConfirmRevokeCredentialDialog from './ConfirmRevokeCredentialDialog.vue' +import CredentialRevokedDialog from './CredentialRevokedDialog.vue' import DashboardUnavailableDialog from './DashboardUnavailableDialog.vue' import DeleteErrorDialog from './DeleteErrorDialog.vue' import DownloadErrorDialog from './DownloadErrorDialog.vue' @@ -16,6 +18,7 @@ import NameRequestInvalidDialog from './NameRequestInvalidDialog.vue' import NotInGoodStandingDialog from '@/components/dialogs/NotInGoodStandingDialog.vue' import PaymentErrorDialog from './PaymentErrorDialog.vue' import ResumeErrorDialog from './ResumeErrorDialog.vue' +import RevokeCredentialErrorDialog from './RevokeCredentialErrorDialog.vue' import SaveErrorDialog from './SaveErrorDialog.vue' import StaffPaymentDialog from './StaffPaymentDialog.vue' @@ -27,6 +30,8 @@ export { CoaWarningDialog, ConfirmDialog, ConfirmDissolutionDialog, + ConfirmRevokeCredentialDialog, + CredentialRevokedDialog, DashboardUnavailableDialog, DeleteErrorDialog, DownloadErrorDialog, @@ -38,6 +43,7 @@ export { NotInGoodStandingDialog, PaymentErrorDialog, ResumeErrorDialog, + RevokeCredentialErrorDialog, SaveErrorDialog, StaffPaymentDialog } diff --git a/src/interfaces/digitalCredentials-interface.ts b/src/interfaces/digitalCredentials-interface.ts index c9afbbe28..b88d1dbf5 100644 --- a/src/interfaces/digitalCredentials-interface.ts +++ b/src/interfaces/digitalCredentials-interface.ts @@ -3,6 +3,7 @@ import { DigitalCredentialTypes } from '@/enums' export interface DigitalCredentialIF { legalName: string credentialType: DigitalCredentialTypes + credentialId: string isIssued: boolean dateOfIssue: string isRevoked: boolean diff --git a/src/services/legal-services.ts b/src/services/legal-services.ts index f23f147f6..8ecb9b0b0 100644 --- a/src/services/legal-services.ts +++ b/src/services/legal-services.ts @@ -1,8 +1,15 @@ // Libraries import axios from '@/axios-auth' import { AxiosResponse } from 'axios' -import { ApiBusinessIF, ApiFilingIF, CommentIF, DocumentIF, FetchDocumentsIF, NameRequestIF, - PresignedUrlIF } from '@/interfaces' +import { + ApiBusinessIF, + ApiFilingIF, + CommentIF, + DocumentIF, + FetchDocumentsIF, + NameRequestIF, + PresignedUrlIF +} from '@/interfaces' import { DigitalCredentialTypes, FilingStatus, Roles } from '@/enums' /** @@ -16,16 +23,15 @@ export default class LegalServices { */ static async fetchBusiness (businessId: string): Promise { const url = `businesses/${businessId}` - return axios.get(url) - .then(response => { - const businessInfo = response?.data?.business as ApiBusinessIF - if (!businessInfo) { - // eslint-disable-next-line no-console - console.log('fetchBusiness() error - invalid response =', response) - throw new Error('Invalid business info') - } - return businessInfo - }) + return axios.get(url).then((response) => { + const businessInfo = response?.data?.business as ApiBusinessIF + if (!businessInfo) { + // eslint-disable-next-line no-console + console.log('fetchBusiness() error - invalid response =', response) + throw new Error('Invalid business info') + } + return businessInfo + }) } /** @@ -45,16 +51,15 @@ export default class LegalServices { */ static async fetchFilings (businessId: string): Promise { const url = `businesses/${businessId}/filings` - return axios.get(url) - .then(response => { - const filings = response?.data?.filings as ApiFilingIF[] - if (!filings) { - // eslint-disable-next-line no-console - console.log('fetchFilings() error - invalid response =', response) - throw new Error('Invalid filings list') - } - return filings - }) + return axios.get(url).then((response) => { + const filings = response?.data?.filings as ApiFilingIF[] + if (!filings) { + // eslint-disable-next-line no-console + console.log('fetchFilings() error - invalid response =', response) + throw new Error('Invalid filings list') + } + return filings + }) } /** @@ -89,9 +94,12 @@ export default class LegalServices { */ static async fetchDraftApp (tempRegNumber: string): Promise { const url = `businesses/${tempRegNumber}/filings` - return axios.get(url) - // workaround because data is at "response.data.data" - .then(response => response?.data) + return ( + axios + .get(url) + // workaround because data is at "response.data.data" + .then((response) => response?.data) + ) } /** @@ -101,9 +109,12 @@ export default class LegalServices { */ static async fetchNameRequest (nrNumber: string): Promise { const url = `nameRequests/${nrNumber}` - return axios.get(url) - // workaround because data is at "response.data.data" - .then(response => response?.data) + return ( + axios + .get(url) + // workaround because data is at "response.data.data" + .then((response) => response?.data) + ) } /** @@ -112,16 +123,15 @@ export default class LegalServices { * @returns the filing object */ static async fetchFiling (url: string): Promise { - return axios.get(url) - .then(response => { - const filing = response?.data?.filing - if (!filing) { - // eslint-disable-next-line no-console - console.log('fetchFiling() error - invalid response =', response) - throw new Error('Invalid filing') - } - return filing - }) + return axios.get(url).then((response) => { + const filing = response?.data?.filing + if (!filing) { + // eslint-disable-next-line no-console + console.log('fetchFiling() error - invalid response =', response) + throw new Error('Invalid filing') + } + return filing + }) } /** @@ -136,16 +146,15 @@ export default class LegalServices { if (isDraft) { url += '?draft=true' } - return axios.post(url, { filing }) - .then(response => { - const filing = response?.data?.filing - if (!filing) { - // eslint-disable-next-line no-console - console.log('createFiling() error - invalid response =', response) - throw new Error('Invalid filing') - } - return filing - }) + return axios.post(url, { filing }).then((response) => { + const filing = response?.data?.filing + if (!filing) { + // eslint-disable-next-line no-console + console.log('createFiling() error - invalid response =', response) + throw new Error('Invalid filing') + } + return filing + }) } /** @@ -161,16 +170,15 @@ export default class LegalServices { if (isDraft) { url += '?draft=true' } - return axios.put(url, { filing }) - .then(response => { - const filing = response?.data?.filing - if (!filing) { - // eslint-disable-next-line no-console - console.log('updateFiling() error - invalid response =', response) - throw new Error('Invalid filing') - } - return filing - }) + return axios.put(url, { filing }).then((response) => { + const filing = response?.data?.filing + if (!filing) { + // eslint-disable-next-line no-console + console.log('updateFiling() error - invalid response =', response) + throw new Error('Invalid filing') + } + return filing + }) } /** @@ -179,16 +187,15 @@ export default class LegalServices { * @returns the comments array */ static async fetchComments (url: string): Promise { - return axios.get(url) - .then(response => { - const comments = response?.data?.comments - if (!comments) { - // eslint-disable-next-line no-console - console.log('fetchComments() error - invalid response =', response) - throw new Error('Invalid comments') - } - return comments - }) + return axios.get(url).then((response) => { + const comments = response?.data?.comments + if (!comments) { + // eslint-disable-next-line no-console + console.log('fetchComments() error - invalid response =', response) + throw new Error('Invalid comments') + } + return comments + }) } /** @@ -197,16 +204,15 @@ export default class LegalServices { * @returns the fetch documents object */ static async fetchDocuments (url: string): Promise { - return axios.get(url) - .then(response => { - const documents = response?.data?.documents - if (!documents) { - // eslint-disable-next-line no-console - console.log('fetchDocuments() error - invalid response =', response) - throw new Error('Invalid documents') - } - return documents - }) + return axios.get(url).then((response) => { + const documents = response?.data?.documents + if (!documents) { + // eslint-disable-next-line no-console + console.log('fetchDocuments() error - invalid response =', response) + throw new Error('Invalid documents') + } + return documents + }) } /** @@ -221,11 +227,11 @@ export default class LegalServices { } const config = { - headers: { 'Accept': 'application/pdf' }, + headers: { Accept: 'application/pdf' }, responseType: 'blob' as 'json' } - return axios.get(document.link, config).then(response => { + return axios.get(document.link, config).then((response) => { if (!response) throw new Error('Null response') /* solution from https://github.com/axios/axios/issues/1392 */ @@ -262,9 +268,9 @@ export default class LegalServices { * @returns True if there are any non-NEW tasks, else False */ static async hasPendingTasks (businessId: string): Promise { - return this.fetchTasks(businessId).then(response => { + return this.fetchTasks(businessId).then((response) => { const tasks = response?.data?.tasks || [] - return tasks.some(task => { + return tasks.some((task) => { if (task?.task?.filing?.header) { if (task.task.filing.header.status !== FilingStatus.NEW) { return true @@ -281,8 +287,7 @@ export default class LegalServices { */ static async getPresignedUrl (fileName: string): Promise { const url = `documents/${fileName}/signatures` - return axios.get(url) - .then(response => response?.data) + return axios.get(url).then((response) => response?.data) } /** @@ -314,12 +319,11 @@ export default class LegalServices { */ static async fetchCredentials (businessId: string): Promise { const url = `businesses/${businessId}/digitalCredentials` - return axios.get(url) - .catch(error => { - // eslint-disable-next-line no-console - console.log(error.message) - return null - }) + return axios.get(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) } /** @@ -329,12 +333,11 @@ export default class LegalServices { */ static async createCredentialInvitation (businessId: string): Promise { const url = `businesses/${businessId}/digitalCredentials/invitation` - return axios.post(url) - .catch(error => { - // eslint-disable-next-line no-console - console.log(error.message) - return null - }) + return axios.post(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) } /** @@ -344,12 +347,11 @@ export default class LegalServices { */ static async fetchCredentialConnections (businessId: string): Promise { const url = `businesses/${businessId}/digitalCredentials/connections` - return axios.get(url) - .catch(error => { - // eslint-disable-next-line no-console - console.log(error.message) - return null - }) + return axios.get(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) } /** @@ -358,14 +360,30 @@ export default class LegalServices { * @param credentialType The credential offer type * @returns the axios response */ - static async sendCredentialOffer (businessId: string, credentialType: DigitalCredentialTypes) - : Promise { + static async sendCredentialOffer ( + businessId: string, + credentialType: DigitalCredentialTypes) + : Promise { const url = `businesses/${businessId}/digitalCredentials/${credentialType}` - return axios.post(url) - .catch(error => { - // eslint-disable-next-line no-console - console.log(error.message) - return null - }) + return axios.post(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) + } + + /** + * Revokes a digital credential. + * @param businessId The business identifier (aka entity inc no) + * @param credentialId The credential identifier + * @returns the axios response + */ + static async revokeCredential (businessId: string, credentialId: string): Promise { + const url = `businesses/${businessId}/digitalCredentials/${credentialId}/revoke` + return axios.post(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) } } From 49c2baaa2fffa5280e5ad8c655b2b4b9e2b027b6 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 19 Oct 2023 02:36:05 +0000 Subject: [PATCH 12/50] feat: DigitalCredentials component: add replacement dialogs Signed-off-by: Akiff Manji --- .../CredentialsDashboard.vue | 43 +++++- .../DigitalCredentials/CredentialsMenu.vue | 11 +- .../DigitalCredentials/CredentialsStepper.vue | 7 - .../DigitalCredentials/CredentialsTable.vue | 9 +- .../ConfirmReplaceCredentialDialog.vue | 123 ++++++++++++++++++ .../dialogs/ConfirmRevokeCredentialDialog.vue | 2 +- .../dialogs/ReplaceCredentialErrorDialog.vue | 64 +++++++++ src/components/dialogs/index.ts | 4 + .../digitalCredentials-interface.ts | 1 + src/services/legal-services.ts | 29 +++++ 10 files changed, 282 insertions(+), 11 deletions(-) create mode 100644 src/components/dialogs/ConfirmReplaceCredentialDialog.vue create mode 100644 src/components/dialogs/ReplaceCredentialErrorDialog.vue diff --git a/src/components/DigitalCredentials/CredentialsDashboard.vue b/src/components/DigitalCredentials/CredentialsDashboard.vue index df662fbb1..90ee64cb4 100644 --- a/src/components/DigitalCredentials/CredentialsDashboard.vue +++ b/src/components/DigitalCredentials/CredentialsDashboard.vue @@ -8,6 +8,13 @@ @proceed="revokeCredential(issuedCredential)" /> + + @@ -30,6 +37,7 @@ v-if="issuedCredentials?.length" :issuedCredentials="issuedCredentials" @onPromptConfirmRevokeCredential="displayConfirmRevokeCredentialDialog" + @onPromptConfirmReplaceCredential="displayConfirmReplaceCredentialDialog" /> @@ -53,9 +61,12 @@ import { LegalServices } from '@/services' import CredentialsInfo from '@/components/DigitalCredentials/CredentialsInfo.vue' import CredentialsLanding from '@/components/DigitalCredentials/CredentialsLanding.vue' import CredentialsTable from '@/components/DigitalCredentials/CredentialsTable.vue' +import ConfirmReplaceCredentialDialog from '@/components/dialogs/ConfirmReplaceCredentialDialog.vue' import ConfirmRevokeCredentialDialog from '@/components/dialogs/ConfirmRevokeCredentialDialog.vue' import CredentialRevokedDialog from '@/components/dialogs/CredentialRevokedDialog.vue' +import ReplaceCredentialErrorDialog from '@/components/dialogs/ReplaceCredentialErrorDialog.vue' import RevokeCredentialErrorDialog from '@/components/dialogs/RevokeCredentialErrorDialog.vue' +import { Routes } from '@/enums' @Component({ components: { @@ -63,7 +74,9 @@ import RevokeCredentialErrorDialog from '@/components/dialogs/RevokeCredentialEr CredentialsLanding, CredentialsTable, ConfirmRevokeCredentialDialog, + ConfirmReplaceCredentialDialog, CredentialRevokedDialog, + ReplaceCredentialErrorDialog, RevokeCredentialErrorDialog } }) @@ -71,7 +84,9 @@ export default class CredentialsDashboard extends Vue { @Getter(useBusinessStore) getIdentifier!: string; confirmRevokeCredentialDialog = false; + confirmReplaceCredentialDialog = false; credentialRevokedDialog = false; + replaceCredentialErrorDialog = false; revokeCredentialErrorDialog = false; issuedCredential: DigitalCredentialIF = null; issuedCredentials: Array = []; @@ -95,6 +110,16 @@ export default class CredentialsDashboard extends Vue { this.confirmRevokeCredentialDialog = false } + displayConfirmReplaceCredentialDialog (issuedCredential: DigitalCredentialIF): void { + this.issuedCredential = issuedCredential + this.confirmReplaceCredentialDialog = true + } + + hideConfirmReplaceCredentialDialog (): void { + this.issuedCredential = null + this.confirmReplaceCredentialDialog = false + } + async revokeCredential (issuedCredential: DigitalCredentialIF): Promise { const revoked = await LegalServices.revokeCredential(this.getIdentifier, issuedCredential.credentialId) .finally(() => { @@ -108,5 +133,21 @@ export default class CredentialsDashboard extends Vue { await this.getCredentials() } } + + async replaceCredential (issuedCredential: DigitalCredentialIF): Promise { + let revokedCredential = issuedCredential.isRevoked ? {} : null + if (!issuedCredential.isRevoked) { + revokedCredential = await LegalServices.revokeCredential(this.getIdentifier, issuedCredential.credentialId) + } + const removedCredential = await LegalServices.removeCredential(this.getIdentifier, issuedCredential.credentialId) + const removedConnection = await LegalServices.removeCredentialConnection(this.getIdentifier) + + this.hideConfirmReplaceCredentialDialog() + if (!(revokedCredential && removedCredential && removedConnection)) { + this.replaceCredentialErrorDialog = true + } else { + this.$router.push({ name: Routes.ISSUE }) + } + } } diff --git a/src/components/DigitalCredentials/CredentialsMenu.vue b/src/components/DigitalCredentials/CredentialsMenu.vue index d6c1bcf9a..8fee64f08 100644 --- a/src/components/DigitalCredentials/CredentialsMenu.vue +++ b/src/components/DigitalCredentials/CredentialsMenu.vue @@ -30,7 +30,10 @@ - + Replace Credential @@ -63,6 +66,12 @@ export default class CredentialsMenu extends Vue { handleConfirmRevokeCredential (issuedCredential: DigitalCredentialIF): DigitalCredentialIF { return issuedCredential } + + /** Emits an event to confirm replace credential. */ + @Emit('onConfirmReplaceCredential') + handleConfirmReplaceCredential (issuedCredential: DigitalCredentialIF): DigitalCredentialIF { + return issuedCredential + } } diff --git a/src/components/DigitalCredentials/CredentialsStepper.vue b/src/components/DigitalCredentials/CredentialsStepper.vue index 618b5e337..bd0710a58 100644 --- a/src/components/DigitalCredentials/CredentialsStepper.vue +++ b/src/components/DigitalCredentials/CredentialsStepper.vue @@ -169,13 +169,6 @@ export default class CredentialsStepper extends Vue { }, { id: 3, - html: ` - In your BC Wallet app, check your notifications. You should have one to get a Person Credential. - Go through the process of accepting it into your wallet. - ` - }, - { - id: 4, html: ` Check your Business Card credentials on the Credential dashboard. diff --git a/src/components/DigitalCredentials/CredentialsTable.vue b/src/components/DigitalCredentials/CredentialsTable.vue index 01b8f122e..3d5d5df99 100644 --- a/src/components/DigitalCredentials/CredentialsTable.vue +++ b/src/components/DigitalCredentials/CredentialsTable.vue @@ -22,7 +22,7 @@ {{ formatCredentialType(item.credentialType) }} @@ -98,6 +99,12 @@ export default class CredentialsTable extends Mixins(DateMixin) { promptConfirmRevokeCredential (issuedCredential: DigitalCredentialIF): DigitalCredentialIF { return issuedCredential } + + /** Emits an event to prompt confirmation to replace credential. */ + @Emit('onPromptConfirmReplaceCredential') + promptConfirmReplaceCredential (issuedCredential: DigitalCredentialIF): DigitalCredentialIF { + return issuedCredential + } } diff --git a/src/components/dialogs/ConfirmReplaceCredentialDialog.vue b/src/components/dialogs/ConfirmReplaceCredentialDialog.vue new file mode 100644 index 000000000..270d1786e --- /dev/null +++ b/src/components/dialogs/ConfirmReplaceCredentialDialog.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/components/dialogs/ConfirmRevokeCredentialDialog.vue b/src/components/dialogs/ConfirmRevokeCredentialDialog.vue index 02f2ea5cf..18e028465 100644 --- a/src/components/dialogs/ConfirmRevokeCredentialDialog.vue +++ b/src/components/dialogs/ConfirmRevokeCredentialDialog.vue @@ -39,7 +39,7 @@ id="dialog-text" class="warning-text" > - This will revoke the credential from a BC Wallet. It cannot be reversed. Do you still want to continue? + This will revoke the credential from your BC Wallet. It cannot be reversed. Do you still want to continue?

diff --git a/src/components/dialogs/ReplaceCredentialErrorDialog.vue b/src/components/dialogs/ReplaceCredentialErrorDialog.vue new file mode 100644 index 000000000..8901900de --- /dev/null +++ b/src/components/dialogs/ReplaceCredentialErrorDialog.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/components/dialogs/index.ts b/src/components/dialogs/index.ts index 357661fcb..201a0f87a 100644 --- a/src/components/dialogs/index.ts +++ b/src/components/dialogs/index.ts @@ -5,6 +5,7 @@ import CancelPaymentErrorDialog from './CancelPaymentErrorDialog.vue' import CoaWarningDialog from './CoaWarningDialog.vue' import { ConfirmDialog } from '@bcrs-shared-components/confirm-dialog' import ConfirmDissolutionDialog from './ConfirmDissolutionDialog.vue' +import ConfirmReplaceCredentialDialog from './ConfirmReplaceCredentialDialog.vue' import ConfirmRevokeCredentialDialog from './ConfirmRevokeCredentialDialog.vue' import CredentialRevokedDialog from './CredentialRevokedDialog.vue' import DashboardUnavailableDialog from './DashboardUnavailableDialog.vue' @@ -18,6 +19,7 @@ import NameRequestInvalidDialog from './NameRequestInvalidDialog.vue' import NotInGoodStandingDialog from '@/components/dialogs/NotInGoodStandingDialog.vue' import PaymentErrorDialog from './PaymentErrorDialog.vue' import ResumeErrorDialog from './ResumeErrorDialog.vue' +import ReplaceCredentialErrorDialog from './ReplaceCredentialErrorDialog.vue' import RevokeCredentialErrorDialog from './RevokeCredentialErrorDialog.vue' import SaveErrorDialog from './SaveErrorDialog.vue' import StaffPaymentDialog from './StaffPaymentDialog.vue' @@ -30,6 +32,7 @@ export { CoaWarningDialog, ConfirmDialog, ConfirmDissolutionDialog, + ConfirmReplaceCredentialDialog, ConfirmRevokeCredentialDialog, CredentialRevokedDialog, DashboardUnavailableDialog, @@ -43,6 +46,7 @@ export { NotInGoodStandingDialog, PaymentErrorDialog, ResumeErrorDialog, + ReplaceCredentialErrorDialog, RevokeCredentialErrorDialog, SaveErrorDialog, StaffPaymentDialog diff --git a/src/interfaces/digitalCredentials-interface.ts b/src/interfaces/digitalCredentials-interface.ts index b88d1dbf5..f85879b4a 100644 --- a/src/interfaces/digitalCredentials-interface.ts +++ b/src/interfaces/digitalCredentials-interface.ts @@ -7,6 +7,7 @@ export interface DigitalCredentialIF { isIssued: boolean dateOfIssue: string isRevoked: boolean + isDeleted: boolean } export interface WalletConnectionIF { diff --git a/src/services/legal-services.ts b/src/services/legal-services.ts index 8ecb9b0b0..c36f13a36 100644 --- a/src/services/legal-services.ts +++ b/src/services/legal-services.ts @@ -354,6 +354,20 @@ export default class LegalServices { }) } + /** + * Removes a credential connection + * @param businessId the business identifier (aka entity inc no) + * @returns the axios response + */ + static async removeCredentialConnection (businessId: string): Promise { + const url = `businesses/${businessId}/digitalCredentials/connection` + return axios.delete(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) + } + /** * Sends a digital credentials offer. * @param businessId The business identifier (aka entity inc no) @@ -386,4 +400,19 @@ export default class LegalServices { return null }) } + + /** + * Removes a digital credential. + * @param businessId The business identifier (aka entity inc no) + * @param credentialId The credential identifier + * @returns the axios response + */ + static async removeCredential (businessId: string, credentialId: string): Promise { + const url = `businesses/${businessId}/digitalCredentials/${credentialId}` + return axios.delete(url).catch((error) => { + // eslint-disable-next-line no-console + console.log(error.message) + return null + }) + } } From fbfdc99b0127d3d6833b1b1bde7219f05a40b7e3 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 19 Oct 2023 02:43:15 +0000 Subject: [PATCH 13/50] feat: devcontainer config Signed-off-by: Akiff Manji --- .devcontainer/devcontainer.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..19f7f6833 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node +{ + "name": "Node.js & TypeScript", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye" + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} From ae9faa61a83ead8e252c2661292a134a38f95509 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 19 Oct 2023 15:45:24 +0000 Subject: [PATCH 14/50] chore: fix linting errors Signed-off-by: Akiff Manji --- .../DigitalCredentials/CredentialsStepper.vue | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/components/DigitalCredentials/CredentialsStepper.vue b/src/components/DigitalCredentials/CredentialsStepper.vue index bd0710a58..089249d1a 100644 --- a/src/components/DigitalCredentials/CredentialsStepper.vue +++ b/src/components/DigitalCredentials/CredentialsStepper.vue @@ -11,24 +11,52 @@

Steps to get your credentials:

- + -
- {{ step.id }} -
+
1
+
+ + Have the + + BC Wallet app + installed on your mobile phone. +
+
+ + + class="credentials-stepper-number ml-n4 my-n4 px-8 + font-weight-bold align-self-stretch d-flex rounded-l" + > +
2
+
+ + Scan the QR code with your BC Wallet to get your Business Card Credential and accept in your BC + Wallet app. + +
+
+ + + +
3
+
+ + Check your Business Card credentials on the + Credential dashboard. +
@@ -84,7 +112,6 @@ style="width: 200px; height: 200px" > @@ -140,9 +167,7 @@ import QrcodeVue from 'qrcode.vue' import { DigitalCredentialIF, WalletConnectionIF } from '@/interfaces' import CredentialsWebSocket from '@/components/DigitalCredentials/CredentialsWebSocket.vue' -Component.registerHooks([ - 'beforeRouteEnter' -]) +Component.registerHooks(['beforeRouteEnter']) // Create a component that extends the Vue class called CredentialsStepper @Component({ components: { QrcodeVue, CredentialsWebSocket } }) @@ -152,29 +177,6 @@ export default class CredentialsStepper extends Vue { credentialTypes = DigitalCredentialTypes; credentialConnection: WalletConnectionIF = null; issuedCredential: DigitalCredentialIF = null; - steps = [ - { - id: 1, - html: ` - Have the - BC Wallet app installed on your mobile phone. - ` - }, - { - id: 2, - html: ` - Scan the QR code with your BC Wallet to get your Business Card Credential and accept in your BC Wallet app. - ` - }, - { - id: 3, - html: ` - Check your Business Card credentials on the - Credential dashboard. - ` - } - ]; async beforeRouteEnter (to, from, next): Promise { next(async (_this) => { From 4e43dc78311ff2db6ad2a640b74fcd91f9c74a3e Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Fri, 20 Oct 2023 16:25:04 +0000 Subject: [PATCH 15/50] chore: bump version number Signed-off-by: Akiff Manji --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 422af5b91..787db9489 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "business-filings-ui", - "version": "6.9.2", + "version": "7.9.2", "private": true, "appName": "Filings UI", "sbcName": "SBC Common Components", @@ -89,4 +89,4 @@ "vuex-module-decorators": "^1.2.0", "wscat": "^5.2.0" } -} +} \ No newline at end of file From ff10cbc50e800fa45fe9d1bc87406f122b14a0e9 Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Fri, 20 Oct 2023 16:27:28 +0000 Subject: [PATCH 16/50] chore: rename route for specificity Signed-off-by: Akiff Manji --- .../CredentialsDashboard.vue | 70 ++++++------------- .../DigitalCredentials/CredentialsLanding.vue | 21 ++---- src/enums/routes.ts | 2 +- src/resources/DigitalCredentialRoutes.ts | 6 +- 4 files changed, 34 insertions(+), 65 deletions(-) diff --git a/src/components/DigitalCredentials/CredentialsDashboard.vue b/src/components/DigitalCredentials/CredentialsDashboard.vue index 90ee64cb4..c98d37faa 100644 --- a/src/components/DigitalCredentials/CredentialsDashboard.vue +++ b/src/components/DigitalCredentials/CredentialsDashboard.vue @@ -1,50 +1,26 @@