From 6e9c635bc991aa56727335a53245c3061e2ac9de Mon Sep 17 00:00:00 2001 From: Phat <39623143+lukachi@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:38:22 +0200 Subject: [PATCH] Update request-metadata-credentials interaction for "Credentials" page (#36) * update metadata interaction --- .../orgs/helpers/org-groups-requests.ts | 93 +++++-------------- src/api/modules/orgs/mocks.ts | 73 +++++++++++---- src/api/modules/orgs/types/org-groups.ts | 8 -- src/api/modules/orgs/types/requests.ts | 58 ++++-------- .../contexts/CredentialsContextProvider.tsx | 26 ++---- .../components/ClaimVCsModal.tsx | 14 ++- .../pages/CredentialsRequests/index.tsx | 4 +- .../OrgGroupsId/components/ApprovedCard.tsx | 28 +----- 8 files changed, 113 insertions(+), 191 deletions(-) diff --git a/src/api/modules/orgs/helpers/org-groups-requests.ts b/src/api/modules/orgs/helpers/org-groups-requests.ts index e6c4db61..e9c08538 100644 --- a/src/api/modules/orgs/helpers/org-groups-requests.ts +++ b/src/api/modules/orgs/helpers/org-groups-requests.ts @@ -3,15 +3,13 @@ import { W3CCredential } from '@rarimo/rarime-connector' import { api } from '@/api/clients' import { CredentialRequest, - GroupedCredentials, - OrgClaimIDMap, OrgGroupCreatedRequest, OrgGroupRequest, - OrgGroupRequestClaim, OrgGroupRequestFilters, OrgGroupRequestMetadata, OrgGroupRequestPublishing, OrgGroupRequestQueryParams, + OrgGroupRequestWithClaims, OrgGroupVCMap, OrgUserRoles, } from '@/api/modules/orgs' @@ -112,6 +110,14 @@ export const loadOrgGroupRequests = async (query?: OrgGroupRequestQueryParams) = return fakeLoadRequestsAll(query) } +export const loadRequestsByUserDid = async (did: string): Promise => { + const { data } = await api.get( + `${ApiServicePaths.Orgs}/v1/users/${did}/requests`, + ) + + return data +} + export const loadOrgGroupRequestById = async (orgId: string, groupId: string, reqId: string) => { const { data } = await api.get( `${ApiServicePaths.Orgs}/v1/orgs/${orgId}/groups/${groupId}/requests/${reqId}`, @@ -229,25 +235,6 @@ export const getOrgGroupPublishingRequests = async ({ return data } -export const loadOrgGroupReqMetadataById = async ( - metadataId: string, -): Promise => { - const { data } = await api.get( - `${ApiServicePaths.Orgs}/v1/orgs/metadata/${metadataId}`, - ) - - return data - - // TODO: remove once backend is ready - // return { - // title: 'title', - // subtitle: 'subtitle', - // appearance: { - // background: '#ffffff', - // }, - // } -} - export const buildCredentialRequest = async ( schemeUrl: string, propertyValue: string, @@ -271,57 +258,19 @@ export const buildCredentialRequest = async ( } } -export const getOrgGroupRequestClaims = async ({ - orgId, - groupId, - reqId, -}: { - orgId: string - groupId: string - reqId: string -}): Promise => { - const { data } = await api.get( - `${ApiServicePaths.Orgs}/v1/orgs/${orgId}/groups/${groupId}/requests/${reqId}/publishing`, - ) - - return data -} - -export const getMetadataBatch = async (vcs: W3CCredential[]): Promise => { - const orgsToClaimIdsMap = vcs.reduce((acc, vc) => { - const issuerDID = vc.issuer - - if (!acc[issuerDID]) acc[issuerDID] = [] - - acc[issuerDID].push(getClaimIdFromVC(vc)) - - return acc - }, {} as OrgClaimIDMap) - - const { data } = await api.get(`${ApiServicePaths.Orgs}/v1/orgs/metadata`, { - query: { - orgsToClaimIdsMap, - }, - }) - - return data - - // return DUMMY_ORG_GROUP_METADATAS // FIXME: remove -} - export const groupVCsToOrgGroups = ( - groupedVCs: GroupedCredentials, + orgGroupRequests: OrgGroupRequestWithClaims[], vcs: W3CCredential[], ): OrgGroupVCMap => { - return groupedVCs.grouped_credentials.map(org => ({ - orgDID: org.org_did, - groups: org.groups.map(group => ({ - groupID: group.group_id, - requests: group.requests.map(req => ({ - reqID: req.req_id, - vcs: vcs.filter(vc => req.claim_ids.includes(getClaimIdFromVC(vc))), - metadata: req.metadata, - })), - })), - })) + return orgGroupRequests.map(orgGroupRequest => { + if (!orgGroupRequest.organization?.did) throw new TypeError('Organization DID is missing') + + const orgRequestClaimIDs = orgGroupRequest.claims.map(claim => claim.id) + + return { + orgDID: orgGroupRequest.organization.did, + groupID: orgGroupRequest.group_id, + vcs: vcs.filter(vc => orgRequestClaimIDs.includes(getClaimIdFromVC(vc))), + } + }) } diff --git a/src/api/modules/orgs/mocks.ts b/src/api/modules/orgs/mocks.ts index 410d489b..d274995d 100644 --- a/src/api/modules/orgs/mocks.ts +++ b/src/api/modules/orgs/mocks.ts @@ -2,7 +2,6 @@ import { W3CCredential } from '@rarimo/rarime-connector' import { - GroupedCredentials, OrgGroupCreatedRequest, OrgGroupRequest, OrgGroupRequestMetadata, @@ -39,6 +38,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ }, created_at: '2021-08-12T14:00:00Z', updated_at: '2021-08-12T13:00:00Z', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, organization: { id: '3a798290-caf1-496a-a7e5-4db32551b13d', type: 'organizations', @@ -65,6 +71,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -114,6 +127,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -163,6 +183,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -212,6 +239,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -261,6 +295,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -310,6 +351,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -359,6 +407,13 @@ export const DUMMY_ORG_GROUP_REQUESTS: OrgGroupRequest[] = [ type: 'requests', org_id: '3a798290-caf1-496a-a7e5-4db32551b13d', group_id: '6c8c1a69-177e-4754-a4e1-d4a7dbf561e8', + metadata: { + title: 'Civic', + subtitle: 'Civic', + appearance: { + background: '#000000', + }, + }, user_did: 'did:iden3:readonly:tKRuUKu3feUEktA38mxN2jdEkbgSAHjq8fVqAGmkw', credential_requests: [ { @@ -635,19 +690,3 @@ const createFakeVCs = (org: FakeOrgSystem): W3CCredential[] => { export const DUMMY_VCS: W3CCredential[] = [ ...FAKE_ORG_DETAILS.reduce((acc, org) => [...acc, ...createFakeVCs(org)], [] as W3CCredential[]), ] - -export const DUMMY_ORG_GROUP_METADATAS: GroupedCredentials = { - id: 'b0dc3814-e754-4596-a117-c4a07dfc65ef', - type: 'grouped_credentials', - grouped_credentials: FAKE_ORG_DETAILS.map(org => ({ - org_did: org.did, - groups: org.groups.map(group => ({ - group_id: group.id, - requests: group.requests.map(req => ({ - req_id: req.id, - claim_ids: req.claim_ids, - metadata: req.metadata, - })), - })), - })), -} diff --git a/src/api/modules/orgs/types/org-groups.ts b/src/api/modules/orgs/types/org-groups.ts index 35346e55..6b9d1358 100644 --- a/src/api/modules/orgs/types/org-groups.ts +++ b/src/api/modules/orgs/types/org-groups.ts @@ -5,14 +5,6 @@ export type OrgGroupMetadata = { description: string } -export type OrgGroupRequestMetadata = { - title: string - subtitle: string - appearance: { - background: string - } -} - export type OrgGroupRule = { name: string scheme: string diff --git a/src/api/modules/orgs/types/requests.ts b/src/api/modules/orgs/types/requests.ts index 4f7ee7b9..3eb38111 100644 --- a/src/api/modules/orgs/types/requests.ts +++ b/src/api/modules/orgs/types/requests.ts @@ -5,7 +5,6 @@ import { OrgGroup, OrgGroupRequestFilters, OrgGroupRequestIncludes, - OrgGroupRequestMetadata, OrgGroupRequestPublishingStatuses, OrgGroupRequestStatuses, } from '@/api/modules/orgs' @@ -20,6 +19,14 @@ export type CredentialRequest = { signature_proof: boolean } +export type OrgGroupRequestMetadata = { + title: string + subtitle: string + appearance: { + background: string + } +} + export type OrgGroupRequest = { id: string type: 'requests' @@ -33,10 +40,18 @@ export type OrgGroupRequest = { } created_at: string updated_at: string + metadata: OrgGroupRequestMetadata organization?: Organization group?: OrgGroup } +export type OrgGroupRequestWithClaims = OrgGroupRequest & { + claims: { + id: string + type: 'claims' + }[] +} + export type OrgGroupCreatedRequest = { id: string type: 'invitations-email' @@ -70,45 +85,8 @@ export type OrgGroupRequestPublishing = { status: OrgGroupRequestPublishingStatuses } -export type OrgGroupRequestClaim = { - id: string - type: 'claims' - claim_id: string - request_id: string - schema_url: string - status: string - created_at: string - updated_at: string - organization?: Organization -} - -export type OrgClaimIDMap = Record - -export type GroupedCredentials = { - id: string - type: 'grouped_credentials' - - grouped_credentials: { - org_did: string - groups: { - group_id: string - requests: { - req_id: string - claim_ids: string[] - metadata: OrgGroupRequestMetadata - }[] - }[] - }[] -} - export type OrgGroupVCMap = { orgDID: string - groups: { - groupID: string - requests: { - reqID: string - vcs: W3CCredential[] - metadata: OrgGroupRequestMetadata - }[] - }[] + groupID: string + vcs: W3CCredential[] }[] diff --git a/src/pages/Credentials/contexts/CredentialsContextProvider.tsx b/src/pages/Credentials/contexts/CredentialsContextProvider.tsx index 2efbdaab..80479bbf 100644 --- a/src/pages/Credentials/contexts/CredentialsContextProvider.tsx +++ b/src/pages/Credentials/contexts/CredentialsContextProvider.tsx @@ -2,18 +2,15 @@ import { CircularProgress } from '@mui/material' import { createContext, PropsWithChildren, useContext } from 'react' import { - getMetadataBatch, groupVCsToOrgGroups, - loadOrgGroupRequests, - OrgGroupRequest, - OrgGroupRequestFilters, - OrgGroupRequestStatuses, + loadRequestsByUserDid, + OrgGroupRequestWithClaims, OrgGroupVCMap, } from '@/api/modules/orgs' import { useLoading, useMetamaskZkpSnapContext } from '@/hooks' type CredentialsContextValue = { - orgGroupRequests: OrgGroupRequest[] + orgGroupRequests: OrgGroupRequestWithClaims[] groupedVCs: OrgGroupVCMap } @@ -34,7 +31,7 @@ export const CredentialsContextProvider = ({ children }: PropsWithChildren) => { isLoading, isLoadingError, } = useLoading<{ - orgGroupRequests: OrgGroupRequest[] + orgGroupRequests: OrgGroupRequestWithClaims[] groupedVCs: OrgGroupVCMap }>( { @@ -44,22 +41,11 @@ export const CredentialsContextProvider = ({ children }: PropsWithChildren) => { async () => { { const [orgGroupRequests, vcs] = await Promise.all([ - // TODO: replace with new endpoint to get all user's requests by his did - loadOrgGroupRequests({ - filter: { - [OrgGroupRequestFilters.UserDid]: userDid, - [OrgGroupRequestFilters.Status]: [ - OrgGroupRequestStatuses.Submitted, - OrgGroupRequestStatuses.Created, - ], - }, - }), + loadRequestsByUserDid(userDid), getCredentials(), ]) - const metadatas = await getMetadataBatch(vcs) - - const groupedVCs = groupVCsToOrgGroups(metadatas, vcs) + const groupedVCs = groupVCsToOrgGroups(orgGroupRequests, vcs) return { orgGroupRequests, groupedVCs } } diff --git a/src/pages/Credentials/pages/CredentialsRequests/components/ClaimVCsModal.tsx b/src/pages/Credentials/pages/CredentialsRequests/components/ClaimVCsModal.tsx index c334bd65..81f85bad 100644 --- a/src/pages/Credentials/pages/CredentialsRequests/components/ClaimVCsModal.tsx +++ b/src/pages/Credentials/pages/CredentialsRequests/components/ClaimVCsModal.tsx @@ -1,14 +1,14 @@ import { Typography } from '@mui/material' import { ComponentProps, useCallback } from 'react' -import { getOrgGroupRequestClaims, OrgGroupRequest } from '@/api/modules/orgs' +import { OrgGroupRequestWithClaims } from '@/api/modules/orgs' import { getClaimOffer, getTargetProperty, loadAndParseCredentialSchema } from '@/api/modules/zkp' import { ErrorHandler } from '@/helpers' import { useLoading, useMetamaskZkpSnapContext } from '@/hooks' import { UiBasicModal, UiButton, UiIcon } from '@/ui' type Props = ComponentProps & { - orgGroupRequest: OrgGroupRequest | undefined + orgGroupRequest: OrgGroupRequestWithClaims | undefined } export default function ClaimVCsModal({ orgGroupRequest, onClose, ...rest }: Props) { @@ -24,14 +24,12 @@ export default function ClaimVCsModal({ orgGroupRequest, onClose, ...rest }: Pro async () => { if (!orgGroupRequest) throw new TypeError('orgGroupRequest is not defined') - const orgGroupRequestClaims = await getOrgGroupRequestClaims({ - orgId: orgGroupRequest.org_id, - groupId: orgGroupRequest.group_id, - reqId: orgGroupRequest.id, - }) + const claimIds = orgGroupRequest.claims?.map(el => el.id) + + if (!claimIds?.length) throw new TypeError('claimIds is not defined') const [claimOffers, vcFields] = await Promise.all([ - Promise.all(orgGroupRequestClaims.map(el => getClaimOffer(userDid, el.claim_id))), + Promise.all(claimIds.map(claimId => getClaimOffer(userDid, claimId))), Promise.all( orgGroupRequest.credential_requests.map(async req => getTargetProperty( diff --git a/src/pages/Credentials/pages/CredentialsRequests/index.tsx b/src/pages/Credentials/pages/CredentialsRequests/index.tsx index b6105222..7ca93292 100644 --- a/src/pages/Credentials/pages/CredentialsRequests/index.tsx +++ b/src/pages/Credentials/pages/CredentialsRequests/index.tsx @@ -3,7 +3,7 @@ import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { NavLink } from 'react-router-dom' -import { OrgGroupRequest, OrgGroupRequestStatuses } from '@/api/modules/orgs' +import { OrgGroupRequestStatuses, OrgGroupRequestWithClaims } from '@/api/modules/orgs' import { PageTitles } from '@/common' import { BusEvents, RoutePaths } from '@/enums' import { bus } from '@/helpers' @@ -22,7 +22,7 @@ export default function CredentialsRequests({ ...rest }: Props) { const [isFillFormDrawerShown, setIsFillFormDrawerShown] = useState(false) const [isClaimModalShown, setIsClaimModalShown] = useState(false) - const [selectedOrgGroupRequest, setSelectedRequest] = useState() + const [selectedOrgGroupRequest, setSelectedRequest] = useState() const handleRequestFilled = useCallback(() => { bus.emit(BusEvents.success, 'Request successfully sent') diff --git a/src/pages/Orgs/pages/OrgsId/pages/OrgGroups/pages/OrgGroupsId/components/ApprovedCard.tsx b/src/pages/Orgs/pages/OrgsId/pages/OrgGroups/pages/OrgGroupsId/components/ApprovedCard.tsx index ced6be48..38adcd22 100644 --- a/src/pages/Orgs/pages/OrgsId/pages/OrgGroups/pages/OrgGroupsId/components/ApprovedCard.tsx +++ b/src/pages/Orgs/pages/OrgsId/pages/OrgGroups/pages/OrgGroupsId/components/ApprovedCard.tsx @@ -1,13 +1,8 @@ import { Stack, StackProps } from '@mui/material' import { useMemo } from 'react' -import { - loadOrgGroupReqMetadataById, - OrgGroupRequest, - OrgGroupRequestMetadata, -} from '@/api/modules/orgs' +import { OrgGroupRequest } from '@/api/modules/orgs' import { VCGroupOverviewCard } from '@/common' -import { useLoading } from '@/hooks' import { useOrgDetails } from '@/pages/Orgs/pages/OrgsId/hooks' interface Props extends StackProps { @@ -17,31 +12,16 @@ interface Props extends StackProps { export default function ApprovedCard({ orgGroupRequest, ...rest }: Props) { const { org } = useOrgDetails() - const metadataId = useMemo(() => { - return orgGroupRequest.credential_requests?.[0].credential_subject.metadata_id - }, [orgGroupRequest.credential_requests]) - const expirationDate = useMemo(() => { return orgGroupRequest.credential_requests?.[0].expiration }, [orgGroupRequest.credential_requests]) - const { data: orgGroupVCsMetadata } = useLoading( - {} as OrgGroupRequestMetadata, - () => { - return loadOrgGroupReqMetadataById(metadataId) - }, - { - loadOnMount: true, - loadArgs: [metadataId], - }, - ) - return (