Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: unify UI for DIDComm and OpenID flows for Offer and details screens #1365

40 changes: 36 additions & 4 deletions packages/legacy/core/App/components/misc/CredentialCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CredentialExchangeRecord, W3cCredentialRecord } from '@credo-ts/core'
import { Attribute, BrandingOverlayType, Predicate } from '@hyperledger/aries-oca/build/legacy'
import React from 'react'
import { Attribute, BrandingOverlayType, CredentialOverlay, Predicate } from '@hyperledger/aries-oca/build/legacy'
import React, { useEffect, useState } from 'react'
import { ViewStyle } from 'react-native'

import { TOKENS, useServices } from '../../container-api'
Expand All @@ -9,8 +9,11 @@ import { GenericFn } from '../../types/fn'

import CredentialCard10 from './CredentialCard10'
import CredentialCard11, { CredentialErrors } from './CredentialCard11'
import OpenIDCredentialCard from '../../modules/openid/components/OpenIDCredentialCard'
import { GenericCredentialExchangeRecord } from '../../types/credentials'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { getCredentialForDisplay } from '../../modules/openid/display'
import { buildOverlayFromW3cCredential } from '../../utils/oca'
import { useTranslation } from 'react-i18next'

interface CredentialCardProps {
credential?: GenericCredentialExchangeRecord
Expand Down Expand Up @@ -42,6 +45,27 @@ const CredentialCard: React.FC<CredentialCardProps> = ({
// add ability to reference credential by ID, allows us to get past react hook restrictions
const [bundleResolver] = useServices([TOKENS.UTIL_OCA_RESOLVER])
const { ColorPallet } = useTheme()
const [overlay, setOverlay] = useState<CredentialOverlay<BrandingOverlay>>({})
const { i18n } = useTranslation()

useEffect(() => {
const resolveOverlay = async (w3cCred: W3cCredentialRecord) => {
const credentialDisplay = getCredentialForDisplay(w3cCred)

const resolvedOverlay = await buildOverlayFromW3cCredential({
credentialDisplay,
language: i18n.language,
resolver: bundleResolver,
})

setOverlay(resolvedOverlay)
}

if (credential instanceof W3cCredentialRecord) {
resolveOverlay(credential)
}
}, [credential, bundleResolver, i18n.language])

const getCredOverlayType = (type: BrandingOverlayType) => {
if (proof) {
return (
Expand Down Expand Up @@ -90,7 +114,15 @@ const CredentialCard: React.FC<CredentialCardProps> = ({
}

if (credential instanceof W3cCredentialRecord) {
return <OpenIDCredentialCard credentialRecord={credential as W3cCredentialRecord} onPress={onPress} />
return (
<CredentialCard11
credential={undefined}
style={style}
onPress={onPress}
brandingOverlay={overlay}
credentialErrors={credentialErrors ?? []}
/>
)
} else {
return getCredOverlayType(bundleResolver.getBrandingOverlayType())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface CredentialCard11Props {
credentialErrors: CredentialErrors[]
hasAltCredentials?: boolean
handleAltCredChange?: () => void
brandingOverlay?: CredentialOverlay<BrandingOverlay>
}

/*
Expand Down Expand Up @@ -93,6 +94,7 @@ const CredentialCard11: React.FC<CredentialCard11Props> = ({
hasAltCredentials,
credentialErrors = [],
handleAltCredChange,
brandingOverlay,
}) => {
const { width } = useWindowDimensions()
const borderRadius = 10
Expand Down Expand Up @@ -285,6 +287,11 @@ const CredentialCard11: React.FC<CredentialCard11Props> = ({
}, [credential, cardData, parseAttribute, flaggedAttributes])

useEffect(() => {
if (brandingOverlay) {
setOverlay(brandingOverlay as unknown as CredentialOverlay<BrandingOverlay>)
return
}

const params = {
identifiers: credential ? getCredentialIdentifiers(credential) : { schemaId, credentialDefinitionId: credDefId },
attributes: proof ? [] : credential?.credentialAttributes,
Expand Down Expand Up @@ -335,6 +342,7 @@ const CredentialCard11: React.FC<CredentialCard11Props> = ({
proof,
credHelpActionOverrides,
navigation,
brandingOverlay,
])

const CredentialCardLogo: React.FC = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Image, StyleSheet, Text, View } from 'react-native'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
import { useTheme } from '../../contexts/theme'
import { toImageSource } from '../../utils/credential'

type Props = {
overlay: CredentialOverlay<BrandingOverlay>
}

const logoHeight = 80
const paddingHorizontal = 24

const CredentialCardLogo: React.FC<Props> = ({ overlay }: Props) => {
const { TextTheme } = useTheme()

const styles = StyleSheet.create({
logoContainer: {
top: -0.5 * logoHeight,
left: paddingHorizontal,
marginBottom: -1 * logoHeight,
width: logoHeight,
height: logoHeight,
backgroundColor: '#ffffff',
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 1,
height: 1,
},
shadowOpacity: 0.3,
},
})

return (
<View style={styles.logoContainer}>
{overlay.brandingOverlay?.logo ? (
<Image
source={toImageSource(overlay.brandingOverlay?.logo)}
style={{
resizeMode: 'cover',
width: logoHeight,
height: logoHeight,
borderRadius: 8,
}}
/>
) : (
<Text style={[TextTheme.title, { fontSize: 0.5 * logoHeight, color: '#000' }]}>
{(overlay.metaOverlay?.name ?? overlay.metaOverlay?.issuer ?? 'C')?.charAt(0).toUpperCase()}
</Text>
)}
</View>
)
}

export default CredentialCardLogo
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
import CardWatermark from '../../components/misc/CardWatermark'
import { useTheme } from '../../contexts/theme'
import { credentialTextColor } from '../../utils/credential'
import { testIdWithKey } from '../../utils/testable'

type Props = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Able to rename to CredentialDetailPrimaryHeaderProps to follow the app convetion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

overlay: CredentialOverlay<BrandingOverlay>
}

const paddingHorizontal = 24
const paddingVertical = 16
const logoHeight = 80

const CredentialDetailPrimaryHeader: React.FC<Props> = ({ overlay }: Props) => {
const { TextTheme, ColorPallet } = useTheme()
const { width, height } = useWindowDimensions()
const styles = StyleSheet.create({
primaryHeaderContainer: {
paddingHorizontal,
paddingVertical,
},
textContainer: {
color: credentialTextColor(ColorPallet, overlay.brandingOverlay?.primaryBackgroundColor),
},
})

return (
<View
testID={testIdWithKey('CredentialDetailsPrimaryHeader')}
style={[styles.primaryHeaderContainer, { zIndex: -1 }]}
>
<View>
{overlay.metaOverlay?.watermark && (
<CardWatermark width={width} height={height} watermark={overlay.metaOverlay?.watermark} />
)}
<Text
testID={testIdWithKey('CredentialIssuer')}
style={[
TextTheme.label,
styles.textContainer,
{
paddingLeft: logoHeight + paddingVertical,
paddingBottom: paddingVertical,
lineHeight: 19,
opacity: 0.8,
},
]}
numberOfLines={1}
>
{overlay.metaOverlay?.issuer}
</Text>
<Text
testID={testIdWithKey('CredentialName')}
style={[
TextTheme.normal,
styles.textContainer,
{
lineHeight: 24,
},
]}
>
{overlay.metaOverlay?.name}
</Text>
</View>
</View>
)
}

export default CredentialDetailPrimaryHeader
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
import { ImageBackground, StyleSheet, View } from 'react-native'
import { toImageSource } from '../../utils/credential'
import { testIdWithKey } from '../../utils/testable'

type Props = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CredentialDetailSecondaryHeaderProps to follow convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

overlay: CredentialOverlay<BrandingOverlay>
}

const logoHeight = 80

const CredentialDetailSecondaryHeader: React.FC<Props> = ({ overlay }: Props) => {
const styles = StyleSheet.create({
secondaryHeaderContainer: {
height: 1.5 * logoHeight,
backgroundColor:
(overlay.brandingOverlay?.backgroundImage
? 'rgba(0, 0, 0, 0)'
: overlay.brandingOverlay?.secondaryBackgroundColor) ?? 'rgba(0, 0, 0, 0.24)',
},
})

return (
<>
{overlay.brandingOverlay?.backgroundImage ? (
<ImageBackground
source={toImageSource(overlay.brandingOverlay?.backgroundImage)}
imageStyle={{
resizeMode: 'cover',
}}
>
<View testID={testIdWithKey('CredentialDetailsSecondaryHeader')} style={styles.secondaryHeaderContainer} />
</ImageBackground>
) : (
<View testID={testIdWithKey('CredentialDetailsSecondaryHeader')} style={styles.secondaryHeaderContainer} />
)}
</>
)
}

export default CredentialDetailSecondaryHeader
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type OpenIDCredentialRecord = W3cCredentialRecord | SdJwtVcRecord | undefined

export type OpenIDCredentialContext = {
openIdState: OpenIDCredentialRecordState
getCredentialById: (id: string) => Promise<W3cCredentialRecord | SdJwtVcRecord | undefined>
storeCredential: (cred: W3cCredentialRecord | SdJwtVcRecord) => Promise<void>
removeCredential: (cred: W3cCredentialRecord | SdJwtVcRecord) => Promise<void>
}
Expand Down Expand Up @@ -87,6 +88,11 @@ export const OpenIDCredentialRecordProvider: React.FC<PropsWithChildren<OpenIDCr
}
}

async function getCredentialById(id: string): Promise<W3cCredentialRecord | SdJwtVcRecord | undefined> {
checkAgent()
return await agent?.w3cCredentials.getCredentialRecordById(id)
}

async function storeCredential(cred: W3cCredentialRecord | SdJwtVcRecord): Promise<void> {
checkAgent()
if (cred instanceof W3cCredentialRecord) {
Expand Down Expand Up @@ -146,6 +152,7 @@ export const OpenIDCredentialRecordProvider: React.FC<PropsWithChildren<OpenIDCr
openIdState: state,
storeCredential: storeCredential,
removeCredential: deleteCredential,
getCredentialById: getCredentialById,
}}
>
{children}
Expand Down
Loading