From 1d4f2ac197d20fb3d2212a20e26bcccf74a101bb Mon Sep 17 00:00:00 2001 From: Aleksei Lunin <alexey.lunin@vereign.com> Date: Mon, 30 Oct 2023 10:20:48 +0300 Subject: [PATCH] add Auth page --- apps/dashboard/src/api/agent-client.ts | 77 ++++++--- apps/dashboard/src/api/gateway-client.ts | 148 +++++++++++++----- apps/dashboard/src/api/index.ts | 38 ++++- apps/dashboard/src/components/App/index.tsx | 22 ++- .../src/components/BasicMessageItem/index.tsx | 7 +- .../BasicMessageItem/styles.module.scss | 2 +- .../BasicMessageList/BasicMessageListStore.ts | 21 +++ .../BasicMessageList/CreateMessage/index.tsx | 42 +++++ .../src/components/BasicMessageList/index.tsx | 25 ++- .../src/components/ProofItem/index.tsx | 12 +- .../components/ProofList/ProofListStore.ts | 2 +- .../src/components/Sidebar/index.tsx | 3 + apps/dashboard/src/main.tsx | 9 +- .../index.tsx | 81 ++++++++++ .../styles.module.scss | 4 + .../modals/IssueCredentialDialog/index.tsx | 10 +- .../RequestProofDialogStore.ts} | 12 +- .../index.tsx | 33 ++-- .../styles.module.scss | 0 .../ViewConnectionlessProofRequest/index.tsx | 68 ++++++++ .../styles.module.scss | 46 ++++++ apps/dashboard/src/routes/config.ts | 6 + .../src/routes/pages/AuthPage/Login.tsx | 50 ++++++ .../src/routes/pages/AuthPage/LoginStore.ts | 61 ++++++++ .../src/routes/pages/AuthPage/Register.tsx | 50 ++++++ .../routes/pages/AuthPage/RegisterStore.ts | 63 ++++++++ .../src/routes/pages/AuthPage/index.tsx | 34 ++++ .../pages/ConnectionCreatePage/index.tsx | 16 +- .../routes/pages/ConnectionViewPage/index.tsx | 6 +- .../src/routes/pages/ProofListPage/index.tsx | 30 ++++ apps/dashboard/src/store/modalStore.tsx | 47 +++--- 31 files changed, 876 insertions(+), 149 deletions(-) create mode 100644 apps/dashboard/src/components/BasicMessageList/CreateMessage/index.tsx create mode 100644 apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/index.tsx create mode 100644 apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/styles.module.scss rename apps/dashboard/src/modals/{IssueProofRequestDialog/IssueProofRequestDialog.ts => RequestProofDialog/RequestProofDialogStore.ts} (93%) rename apps/dashboard/src/modals/{IssueProofRequestDialog => RequestProofDialog}/index.tsx (72%) rename apps/dashboard/src/modals/{IssueProofRequestDialog => RequestProofDialog}/styles.module.scss (100%) create mode 100644 apps/dashboard/src/modals/ViewConnectionlessProofRequest/index.tsx create mode 100644 apps/dashboard/src/modals/ViewConnectionlessProofRequest/styles.module.scss create mode 100644 apps/dashboard/src/routes/pages/AuthPage/Login.tsx create mode 100644 apps/dashboard/src/routes/pages/AuthPage/LoginStore.ts create mode 100644 apps/dashboard/src/routes/pages/AuthPage/Register.tsx create mode 100644 apps/dashboard/src/routes/pages/AuthPage/RegisterStore.ts create mode 100644 apps/dashboard/src/routes/pages/AuthPage/index.tsx diff --git a/apps/dashboard/src/api/agent-client.ts b/apps/dashboard/src/api/agent-client.ts index 91caad7e..e6fcf21b 100644 --- a/apps/dashboard/src/api/agent-client.ts +++ b/apps/dashboard/src/api/agent-client.ts @@ -404,7 +404,7 @@ export class RestControllerClient { return Promise.resolve<CreddefRecordDto>(null as any); } - issueCredential(body: IssueCredentialRequestDto): Promise<CredentialRecordDto> { + issueCredential(body: IssueCredentialRequestDto): Promise<CredentialIssueResponseDto> { let url_ = this.baseUrl + "/api/v1/credentials/issue"; url_ = url_.replace(/[?&]$/, ""); @@ -424,13 +424,13 @@ export class RestControllerClient { }); } - protected processIssueCredential(response: Response): Promise<CredentialRecordDto> { + protected processIssueCredential(response: Response): Promise<CredentialIssueResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; - result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as CredentialRecordDto; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as CredentialIssueResponseDto; return result201; }); } else if (status !== 200 && status !== 204) { @@ -438,7 +438,7 @@ export class RestControllerClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve<CredentialRecordDto>(null as any); + return Promise.resolve<CredentialIssueResponseDto>(null as any); } credentials(): Promise<CredentialRecordDto[]> { @@ -511,7 +511,7 @@ export class RestControllerClient { return Promise.resolve<CredentialRecordDto[]>(null as any); } - getCredentialById(id: string): Promise<any> { + getCredentialById(id: string): Promise<CredentialRecordDto> { let url_ = this.baseUrl + "/api/v1/credentials/{id}"; if (id === undefined || id === null) throw new Error("The parameter 'id' must be defined."); @@ -530,13 +530,13 @@ export class RestControllerClient { }); } - protected processGetCredentialById(response: Response): Promise<any> { + protected processGetCredentialById(response: Response): Promise<CredentialRecordDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; - result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as any; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as CredentialRecordDto; return result200; }); } else if (status !== 200 && status !== 204) { @@ -544,7 +544,7 @@ export class RestControllerClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve<any>(null as any); + return Promise.resolve<CredentialRecordDto>(null as any); } deleteCredentialById(id: string): Promise<void> { @@ -931,7 +931,7 @@ export class RestControllerClient { return Promise.resolve<void>(null as any); } - issueProof(body: IssueProofRequestDto): Promise<any> { + issueProof(body: IssueProofRequestDto): Promise<ProofIssueResponseDto> { let url_ = this.baseUrl + "/api/v1/credentials/proof/issue"; url_ = url_.replace(/[?&]$/, ""); @@ -951,13 +951,13 @@ export class RestControllerClient { }); } - protected processIssueProof(response: Response): Promise<any> { + protected processIssueProof(response: Response): Promise<ProofIssueResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; - result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as any; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ProofIssueResponseDto; return result201; }); } else if (status !== 200 && status !== 204) { @@ -965,10 +965,10 @@ export class RestControllerClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve<any>(null as any); + return Promise.resolve<ProofIssueResponseDto>(null as any); } - acceptProof(body: ProofReqDto): Promise<any> { + acceptProof(body: ProofReqDto): Promise<ProofRecordDto> { let url_ = this.baseUrl + "/api/v1/credentials/proof/accept"; url_ = url_.replace(/[?&]$/, ""); @@ -988,13 +988,13 @@ export class RestControllerClient { }); } - protected processAcceptProof(response: Response): Promise<any> { + protected processAcceptProof(response: Response): Promise<ProofRecordDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; - result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as any; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ProofRecordDto; return result201; }); } else if (status !== 200 && status !== 204) { @@ -1002,7 +1002,7 @@ export class RestControllerClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve<any>(null as any); + return Promise.resolve<ProofRecordDto>(null as any); } declineProofRequest(proof_record_id: string): Promise<ProofRecordDto> { @@ -1150,7 +1150,7 @@ export interface IssueCredentialAttributes { } export interface IssueCredentialRequestDto { - connectionId: string; + connectionId?: string; credentialDefinitionId: string; attributes: IssueCredentialAttributes[]; @@ -1169,6 +1169,14 @@ export interface CredentialRecordDto { [key: string]: any; } +export interface CredentialIssueResponseDto { + credentialUrl: string | null; + shortCredentialUrl: string | null; + credentialRecord: CredentialRecordDto; + + [key: string]: any; +} + export interface CredentialFilterDto { states?: States[]; connectionId?: string; @@ -1178,16 +1186,18 @@ export interface CredentialFilterDto { export interface MakeBasicMessageRequestDto { connectionId: string; - message: string; + content: string; [key: string]: any; } export interface MessageRecordDto { connectionId: string; + role: MessageRecordDtoRole; + sentTime: string; from?: string; to?: string; - message: string; + content: string; id: string; createdAt: Date; updatedAt?: Date; @@ -1204,7 +1214,7 @@ export interface MessageFilterDto { export interface ProofRecordDto { connectionId?: string; - state: string; + state: ProofRecordDtoState; id: string; createdAt: Date; updatedAt?: Date; @@ -1235,8 +1245,16 @@ export interface IssueProofRequestDto { [key: string]: any; } +export interface ProofIssueResponseDto { + proofUrl: string | null; + shortProofUrl: string | null; + proofRecord: ProofRecordDto; + + [key: string]: any; +} + export interface ProofReqDto { - proofRecordId: string; + proofId: string; proofUrl: string; [key: string]: any; @@ -1270,11 +1288,28 @@ export enum States { Abandoned = "abandoned", } +export enum MessageRecordDtoRole { + Sender = "sender", + Receiver = "receiver", +} + export enum MessageFilterDtoRole { Sender = "sender", Receiver = "receiver", } +export enum ProofRecordDtoState { + ProposalSent = "proposal-sent", + ProposalReceived = "proposal-received", + RequestSent = "request-sent", + RequestReceived = "request-received", + PresentationSent = "presentation-sent", + PresentationReceived = "presentation-received", + Declined = "declined", + Abandoned = "abandoned", + Done = "done", +} + export enum States2 { ProposalSent = "proposal-sent", ProposalReceived = "proposal-received", diff --git a/apps/dashboard/src/api/gateway-client.ts b/apps/dashboard/src/api/gateway-client.ts index cbc879c4..cd58bbf3 100644 --- a/apps/dashboard/src/api/gateway-client.ts +++ b/apps/dashboard/src/api/gateway-client.ts @@ -41,7 +41,13 @@ export class ConnectionControllerClient { protected processCreateInvitation(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -88,7 +94,13 @@ export class ConnectionControllerClient { protected processAcceptInvitation(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -137,7 +149,7 @@ export class ConnectionControllerClient { protected processList(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -183,7 +195,7 @@ export class ConnectionControllerClient { protected processGetConnectionById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -229,7 +241,7 @@ export class ConnectionControllerClient { protected processDeleteConnectionById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -287,7 +299,13 @@ export class AttestationControllerClient { protected processCreateSchema(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -336,7 +354,7 @@ export class AttestationControllerClient { protected processListSchema(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -383,7 +401,13 @@ export class AttestationControllerClient { protected processGetSchemaById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -432,7 +456,7 @@ export class AttestationControllerClient { protected processCredentialDefinitions(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -479,7 +503,13 @@ export class AttestationControllerClient { protected processGetCredentialDefinitionsById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -532,7 +562,13 @@ export class AttestationControllerClient { protected processCreateCredentialDefinition(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -585,7 +621,13 @@ export class AttestationControllerClient { protected processIssueCredential(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -634,7 +676,7 @@ export class AttestationControllerClient { protected processCredentials(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -681,7 +723,7 @@ export class AttestationControllerClient { protected processCredentialsQuery(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -689,7 +731,9 @@ export class AttestationControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 500) { return response.text().then((_responseText) => { @@ -731,7 +775,7 @@ export class AttestationControllerClient { protected processGetCredentialById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -783,7 +827,7 @@ export class AttestationControllerClient { protected processDeleteCredentialById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -832,7 +876,7 @@ export class AttestationControllerClient { protected processGetCredentialOffers(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -878,7 +922,7 @@ export class AttestationControllerClient { protected processAcceptCredential(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -886,7 +930,9 @@ export class AttestationControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 500) { return response.text().then((_responseText) => { @@ -928,7 +974,7 @@ export class AttestationControllerClient { protected processDeclineCredential(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -936,7 +982,9 @@ export class AttestationControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 500) { return response.text().then((_responseText) => { @@ -979,7 +1027,7 @@ export class AttestationControllerClient { protected processSendMessage(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -987,7 +1035,9 @@ export class AttestationControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 400) { return response.text().then((_responseText) => { @@ -1036,7 +1086,7 @@ export class AttestationControllerClient { protected processQueryMessages(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1044,7 +1094,9 @@ export class AttestationControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 400) { return response.text().then((_responseText) => { @@ -1092,7 +1144,7 @@ export class AttestationControllerClient { protected processDeleteMessage(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1152,7 +1204,7 @@ export class ProofControllerClient { protected processProofs(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1199,7 +1251,7 @@ export class ProofControllerClient { protected processProofsQuery(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1207,7 +1259,9 @@ export class ProofControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 500) { return response.text().then((_responseText) => { @@ -1249,7 +1303,7 @@ export class ProofControllerClient { protected processGetProofById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1295,7 +1349,7 @@ export class ProofControllerClient { protected processDeleteProofById(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1316,7 +1370,7 @@ export class ProofControllerClient { } /** - * Request proof for credential + * Issue proof for credential * @return Request is accepted for execution, the response id will match the event id received from the web socket */ issueProof(body: IssueProofRequestDto): Promise<GatewayAcceptedResponseDto> { @@ -1342,7 +1396,13 @@ export class ProofControllerClient { protected processIssueProof(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1395,7 +1455,13 @@ export class ProofControllerClient { protected processAcceptProof(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 201) { + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result200; + }); + } else if (status === 201) { return response.text().then((_responseText) => { let result201: any = null; result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1441,7 +1507,7 @@ export class ProofControllerClient { protected processDeclineProofRequest(response: Response): Promise<GatewayAcceptedResponseDto> { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 200 || status === 201) { + if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; @@ -1449,7 +1515,9 @@ export class ProofControllerClient { }); } else if (status === 201) { return response.text().then((_responseText) => { - return throwException("A server side error occurred.", status, _responseText, _headers); + let result201: any = null; + result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as GatewayAcceptedResponseDto; + return result201; }); } else if (status === 500) { return response.text().then((_responseText) => { @@ -1514,7 +1582,7 @@ export interface IssueCredentialAttributes { } export interface IssueCredentialRequestDto { - connectionId: string; + connectionId?: string; credentialDefinitionId: string; attributes: IssueCredentialAttributes[]; @@ -1530,7 +1598,7 @@ export interface CredentialFilterDto { export interface MakeBasicMessageRequestDto { connectionId: string; - message: string; + content: string; [key: string]: any; } @@ -1566,7 +1634,7 @@ export interface IssueProofRequestDto { } export interface ProofReqDto { - proofRecordId: string; + proofId: string; proofUrl: string; [key: string]: any; diff --git a/apps/dashboard/src/api/index.ts b/apps/dashboard/src/api/index.ts index 4631687a..f009e21b 100644 --- a/apps/dashboard/src/api/index.ts +++ b/apps/dashboard/src/api/index.ts @@ -1,7 +1,8 @@ import { ConnectionRecordDto, CreateCredentialDefinitionRequestDto, - CreateInvitationResponseDto, CreateSchemaRequestDto, + CreateInvitationResponseDto, + CreateSchemaRequestDto, CreddefRecordDto, IssueCredentialRequestDto, IdReqDto, @@ -14,13 +15,16 @@ import { ProofRecordDto, ProofFilterDto, IssueProofRequestDto, - ProofReqDto + ProofReqDto, + ProofIssueResponseDto, + CredentialIssueResponseDto } from "./agent-client"; import { ConnectionControllerClient, AttestationControllerClient, - ProofControllerClient, GatewayAcceptedResponseDto, + ProofControllerClient, + GatewayAcceptedResponseDto, } from "./gateway-client"; @@ -47,6 +51,8 @@ interface GatewayMessageType { // type RestControllerClientType = InstanceType<typeof RestControllerClient>; // type OmittedRestControllerClientType = Omit<RestControllerClientType, 'http' | 'baseUrl'>; +type BasicMessageReceivedCallback = (event: MessageRecordDto) => void; + class ApiClient /* implements OmittedRestControllerClientType */ { private _ws!: WebSocket; private _wsMessages: GatewayMessageType[] = []; @@ -55,6 +61,19 @@ class ApiClient /* implements OmittedRestControllerClientType */ { private _attestation!: AttestationControllerClient; private _proof!: ProofControllerClient; + private _messageCallbacks: { id: string, cb: BasicMessageReceivedCallback }[] = []; + public subscribeToBasicMessages = (cb: (event: MessageRecordDto) => void) => { + const id = Math.random().toString(); + this._messageCallbacks.push({ id: id, cb }); + + return () => { + const index = this._messageCallbacks.findIndex(p => p.id === id); + if (index >= 0) { + this._messageCallbacks.splice(index, 1); + } + }; + } + /* rest api methods */ public createInvitation = (): Promise<CreateInvitationResponseDto> => this._waitForResponse(this._connection.createInvitation()) @@ -86,7 +105,7 @@ class ApiClient /* implements OmittedRestControllerClientType */ { public createCredentialDefinition = (body: CreateCredentialDefinitionRequestDto): Promise<CreddefRecordDto> => this._waitForResponse(this._attestation.createCredentialDefinition(body)); - public issueCredential = (body: IssueCredentialRequestDto): Promise<CredentialRecordDto> => + public issueCredential = (body: IssueCredentialRequestDto): Promise<CredentialIssueResponseDto> => this._waitForResponse(this._attestation.issueCredential(body)); public credentials = (): Promise<CredentialRecordDto[]> => @@ -132,7 +151,7 @@ class ApiClient /* implements OmittedRestControllerClientType */ { public deleteProofById = (proof_record_id: string): Promise<void> => this._waitForResponse(this._proof.deleteProofById(proof_record_id)); - public issueProof = (body: IssueProofRequestDto): Promise<ProofRecordDto> => + public issueProof = (body: IssueProofRequestDto): Promise<ProofIssueResponseDto> => this._waitForResponse(this._proof.issueProof(body)); public acceptProof = (body: ProofReqDto): Promise<ProofRecordDto> => @@ -230,6 +249,7 @@ class ApiClient /* implements OmittedRestControllerClientType */ { ws.addEventListener('message', (event) => { console.log('Message from server: ', event.data); const data = JSON.parse(event.data, this.jsonParseReviver); + this._checkIncomingBasicMessage(data); this._wsMessages.push(data); }); @@ -247,6 +267,14 @@ class ApiClient /* implements OmittedRestControllerClientType */ { console.error(`WebSocket Error: ${error}`); }); } + + private _checkIncomingBasicMessage = (event: GatewayMessageType) => { + if (event.source === "agent-basic-message-afj") { + const data = event.data as MessageRecordDto; + + this._messageCallbacks.forEach(subscription => subscription.cb(data)); + } + } } export default new ApiClient(); diff --git a/apps/dashboard/src/components/App/index.tsx b/apps/dashboard/src/components/App/index.tsx index a4846785..7d41907b 100644 --- a/apps/dashboard/src/components/App/index.tsx +++ b/apps/dashboard/src/components/App/index.tsx @@ -1,18 +1,36 @@ import React, { useEffect, useState } from "react"; -import {Spin} from "antd"; -import { ToastContainer } from "react-toastify"; +import {Button, Spin} from "antd"; +import {toast, ToastContainer} from "react-toastify"; import PageRoutes from "@dashboard/routes"; import Sidebar from "../Sidebar"; import modalStore from "@dashboard/store/modalStore"; import {observer} from "mobx-react"; +import api from "@dashboard/api"; +import {useNavigate} from "react-router-dom"; +import config from "@dashboard/routes/config"; import s from "./styles.module.scss"; const App = observer(() => { + const navigate = useNavigate(); const [isAppLoading, setIsAppLoading] = useState(true); useEffect(() => { (async () => { + api.subscribeToBasicMessages((message) => { + toast.info(( + <div> + You received a new message from {message.from || message.connectionId}. + <div> + <Button type="primary" onClick={() => { + navigate(config.connection_view.getLink(message.connectionId)) + }}> + View message + </Button> + </div> + </div> + )); + }); setIsAppLoading(false); })(); }, []); diff --git a/apps/dashboard/src/components/BasicMessageItem/index.tsx b/apps/dashboard/src/components/BasicMessageItem/index.tsx index 1d593ed8..8e057cad 100644 --- a/apps/dashboard/src/components/BasicMessageItem/index.tsx +++ b/apps/dashboard/src/components/BasicMessageItem/index.tsx @@ -14,13 +14,10 @@ const BasicMessageItem = observer(({ item, onClick }: BasicMessageItemProps) => return ( <div className={classNames(s.item, { [s.clickable]: onClick })} onClick={onClick}> <div> - From: {item.from} + Role: {item.role} </div> <div> - To: {item.to} - </div> - <div> - Message: {item.message} + Message: {item.content} </div> <div className={s.createdAt}> diff --git a/apps/dashboard/src/components/BasicMessageItem/styles.module.scss b/apps/dashboard/src/components/BasicMessageItem/styles.module.scss index 221d8432..5a5a0d4c 100644 --- a/apps/dashboard/src/components/BasicMessageItem/styles.module.scss +++ b/apps/dashboard/src/components/BasicMessageItem/styles.module.scss @@ -1,6 +1,6 @@ .item { display: flex; - flex-direction: row; + flex-direction: column; margin: 4px 0; border: 1px solid rgba(0, 0, 0, 0.1); diff --git a/apps/dashboard/src/components/BasicMessageList/BasicMessageListStore.ts b/apps/dashboard/src/components/BasicMessageList/BasicMessageListStore.ts index 52c38947..4f416bb6 100644 --- a/apps/dashboard/src/components/BasicMessageList/BasicMessageListStore.ts +++ b/apps/dashboard/src/components/BasicMessageList/BasicMessageListStore.ts @@ -6,6 +6,7 @@ import {MessageRecordDto} from "@dashboard/api/agent-client"; class BasicMessageListStore { public loading = false; + public sendingMessage = false; public items: MessageRecordDto[] = []; constructor() { makeAutoObservable(this); @@ -27,6 +28,26 @@ class BasicMessageListStore { runInAction(() => this.loading = false); } } + + public sendMessage = async (connectionId: string, content: string) => { + runInAction(() => this.sendingMessage = true); + try { + const message = await api.sendMessage({ + connectionId: connectionId, + content: content + }); + runInAction(() => { + this.items.push(message); + this.sendingMessage = false; + }); + return true; + } catch (e: any) { + toast(e.message); + console.error(e); + runInAction(() => this.sendingMessage = false); + } + return false; + } } export type { BasicMessageListStore }; diff --git a/apps/dashboard/src/components/BasicMessageList/CreateMessage/index.tsx b/apps/dashboard/src/components/BasicMessageList/CreateMessage/index.tsx new file mode 100644 index 00000000..196ffa17 --- /dev/null +++ b/apps/dashboard/src/components/BasicMessageList/CreateMessage/index.tsx @@ -0,0 +1,42 @@ +import React, {useState} from "react"; +import {observer} from "mobx-react"; +import {Button, Input} from 'antd'; + +export interface CreateMessageProps { + onCreateMessage: (message: string) => Promise<boolean>; +} + +const CreateMessage: React.FC<CreateMessageProps> = observer(({ onCreateMessage }) => { + const [text, setText] = useState(''); + const [loading, setLoading] = useState(false); + + const handleCreate = async () => { + setLoading(true); + try { + const result = await onCreateMessage(text); + if (result) { + setText(''); + } + } + catch (e) { + + } + setLoading(false); + } + return ( + <div> + <div>Create a message</div> + <Input.TextArea + rows={6} + value={text} + onChange={(e) => { setText(e.target.value) }} + disabled={loading} + /> + <Button onClick={handleCreate} disabled={loading} loading={loading}> + Send message + </Button> + </div> + ); +}); + +export default CreateMessage; diff --git a/apps/dashboard/src/components/BasicMessageList/index.tsx b/apps/dashboard/src/components/BasicMessageList/index.tsx index 3c538dff..5a3e0fe0 100644 --- a/apps/dashboard/src/components/BasicMessageList/index.tsx +++ b/apps/dashboard/src/components/BasicMessageList/index.tsx @@ -5,16 +5,27 @@ import BasicMessageListStore from './BasicMessageListStore'; import NoRecordsMessage from "../NoRecordsMessage"; import BasicMessageItem from "@dashboard/components/BasicMessageItem"; import modalStore from "@dashboard/store/modalStore"; +import api from "@dashboard/api"; +import CreateMessage from "@dashboard/components/BasicMessageList/CreateMessage"; -export interface ProofListProps { +export interface BasicMessageListProps { connectionId: string | null; } -const ProofList: React.FC<ProofListProps> = observer(({ connectionId }) => { +const BasicMessageList: React.FC<BasicMessageListProps> = observer(({ connectionId }) => { const [store] = useState(() => new BasicMessageListStore()); useEffect(() => { - store.loadAll(connectionId) + store.loadAll(connectionId); + + const unsubscribe = api.subscribeToBasicMessages((message) => { + if (connectionId === message.connectionId) { + store.items.push(message); + } + }); + return () => { + unsubscribe(); + }; }, []) return ( <div> @@ -31,8 +42,14 @@ const ProofList: React.FC<ProofListProps> = observer(({ connectionId }) => { {store.loading && ( <Spin /> )} + + {connectionId && ( + <div> + <CreateMessage onCreateMessage={message => store.sendMessage(connectionId, message)}/> + </div> + )} </div> ); }); -export default ProofList; +export default BasicMessageList; diff --git a/apps/dashboard/src/components/ProofItem/index.tsx b/apps/dashboard/src/components/ProofItem/index.tsx index 256ce3e4..f6947dcc 100644 --- a/apps/dashboard/src/components/ProofItem/index.tsx +++ b/apps/dashboard/src/components/ProofItem/index.tsx @@ -1,16 +1,16 @@ import React from "react"; import { observer } from "mobx-react"; import {Button, Space} from "antd"; -import {CredentialRecordDtoState, ProofRecordDto} from "@dashboard/api/agent-client"; +import {ProofRecordDto} from "@dashboard/api/agent-client"; import s from './styles.module.scss'; interface ProofItemProps { item: ProofRecordDto; onOpen?: () => void; onRemove?: () => void; - onAccept: () => void; - onDecline: () => void; - statusChanging: boolean; + onAccept?: () => void; + onDecline?: () => void; + statusChanging?: boolean; } const ProofItem = observer(({ @@ -28,12 +28,12 @@ const ProofItem = observer(({ </pre> <Space direction="horizontal"> {onOpen && <Button onClick={onOpen}>Go to credential</Button>} - {item.state === 'request-received' && ( + {onAccept && item.state === 'request-received' && ( <Button disabled={statusChanging} onClick={onAccept} type="primary"> Accept </Button> )} - {item.state === 'request-received' && ( + {onDecline && item.state === 'request-received' && ( <Button disabled={statusChanging} onClick={onDecline} danger> Decline </Button> diff --git a/apps/dashboard/src/components/ProofList/ProofListStore.ts b/apps/dashboard/src/components/ProofList/ProofListStore.ts index a7d9984f..101e1055 100644 --- a/apps/dashboard/src/components/ProofList/ProofListStore.ts +++ b/apps/dashboard/src/components/ProofList/ProofListStore.ts @@ -37,7 +37,7 @@ class ProofListStore { }); try { const credRecord = await api.acceptProof({ - proofRecordId: proofRecordId, + proofId: proofRecordId, proofUrl: "" }); runInAction(() => { diff --git a/apps/dashboard/src/components/Sidebar/index.tsx b/apps/dashboard/src/components/Sidebar/index.tsx index ae148617..012e3857 100644 --- a/apps/dashboard/src/components/Sidebar/index.tsx +++ b/apps/dashboard/src/components/Sidebar/index.tsx @@ -22,6 +22,9 @@ const Sidebar = () => { <Link className={s.link} to={config.proof_list.getLink()}> Proof List </Link> + <Link className={s.link} to={config.auth.getLink()}> + Auth + </Link> </div> ); }; diff --git a/apps/dashboard/src/main.tsx b/apps/dashboard/src/main.tsx index 956965d7..f870f8ec 100644 --- a/apps/dashboard/src/main.tsx +++ b/apps/dashboard/src/main.tsx @@ -1,8 +1,8 @@ -import * as ReactDOM from "react-dom/client"; +import * as ReactDOM from 'react-dom/client'; import { BrowserRouter } from "react-router-dom"; import { ConfigProvider } from "antd"; import getConfig from "./utils/getConfig"; -import App from "./components/App"; +import App from './components/App'; import api, {setConfig} from "./api"; import "react-toastify/dist/ReactToastify.css"; @@ -12,7 +12,7 @@ const config = getConfig(); setConfig({ websocketUrl: config.WS_GATEWAY, gatewayUrl: config.HTTP_GATEWAY, - getToken: async () => "", + getToken: async () => '' }); api.initialize(); @@ -20,8 +20,9 @@ api.initialize(); // @ts-ignore window.api = api; + const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement, + document.getElementById('root') as HTMLElement ); root.render( <BrowserRouter> diff --git a/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/index.tsx b/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/index.tsx new file mode 100644 index 00000000..7c46c641 --- /dev/null +++ b/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/index.tsx @@ -0,0 +1,81 @@ +import React, { useEffect, useState } from "react"; +import { observer } from "mobx-react"; +import { Form, Input, Button } from 'antd'; +import api from "@dashboard/api"; +import {toast} from "react-toastify"; +import Modal, {FcProps} from "@dashboard/components/Modal"; +import {ProofRecordDto} from "@dashboard/api/agent-client"; +import s from "./styles.module.scss"; + +export interface AcceptConnectionlessProofRequestDialogProps { + onProofReceived: (proofRecord: ProofRecordDto) => void; +} + +const AcceptConnectionlessProofRequestDialog = observer(({ + setTitle, + onClose, + data +}: FcProps<AcceptConnectionlessProofRequestDialogProps>) => { + useEffect(() => { + setTitle('Accept proof request by URL'); + }, []); + + const [loading, setLoading] = useState(false); + + const onFinish = async ({ proofUrl }: any) => { + try { + setLoading(true); + const proofRecord = await api.acceptProof({ + proofUrl, + proofId: "" + }); + toast(`Proof request accepted`); + if (proofRecord) { + data.onProofReceived(proofRecord); + onClose(); + } + } catch (e: any) { + console.error(e); + toast(e.message); + } + setLoading(false); + }; + + return ( + <Modal.Body> + <div className={s.body}> + <Form + layout="vertical" + initialValues={{ + proofUrl: '' + }} + onFinish={onFinish} + autoComplete="off" + > + <Form.Item + label="proof url" + name="proofUrl" + rules={[{ required: true, message: 'Please enter proof url!' }]} + > + <Input.TextArea rows={12} /> + </Form.Item> + + <div className={s.footerActions}> + <Button type="primary" htmlType="submit" disabled={loading}> + Accept + </Button> + <Button + className={s.cancelButton} + onClick={onClose} + disabled={loading} + > + Close + </Button> + </div> + </Form> + </div> + </Modal.Body> + ); +}); + +export default AcceptConnectionlessProofRequestDialog; diff --git a/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/styles.module.scss b/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/styles.module.scss new file mode 100644 index 00000000..5cc463b5 --- /dev/null +++ b/apps/dashboard/src/modals/AcceptConnectionlessProofRequestDialog/styles.module.scss @@ -0,0 +1,4 @@ +.footerActions { + display: flex; + justify-content: space-around; +} diff --git a/apps/dashboard/src/modals/IssueCredentialDialog/index.tsx b/apps/dashboard/src/modals/IssueCredentialDialog/index.tsx index 88dc7cc4..77758ef4 100644 --- a/apps/dashboard/src/modals/IssueCredentialDialog/index.tsx +++ b/apps/dashboard/src/modals/IssueCredentialDialog/index.tsx @@ -2,13 +2,13 @@ import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; import {Form, Input, Button, Spin, Select} from 'antd'; import Modal, {FcProps} from "@dashboard/components/Modal"; -import {CredentialRecordDto} from "@dashboard/api/agent-client"; +import {CredentialIssueResponseDto} from "@dashboard/api/agent-client"; import IssueCredentialDialogStore from "./IssueCredentialDialogStore"; import s from "./styles.module.scss"; export interface IssueCredentialDialogProps { connectionId: string; - onCredentialIssued: (cred: CredentialRecordDto) => void; + onCredentialIssued: (cred: CredentialIssueResponseDto) => void; } const IssueCredentialDialog = observer(({ @@ -23,9 +23,9 @@ const IssueCredentialDialog = observer(({ }, []); const onFinish = async ({ attributes }: any) => { - const credential = await store.issueCredential(attributes); - if (credential) { - data.onCredentialIssued(credential); + const response = await store.issueCredential(attributes); + if (response) { + data.onCredentialIssued(response); onClose(); } } diff --git a/apps/dashboard/src/modals/IssueProofRequestDialog/IssueProofRequestDialog.ts b/apps/dashboard/src/modals/RequestProofDialog/RequestProofDialogStore.ts similarity index 93% rename from apps/dashboard/src/modals/IssueProofRequestDialog/IssueProofRequestDialog.ts rename to apps/dashboard/src/modals/RequestProofDialog/RequestProofDialogStore.ts index 196e215e..e91a5aaa 100644 --- a/apps/dashboard/src/modals/IssueProofRequestDialog/IssueProofRequestDialog.ts +++ b/apps/dashboard/src/modals/RequestProofDialog/RequestProofDialogStore.ts @@ -10,9 +10,9 @@ interface ProofUiAttribute { attributeName: string | null; } -class IssueProofRequestDialog { +class RequestProofDialogStore { public initLoading = false; - public connectionId!: string; + public connectionId: string | undefined = undefined; public credDefList: CreddefRecordDto[] = []; public rows: ProofUiAttribute[] = []; @@ -41,7 +41,7 @@ class IssueProofRequestDialog { makeAutoObservable(this); } - public async init(connectionId: string) { + public async init(connectionId: string | undefined) { runInAction(() => { this.initLoading = true; this.connectionId = connectionId; @@ -123,7 +123,7 @@ class IssueProofRequestDialog { schemaId: p.schema!.id })) }); - toast("Proof request sent"); + toast("Proof request created"); runInAction(() => { this.issuingLoading = false; }); @@ -140,6 +140,6 @@ class IssueProofRequestDialog { } -export type { IssueProofRequestDialog }; +export type { RequestProofDialogStore }; -export default IssueProofRequestDialog; +export default RequestProofDialogStore; diff --git a/apps/dashboard/src/modals/IssueProofRequestDialog/index.tsx b/apps/dashboard/src/modals/RequestProofDialog/index.tsx similarity index 72% rename from apps/dashboard/src/modals/IssueProofRequestDialog/index.tsx rename to apps/dashboard/src/modals/RequestProofDialog/index.tsx index 675b2c7a..3c4d432f 100644 --- a/apps/dashboard/src/modals/IssueProofRequestDialog/index.tsx +++ b/apps/dashboard/src/modals/RequestProofDialog/index.tsx @@ -2,23 +2,28 @@ import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; import {Button, Spin, Select, Space} from 'antd'; import Modal, {FcProps} from "@dashboard/components/Modal"; -import {ProofRecordDto} from "@dashboard/api/agent-client"; -import IssueProofRequestDialog from "./IssueProofRequestDialog"; +import {ProofIssueResponseDto} from "@dashboard/api/agent-client"; +import RequestProofDialogStore from "./RequestProofDialogStore"; import s from "./styles.module.scss"; -export interface IssueProofRequestDialogProps { - connectionId: string; - onProofRequestIssued: (cred: ProofRecordDto) => void; +export interface RequestProofDialogProps { + connectionId?: string; + onProofRequestIssued: (cred: ProofIssueResponseDto) => void; } -const IssueCredentialDialog = observer(({ +const RequestProofDialog = observer(({ setTitle, onClose, data -}: FcProps<IssueProofRequestDialogProps>) => { - const [store] = useState(() => new IssueProofRequestDialog()); +}: FcProps<RequestProofDialogProps>) => { + const [store] = useState(() => new RequestProofDialogStore()); useEffect(() => { - setTitle('Send proof request to ' + data.connectionId); + if (data.connectionId) { + setTitle('Request proof from ' + data.connectionId); + } else { + setTitle('Create connectionless proof request'); + } + store.init(data.connectionId); }, []); @@ -32,10 +37,10 @@ const IssueCredentialDialog = observer(({ <div> {store.rows.map((row, rowIndex) => ( - <Space direction="horizontal" className={s.row}> + <Space direction="horizontal" className={s.row} key={rowIndex}> <Select placeholder="Select credential" - style={{ width: 300 }} + // style={{ width: 300 }} value={row.credentialDefinitionId} showSearch onChange={val => store.selectCredDef(rowIndex, val)} @@ -50,7 +55,7 @@ const IssueCredentialDialog = observer(({ {row.schema && ( <Select placeholder="Select attribute" - style={{ width: 300 }} + // style={{ width: 300 }} value={row.attributeName} showSearch onChange={val => store.selectAttributeName(rowIndex, val)} @@ -76,7 +81,7 @@ const IssueCredentialDialog = observer(({ } }} > - Submit proof request + Request proof </Button> </Space> </div> @@ -85,4 +90,4 @@ const IssueCredentialDialog = observer(({ ); }); -export default IssueCredentialDialog; +export default RequestProofDialog; diff --git a/apps/dashboard/src/modals/IssueProofRequestDialog/styles.module.scss b/apps/dashboard/src/modals/RequestProofDialog/styles.module.scss similarity index 100% rename from apps/dashboard/src/modals/IssueProofRequestDialog/styles.module.scss rename to apps/dashboard/src/modals/RequestProofDialog/styles.module.scss diff --git a/apps/dashboard/src/modals/ViewConnectionlessProofRequest/index.tsx b/apps/dashboard/src/modals/ViewConnectionlessProofRequest/index.tsx new file mode 100644 index 00000000..ba9cfd77 --- /dev/null +++ b/apps/dashboard/src/modals/ViewConnectionlessProofRequest/index.tsx @@ -0,0 +1,68 @@ +import React, { useEffect } from "react"; +import { observer } from "mobx-react"; +import QRCode from "react-qr-code"; +import Modal, {FcProps} from "@dashboard/components/Modal"; +import {ProofRecordDto} from "@dashboard/api/agent-client"; +import ProofItem from "@dashboard/components/ProofItem"; +import s from "./styles.module.scss"; + +export interface ViewConnectionlessProofRequestProps { + proofUrl: string; + proofRecord: ProofRecordDto; +} + +const ViewConnectionlessProofRequest = observer(({ + setTitle, + setWidth, + setClassName, + onClose, + data +}: FcProps<ViewConnectionlessProofRequestProps>) => { + useEffect(() => { + setClassName(s.modal); + setWidth('80vw'); + setTitle('Connectionless proof request'); + }, []); + + return ( + <Modal.Body className={s.body}> + <div className={s.info}> + <div> + <div className={s.qrCodeHint}> + Scan this QR code with mobile wallet + </div> + <div className={s.qrWrapper}> + <QRCode + value={data.proofUrl} + size={500} + /> + </div> + <div> + <div className={s.urlTitle}> + Proof request URL: + </div> + <div className={s.url}> + <b> + {data.proofUrl} + </b> + </div> + <div className={s.urlHint}> + Copy this URL and send it to the person you want to request proof from + </div> + <br /> + {data.proofRecord.oob && ( + <div> + Details: + <ProofItem + item={data.proofRecord} + /> + </div> + )} + </div> + </div> + </div> + </Modal.Body> + ); +}); + +export default ViewConnectionlessProofRequest; diff --git a/apps/dashboard/src/modals/ViewConnectionlessProofRequest/styles.module.scss b/apps/dashboard/src/modals/ViewConnectionlessProofRequest/styles.module.scss new file mode 100644 index 00000000..66d3a4f7 --- /dev/null +++ b/apps/dashboard/src/modals/ViewConnectionlessProofRequest/styles.module.scss @@ -0,0 +1,46 @@ +.modal { + top: 40px; +} + +.body { + height: calc(100vh - 140px); +} + +.qrWrapper { + display: flex; + align-items: center; + justify-content: center; + background: white; + padding: 16px; +} + +.info { + display: flex; + flex-direction: column; + justify-content: space-between; + overflow: scroll; +} + +.urlTitle { + margin-top: 12px; + font-weight: bold; +} + +.url { + margin-top: 12px; + word-break: break-word; + border-right: 8px; + background-color: rgba(0,0,0, 0.04); + padding: 8px; +} + +.urlHint { + margin-top: 12px; + font-size: 16px; +} + +.qrCodeHint { + text-align: center; + margin: 24px 0 12px 0; + font-size: 18px; +} \ No newline at end of file diff --git a/apps/dashboard/src/routes/config.ts b/apps/dashboard/src/routes/config.ts index 5465d334..dfe057b6 100644 --- a/apps/dashboard/src/routes/config.ts +++ b/apps/dashboard/src/routes/config.ts @@ -5,6 +5,7 @@ import SchemaListPage from "./pages/SchemaListPage"; import CredentialDefListPage from "./pages/CredentialDefListPage"; import CredentialListPage from "./pages/CredentialListPage"; import ProofListPage from "./pages/ProofListPage"; +import AuthPage from "./pages/AuthPage"; const routes = { connection_create: { @@ -42,6 +43,11 @@ const routes = { route: "/proof/list", getLink: () => "/proof/list", }, + auth: { + Component: AuthPage, + route: "/auth", + getLink: () => "/auth", + }, }; export default routes; diff --git a/apps/dashboard/src/routes/pages/AuthPage/Login.tsx b/apps/dashboard/src/routes/pages/AuthPage/Login.tsx new file mode 100644 index 00000000..5cc1cc29 --- /dev/null +++ b/apps/dashboard/src/routes/pages/AuthPage/Login.tsx @@ -0,0 +1,50 @@ +import React, {useEffect, useState} from "react"; +import {observer} from "mobx-react"; +import QRCode from "react-qr-code"; +import LoginStore from "@dashboard/routes/pages/AuthPage/LoginStore"; +import { Spin } from "antd"; + +const Login = observer(() => { + const [store] = useState(() => new LoginStore()); + useEffect(() => { + store.initialize(); + }, []); + + return ( + <div> + {store.loading && ( + <div> + <Spin /> + Loading... + </div> + )} + <p> + Scan this QR code in order to send proof with information about issued credentials by out system<br /> + Doing that you will be autorized<br /> + Credentials will contains: <br /> + SchemaId: {store.schemaId} + Schema attributes: {store.schema?.attributes.join(', ')} + CreddefId: {store.creddef?.id} + + </p> + <QRCode value={store.shortProofUrl || ''} size={256} /> + + <br/> + <div> + Technical information: + </div> + <div> + proofUrl: {store.proofUrl} + </div> + <div> + proof record:<br /> + <pre> + {JSON.stringify(store.proofRecord || {}, null, 2)} + </pre> + </div> + </div> + + ); +}); + +export default Login; diff --git a/apps/dashboard/src/routes/pages/AuthPage/LoginStore.ts b/apps/dashboard/src/routes/pages/AuthPage/LoginStore.ts new file mode 100644 index 00000000..2f978697 --- /dev/null +++ b/apps/dashboard/src/routes/pages/AuthPage/LoginStore.ts @@ -0,0 +1,61 @@ +import {makeAutoObservable, runInAction} from "mobx"; +import api from "@dashboard/api"; +import { + CreddefRecordDto, + ProofRecordDto, + SchemaRecordDto +} from "@dashboard/api/agent-client"; +import {toast} from "react-toastify"; +import {v4} from "uuid"; + + +class ConnectionListStore { + public loading = false; + public id = v4(); + public schemaId = 'did:indy:bcovrin:test:FcZ4aS728oRGVdNUKVaECP/anoncreds/v0/SCHEMA/SelfIdentity/1.0'; + public schema: SchemaRecordDto | null = null; + public creddef: CreddefRecordDto | null = null; + public shortProofUrl: string | null = null; + public proofUrl: string | null = null; + public proofRecord: ProofRecordDto | null = null; + + constructor() { + makeAutoObservable(this); + } + + public async initialize() { + runInAction(() => this.loading = true); + try { + const schema = await api.getSchemaById({ id: this.schemaId }); + const credDefs = await api.credentialDefinitions(); + let requiredCredDef = credDefs.find((credDef) => credDef.schemaId === this.schemaId); + if (!requiredCredDef) { + requiredCredDef = await api.createCredentialDefinition({ schemaId: this.schemaId, tag: 'SelfIdentity' }); + } + + const { shortProofUrl, proofUrl, proofRecord } = await api.issueProof({ + attributes: [{ + attributeName: 'identity-name', + credentialDefinitionId: requiredCredDef.id, + schemaId: this.schemaId + }] + }) + runInAction(() => { + this.schema = schema; + this.creddef = requiredCredDef!; + this.shortProofUrl = shortProofUrl; + this.proofUrl = proofUrl; + this.proofRecord = proofRecord; + this.loading = false; + }); + } catch (e: any) { + console.error(e); + toast.error(e.message); + runInAction(() => this.loading = false); + } + } +} + +export type { ConnectionListStore }; + +export default ConnectionListStore; diff --git a/apps/dashboard/src/routes/pages/AuthPage/Register.tsx b/apps/dashboard/src/routes/pages/AuthPage/Register.tsx new file mode 100644 index 00000000..f55dbc06 --- /dev/null +++ b/apps/dashboard/src/routes/pages/AuthPage/Register.tsx @@ -0,0 +1,50 @@ +import React, {useEffect, useState} from "react"; +import {observer} from "mobx-react"; +import QRCode from "react-qr-code"; +import RegisterStore from "@dashboard/routes/pages/AuthPage/RegisterStore"; +import { Spin } from "antd"; + +const Register = observer(() => { + const [store] = useState(() => new RegisterStore()); + useEffect(() => { + store.initialize(); + }, []); + + return ( + <div> + {store.loading && ( + <div> + <Spin /> + Loading... + </div> + )} + <p> + Scan this QR code in order to receive connection-less credentials<br /> + Using this credentials you will be able to authorize in our system<br /> + Credentials contains: <br /> + SchemaId: {store.schemaId} + Schema attributes: {store.schema?.attributes.join(', ')} + CreddefId: {store.creddef?.id} + + </p> + <QRCode value={store.shortCredentialUrl || ''} size={256} /> + + <br/> + <div> + Technical information: + </div> + <div> + credentialUrl: {store.credentialUrl} + </div> + <div> + crendential record:<br /> + <pre> + {JSON.stringify(store.credentialRecord || {}, null, 2)} + </pre> + </div> + </div> + + ); +}); + +export default Register; diff --git a/apps/dashboard/src/routes/pages/AuthPage/RegisterStore.ts b/apps/dashboard/src/routes/pages/AuthPage/RegisterStore.ts new file mode 100644 index 00000000..d88afe83 --- /dev/null +++ b/apps/dashboard/src/routes/pages/AuthPage/RegisterStore.ts @@ -0,0 +1,63 @@ +import {makeAutoObservable, runInAction} from "mobx"; +import api from "@dashboard/api"; +import { + ConnectionRecordDto, + CreddefRecordDto, + CredentialRecordDto, + IssueCredentialAttributes, + SchemaRecordDto +} from "@dashboard/api/agent-client"; +import {toast} from "react-toastify"; +import {v4} from "uuid"; + + +class ConnectionListStore { + public loading = false; + public id = v4(); + public schemaId = 'did:indy:bcovrin:test:FcZ4aS728oRGVdNUKVaECP/anoncreds/v0/SCHEMA/SelfIdentity/1.0'; + public schema: SchemaRecordDto | null = null; + public creddef: CreddefRecordDto | null = null; + public shortCredentialUrl: string | null = null; + public credentialUrl: string | null = null; + public credentialRecord: CredentialRecordDto | null = null; + + constructor() { + makeAutoObservable(this); + } + + public async initialize() { + runInAction(() => this.loading = true); + try { + const schema = await api.getSchemaById({ id: this.schemaId }); + const credDefs = await api.credentialDefinitions(); + let requiredCredDef = credDefs.find((credDef) => credDef.schemaId === this.schemaId); + if (!requiredCredDef) { + requiredCredDef = await api.createCredentialDefinition({ schemaId: this.schemaId, tag: 'SelfIdentity' }); + } + + const { shortCredentialUrl, credentialUrl, credentialRecord } = await api.issueCredential({ + credentialDefinitionId: requiredCredDef.id, + attributes: [{ + name: 'identity-name', + value: this.id, + }] + }) + runInAction(() => { + this.schema = schema; + this.creddef = requiredCredDef!; + this.shortCredentialUrl = shortCredentialUrl; + this.credentialUrl = credentialUrl; + this.credentialRecord = credentialRecord; + this.loading = false; + }); + } catch (e: any) { + console.error(e); + toast.error(e.message); + runInAction(() => this.loading = false); + } + } +} + +export type { ConnectionListStore }; + +export default ConnectionListStore; diff --git a/apps/dashboard/src/routes/pages/AuthPage/index.tsx b/apps/dashboard/src/routes/pages/AuthPage/index.tsx new file mode 100644 index 00000000..d208f557 --- /dev/null +++ b/apps/dashboard/src/routes/pages/AuthPage/index.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import {observer} from "mobx-react"; +import {Tabs, TabsProps} from "antd"; +import Login from "./Login"; +import Register from "./Register"; + +const AuthPage = observer(() => { + const onChange = (key: string) => { + console.log(key); + }; + + + const items: TabsProps['items'] = [ + { + key: '1', + label: 'Login', + children: <Login />, + }, + { + key: '2', + label: 'Registration', + children: <Register />, + } + ]; + + return ( + <div> + <Tabs defaultActiveKey="1" items={items} onChange={onChange} /> + </div> + + ); +}); + +export default AuthPage; diff --git a/apps/dashboard/src/routes/pages/ConnectionCreatePage/index.tsx b/apps/dashboard/src/routes/pages/ConnectionCreatePage/index.tsx index 10f7a1fc..eaad0ea3 100644 --- a/apps/dashboard/src/routes/pages/ConnectionCreatePage/index.tsx +++ b/apps/dashboard/src/routes/pages/ConnectionCreatePage/index.tsx @@ -1,6 +1,7 @@ import React, {useEffect, useState} from "react"; import { observer } from "mobx-react"; -import {QRCode, Spin } from 'antd'; +import { Spin } from 'antd'; +import QRCode from "react-qr-code"; import ConnectionCreatePageStore from './ConnectionCreatePageStore'; import s from './styles.module.scss'; @@ -38,14 +39,11 @@ const ConnectionCreatePage = observer(() => { <div className={s.qrCodeHint}> Or scan this QR code with your mobile wallet </div> - <div style={{ background: 'white', padding: '16px' }}> - <QRCode - errorLevel="H" - status={store.loading ? "loading" : "active"} - value={store.invitationUrl || ""} - icon="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" - /> - </div> + {store.invitationUrl && ( + <div style={{ background: 'white', padding: '16px' }}> + <QRCode value={store.invitationUrl} /> + </div> + )} <br /> {store.oob && ( <div> diff --git a/apps/dashboard/src/routes/pages/ConnectionViewPage/index.tsx b/apps/dashboard/src/routes/pages/ConnectionViewPage/index.tsx index 0e197e7a..706712ef 100644 --- a/apps/dashboard/src/routes/pages/ConnectionViewPage/index.tsx +++ b/apps/dashboard/src/routes/pages/ConnectionViewPage/index.tsx @@ -8,6 +8,7 @@ import JsonDetails from "@dashboard/components/JsonDetails"; import CredentialList from "@dashboard/components/CredentialList"; import ProofList from "@dashboard/components/ProofList"; import modalStore from "@dashboard/store/modalStore"; +import BasicMessageList from "@dashboard/components/BasicMessageList"; const ConnectionViewPage = observer(() => { @@ -36,7 +37,7 @@ const ConnectionViewPage = observer(() => { </Button> <Button onClick={() => { - modalStore.openIssueProofRequestDialog({ + modalStore.openRequestProofDialog({ connectionId: id, onProofRequestIssued: (proofRequest) => { setTimeout(() => { @@ -71,6 +72,9 @@ const ConnectionViewPage = observer(() => { <h3>Proofs</h3> <ProofList connectionId={id} /> + <h3>Messages</h3> + <BasicMessageList connectionId={id} /> + <JsonDetails object={store.connection} /> </div> ); diff --git a/apps/dashboard/src/routes/pages/ProofListPage/index.tsx b/apps/dashboard/src/routes/pages/ProofListPage/index.tsx index 2e8b8cd0..4b4b2944 100644 --- a/apps/dashboard/src/routes/pages/ProofListPage/index.tsx +++ b/apps/dashboard/src/routes/pages/ProofListPage/index.tsx @@ -1,10 +1,40 @@ import React from "react"; import {observer} from "mobx-react"; import ProofList from "@dashboard/components/ProofList"; +import {Button, Space} from "antd"; +import modalStore from "@dashboard/store/modalStore"; const ProofListPage = observer(() => { return ( <div> + <Space direction="horizontal"> + <Button + onClick={() => { + modalStore.openRequestProofDialog({ + connectionId: undefined, + onProofRequestIssued: (proofRequest) => { + modalStore.openViewConnectionlessProofRequest({ + proofUrl: proofRequest.proofUrl!, + proofRecord: proofRequest.proofRecord + }) + } + }) + }} + > + Create connectionless proof request + </Button> + <Button + onClick={() => { + modalStore.openAcceptConnectionlessProofRequestDialog({ + onProofReceived: (proofRecord) => { + window.location.reload(); + } + }) + }} + > + Accept connectionless proof request + </Button> + </Space> <h2>Proof List</h2> <div> <ProofList connectionId={null} /> diff --git a/apps/dashboard/src/store/modalStore.tsx b/apps/dashboard/src/store/modalStore.tsx index c0741f41..c6538871 100644 --- a/apps/dashboard/src/store/modalStore.tsx +++ b/apps/dashboard/src/store/modalStore.tsx @@ -1,25 +1,25 @@ import React from "react"; import { action, makeAutoObservable } from "mobx"; -import Modal, { FcProps } from "@dashboard/components/Modal"; -import ConfirmDialog, { - ConfirmDialogProps, -} from "@dashboard/modals/ConfirmDialog"; -import ReceiveInvitationDialog, { - ReceiveInvitationDialogProps, -} from "@dashboard/modals/ReceiveInvitationDialog"; +import {v4 as uuidv4} from "uuid"; +import Modal, {FcProps} from "@dashboard/components/Modal"; +import ConfirmDialog, {ConfirmDialogProps} from "@dashboard/modals/ConfirmDialog"; +import ReceiveInvitationDialog, { ReceiveInvitationDialogProps } from "@dashboard/modals/ReceiveInvitationDialog"; import NewCredentialDefDialog, { NewCredentialDefDialogProps } from "@dashboard/modals/NewCredentialDefDialog"; import NewSchemaDialog, { NewSchemaDialogProps } from "@dashboard/modals/NewSchemaDialog"; import ViewJsonDialog, { ViewJsonDialogProps } from "@dashboard/modals/ViewJsonDialog"; import IssueCredentialDialog, { IssueCredentialDialogProps } from "@dashboard/modals/IssueCredentialDialog"; -import IssueProofRequestDialog, { IssueProofRequestDialogProps } from "@dashboard/modals/IssueProofRequestDialog"; +import RequestProofDialog, { RequestProofDialogProps } from "@dashboard/modals/RequestProofDialog"; +import ViewConnectionlessProofRequest, { ViewConnectionlessProofRequestProps } from "@dashboard/modals/ViewConnectionlessProofRequest"; +import AcceptConnectionlessProofRequestDialog, { AcceptConnectionlessProofRequestDialogProps } from "@dashboard/modals/AcceptConnectionlessProofRequestDialog"; class ModalStore { - public modals: { id: string, modal: React.ReactNode }[] = []; + public modals: { id: string, modal: any }[] = []; constructor() { makeAutoObservable(this); } + private removeModal = action((id: string) => { const modalIndex = this.modals.findIndex(p => p.id === id); if (modalIndex >= 0) { @@ -27,8 +27,9 @@ class ModalStore { } }); + protected open<TData>(Component: React.FC<FcProps<TData>>, data: TData) { - const id = Math.random().toString(); + const id = uuidv4(); this.modals.push({ id: id, modal: ( @@ -39,24 +40,20 @@ class ModalStore { }} data={data} /> - ), + ) }); } - public openConfirmDialog = (data: ConfirmDialogProps) => - this.open(ConfirmDialog, data); - public openReceiveInvitationDialog = (data: ReceiveInvitationDialogProps) => - this.open(ReceiveInvitationDialog, data); - public openNewCredentialDefDialog = (data: NewCredentialDefDialogProps) => - this.open(NewCredentialDefDialog, data); - public openNewSchemaDialog = (data: NewSchemaDialogProps) => - this.open(NewSchemaDialog, data); - public openViewJsonDialog = (data: ViewJsonDialogProps) => - this.open(ViewJsonDialog, data); - public openIssueCredentialDialog = (data: IssueCredentialDialogProps) => - this.open(IssueCredentialDialog, data); - public openIssueProofRequestDialog = (data: IssueProofRequestDialogProps) => - this.open(IssueProofRequestDialog, data); + public openConfirmDialog = (data: ConfirmDialogProps) => this.open(ConfirmDialog, data); + public openReceiveInvitationDialog = (data: ReceiveInvitationDialogProps) => this.open(ReceiveInvitationDialog, data); + public openNewCredentialDefDialog = (data: NewCredentialDefDialogProps) => this.open(NewCredentialDefDialog, data); + public openNewSchemaDialog = (data: NewSchemaDialogProps) => this.open(NewSchemaDialog, data); + public openViewJsonDialog = (data: ViewJsonDialogProps) => this.open(ViewJsonDialog, data); + public openIssueCredentialDialog = (data: IssueCredentialDialogProps) => this.open(IssueCredentialDialog, data); + public openRequestProofDialog = (data: RequestProofDialogProps) => this.open(RequestProofDialog, data); + public openViewConnectionlessProofRequest = (data: ViewConnectionlessProofRequestProps) => this.open(ViewConnectionlessProofRequest, data); + public openAcceptConnectionlessProofRequestDialog = (data: AcceptConnectionlessProofRequestDialogProps) => this.open(AcceptConnectionlessProofRequestDialog, data); + } export type { ModalStore }; -- GitLab