From 93eab55fb0cde03c943805f646992fddf56e0c47 Mon Sep 17 00:00:00 2001 From: Hjort Date: Tue, 29 Aug 2023 14:54:15 +0200 Subject: [PATCH 01/29] UI changes --- .../DisplayStatement/DisplayStatement.tsx | 6 +- .../Web3ProofRequest/CredentialSelector.tsx | 1 + .../pages/Web3ProofRequest/DisplayBox.tsx | 165 ++++++++++++++++++ .../VerifiableCredentialStatement.tsx | 24 +-- .../Web3ProofRequest/Web3ProofRequest.scss | 29 +++ 5 files changed, 210 insertions(+), 15 deletions(-) create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/DisplayBox.tsx diff --git a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx index 53c164a8..d14d3c90 100644 --- a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx @@ -34,11 +34,11 @@ export type StatementLine = { isRequirementMet: boolean; }; -type StatementLineProps = StatementLine; +type StatementLineProps = StatementLine & ClassName; -export function DisplayStatementLine({ attribute, value, isRequirementMet }: StatementLineProps) { +export function DisplayStatementLine({ attribute, value, isRequirementMet, className }: StatementLineProps) { return ( -
  • +
  • {attribute}:
    {value} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx index 2da3fb7f..877b68a5 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx @@ -19,6 +19,7 @@ export default function CredentialSelector({ options, onChange, displayOption return ( + issuer Index:

    Attribute values:

    degreeType: From 42dd99f4a1afa811aad198630d6aa0aaf35c3019 Mon Sep 17 00:00:00 2001 From: Hjort Date: Tue, 29 Aug 2023 16:45:56 +0200 Subject: [PATCH 03/29] Further UI change --- .../Web3ProofRequest/Display/DisplayBox.tsx | 40 +++++ .../Display/DisplayRevealStatements.tsx | 63 +++++++ .../Display/DisplaySecretStatements.tsx | 99 +++++++++++ .../pages/Web3ProofRequest/Display/utils.ts | 7 + .../pages/Web3ProofRequest/DisplayBox.tsx | 165 ------------------ .../VerifiableCredentialStatement.tsx | 162 ++--------------- .../Web3ProofRequest/Web3ProofRequest.scss | 17 +- .../popup/pages/Web3ProofRequest/i18n/en.ts | 8 +- .../src/popup/pages/Web3ProofRequest/utils.ts | 27 +++ 9 files changed, 264 insertions(+), 324 deletions(-) create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts delete mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/DisplayBox.tsx diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx new file mode 100644 index 00000000..7464ecaa --- /dev/null +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx @@ -0,0 +1,40 @@ +import Button from '@popup/shared/Button'; +import Modal from '@popup/shared/Modal'; +import clsx from 'clsx'; +import React, { ReactNode, useState } from 'react'; +import { ClassName } from 'wallet-common-helpers'; +import InfoTooltipIcon from '@assets/svg/info-tooltip.svg'; + +type DisplayBoxProps = ClassName & { + header: string; + children: ReactNode; + infoBox: ReactNode; +}; + +export function DisplayBox({ className, children, header, infoBox }: DisplayBoxProps) { + const [open, setOpen] = useState(false); + + return ( +
    +
    +
    {header}
    + setOpen(true)} + onClose={() => setOpen(false)} + trigger={ + + } + > + {infoBox} + + +
    + {children} +
    + ); +} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx new file mode 100644 index 00000000..00d9db7b --- /dev/null +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx @@ -0,0 +1,63 @@ +import { AttributeType, RevealStatementV2 } from '@concordium/web-sdk'; +import { VerifiableCredentialSchema } from '@shared/storage/types'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { ClassName } from 'wallet-common-helpers'; +import { DisplayStatementLine } from '../../IdProofRequest/DisplayStatement/DisplayStatement'; +import { DisplayBox } from './DisplayBox'; +import { getPropertyTitle } from './utils'; + +type RevealProps = ClassName & { + dappName: string; + statements: RevealStatementV2[]; + attributes: Record; + schema: VerifiableCredentialSchema; + className: string; +}; + +export function DisplayRevealStatements({ className, statements, attributes, dappName, schema }: RevealProps) { + const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); + const header = t('headers.reveal'); + + const lines = statements.map((s) => { + const value = attributes[s.attributeTag]; + const title = getPropertyTitle(s.attributeTag, schema); + return { + attribute: title, + value: value.toString() ?? 'Unavailable', + isRequirementMet: value !== undefined, + }; + }); + + return ( + +

    {t('revealTooltip.header')}

    +

    {t('revealTooltip.body')}

    + + } + > +
      + {lines.map((l, i) => ( + + ))} +
    +
    + }} + values={{ dappName }} + /> +
    +
    + ); +} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx new file mode 100644 index 00000000..1a447bb9 --- /dev/null +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -0,0 +1,99 @@ +import { AttributeType, StatementTypes } from '@concordium/web-sdk'; +import { DisplayStatementLine } from '@popup/pages/IdProofRequest/DisplayStatement/DisplayStatement'; +import { VerifiableCredentialSchema } from '@shared/storage/types'; +import React from 'react'; +import { TFunction, useTranslation } from 'react-i18next'; +import { ClassName } from 'wallet-common-helpers'; +import { DisplayBox } from './DisplayBox'; +import { SecretStatementV2 } from '../utils'; +import { getPropertyTitle } from './utils'; + +type SecretProps = ClassName & { + statements: SecretStatementV2[]; + attributes: Record; + schema: VerifiableCredentialSchema; + className: string; +}; + +function getStatementValue( + statement: SecretStatementV2, + schema: VerifiableCredentialSchema, + t: TFunction<'web3IdProofRequest', 'displayStatement'> +): string { + const name = getPropertyTitle(statement.attributeTag, schema); + if (statement.type === StatementTypes.AttributeInRange) { + return t('proofs.range', { name, upper: statement.upper, lower: statement.lower }); + } + if (statement.type === StatementTypes.AttributeInSet) { + return t('proofs.membership', { name }); + } + if (statement.type === StatementTypes.AttributeNotInSet) { + return t('proofs.nonMembership', { name }); + } + + throw new Error('Unknown statement type'); +} + +function getStatementDescription( + statement: SecretStatementV2, + schema: VerifiableCredentialSchema, + t: TFunction<'web3IdProofRequest', 'displayStatement'> +) { + const name = getPropertyTitle(statement.attributeTag, schema); + const listToString = (list: AttributeType[]) => list.map((member) => member.toString()).join(', '); + + switch (statement.type) { + case StatementTypes.AttributeInRange: + return t('descriptions.range', { name, lower: statement.lower, upper: statement.upper }); + case StatementTypes.AttributeInSet: + return t('descriptions.membership', { name, setNames: listToString(statement.set) }); + case StatementTypes.AttributeNotInSet: + return t('descriptions.nonMembership', { name, setNames: listToString(statement.set) }); + default: + throw new Error(`Unknown statement type encountered: ${statement.type}`); + } +} + +export function DisplaySecretStatements({ schema, statements, className }: SecretProps) { + const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); + const header = t('headers.secret'); + + const lines = statements.map((s) => { + const value = getStatementValue(s, schema, t); + const title = getPropertyTitle(s.attributeTag, schema); + const description = getStatementDescription(s, schema, t); + return { + attribute: title, + value: value.toString() ?? 'Unavailable', + isRequirementMet: value !== undefined, + description, + }; + }); + + return ( + +

    {t('secretTooltip.header')}

    +

    {t('secretTooltip.body')}

    + + } + > +
      + {lines.map(({ description, ...l }, i) => ( +
      + +
      {description}
      +
      + ))} +
    +
    + ); +} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts new file mode 100644 index 00000000..9a9b669d --- /dev/null +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts @@ -0,0 +1,7 @@ +import { VerifiableCredentialSchema } from '@shared/storage/types'; + +export function getPropertyTitle(attributeTag: string, schema: VerifiableCredentialSchema) { + // TODO use localization here + const property = schema.properties.credentialSubject.properties.attributes.properties[attributeTag]; + return property ? property.title : attributeTag; +} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/DisplayBox.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/DisplayBox.tsx deleted file mode 100644 index 64beb899..00000000 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/DisplayBox.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import Button from '@popup/shared/Button'; -import Modal from '@popup/shared/Modal'; -import clsx from 'clsx'; -import React, { ReactNode, useState } from 'react'; -import { ClassName } from 'wallet-common-helpers'; -import InfoTooltipIcon from '@assets/svg/info-tooltip.svg'; -import { AttributeType, RevealStatementV2, StatementTypes } from '@concordium/web-sdk'; -import { Trans, useTranslation } from 'react-i18next'; -import { getPropertyTitle } from './VerifiableCredentialStatement'; -import { VerifiableCredentialSchema } from '@shared/storage/types'; -import { DisplayStatementLine } from '../IdProofRequest/DisplayStatement/DisplayStatement'; -import { SecretStatementV2 } from './utils'; -import { useStatementValue } from '../IdProofRequest/DisplayStatement/utils'; -import { TFunction } from 'react-i18next'; - -type DisplayBoxProps = ClassName & { - header: string; - children: ReactNode; - infoBox: ReactNode; -} - -export function DisplayBox ({ className, children, header, infoBox }: DisplayBoxProps) { - const [open, setOpen] = useState(false); - - return ( -
    -
    -
    - {header} -
    - setOpen(true)} - onClose={() => setOpen(false)} - trigger={ - - } - > - {infoBox} - -
    - {children} -
    - ); -} - -type RevealProps = ClassName & { - dappName: string; - statements: RevealStatementV2[]; - attributes: Record; - schema: VerifiableCredentialSchema; - className: string; -} - -export function DisplayRevealStatements({ className, statements, attributes, dappName, schema}: RevealProps) { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); - const header = t('headers.reveal'); - - const lines = statements.map((s) => { - const value = attributes[s.attributeTag]; - const title = getPropertyTitle(s.attributeTag, schema); - return { - attribute: title, - value: value.toString() ?? 'Unavailable', - isRequirementMet: value !== undefined, - }; - }); - - return ( - )}> -
      - {lines.map((l, i) => ( - - ))} -
    -
    - }} - values={{ dappName }} - /> -
    -
    - ) -} - -type SecretProps = ClassName & { - dappName: string; - statements: SecretStatementV2[]; - attributes: Record; - schema: VerifiableCredentialSchema; - className: string; -} - -function getStatementValue(statement: SecretStatementV2, schema: VerifiableCredentialSchema, t: TFunction<'web3IdProofRequest', 'displayStatement.proofs'>): string { - const name = getPropertyTitle(statement.attributeTag, schema); - if (statement.type === StatementTypes.AttributeInRange) { - return t('range', { name, upper: statement.upper, lower: statement.lower }); - } - if (statement.type === StatementTypes.AttributeInSet) { - return t('membership', { name }); - } - if (statement.type === StatementTypes.AttributeNotInSet) { - return t('nonMembership', { name }); - } - - throw new Error('Unknown statement type'); -} - -export function getStatementDescription(statement: SecretStatementV2, schema: VerifiableCredentialSchema, t: TFunction<'web3IdProofRequest', 'displayStatement.descriptions'>) { - const name = getPropertyTitle(statement.attributeTag, schema); - const listToString = (list: AttributeType[]) => list.map((member) => member.toString()).join(', '); - - switch (statement.type) { - case StatementTypes.AttributeInRange: - return t('range', { name, lower: statement.lower, upper: statement.upper }); - case StatementTypes.AttributeInSet: - return t('membership', { name, setNames: listToString(statement.set) }); - case StatementTypes.AttributeNotInSet: - return t('nonMembership', { name, setNames: listToString(statement.set) }); - default: - throw new Error(`Unknown statement type encountered: ${statement.type}`); - } -} - -export function DisplaySecretStatements({ schema, statements, className, dappName }: SecretProps) { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); - const header = t('headers.secret'); - - const lines = statements.map((s) => { - const value = getStatementValue(s, schema, t); - const title = getPropertyTitle(s.attributeTag, schema); - const description = getStatementDescription(s, schema, t); - return { - attribute: title, - value: value.toString() ?? 'Unavailable', - isRequirementMet: value !== undefined, - description - }; - }); - - return ( - )}> -
      - {lines.map((l, i) => ( - - ))} -
    -
    - ) - -} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx index b840a87d..9cf32cc9 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx @@ -1,155 +1,16 @@ -import { - AtomicStatementV2, - RevealStatementV2, - StatementTypes, - VerifiableCredentialStatement, - CredentialSubject, - AttributeType, -} from '@concordium/web-sdk'; +import { RevealStatementV2, StatementTypes, VerifiableCredentialStatement } from '@concordium/web-sdk'; import { storedVerifiableCredentialSchemasAtom } from '@popup/store/verifiable-credential'; -import { VerifiableCredential, VerifiableCredentialSchema, VerifiableCredentialStatus } from '@shared/storage/types'; +import { VerifiableCredential, VerifiableCredentialStatus } from '@shared/storage/types'; import { getVerifiableCredentialPublicKeyfromSubjectDID } from '@shared/utils/verifiable-credential-helpers'; import { useAtomValue } from 'jotai'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { ClassName } from 'wallet-common-helpers'; -import { DisplayStatementView, StatementLine } from '../IdProofRequest/DisplayStatement/DisplayStatement'; import { VerifiableCredentialCard } from '../VerifiableCredential/VerifiableCredentialCard'; import { useCredentialLocalization, useCredentialMetadata } from '../VerifiableCredential/VerifiableCredentialHooks'; import CredentialSelector from './CredentialSelector'; -import { DisplayRevealStatements, DisplaySecretStatements } from './DisplayBox'; +import { DisplayRevealStatements } from './Display/DisplayRevealStatements'; +import { DisplaySecretStatements } from './Display/DisplaySecretStatements'; import { createWeb3IdDIDFromCredential, DisplayCredentialStatementProps, SecretStatementV2 } from './utils'; -export function getPropertyTitle(attributeTag: string, schema: VerifiableCredentialSchema) { - // TODO use localization here - const property = schema.properties.credentialSubject.properties.attributes.properties[attributeTag]; - return property ? property.title : attributeTag; -} - -function useStatementValue(statement: SecretStatementV2, schema: VerifiableCredentialSchema): string { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement.proofs' }); - - const name = getPropertyTitle(statement.attributeTag, schema); - if (statement.type === StatementTypes.AttributeInRange) { - return t('range', { name, upper: statement.upper, lower: statement.lower }); - } - if (statement.type === StatementTypes.AttributeInSet) { - return t('membership', { name }); - } - if (statement.type === StatementTypes.AttributeNotInSet) { - return t('nonMembership', { name }); - } - - throw new Error('Unknown statement type'); -} - -export function useStatementDescription(statement: SecretStatementV2, schema: VerifiableCredentialSchema) { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement.descriptions' }); - const name = getPropertyTitle(statement.attributeTag, schema); - const listToString = (list: AttributeType[]) => list.map((member) => member.toString()).join(', '); - - switch (statement.type) { - case StatementTypes.AttributeInRange: - return t('range', { name, lower: statement.lower, upper: statement.upper }); - case StatementTypes.AttributeInSet: - return t('membership', { name, setNames: listToString(statement.set) }); - case StatementTypes.AttributeNotInSet: - return t('nonMembership', { name, setNames: listToString(statement.set) }); - default: - throw new Error(`Unknown statement type encountered: ${statement.type}`); - } -} - -type DisplayWeb3StatementProps = ClassName & { - statements: Statement; - dappName: string; - schema: VerifiableCredentialSchema; -}; - -type AttributeInfo = { - name: string; - value: AttributeType; -}; - -function extractAttributesFromCredentialSubjectForSingleStatement( - { attributeTag }: AtomicStatementV2, - credentialSubject: CredentialSubject -): AttributeInfo { - return { name: attributeTag, value: credentialSubject.attributes[attributeTag] }; -} - -function extractAttributesFromCredentialSubject( - statements: AtomicStatementV2[], - credentialSubject: CredentialSubject -): Record { - return statements.reduce>((acc, statement) => { - acc[statement.attributeTag] = extractAttributesFromCredentialSubjectForSingleStatement( - statement, - credentialSubject - ); - return acc; - }, {}); -} - -type DisplayWeb3RevealStatementProps = DisplayWeb3StatementProps & { - credential: CredentialSubject; -}; - -export function DisplayWeb3RevealStatement({ - statements, - dappName, - credential, - className, - schema, -}: DisplayWeb3RevealStatementProps) { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); - const attributes = extractAttributesFromCredentialSubject(statements, credential); - const header = t('headers.reveal'); - - const lines: StatementLine[] = statements.map((s) => { - const { value } = attributes[s.attributeTag]; - const title = getPropertyTitle(s.attributeTag, schema); - return { - attribute: title, - value: value.toString() ?? 'Unavailable', - isRequirementMet: value !== undefined, - }; - }); - - return ; -} - -export function DisplayWeb3SecretStatement({ - statements, - dappName, - className, - schema, -}: DisplayWeb3StatementProps) { - const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); - const value = useStatementValue(statements, schema); - const header = t('headers.secret'); - const title = getPropertyTitle(statements.attributeTag, schema); - const description = useStatementDescription(statements, schema); - - const lines: StatementLine[] = [ - { - attribute: title, - value, - isRequirementMet: value !== undefined, - }, - ]; - - return ( - - ); -} - export default function DisplayWeb3Statement({ credentialStatement, validCredentials, @@ -218,15 +79,14 @@ export default function DisplayWeb3Statement({ schema={schema} /> )} - {secrets.length !== 0 && ( - - )} + )}
    ); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 9ae276ea..e1d7d4e7 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -20,17 +20,18 @@ .display-box { border-radius: 16px; - box-shadow: 0px 0px 15px 0px #0000001A; + box-shadow: 0 0 15px 0 #0000001a; &__header { - background: linear-gradient(91.35deg, #B6DADF 13.38%, #DAECEF 93.45%); + background: linear-gradient(91.35deg, #b6dadf 13.38%, #daecef 93.45%); border-top-left-radius: 16px; border-top-right-radius: 16px; height: 48px; padding: 15px; display: flex; justify-content: space-between; - } + color: $color-secondary-ocean-blue; + } &__tooltip-icon { height: 24px; @@ -38,11 +39,19 @@ } .display-reveal-statements { - &__line { &:not(:last-child) { margin-bottom: 8px; } } +} + +.display-secret-statements { + &__line { + margin-top: 5px; + &:not(:last-child) { + border-bottom: 1px solid #e5e5e5; + } + } } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index 070f05d4..e1c6a3b4 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -9,12 +9,12 @@ export default { revealDescription: '<1>Important: {{dappName}} will be given all the information above. You should only accept, if you trust the service, and you are familiar with their privacy policy.', revealTooltip: { - header: 'Revealing information <1 />', - body: 'When you reveal information to a third party, you effectively hand over the information to them. This means you should only do this if you agree to their data usage and protection policies.\n\nYou can read more in\n<1>the developer documentation.', + header: 'Information to reveal', + body: 'When you reveal information for a third party, you effectively hand over the information to them. This means that you should only do this if you have absolute trust in them, and if you are familiar with their data usage and protection procedures.\n\nYou can read more on\ndeveloper.concordium.software', }, secretTooltip: { - header: 'Zero Knowledge proofs', - body: 'Zero Knowledge proofs are a way of proving something to a service or dApp without revealing the exact personal information. One example can be that you prove that you are over 18 years old without revealing your exact age. Another example could be proving your residency is within a given set of countries without revealing which of those countries you reside within.\n\nYou can read more in\n<1>the developer documentation.', + header: 'Zero Knowledge proof', + body: 'Zero-knowledge proofs are a way of proving something to a service or dApp without revealing the exact personal information. One example can be that you prove that you are over 18 years old without revealing your exact date of birth. Another example could be that you live in one of a range of countries without revealing exactly which country you live in.\n\nYou can read more on\ndeveloper.concordium.software', }, headers: { reveal: 'Information to reveal', diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/utils.ts index 6123bc5c..24d4fe70 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/utils.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/utils.ts @@ -10,6 +10,8 @@ import { RevealStatementV2, createWeb3IdDID, canProveCredentialStatement, + AttributeType, + CredentialSubject, } from '@concordium/web-sdk'; import { isIdentityOfCredential } from '@shared/utils/identity-helpers'; import { @@ -134,3 +136,28 @@ export function createWeb3IdDIDFromCredential(credential: VerifiableCredential, BigInt(contractAddress.subindex) ); } + +type AttributeInfo = { + name: string; + value: AttributeType; +}; + +function extractAttributesFromCredentialSubjectForSingleStatement( + { attributeTag }: AtomicStatementV2, + credentialSubject: CredentialSubject +): AttributeInfo { + return { name: attributeTag, value: credentialSubject.attributes[attributeTag] }; +} + +export function extractAttributesFromCredentialSubject( + statements: AtomicStatementV2[], + credentialSubject: CredentialSubject +): Record { + return statements.reduce>((acc, statement) => { + acc[statement.attributeTag] = extractAttributesFromCredentialSubjectForSingleStatement( + statement, + credentialSubject + ); + return acc; + }, {}); +} From e039caf5574bfbadba561bbc21a1a3dde7814425 Mon Sep 17 00:00:00 2001 From: Hjort Date: Tue, 29 Aug 2023 17:22:50 +0200 Subject: [PATCH 04/29] Selector WIP --- .../Web3ProofRequest/CredentialSelector.tsx | 50 ++++++++++++------- .../VerifiableCredentialStatement.tsx | 27 ++++++++-- .../Web3ProofRequest/Web3ProofRequest.scss | 10 ++++ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx index 877b68a5..65922f0b 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx @@ -1,37 +1,51 @@ -import React, { useState } from 'react'; +import Button from '@popup/shared/Button'; +import Modal from '@popup/shared/Modal'; +import React, { ComponentType, useState } from 'react'; interface Props { options: T[]; + initialIndex?: number; onChange: (x: T) => void; - displayOption: (x: T) => string; + DisplayOption: ComponentType<{ option: T }>; } /** * Component to select a credential, either account credential or web3Id credential. */ -export default function CredentialSelector({ options, onChange, displayOption }: Props) { - const [chosenIndex, setChosenIndex] = useState(0); +export default function CredentialSelector({ + options, + initialIndex = 0, + onChange, + DisplayOption, +}: Props) { + const [chosenIndex, setChosenIndex] = useState(initialIndex); + const [open, setOpen] = useState(false); if (options.length === 0) { - // TODO Translate - return
    No candidate available
    ; + return null; + } + + function onClick(index: number) { + setChosenIndex(index); + onChange(options[index]); } return ( - + ); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx index 9cf32cc9..2ec49f35 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx @@ -1,7 +1,8 @@ +import { MetadataUrl } from '@concordium/browser-wallet-api-helpers/lib/wallet-api-types'; import { RevealStatementV2, StatementTypes, VerifiableCredentialStatement } from '@concordium/web-sdk'; +import Img from '@popup/shared/Img'; import { storedVerifiableCredentialSchemasAtom } from '@popup/store/verifiable-credential'; import { VerifiableCredential, VerifiableCredentialStatus } from '@shared/storage/types'; -import { getVerifiableCredentialPublicKeyfromSubjectDID } from '@shared/utils/verifiable-credential-helpers'; import { useAtomValue } from 'jotai'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { VerifiableCredentialCard } from '../VerifiableCredential/VerifiableCredentialCard'; @@ -11,6 +12,25 @@ import { DisplayRevealStatements } from './Display/DisplayRevealStatements'; import { DisplaySecretStatements } from './Display/DisplaySecretStatements'; import { createWeb3IdDIDFromCredential, DisplayCredentialStatementProps, SecretStatementV2 } from './utils'; +function Logo({ logo }: { logo: MetadataUrl }) { + return ; +} + +export function DisplayVC({ option }: { option: VerifiableCredential }) { + const metadata = useCredentialMetadata(option); + + if (!metadata) { + return null; + } + + return ( +
    + +
    {metadata.title}
    +
    + ); +} + export default function DisplayWeb3Statement({ credentialStatement, validCredentials, @@ -64,10 +84,9 @@ export default function DisplayWeb3Statement({ metadata={metadata} localization={localization.result} /> - - options={validCredentials} - displayOption={(option) => getVerifiableCredentialPublicKeyfromSubjectDID(option.id)} + DisplayOption={DisplayVC} onChange={onChange} /> {reveals.length !== 0 && ( diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index e1d7d4e7..8a4477ef 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -55,3 +55,13 @@ } } } + +.verifiable-credential { + &__selector { + width: 376px; + height: 60px; + border-radius: 12px; + box-shadow: 0 0 15px 0 #0000001a; + background: #fff; + } +} From d238334ad93e99f33b95230e9894bea5cd8e31cb Mon Sep 17 00:00:00 2001 From: Hjort Date: Wed, 30 Aug 2023 13:13:03 +0200 Subject: [PATCH 05/29] More proof UI --- .../Web3ProofRequest/CredentialSelector.tsx | 19 +++- .../Web3ProofRequest/Display/DisplayBox.tsx | 2 +- .../VerifiableCredentialStatement.tsx | 26 +++--- .../Web3ProofRequest/Web3ProofRequest.scss | 90 ++++++++++++++++++- .../Web3ProofRequest/Web3ProofRequest.tsx | 27 ++++-- .../popup/pages/Web3ProofRequest/i18n/en.ts | 6 ++ .../src/popup/shared/Modal/Modal.tsx | 7 +- .../src/popup/styles/config/_typography.scss | 14 --- 8 files changed, 149 insertions(+), 42 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx index 65922f0b..4ba17e8a 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx @@ -1,12 +1,14 @@ import Button from '@popup/shared/Button'; import Modal from '@popup/shared/Modal'; import React, { ComponentType, useState } from 'react'; +import BackIcon from '@assets/svg/back-arrow.svg'; interface Props { options: T[]; initialIndex?: number; onChange: (x: T) => void; DisplayOption: ComponentType<{ option: T }>; + header: string; } /** @@ -17,6 +19,7 @@ export default function CredentialSelector({ initialIndex = 0, onChange, DisplayOption, + header, }: Props) { const [chosenIndex, setChosenIndex] = useState(initialIndex); const [open, setOpen] = useState(false); @@ -28,21 +31,33 @@ export default function CredentialSelector({ function onClick(index: number) { setChosenIndex(index); onChange(options[index]); + setOpen(false); } return ( setOpen(true)} onClose={() => setOpen(false)} trigger={ - } + className="p-0" > +
    +

    {header}

    + +
    {options.map((opt, index) => ( - ))} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx index 7464ecaa..620e82da 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx @@ -29,7 +29,7 @@ export function DisplayBox({ className, children, header, infoBox }: DisplayBoxP } > {infoBox} -
    diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx index 2ec49f35..97358c2d 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx @@ -1,21 +1,16 @@ -import { MetadataUrl } from '@concordium/browser-wallet-api-helpers/lib/wallet-api-types'; import { RevealStatementV2, StatementTypes, VerifiableCredentialStatement } from '@concordium/web-sdk'; import Img from '@popup/shared/Img'; import { storedVerifiableCredentialSchemasAtom } from '@popup/store/verifiable-credential'; -import { VerifiableCredential, VerifiableCredentialStatus } from '@shared/storage/types'; +import { VerifiableCredential } from '@shared/storage/types'; import { useAtomValue } from 'jotai'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { VerifiableCredentialCard } from '../VerifiableCredential/VerifiableCredentialCard'; +import { useTranslation } from 'react-i18next'; import { useCredentialLocalization, useCredentialMetadata } from '../VerifiableCredential/VerifiableCredentialHooks'; import CredentialSelector from './CredentialSelector'; import { DisplayRevealStatements } from './Display/DisplayRevealStatements'; import { DisplaySecretStatements } from './Display/DisplaySecretStatements'; import { createWeb3IdDIDFromCredential, DisplayCredentialStatementProps, SecretStatementV2 } from './utils'; -function Logo({ logo }: { logo: MetadataUrl }) { - return ; -} - export function DisplayVC({ option }: { option: VerifiableCredential }) { const metadata = useCredentialMetadata(option); @@ -25,8 +20,10 @@ export function DisplayVC({ option }: { option: VerifiableCredential }) { return (
    - -
    {metadata.title}
    +
    + +
    +
    {metadata.title}
    ); } @@ -38,6 +35,7 @@ export default function DisplayWeb3Statement({ setChosenId, net, }: DisplayCredentialStatementProps) { + const { t } = useTranslation('web3IdProofRequest'); const reveals = credentialStatement.statement.filter( (s) => s.type === StatementTypes.RevealAttribute ) as RevealStatementV2[]; @@ -75,19 +73,15 @@ export default function DisplayWeb3Statement({ return null; } + // TODO translate selector header return (
    - +

    {t('descriptions.verifiableCredential')}

    options={validCredentials} DisplayOption={DisplayVC} onChange={onChange} + header="Select verifiable credential" /> {reveals.length !== 0 && ( - - + {currentStatementIndex > 0 && ( + + )} {currentStatementIndex === statements.length - 1 ? ( ) : ( )} - +
    ); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index e1c6a3b4..e37b1e6f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -2,6 +2,7 @@ export default { header: '{{dappName}} requests the following information about you:', accept: 'Accept', continue: 'Continue', + back: 'Back', reject: 'Reject', displayStatement: { requirementsMet: 'You meet this requirement', @@ -32,6 +33,11 @@ export default { missingAttribute: 'The attribute cannot be found on the identity "{{identityName}}"', }, }, + descriptions: { + verifiableCredential: 'Select a verifiable credential to reveal/prove the requested information.', + accountCredential: + 'Select an account associated with the identity whose credentials will be used to reveal/prove the requested information.', + }, failedProof: 'Unable to create proof', failedProofReason: 'Unable to create proof due to: {{ reason }}', unableToProve: diff --git a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx index 5d172680..17323363 100644 --- a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx +++ b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx @@ -51,6 +51,10 @@ export type ModalProps = { onOpen?(): void; onClose?(): void; bottom?: boolean; + /** + * Used to overwrite styling for the modal content box + */ + className?: string; }; /** @@ -64,6 +68,7 @@ export type ModalProps = { */ export default function Modal({ trigger, + className, disableClose = false, open: isOpenOverride, error = false, @@ -143,7 +148,7 @@ export default function Modal({ {!isExiting && ( Date: Wed, 30 Aug 2023 13:14:38 +0200 Subject: [PATCH 06/29] Add new styling --- packages/browser-wallet/src/popup/index.scss | 6 + .../Web3ProofRequest/Web3ProofRequest.scss | 3 +- .../src/popup/styles-new/config/_bundle.scss | 2 + .../src/popup/styles-new/config/_colors.scss | 56 +++++++ .../popup/styles-new/config/_typography.scss | 146 ++++++++++++++++++ 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 packages/browser-wallet/src/popup/styles-new/config/_bundle.scss create mode 100644 packages/browser-wallet/src/popup/styles-new/config/_colors.scss create mode 100644 packages/browser-wallet/src/popup/styles-new/config/_typography.scss diff --git a/packages/browser-wallet/src/popup/index.scss b/packages/browser-wallet/src/popup/index.scss index 694da9a1..27323526 100644 --- a/packages/browser-wallet/src/popup/index.scss +++ b/packages/browser-wallet/src/popup/index.scss @@ -1,3 +1,9 @@ +// New styling + +@import 'styles-new/config/bundle'; + +// Old styling + @import 'styles/config/bundle'; @import 'styles/elements/bundle'; diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 0075b3df..8cfdb182 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -18,8 +18,9 @@ &__credential-statement-container { height: calc(100% - 115px); - overflow-y: overlay; margin-bottom: rem(20px); + scrollbar-gutter: stable; + margin-right: 16px; } &__selector-icon { diff --git a/packages/browser-wallet/src/popup/styles-new/config/_bundle.scss b/packages/browser-wallet/src/popup/styles-new/config/_bundle.scss new file mode 100644 index 00000000..69708e5b --- /dev/null +++ b/packages/browser-wallet/src/popup/styles-new/config/_bundle.scss @@ -0,0 +1,2 @@ +@import 'colors'; +@import 'typography'; diff --git a/packages/browser-wallet/src/popup/styles-new/config/_colors.scss b/packages/browser-wallet/src/popup/styles-new/config/_colors.scss new file mode 100644 index 00000000..66f9e78a --- /dev/null +++ b/packages/browser-wallet/src/popup/styles-new/config/_colors.scss @@ -0,0 +1,56 @@ +// Color definitions + +// Primary Colors +$color-primary-mineral-blue: #48a2ae; +$color-primary-mineral-80: #6db5be; +$color-primary-mineral-60: #91c7ce; +$color-primary-mineral-40: #b6dadf; +$color-primary-mineral-20: #daecef; +$color-primary-mineral-10: #ecf6f7; +$color-primary-mineral-05: #f6fafb; + +// Secondary Colors +$color-secondary-dark-blue: #052535; +$color-secondary-ocean-140: #013243; +$color-secondary-ocean-120: #01475f; +$color-secondary-ocean-blue: #005a78; +$color-secondary-ocean-80: #337b93; +$color-secondary-ocean-60: #7facbb; +$color-secondary-egg-shell-white: #fffde4; +$color-secondary-off-white: #ebf0f0; + +// Neutral Colors +$color-neutral-black: #000; +$color-neutral-gray-90: #191919; +$color-neutral-gray-80: #333; +$color-neutral-gray-70: #4c4c4c; +$color-neutral-gray-60: #666; +$color-neutral-gray-50: #7f7f7f; +$color-neutral-gray-40: #999; +$color-neutral-gray-30: #b2b2b2; +$color-neutral-gray-20: #ccc; +$color-neutral-gray-10: #e5e5e5; +$color-neutral-gray-05: #f2f2f2; +$color-neutral-white: #fff; + +// State Colors +$color-feedback-negative-dark: #ab2b2b; +$color-feedback-negative-base: #dc5050; +$color-feedback-negative-light: #e87e90; +$color-feedback-positive-dark: #189e46; +$color-feedback-positive-base: #33c364; +$color-feedback-positive-light: #8be7aa; +$color-feedback-warning-dark: #c89e0a; +$color-feedback-warning-base: #fbcd29; +$color-feedback-warning-light: #f6db9a; +$color-feedback-info-dark: #075cab; +$color-feedback-info-base: #2485df; +$color-feedback-info-light: #65a4dd; +$color-feedback-help-dark: #53198e; +$color-feedback-help-base: #7939ba; +$color-feedback-help-light: #b37cdf; + +// Grdients +$gradient-dark-mineral-blue-bg: linear-gradient(144deg, #005a78 0%, #2e8894 100%); +$gradient-dark-mineral-blue-button: linear-gradient(161deg, #005a78 0%, #48a2ae 100%); +$gradient-disable-button: linear-gradient(170deg, #ccc 0%, #e5e5e5 100%); diff --git a/packages/browser-wallet/src/popup/styles-new/config/_typography.scss b/packages/browser-wallet/src/popup/styles-new/config/_typography.scss new file mode 100644 index 00000000..3406c129 --- /dev/null +++ b/packages/browser-wallet/src/popup/styles-new/config/_typography.scss @@ -0,0 +1,146 @@ +@use 'sass:map'; +@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;700&display=swap'); + +$t-font-family-ibm: 'IBM Plex Sans', sans-serif; +$t-font-weight-light: 300; +$t-font-weight-regular: 400; +$t-font-weight-medium: 500; +$t-font-weight-semi-bold: 600; +$t-font-weight-bold: 700; + +$s-type-config: ( + display: ( + font-weight: $t-font-weight-bold, + styles: ( + display1: ( + font-size: 40px, + line-height: 47px, + ), + display2: ( + font-size: 32px, + line-height: 36px, + ), + display3: ( + font-size: 25px, + line-height: 30px, + ), + display4: ( + font-size: 20px, + line-height: 24px, + ), + display5: ( + font-size: 16px, + line-height: 19px, + ), + display6: ( + font-size: 14px, + line-height: 17px, + ), + ), + ), + heading: ( + font-weight: $t-font-weight-medium, + styles: ( + heading1: ( + font-size: 28px, + line-height: 36px, + ), + heading2: ( + font-size: 24px, + line-height: 32px, + ), + heading3: ( + font-size: 20px, + line-height: 28px, + ), + heading4: ( + font-size: 18px, + line-height: 26px, + ), + heading5: ( + font-size: 16px, + line-height: 20px, + ), + heading6: ( + font-size: 14px, + line-height: 18px, + ), + heading7: ( + font-size: 12px, + line-height: 16px, + ), + ), + ), + body: ( + font-weight: $t-font-weight-regular, + styles: ( + bodyXL: ( + font-size: 20px, + line-height: 26px, + ), + bodyL: ( + font-size: 16px, + line-height: 20px, + ), + bodyM: ( + font-size: 14px, + line-height: 18px, + ), + bodyS: ( + font-size: 12px, + line-height: 16px, + ), + bodyXS: ( + font-size: 11px, + line-height: 14px, + ), + ), + ), + bodyLight: ( + font-weight: $t-font-weight-light, + styles: ( + bodyLightXL: ( + font-size: 20px, + line-height: 26px, + ), + bodyLightL: ( + font-size: 16px, + line-height: 20px, + ), + bodyLightM: ( + font-size: 14px, + line-height: 18px, + ), + bodyLightS: ( + font-size: 12px, + line-height: 16px, + ), + bodyLightXS: ( + font-size: 11px, + line-height: 14px, + ), + ), + ), + button: ( + font-weight: $t-font-weight-semi-bold, + styles: ( + button: ( + font-size: 14px, + line-height: 20px, + ), + ), + ), +); + +@each $cat-name, $cat-content in $s-type-config { + $style-weight: map.get($cat-content, 'font-weight'); + @each $style-name, $style-content in map.get($cat-content, 'styles') { + .#{$style-name} { + font-weight: $style-weight; + font-family: $t-font-family-ibm; + @each $key, $value in $style-content { + #{$key}: #{$value}; + } + } + } +} From 4556444767eb8920da8987ea0cda43cabfd5adef Mon Sep 17 00:00:00 2001 From: Hjort Date: Wed, 30 Aug 2023 13:41:40 +0200 Subject: [PATCH 07/29] Improve add-web3Id example --- examples/add-example-Web3Id/index.html | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/add-example-Web3Id/index.html b/examples/add-example-Web3Id/index.html index e741778d..144bfc74 100644 --- a/examples/add-example-Web3Id/index.html +++ b/examples/add-example-Web3Id/index.html @@ -43,10 +43,17 @@ b .revealAttribute('degreeType') .revealAttribute('degreeName') - .addMembership('graduationDate', [ - graduationDate.valueAsDate, - new Date('2023-08-28T00:00:00.000Z'), - ]) + .revealAttribute('graduationDate') + ) + .addForVerifiableCredentials([{ index: 6105n, subindex: 0n }], (b) => + b + .addNonMembership('degreeType', ['test', 'test2']) + .addMembership('degreeName', ['Bachelor of Science and Arts', 'Bachelor of Finance']) + .addRange( + 'graduationDate', + new Date('1900-08-28T00:00:00.000Z'), + new Date('2030-08-28T00:00:00.000Z') + ) ) .getStatements(); @@ -100,7 +107,7 @@ attributes: values, }, credentialSchema: { - id: 'https://gist.githubusercontent.com/shjortConcordium/a2dc69761d2007c308f6511abaa3eb70/raw/11ad6745dcfa57e7049b08be146858a928a7aa82/gistfile1.txt', + id: web3Schema.value, type: 'JsonSchema2023', }, }, @@ -162,6 +169,13 @@

    Account address:

    value="https://raw.githubusercontent.com/Concordium/concordium-web3id/credential-metadata-example/examples/json-schemas/metadata/credential-metadata.json" />
    + Web3Id Schema: + +
    issuer Index:

    Attribute values:

    From 2c84262a67bfacf67aa9a5b30a8bb9cce39776ab Mon Sep 17 00:00:00 2001 From: Hjort Date: Thu, 31 Aug 2023 08:55:32 +0200 Subject: [PATCH 08/29] More UI --- .../src/assets/svg/warning-triangle.svg | 5 + .../ExternalRequestLayout.scss | 1 - .../ExternalRequestLayout.tsx | 7 +- .../popup/page-layouts/MainLayout/i18n/en.ts | 2 +- .../AddWeb3IdCredential.tsx | 2 +- .../ConnectAccountsRequest.tsx | 4 +- .../ConnectionRequest/ConnectionRequest.tsx | 2 +- .../ExternalAddTokens/ExternalAddTokens.tsx | 2 +- .../pages/IdProofRequest/IdProofRequest.tsx | 2 +- .../pages/SendTransaction/SendTransaction.tsx | 2 +- .../popup/pages/SignMessage/SignMessage.tsx | 2 +- .../Web3ProofRequest/AccountStatement.tsx | 59 ++++++--- .../Display/DisplayRevealStatements.tsx | 31 +++-- .../Display/DisplaySecretStatements.tsx | 58 +++++---- .../Display/DisplayStatementLine.tsx | 30 +++++ .../pages/Web3ProofRequest/Display/utils.ts | 15 ++- .../VerifiableCredentialStatement.tsx | 13 +- .../Web3ProofRequest/Web3ProofRequest.scss | 45 ++++++- .../Web3ProofRequest/Web3ProofRequest.tsx | 122 +++++++++--------- .../popup/pages/Web3ProofRequest/i18n/en.ts | 4 + .../browser-wallet/src/popup/shell/Root.tsx | 2 + .../src/popup/styles-new/config/_colors.scss | 4 + .../src/popup/styles/util/_flex.scss | 4 + .../src/shared/storage/types.ts | 21 ++- 24 files changed, 294 insertions(+), 145 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svg/warning-triangle.svg create mode 100644 packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx diff --git a/packages/browser-wallet/src/assets/svg/warning-triangle.svg b/packages/browser-wallet/src/assets/svg/warning-triangle.svg new file mode 100644 index 00000000..a6409582 --- /dev/null +++ b/packages/browser-wallet/src/assets/svg/warning-triangle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.scss b/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.scss index e4d26bdb..896ebb78 100644 --- a/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.scss +++ b/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.scss @@ -4,7 +4,6 @@ background-color: $color-bg; &__main { - padding: rem(10px); height: calc(100% - $account-page-details-height); overflow: overlay; } diff --git a/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.tsx b/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.tsx index 50718d9c..a52ac889 100644 --- a/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.tsx +++ b/packages/browser-wallet/src/popup/page-layouts/ExternalRequestLayout/ExternalRequestLayout.tsx @@ -8,6 +8,7 @@ import Toast from '@popup/shared/Toast/Toast'; import { useCredential } from '@popup/shared/utils/account-helpers'; import AccountDetails from '@popup/pages/Account/AccountDetails'; import clsx from 'clsx'; +import { ClassName } from 'wallet-common-helpers'; function Header() { const { t } = useTranslation('mainLayout'); @@ -61,7 +62,7 @@ interface Props { children?: ReactNode; } -export default function ExternalRequestLayout({ children }: Props) { +export default function ExternalRequestLayout({ children, className }: Props & ClassName) { const { state } = useLocation() as Location; const account = useCredential(state.payload.accountAddress); @@ -70,7 +71,9 @@ export default function ExternalRequestLayout({ children }: Props) {
    {account && } -
    {children}
    +
    + {children} +
    diff --git a/packages/browser-wallet/src/popup/page-layouts/MainLayout/i18n/en.ts b/packages/browser-wallet/src/popup/page-layouts/MainLayout/i18n/en.ts index b4717f67..ca516e4b 100644 --- a/packages/browser-wallet/src/popup/page-layouts/MainLayout/i18n/en.ts +++ b/packages/browser-wallet/src/popup/page-layouts/MainLayout/i18n/en.ts @@ -20,7 +20,7 @@ const t = { connectAccountsRequest: 'Connect accounts', addTokens: 'Add tokens', idProof: 'Proof of identity', - web3IdProof: 'Proof of identity', + web3IdProof: 'Proof of identity request', request: 'Signature Request', connect: 'New connection', allowlistingRequest: 'Allowlisting request', diff --git a/packages/browser-wallet/src/popup/pages/AddWeb3IdCredential/AddWeb3IdCredential.tsx b/packages/browser-wallet/src/popup/pages/AddWeb3IdCredential/AddWeb3IdCredential.tsx index 818c85ae..bfd8ddef 100644 --- a/packages/browser-wallet/src/popup/pages/AddWeb3IdCredential/AddWeb3IdCredential.tsx +++ b/packages/browser-wallet/src/popup/pages/AddWeb3IdCredential/AddWeb3IdCredential.tsx @@ -214,7 +214,7 @@ export default function AddWeb3IdCredential({ onAllow, onReject }: Props) { const urlDisplay = displayUrl(url); return ( - +
    {error && (
    diff --git a/packages/browser-wallet/src/popup/pages/ConnectAccountsRequest/ConnectAccountsRequest.tsx b/packages/browser-wallet/src/popup/pages/ConnectAccountsRequest/ConnectAccountsRequest.tsx index 271f3ad9..8f691a9e 100644 --- a/packages/browser-wallet/src/popup/pages/ConnectAccountsRequest/ConnectAccountsRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/ConnectAccountsRequest/ConnectAccountsRequest.tsx @@ -18,7 +18,7 @@ type Props = { }; function LoadingConnectAccountsRequest() { - return ; + return ; } export default function ConnectAccountsRequest({ onAllow, onReject }: Props) { @@ -51,7 +51,7 @@ export default function ConnectAccountsRequest({ onAllow, onReject }: Props) { const urlDisplay = displayUrl(url); return ( - +

    {t('header', { url: urlDisplay })}

    diff --git a/packages/browser-wallet/src/popup/pages/ConnectionRequest/ConnectionRequest.tsx b/packages/browser-wallet/src/popup/pages/ConnectionRequest/ConnectionRequest.tsx index b60b8a7b..868325a2 100644 --- a/packages/browser-wallet/src/popup/pages/ConnectionRequest/ConnectionRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/ConnectionRequest/ConnectionRequest.tsx @@ -52,7 +52,7 @@ export default function ConnectionRequest({ onAllow, onReject }: Props) { const urlDisplay = displayUrl(url); return ( - +
    {t('waiting')}
    diff --git a/packages/browser-wallet/src/popup/pages/ExternalAddTokens/ExternalAddTokens.tsx b/packages/browser-wallet/src/popup/pages/ExternalAddTokens/ExternalAddTokens.tsx index 5749c5f3..57511c66 100644 --- a/packages/browser-wallet/src/popup/pages/ExternalAddTokens/ExternalAddTokens.tsx +++ b/packages/browser-wallet/src/popup/pages/ExternalAddTokens/ExternalAddTokens.tsx @@ -118,7 +118,7 @@ export default function SignMessage({ respond }: Props) { const allExisting = addingTokens.every(({ status }) => status === ChoiceStatus.existing); return ( - + {detailView !== undefined && ( +

    {t('header', { dappName })}

    diff --git a/packages/browser-wallet/src/popup/pages/SendTransaction/SendTransaction.tsx b/packages/browser-wallet/src/popup/pages/SendTransaction/SendTransaction.tsx index 85b75274..8fe21c78 100644 --- a/packages/browser-wallet/src/popup/pages/SendTransaction/SendTransaction.tsx +++ b/packages/browser-wallet/src/popup/pages/SendTransaction/SendTransaction.tsx @@ -110,7 +110,7 @@ export default function SendTransaction({ onSubmit, onReject }: Props) { }, [payload, key, cost]); return ( - +

    {t('description', { dApp: displayUrl(url) })}

    diff --git a/packages/browser-wallet/src/popup/pages/SignMessage/SignMessage.tsx b/packages/browser-wallet/src/popup/pages/SignMessage/SignMessage.tsx index 4617fed5..2907fb4d 100644 --- a/packages/browser-wallet/src/popup/pages/SignMessage/SignMessage.tsx +++ b/packages/browser-wallet/src/popup/pages/SignMessage/SignMessage.tsx @@ -112,7 +112,7 @@ export default function SignMessage({ onSubmit, onReject }: Props) { }, [state.payload.message, state.payload.accountAddress, key]); return ( - +

    {t('description', { dApp: displayUrl(url) })}

    diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx index f636598c..08b3ec00 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx @@ -5,8 +5,9 @@ import { StatementTypes, AttributeKey, AttributeList, + IDENTITY_SUBJECT_SCHEMA, } from '@concordium/web-sdk'; -import { displaySplitAddress, useIdentityOf } from '@popup/shared/utils/account-helpers'; +import { displaySplitAddress, useIdentityName, useIdentityOf } from '@popup/shared/utils/account-helpers'; import { useDisplayAttributeValue, useGetAttributeName } from '@popup/shared/utils/identity-helpers'; import { WalletCredential, ConfirmedIdentity } from '@shared/storage/types'; import React, { useCallback, useEffect, useState } from 'react'; @@ -23,6 +24,25 @@ import { useStatementName, useStatementValue, } from '../IdProofRequest/DisplayStatement/utils'; +import { DisplayRevealStatements } from './Display/DisplayRevealStatements'; +import { DisplaySecretStatements } from './Display/DisplaySecretStatements'; + +export function DisplayAccount({ option }: { option: WalletCredential }) { + const identityName = useIdentityName(option); + + if (!identityName) { + return null; + } + + return ( +
    +
    +
    {displaySplitAddress(option.address)}
    +
    {identityName}
    +
    +
    + ); +} type DisplaySecretStatementV2Props = ClassName & { identity?: ConfirmedIdentity; @@ -97,12 +117,14 @@ export default function AccountStatement({ setChosenId, net, }: DisplayCredentialStatementProps) { + const { t } = useTranslation('web3IdProofRequest'); const reveals = credentialStatement.statement.filter( (s) => s.type === StatementTypes.RevealAttribute ) as RevealStatementV2[]; const secrets = credentialStatement.statement.filter( (s) => s.type !== StatementTypes.RevealAttribute ) as SecretStatementV2[]; + const displayAttribute = useDisplayAttributeValue(); const [chosenCredential, setChosenCredential] = useState(validCredentials[0]); // We do the type cast, because the check should have been done to filter validCredentials. @@ -120,31 +142,38 @@ export default function AccountStatement({ } }, []); + if (!identity) { + return null; + } + return (
    - {t('descriptions.accountCredential')}

    + options={validCredentials} - displayOption={(option) => displaySplitAddress(option.address)} + DisplayOption={DisplayAccount} onChange={onChange} + header={t('select.accountCredential')} /> {reveals.length !== 0 && ( - )} - {secrets.map((s, i) => ( - - ))} + )}
    ); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx index 00d9db7b..4d3cd74b 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx @@ -1,21 +1,23 @@ import { AttributeType, RevealStatementV2 } from '@concordium/web-sdk'; -import { VerifiableCredentialSchema } from '@shared/storage/types'; import React from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { ClassName } from 'wallet-common-helpers'; -import { DisplayStatementLine } from '../../IdProofRequest/DisplayStatement/DisplayStatement'; +import WarningTriangleIcon from '@assets/svg/warning-triangle.svg'; +import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; -import { getPropertyTitle } from './utils'; +import { DisplayProps, getPropertyTitle } from './utils'; -type RevealProps = ClassName & { +type Props = DisplayProps & { dappName: string; - statements: RevealStatementV2[]; - attributes: Record; - schema: VerifiableCredentialSchema; - className: string; }; -export function DisplayRevealStatements({ className, statements, attributes, dappName, schema }: RevealProps) { +export function DisplayRevealStatements({ + className, + statements, + attributes, + dappName, + schema, + formatAttribute = (_, value) => value.toString(), +}: Props) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.reveal'); @@ -24,7 +26,7 @@ export function DisplayRevealStatements({ className, statements, attributes, dap const title = getPropertyTitle(s.attributeTag, schema); return { attribute: title, - value: value.toString() ?? 'Unavailable', + value: formatAttribute(s.attributeTag, value) ?? 'Unavailable', isRequirementMet: value !== undefined, }; }); @@ -35,12 +37,13 @@ export function DisplayRevealStatements({ className, statements, attributes, dap header={header} infoBox={ <> +

    {t('revealTooltip.header')}

    {t('revealTooltip.body')}

    } > -
      +
        {lines.map((l, i) => ( ))}
      -
      +
      }} + components={{ 1: }} values={{ dappName }} />
      diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx index 1a447bb9..9617edf2 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -1,28 +1,25 @@ import { AttributeType, StatementTypes } from '@concordium/web-sdk'; -import { DisplayStatementLine } from '@popup/pages/IdProofRequest/DisplayStatement/DisplayStatement'; -import { VerifiableCredentialSchema } from '@shared/storage/types'; +import { CredentialSchemaSubject } from '@shared/storage/types'; import React from 'react'; import { TFunction, useTranslation } from 'react-i18next'; -import { ClassName } from 'wallet-common-helpers'; +import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; import { SecretStatementV2 } from '../utils'; -import { getPropertyTitle } from './utils'; +import { DisplayProps, getPropertyTitle } from './utils'; -type SecretProps = ClassName & { - statements: SecretStatementV2[]; - attributes: Record; - schema: VerifiableCredentialSchema; - className: string; -}; - -function getStatementValue( +function getStatementValue( statement: SecretStatementV2, - schema: VerifiableCredentialSchema, - t: TFunction<'web3IdProofRequest', 'displayStatement'> + schema: CredentialSchemaSubject, + t: TFunction<'web3IdProofRequest', 'displayStatement'>, + formatAttribute: (key: string, value: Attribute) => string ): string { const name = getPropertyTitle(statement.attributeTag, schema); if (statement.type === StatementTypes.AttributeInRange) { - return t('proofs.range', { name, upper: statement.upper, lower: statement.lower }); + return t('proofs.range', { + name, + upper: formatAttribute(statement.attributeTag, statement.upper as Attribute), + lower: formatAttribute(statement.attributeTag, statement.lower as Attribute), + }); } if (statement.type === StatementTypes.AttributeInSet) { return t('proofs.membership', { name }); @@ -34,17 +31,23 @@ function getStatementValue( throw new Error('Unknown statement type'); } -function getStatementDescription( +function getStatementDescription( statement: SecretStatementV2, - schema: VerifiableCredentialSchema, - t: TFunction<'web3IdProofRequest', 'displayStatement'> + schema: CredentialSchemaSubject, + t: TFunction<'web3IdProofRequest', 'displayStatement'>, + formatAttribute: (key: string, value: Attribute) => string ) { const name = getPropertyTitle(statement.attributeTag, schema); - const listToString = (list: AttributeType[]) => list.map((member) => member.toString()).join(', '); + const listToString = (list: AttributeType[]) => + list.map((member) => formatAttribute(statement.attributeTag, member as Attribute)).join(', '); switch (statement.type) { case StatementTypes.AttributeInRange: - return t('descriptions.range', { name, lower: statement.lower, upper: statement.upper }); + return t('descriptions.range', { + name, + upper: formatAttribute(statement.attributeTag, statement.upper as Attribute), + lower: formatAttribute(statement.attributeTag, statement.lower as Attribute), + }); case StatementTypes.AttributeInSet: return t('descriptions.membership', { name, setNames: listToString(statement.set) }); case StatementTypes.AttributeNotInSet: @@ -54,14 +57,19 @@ function getStatementDescription( } } -export function DisplaySecretStatements({ schema, statements, className }: SecretProps) { +export function DisplaySecretStatements({ + schema, + statements, + className, + formatAttribute = (_, value) => value.toString(), +}: DisplayProps) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.secret'); const lines = statements.map((s) => { - const value = getStatementValue(s, schema, t); + const value = getStatementValue(s, schema, t, formatAttribute); const title = getPropertyTitle(s.attributeTag, schema); - const description = getStatementDescription(s, schema, t); + const description = getStatementDescription(s, schema, t, formatAttribute); return { attribute: title, value: value.toString() ?? 'Unavailable', @@ -81,7 +89,7 @@ export function DisplaySecretStatements({ schema, statements, className }: Secre } > -
        +
          {lines.map(({ description, ...l }, i) => (
          -
          {description}
          +
          {description}
          ))}
        diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx new file mode 100644 index 00000000..2495101b --- /dev/null +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx @@ -0,0 +1,30 @@ +import clsx from 'clsx'; +import React from 'react'; +import { ClassName } from 'wallet-common-helpers'; + +import CheckmarkIcon from '@assets/svg/checkmark-dark-green.svg'; +import CrossIcon from '@assets/svg/cross.svg'; + +export type StatementLine = { + attribute: string; + value: string; + isRequirementMet: boolean; +}; + +type StatementLineProps = StatementLine & ClassName; + +export function DisplayStatementLine({ attribute, value, isRequirementMet, className }: StatementLineProps) { + return ( +
      • +
        {attribute}:
        +
        + {value} + {isRequirementMet ? ( + + ) : ( + + )} +
        +
      • + ); +} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts index 9a9b669d..802f1a87 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts @@ -1,7 +1,16 @@ -import { VerifiableCredentialSchema } from '@shared/storage/types'; +import { CredentialSchemaSubject } from '@shared/storage/types'; +import { ClassName } from 'wallet-common-helpers'; -export function getPropertyTitle(attributeTag: string, schema: VerifiableCredentialSchema) { +export function getPropertyTitle(attributeTag: string, schemaSubject: CredentialSchemaSubject) { // TODO use localization here - const property = schema.properties.credentialSubject.properties.attributes.properties[attributeTag]; + const property = schemaSubject.properties.attributes.properties[attributeTag]; return property ? property.title : attributeTag; } + +export type DisplayProps = ClassName & { + statements: StatementType[]; + attributes: Record; + schema: CredentialSchemaSubject; + className: string; + formatAttribute?: (key: string, value: Attribute) => string; +}; diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx index 97358c2d..05e0c9be 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx @@ -73,31 +73,30 @@ export default function DisplayWeb3Statement({ return null; } - // TODO translate selector header return (
        -

        {t('descriptions.verifiableCredential')}

        +

        {t('descriptions.verifiableCredential')}

        options={validCredentials} DisplayOption={DisplayVC} onChange={onChange} - header="Select verifiable credential" + header={t('select.verifiableCredential')} /> {reveals.length !== 0 && ( )} {secrets.length !== 0 && ( )}
        diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 8cfdb182..ac3770f9 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -5,11 +5,20 @@ height: 100%; } + &__statement { + margin-top: 25px; + } + &__actions { + height: 115px; margin-top: auto; display: grid; grid-auto-flow: column; column-gap: 7px; + padding-top: 35px; + padding-left: 32px; + padding-right: 32px; + box-shadow: 0 0 30px 0 #0003; } &__loading-icon { @@ -18,9 +27,10 @@ &__credential-statement-container { height: calc(100% - 115px); - margin-bottom: rem(20px); - scrollbar-gutter: stable; - margin-right: 16px; + scrollbar-gutter: stable both-edges; + padding-right: 16px; + padding-left: 16px; + overflow-y: auto; } &__selector-icon { @@ -65,6 +75,13 @@ &__continue-button { flex-grow: 1; } + + &__description { + height: 120px; + padding-top: 32px; + color: $color-neutral-gray-50; + margin: 0; + } } .new-button-styling { @@ -95,14 +112,29 @@ } .display-reveal-statements { + &__body { + padding: 16px; + margin: 0; + } + &__line { &:not(:last-child) { margin-bottom: 8px; } } + + &__description { + color: $color-neutral-gray-30; + padding: 8px 16px 16px; + } } .display-secret-statements { + &__body { + padding: 16px; + margin: 0; + } + &__line { margin-top: 5px; @@ -110,12 +142,17 @@ border-bottom: 1px solid #e5e5e5; } } + + &__description { + color: $color-neutral-gray-30; + padding: 8px 16px 16px; + } } .verifiable-credential { &__selector { width: 100%; - margin: 10px 0; + margin: 0; height: 60px; border-radius: 12px; box-shadow: 0 0 15px 0 #0000001a; diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx index 3926e19a..865c48ba 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx @@ -218,72 +218,70 @@ export default function Web3ProofRequest({ onReject, onSubmit }: Props) { } return ( - -
        - - setIds((currentIds) => { - const newIds = [...currentIds]; - newIds[currentStatementIndex] = newId; - return newIds; - }) - } - /> -
        + + + setIds((currentIds) => { + const newIds = [...currentIds]; + newIds[currentStatementIndex] = newId; + return newIds; + }) + } + /> +
        + + {currentStatementIndex > 0 && ( + )} + {currentStatementIndex === statements.length - 1 ? ( + + ) : ( + - {currentStatementIndex > 0 && ( - - )} - {currentStatementIndex === statements.length - 1 ? ( - - ) : ( - - )} -
        + )}
        ); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index e37b1e6f..9acb4ac4 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -33,6 +33,10 @@ export default { missingAttribute: 'The attribute cannot be found on the identity "{{identityName}}"', }, }, + select: { + verifiableCredential: 'Select verifiable credential', + accountCredential: 'Select Account', + }, descriptions: { verifiableCredential: 'Select a verifiable credential to reveal/prove the requested information.', accountCredential: diff --git a/packages/browser-wallet/src/popup/shell/Root.tsx b/packages/browser-wallet/src/popup/shell/Root.tsx index 4618bb4f..637fd833 100644 --- a/packages/browser-wallet/src/popup/shell/Root.tsx +++ b/packages/browser-wallet/src/popup/shell/Root.tsx @@ -45,6 +45,8 @@ function useScaling() { } if (dimensions && isSpawnedWindow) { + // TODO only for web3IdRequest? + dimensions = { width: 440, height: 870 }; // Send a message to the BG script to resize the window. popupMessageHandler.sendInternalMessage(InternalMessageType.SetViewSize, dimensions).catch(noOp); } diff --git a/packages/browser-wallet/src/popup/styles-new/config/_colors.scss b/packages/browser-wallet/src/popup/styles-new/config/_colors.scss index 66f9e78a..a04ccddc 100644 --- a/packages/browser-wallet/src/popup/styles-new/config/_colors.scss +++ b/packages/browser-wallet/src/popup/styles-new/config/_colors.scss @@ -54,3 +54,7 @@ $color-feedback-help-light: #b37cdf; $gradient-dark-mineral-blue-bg: linear-gradient(144deg, #005a78 0%, #2e8894 100%); $gradient-dark-mineral-blue-button: linear-gradient(161deg, #005a78 0%, #48a2ae 100%); $gradient-disable-button: linear-gradient(170deg, #ccc 0%, #e5e5e5 100%); + +.color-feedback-negative-dark { + color: $color-feedback-negative-dark; +} diff --git a/packages/browser-wallet/src/popup/styles/util/_flex.scss b/packages/browser-wallet/src/popup/styles/util/_flex.scss index a6fe43c3..a9a103a8 100644 --- a/packages/browser-wallet/src/popup/styles/util/_flex.scss +++ b/packages/browser-wallet/src/popup/styles/util/_flex.scss @@ -32,6 +32,10 @@ align-items: center; } +.align-start { + align-items: flex-start; +} + .flex-child-fill { flex: 1; } diff --git a/packages/browser-wallet/src/shared/storage/types.ts b/packages/browser-wallet/src/shared/storage/types.ts index 1ef3c8c5..a3fe242e 100644 --- a/packages/browser-wallet/src/shared/storage/types.ts +++ b/packages/browser-wallet/src/shared/storage/types.ts @@ -5,6 +5,8 @@ import type { HexString, IdentityObjectV1, Network, + SimplePropertyDetails, + TimestampPropertyDetails, Versioned, } from '@concordium/web-sdk'; @@ -315,15 +317,28 @@ export type TimestampProperty = { description?: string; }; +type IdDetails = { + title: string; + description?: string; + type: 'string'; +}; + type CredentialSchemaAttributes = { - properties: Record; + properties: Record< + string, + CredentialSchemaProperty | TimestampProperty | SimplePropertyDetails | TimestampPropertyDetails + >; required: string[]; + title?: string; + type: 'object'; + description?: string; + format?: string; } & CredentialSchemaProperty; -interface CredentialSchemaSubject { +export interface CredentialSchemaSubject { type: string; properties: { - id: CredentialSchemaProperty; + id: IdDetails; attributes: CredentialSchemaAttributes; }; required: string[]; From bfce90d9c511871f43dc6a975d38fbb21a72518a Mon Sep 17 00:00:00 2001 From: Hjort Date: Thu, 31 Aug 2023 14:21:41 +0200 Subject: [PATCH 09/29] Adjustment to selector / modals --- .../src/assets/svg/down-arrow.svg | 15 +++++++ .../Web3ProofRequest/CredentialSelector.tsx | 9 +++-- .../Web3ProofRequest/Display/DisplayBox.tsx | 1 + .../Web3ProofRequest/Web3ProofRequest.scss | 40 +++++++++++++------ .../src/popup/shared/Modal/Modal.scss | 6 +++ .../src/popup/shared/Modal/Modal.tsx | 4 +- 6 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svg/down-arrow.svg diff --git a/packages/browser-wallet/src/assets/svg/down-arrow.svg b/packages/browser-wallet/src/assets/svg/down-arrow.svg new file mode 100644 index 00000000..d5fbc19f --- /dev/null +++ b/packages/browser-wallet/src/assets/svg/down-arrow.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx index 4ba17e8a..5e4accca 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/CredentialSelector.tsx @@ -1,7 +1,7 @@ import Button from '@popup/shared/Button'; import Modal from '@popup/shared/Modal'; import React, { ComponentType, useState } from 'react'; -import BackIcon from '@assets/svg/back-arrow.svg'; +import ArrowIcon from '@assets/svg/down-arrow.svg'; interface Props { options: T[]; @@ -41,15 +41,16 @@ export default function CredentialSelector({ onOpen={() => setOpen(true)} onClose={() => setOpen(false)} trigger={ - } - className="p-0" + className="verifiable-credential__selector-modal" >

        {header}

        - +
        {options.map((opt, index) => (
        @@ -271,7 +271,7 @@ export default function Web3ProofRequest({ onReject, onSubmit }: Props) { {creatingProof ? ( ) : ( - t('accept') + t('approve') )} ) : ( diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts index 9b030d36..bab7f6f1 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts @@ -2,7 +2,7 @@ import type en from './en'; const t: typeof en = { header: '{{dappName}} anmoder om følgende information om dig:', - accept: 'Godkend', + approve: 'Godkend', reject: 'Afvis', continue: 'Fortsæt', displayStatement: { diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index 9acb4ac4..c747a0ba 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -1,6 +1,6 @@ export default { header: '{{dappName}} requests the following information about you:', - accept: 'Accept', + approve: 'Approve', continue: 'Continue', back: 'Back', reject: 'Reject', From c97d2dcb67f1ca2f39dd23daa43abae2bd4a83a5 Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 15:57:54 +0200 Subject: [PATCH 13/29] Fix tooltip help button --- packages/browser-wallet/src/assets/svg/help.svg | 5 +++++ .../popup/pages/Web3ProofRequest/Display/DisplayBox.tsx | 4 ++-- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 ++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svg/help.svg diff --git a/packages/browser-wallet/src/assets/svg/help.svg b/packages/browser-wallet/src/assets/svg/help.svg new file mode 100644 index 00000000..128a8b6b --- /dev/null +++ b/packages/browser-wallet/src/assets/svg/help.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx index 2cab8e33..a2c4c5d0 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx @@ -3,7 +3,7 @@ import Modal from '@popup/shared/Modal'; import clsx from 'clsx'; import React, { ReactNode, useState } from 'react'; import { ClassName } from 'wallet-common-helpers'; -import InfoTooltipIcon from '@assets/svg/info-tooltip.svg'; +import InfoTooltipIcon from '@assets/svg/help.svg'; type DisplayBoxProps = ClassName & { header: string; @@ -24,7 +24,7 @@ export function DisplayBox({ className, children, header, infoBox }: DisplayBoxP onOpen={() => setOpen(true)} onClose={() => setOpen(false)} trigger={ - } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 3bb182e3..6b1354ea 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -102,8 +102,16 @@ color: $color-secondary-ocean-blue; } + &__tooltip-button { + align-items: center; + } + &__tooltip-icon { height: 24px; + + path { + fill: $color-secondary-ocean-blue; + } } } From 03209b51dd5f8d8c407018c361a59fd58716e2f0 Mon Sep 17 00:00:00 2001 From: Hjort Date: Thu, 31 Aug 2023 16:00:24 +0200 Subject: [PATCH 14/29] Fix errors --- .../popup/pages/Web3ProofRequest/AccountStatement.tsx | 6 +++--- .../src/popup/pages/Web3ProofRequest/i18n/da.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx index 08b3ec00..0c890a8d 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx @@ -9,7 +9,7 @@ import { } from '@concordium/web-sdk'; import { displaySplitAddress, useIdentityName, useIdentityOf } from '@popup/shared/utils/account-helpers'; import { useDisplayAttributeValue, useGetAttributeName } from '@popup/shared/utils/identity-helpers'; -import { WalletCredential, ConfirmedIdentity } from '@shared/storage/types'; +import { WalletCredential, ConfirmedIdentity, CredentialSchemaSubject } from '@shared/storage/types'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ClassName } from 'wallet-common-helpers'; @@ -162,7 +162,7 @@ export default function AccountStatement({ attributes={identity.idObject.value.attributeList.chosenAttributes} statements={reveals} formatAttribute={displayAttribute} - schema={IDENTITY_SUBJECT_SCHEMA} + schema={IDENTITY_SUBJECT_SCHEMA as CredentialSchemaSubject} /> )} {secrets.length !== 0 && ( @@ -171,7 +171,7 @@ export default function AccountStatement({ attributes={identity.idObject.value.attributeList.chosenAttributes} statements={secrets} formatAttribute={displayAttribute} - schema={IDENTITY_SUBJECT_SCHEMA} + schema={IDENTITY_SUBJECT_SCHEMA as CredentialSchemaSubject} /> )}
      diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts index 9b030d36..8680c384 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts @@ -4,6 +4,7 @@ const t: typeof en = { header: '{{dappName}} anmoder om følgende information om dig:', accept: 'Godkend', reject: 'Afvis', + back: 'Tilbage', continue: 'Fortsæt', displayStatement: { requirementsMet: 'Du opfylder kravet', @@ -34,6 +35,15 @@ const t: typeof en = { missingAttribute: 'Denne Attribut kan ikke findes på identiteten "{{identityName}}"', }, }, + select: { + verifiableCredential: 'Vælg verifiable credential', + accountCredential: 'Væg Account', + }, + descriptions: { + verifiableCredential: 'Vælg en verifiable credential til at afsløre/bevise den anmodet information.', + accountCredential: + 'Vælg en account, hvis forbundne identity skal bruges til at afsløre/bevise den anmodet information.', + }, failedProof: 'Bevis kunne ikke oprettes', failedProofReason: 'Bevis kunne ikke oprettes: {{ reason }}', unableToProve: From 73d4c15ceddb98cc09dab8fad742f4082056d3bc Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 16:23:47 +0200 Subject: [PATCH 15/29] Format credential dates better --- .../pages/VerifiableCredential/VerifiableCredentialCard.tsx | 5 ++++- .../Web3ProofRequest/Display/DisplayRevealStatements.tsx | 4 ++-- .../Web3ProofRequest/Display/DisplaySecretStatements.tsx | 4 ++-- .../src/popup/pages/Web3ProofRequest/Display/utils.ts | 6 ++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx b/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx index 36276339..252b5a06 100644 --- a/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx +++ b/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx @@ -10,6 +10,7 @@ import { AttributeType, CredentialSubject } from '@concordium/web-sdk'; import { VerifiableCredentialStatus, MetadataUrl, VerifiableCredentialSchema } from '@shared/storage/types'; import { useTranslation } from 'react-i18next'; import StatusIcon from './VerifiableCredentialStatus'; +import { defaultFormatAttribute } from '../Web3ProofRequest/Display/utils'; function Logo({ logo }: { logo: MetadataUrl }) { return ; @@ -38,7 +39,9 @@ export function DisplayAttribute({ return (
      -
      {attributeValue.toString()}
      +
      + {defaultFormatAttribute(attributeKey, attributeValue)} +
      ); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx index 4d3cd74b..aac0f3c9 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx @@ -4,7 +4,7 @@ import { Trans, useTranslation } from 'react-i18next'; import WarningTriangleIcon from '@assets/svg/warning-triangle.svg'; import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; -import { DisplayProps, getPropertyTitle } from './utils'; +import { DisplayProps, defaultFormatAttribute, getPropertyTitle } from './utils'; type Props = DisplayProps & { dappName: string; @@ -16,7 +16,7 @@ export function DisplayRevealStatements({ attributes, dappName, schema, - formatAttribute = (_, value) => value.toString(), + formatAttribute = defaultFormatAttribute, }: Props) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.reveal'); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx index 9617edf2..ad7d2c37 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -5,7 +5,7 @@ import { TFunction, useTranslation } from 'react-i18next'; import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; import { SecretStatementV2 } from '../utils'; -import { DisplayProps, getPropertyTitle } from './utils'; +import { DisplayProps, defaultFormatAttribute, getPropertyTitle } from './utils'; function getStatementValue( statement: SecretStatementV2, @@ -61,7 +61,7 @@ export function DisplaySecretStatements({ schema, statements, className, - formatAttribute = (_, value) => value.toString(), + formatAttribute = defaultFormatAttribute, }: DisplayProps) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.secret'); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts index 802f1a87..f089d64f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts @@ -1,4 +1,6 @@ +import { AttributeType } from '@concordium/web-sdk'; import { CredentialSchemaSubject } from '@shared/storage/types'; +import { withDateAndTime } from '@shared/utils/time-helpers'; import { ClassName } from 'wallet-common-helpers'; export function getPropertyTitle(attributeTag: string, schemaSubject: CredentialSchemaSubject) { @@ -14,3 +16,7 @@ export type DisplayProps = ClassName & { className: string; formatAttribute?: (key: string, value: Attribute) => string; }; + +export function defaultFormatAttribute(_: string, value: Attribute) { + return value instanceof Date ? withDateAndTime(value) : value.toString(); +} From 8b8cbdd1f4b5e2a8fd6a980d93e6467b49726b33 Mon Sep 17 00:00:00 2001 From: Hjort Date: Thu, 31 Aug 2023 16:26:33 +0200 Subject: [PATCH 16/29] Improve page notProvable page --- examples/add-example-Web3Id/index.html | 1 + .../Web3ProofRequest/AccountStatement.tsx | 86 +------------------ .../Display/DisplayRevealStatements.tsx | 2 +- .../Display/DisplaySecretStatements.tsx | 1 + .../Web3ProofRequest/Web3ProofRequest.tsx | 50 ++++++++--- .../popup/pages/Web3ProofRequest/i18n/da.ts | 3 +- .../popup/pages/Web3ProofRequest/i18n/en.ts | 3 +- 7 files changed, 48 insertions(+), 98 deletions(-) diff --git a/examples/add-example-Web3Id/index.html b/examples/add-example-Web3Id/index.html index 1ad680c0..17fd3070 100644 --- a/examples/add-example-Web3Id/index.html +++ b/examples/add-example-Web3Id/index.html @@ -44,6 +44,7 @@ .revealAttribute('degreeType') .revealAttribute('degreeName') .revealAttribute('graduationDate') + .revealAttribute('test') ) .addForVerifiableCredentials([{ index: 6105n, subindex: 0n }], (b) => b diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx index 0c890a8d..f3d8dbf3 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx @@ -1,31 +1,19 @@ import { AccountCredentialStatement, createAccountDID, + IDENTITY_SUBJECT_SCHEMA, RevealStatementV2, StatementTypes, - AttributeKey, - AttributeList, - IDENTITY_SUBJECT_SCHEMA, } from '@concordium/web-sdk'; import { displaySplitAddress, useIdentityName, useIdentityOf } from '@popup/shared/utils/account-helpers'; -import { useDisplayAttributeValue, useGetAttributeName } from '@popup/shared/utils/identity-helpers'; -import { WalletCredential, ConfirmedIdentity, CredentialSchemaSubject } from '@shared/storage/types'; +import { useDisplayAttributeValue } from '@popup/shared/utils/identity-helpers'; +import { ConfirmedIdentity, CredentialSchemaSubject, WalletCredential } from '@shared/storage/types'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ClassName } from 'wallet-common-helpers'; -import { DisplayStatementView, StatementLine } from '../IdProofRequest/DisplayStatement/DisplayStatement'; import CredentialSelector from './CredentialSelector'; -import { DisplayCredentialStatementProps, SecretStatementV2 } from './utils'; -import { - isoToCountryName, - SecretStatement, - useStatementDescription, - useStatementHeader, - useStatementName, - useStatementValue, -} from '../IdProofRequest/DisplayStatement/utils'; import { DisplayRevealStatements } from './Display/DisplayRevealStatements'; import { DisplaySecretStatements } from './Display/DisplaySecretStatements'; +import { DisplayCredentialStatementProps, SecretStatementV2 } from './utils'; export function DisplayAccount({ option }: { option: WalletCredential }) { const identityName = useIdentityName(option); @@ -44,72 +32,6 @@ export function DisplayAccount({ option }: { option: WalletCredential }) { ); } -type DisplaySecretStatementV2Props = ClassName & { - identity?: ConfirmedIdentity; - dappName: string; - statement: SecretStatementV2; -}; - -export function DisplaySecretStatementV2({ dappName, statement, identity, className }: DisplaySecretStatementV2Props) { - const v1Statement: SecretStatement = statement as SecretStatement; - const header = useStatementHeader(v1Statement); - const value = useStatementValue(v1Statement); - const description = useStatementDescription(v1Statement, identity); - const attribute = useStatementName(v1Statement); - - const lines: StatementLine[] = [ - { - attribute, - value, - isRequirementMet: identity !== undefined, - }, - ]; - - return ( - - ); -} - -type DisplayRevealStatementV2Props = ClassName & { - identity?: ConfirmedIdentity; - dappName: string; - statements: RevealStatementV2[]; -}; - -export function DisplayRevealStatementV2({ dappName, statements, identity, className }: DisplayRevealStatementV2Props) { - const { t, i18n } = useTranslation('idProofRequest', { keyPrefix: 'displayStatement' }); - const getAttributeName = useGetAttributeName(); - const displayAttribute = useDisplayAttributeValue(); - const header = t('headers.reveal'); - const attributes = identity - ? identity.idObject.value.attributeList.chosenAttributes - : ({} as AttributeList['chosenAttributes']); - - const lines: StatementLine[] = statements.map((s) => { - const stringTag = s.attributeTag as AttributeKey; - const raw = attributes[stringTag]; - let value = displayAttribute(stringTag, raw ?? ''); - - if (value && ['countryOfResidence', 'nationality', 'idDocIssuer'].includes(stringTag)) { - value = isoToCountryName(i18n.resolvedLanguage)(value); - } - - return { - attribute: getAttributeName(stringTag), - value: value ?? 'Unavailable', - isRequirementMet: raw !== undefined, - }; - }); - - return ; -} - export default function AccountStatement({ credentialStatement, validCredentials, diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx index 4d3cd74b..2eb2e709 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx @@ -16,7 +16,7 @@ export function DisplayRevealStatements({ attributes, dappName, schema, - formatAttribute = (_, value) => value.toString(), + formatAttribute = (_, value) => value?.toString(), }: Props) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.reveal'); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx index 9617edf2..a0169641 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -73,6 +73,7 @@ export function DisplaySecretStatements({ return { attribute: title, value: value.toString() ?? 'Unavailable', + // TODO this is not enough for secrets isRequirementMet: value !== undefined, description, }; diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx index 865c48ba..6c3c779f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx @@ -11,6 +11,8 @@ import { ConcordiumGRPCClient, CommitmentInput, isVerifiableCredentialStatement, + CredentialStatement, + Network, } from '@concordium/web-sdk'; import { InternalMessageType } from '@concordium/browser-wallet-message-hub'; @@ -25,7 +27,6 @@ import PendingArrows from '@assets/svg/pending-arrows.svg'; import ExternalRequestLayout from '@popup/page-layouts/ExternalRequestLayout'; import { fullscreenPromptContext } from '@popup/page-layouts/FullscreenPromptLayout'; import Button from '@popup/shared/Button'; -import ButtonGroup from '@popup/shared/ButtonGroup'; import { displayUrl } from '@popup/shared/utils/string-helpers'; import { storedVerifiableCredentialsAtom, @@ -35,7 +36,7 @@ import { useConfirmedIdentities } from '@popup/shared/utils/identity-helpers'; import { parse } from '@shared/utils/payload-helpers'; import { VerifiableCredential, VerifiableCredentialStatus } from '@shared/storage/types'; import { getVerifiableCredentialStatus } from '@shared/utils/verifiable-credential-helpers'; -import { useAsyncMemo } from 'wallet-common-helpers'; +import { noOp, useAsyncMemo } from 'wallet-common-helpers'; import { stringify } from '@concordium/browser-wallet-api/src/util'; import CloseIcon from '@assets/svg/cross.svg'; import { @@ -75,19 +76,39 @@ async function getAllCredentialStatuses( return Object.fromEntries(statuses); } -function DisplayNotProvable({ onClick, dappName }: { onClick: () => void; dappName: string }) { +function DisplayNotProvable({ + onClick, + dappName, + statement, + net, +}: { + onClick: () => void; + dappName: string; + statement: CredentialStatement; + net: Network; +}) { const { t } = useTranslation('web3IdProofRequest'); + const credentials = useAtomValue(credentialsAtom); + const verifiableCredentials = useAtomValue(storedVerifiableCredentialsAtom); + const validCredentials = isAccountCredentialStatement(statement) ? credentials : verifiableCredentials.value; + // TODO fix display of reject button return (
      -

      {t('unableToProve', { dappName })}

      - - - - +

      {t('descriptions.unableToProve')}

      + + +
      ); @@ -214,7 +235,14 @@ export default function Web3ProofRequest({ onReject, onSubmit }: Props) { } if (!canProve) { - return ; + return ( + !v.length)]} + /> + ); } return ( diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts index 8680c384..b0505ad7 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts @@ -43,11 +43,10 @@ const t: typeof en = { verifiableCredential: 'Vælg en verifiable credential til at afsløre/bevise den anmodet information.', accountCredential: 'Vælg en account, hvis forbundne identity skal bruges til at afsløre/bevise den anmodet information.', + unableToProve: 'One or more attributes does not meet the requirements from the verifier.', // TODO }, failedProof: 'Bevis kunne ikke oprettes', failedProofReason: 'Bevis kunne ikke oprettes: {{ reason }}', - unableToProve: - ' {{ dappName }} har anmodet et bevis for identitet fra dig, men du opfølger ikke kravene for beviset, så du kan ikke lave et bevis', }; export default t; diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index 9acb4ac4..4fe7cdf6 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -41,9 +41,8 @@ export default { verifiableCredential: 'Select a verifiable credential to reveal/prove the requested information.', accountCredential: 'Select an account associated with the identity whose credentials will be used to reveal/prove the requested information.', + unableToProve: 'One or more attributes does not meet the requirements from the verifier.', }, failedProof: 'Unable to create proof', failedProofReason: 'Unable to create proof due to: {{ reason }}', - unableToProve: - ' {{ dappName }} has requested a proof of identity from you, however you are unable to fulfill the request', }; From 80d296d9842c5cfbe70d451ecbe537049cc4f5eb Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 08:53:33 +0200 Subject: [PATCH 17/29] Fix statement margins --- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 6b1354ea..43abfb4f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -7,6 +7,10 @@ &__statement { margin-top: 25px; + + &:last-child { + margin-bottom: 25px; + } } &__actions { @@ -140,7 +144,9 @@ } &__line { - margin-top: 5px; + &:not(:first-child) { + margin-top: 8px; + } &:not(:last-child) { border-bottom: 1px solid #e5e5e5; From ccd23814afc95006640457fe156ad7f72f79e090 Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 09:08:43 +0200 Subject: [PATCH 18/29] Fix selector scrollbar --- .../pages/Web3ProofRequest/Web3ProofRequest.scss | 2 +- .../browser-wallet/src/popup/shared/Modal/Modal.scss | 4 ++++ .../browser-wallet/src/popup/shared/Modal/Modal.tsx | 11 ++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 43abfb4f..ed7f4249 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -178,7 +178,7 @@ margin-top: 178px; margin-left: 32px; margin-right: 32px; - width: calc(100% - 64px); + width: calc(100% - 48px); } &__selector-item { diff --git a/packages/browser-wallet/src/popup/shared/Modal/Modal.scss b/packages/browser-wallet/src/popup/shared/Modal/Modal.scss index bb5ca960..b9b01f40 100644 --- a/packages/browser-wallet/src/popup/shared/Modal/Modal.scss +++ b/packages/browser-wallet/src/popup/shared/Modal/Modal.scss @@ -19,6 +19,10 @@ justify-content: center; } + &--stable-scrollbar-gutter { + scrollbar-gutter: stable; + } + &__content { position: relative; width: 90%; diff --git a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx index 8391ee5d..bcb2d688 100644 --- a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx +++ b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx @@ -52,6 +52,7 @@ export type ModalProps = { onClose?(): void; bottom?: boolean; middle?: boolean; + stableScrollbarGutter?: boolean; /** * Used to overwrite styling for the modal content box */ @@ -77,6 +78,7 @@ export default function Modal({ onClose = noOp, bottom = false, middle = false, + stableScrollbarGutter = false, children, }: PropsWithChildren>): JSX.Element | null { const [{ isOpen, isExiting }, setOpenState] = useState({ isOpen: false, isExiting: false }); @@ -145,7 +147,14 @@ export default function Modal({ <> {triggerWithOpen} {isOpen && ( - + {!isExiting && ( Date: Fri, 1 Sep 2023 09:12:22 +0200 Subject: [PATCH 19/29] Fix linting issue --- .../pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx index d14d3c90..f0f71110 100644 --- a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx @@ -38,7 +38,7 @@ type StatementLineProps = StatementLine & ClassName; export function DisplayStatementLine({ attribute, value, isRequirementMet, className }: StatementLineProps) { return ( -
    • +
    • {attribute}:
      {value} From 2b6349569a5197de6309ae5c5ffae45db33b9843 Mon Sep 17 00:00:00 2001 From: Hjort Date: Fri, 1 Sep 2023 09:41:58 +0200 Subject: [PATCH 20/29] Fixes for notProvablePage --- .../pages/Web3ProofRequest/AccountStatement.tsx | 5 ++++- .../Display/DisplaySecretStatements.tsx | 6 +++--- .../VerifiableCredentialStatement.tsx | 5 ++++- .../pages/Web3ProofRequest/Web3ProofRequest.scss | 15 +++++++++++++-- .../pages/Web3ProofRequest/Web3ProofRequest.tsx | 16 ++++++++++------ .../src/popup/pages/Web3ProofRequest/utils.ts | 1 + 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx index f3d8dbf3..b4787b29 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/AccountStatement.tsx @@ -38,6 +38,7 @@ export default function AccountStatement({ dappName, setChosenId, net, + showDescription, }: DisplayCredentialStatementProps) { const { t } = useTranslation('web3IdProofRequest'); const reveals = credentialStatement.statement.filter( @@ -70,7 +71,9 @@ export default function AccountStatement({ return (
      -

      {t('descriptions.accountCredential')}

      + {showDescription && ( +

      {t('descriptions.accountCredential')}

      + )} options={validCredentials} DisplayOption={DisplayAccount} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx index a0169641..d8b44a74 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -1,4 +1,4 @@ -import { AttributeType, StatementTypes } from '@concordium/web-sdk'; +import { AttributeType, canProveAtomicStatement, StatementTypes } from '@concordium/web-sdk'; import { CredentialSchemaSubject } from '@shared/storage/types'; import React from 'react'; import { TFunction, useTranslation } from 'react-i18next'; @@ -60,6 +60,7 @@ function getStatementDescription( export function DisplaySecretStatements({ schema, statements, + attributes, className, formatAttribute = (_, value) => value.toString(), }: DisplayProps) { @@ -73,8 +74,7 @@ export function DisplaySecretStatements({ return { attribute: title, value: value.toString() ?? 'Unavailable', - // TODO this is not enough for secrets - isRequirementMet: value !== undefined, + isRequirementMet: canProveAtomicStatement(s, attributes), description, }; }); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx index 69334baa..67a91532 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/VerifiableCredentialStatement.tsx @@ -36,6 +36,7 @@ export default function DisplayWeb3Statement({ dappName, setChosenId, net, + showDescription, }: DisplayCredentialStatementProps) { const { t } = useTranslation('web3IdProofRequest'); const reveals = credentialStatement.statement.filter( @@ -68,7 +69,9 @@ export default function DisplayWeb3Statement({ return (
      -

      {t('descriptions.verifiableCredential')}

      + {showDescription && ( +

      {t('descriptions.verifiableCredential')}

      + )} options={validCredentials} DisplayOption={DisplayVC} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 0cd76e47..aa3fbb24 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -59,9 +59,18 @@ &__reject-button { width: 56px; + } + + &__reject-button, + &__not-provable-button { height: 48px; border-radius: 16px; - background: #ab2b2b; + background: $color-feedback-negative-dark; + } + + &__not-provable-description { + margin-left: 32px; + margin-right: 32px; } &__back-button { @@ -72,11 +81,13 @@ flex-grow: 1; } + &__not-provable-description, &__description { height: 120px; padding-top: 32px; color: $color-neutral-gray-50; - margin: 0; + margin-top: 0; + margin-bottom: 0; } } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx index 6c3c779f..40b96848 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx @@ -92,11 +92,12 @@ function DisplayNotProvable({ const verifiableCredentials = useAtomValue(storedVerifiableCredentialsAtom); const validCredentials = isAccountCredentialStatement(statement) ? credentials : verifiableCredentials.value; - // TODO fix display of reject button return (
      -

      {t('descriptions.unableToProve')}

      +

      + {t('descriptions.unableToProve')} +

      - - +
      + +
      ); @@ -261,6 +264,7 @@ export default function Web3ProofRequest({ onReject, onSubmit }: Props) { return newIds; }) } + showDescription />