Skip to content
New issue

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

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

Already on GitHub? # to your account

Display CIP8 profile info in Transaction Feed #37

Merged
merged 49 commits into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9b752fc
migrating PR
isabellewei Feb 20, 2021
6ba7a7f
migrating PR
isabellewei Feb 20, 2021
39a4b7f
missed changes
isabellewei Feb 22, 2021
5583ebb
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Feb 22, 2021
b0d73e9
missed changes
isabellewei Feb 22, 2021
1f468b4
throw error when uploading
isabellewei Feb 23, 2021
68ec1fa
get working in new repo :)
isabellewei Feb 24, 2021
c273a3f
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Feb 24, 2021
fb9e154
PR comments
isabellewei Feb 25, 2021
c2609cf
more PR comments
isabellewei Feb 26, 2021
63e5284
tests
isabellewei Mar 5, 2021
dc47a82
stokado changes
isabellewei Mar 5, 2021
e5a5117
Merge branch 'main' of github.com:celo-org/wallet into isabellewei/CI…
isabellewei Mar 8, 2021
6b243ca
tests
isabellewei Mar 19, 2021
044ebde
use DEK as signer and add graphQL account type
isabellewei Mar 28, 2021
dd5fcb3
update tests
isabellewei Mar 29, 2021
b570f55
register DEK on app open
isabellewei Mar 29, 2021
5ced14a
use EIP712 and expiration for writing data
isabellewei Apr 1, 2021
44a92a7
Addressing PR comments
isabellewei Apr 13, 2021
d590f1a
merging changes
isabellewei Apr 13, 2021
084a6af
PR comments
isabellewei Apr 16, 2021
972e181
merging from main
isabellewei Apr 19, 2021
16b0b4b
update UploadServiceDataWrapper read function
isabellewei Apr 22, 2021
213435c
Merge branch 'main' of github.com:celo-org/wallet into isabellewei/CI…
isabellewei Apr 22, 2021
454ba0a
get tests to pass
isabellewei Apr 22, 2021
cfba1c6
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Apr 22, 2021
208a0fc
fix build issues
isabellewei Apr 26, 2021
6c48af4
fix tests and bad import
isabellewei Apr 26, 2021
7cd538f
Merge branch 'main' of github.com:celo-org/wallet into isabellewei/CI…
isabellewei Apr 26, 2021
5bdf66f
fix yarn.lock
isabellewei Apr 26, 2021
43cf1ee
run prettier
isabellewei Apr 26, 2021
530d2ae
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Apr 26, 2021
e6610db
register DEK on account import, failed uploading symmetric keys is no…
isabellewei Apr 27, 2021
73be650
upload name and picture when restoring account
isabellewei Apr 27, 2021
037383d
update import test
isabellewei Apr 27, 2021
9bc41dd
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Apr 27, 2021
aa19829
Merge branch 'main' into isabellewei/CIP8valoraIntegration
mergify[bot] Apr 27, 2021
d66a688
only add firebase info to addressToDisplayInfo mapping
isabellewei Apr 28, 2021
a332b4b
Merge branch 'main' into isabellewei/CIP8valoraIntegration
mergify[bot] Apr 28, 2021
60bf04a
update snapshots
isabellewei Apr 29, 2021
679e2e9
Merge branch 'isabellewei/CIP8valoraIntegration' of github.com:celo-o…
isabellewei Apr 29, 2021
b629003
Merge branch 'main' of github.com:celo-org/wallet into isabellewei/di…
isabellewei Apr 29, 2021
ce31c29
fix tests
isabellewei May 3, 2021
5f8cbf9
PR comments
isabellewei May 3, 2021
9b76323
Merge branch 'main' into isabellewei/displayTransactionProfiles
May 3, 2021
97e1f70
Merge conflicts and other small fixes
May 3, 2021
c38a91e
Fix lint
May 3, 2021
cc36813
Fix test
May 3, 2021
d1e2bf6
Fix linter
May 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/mobile/src/account/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as RNLocalize from 'react-native-localize'
import { createSelector } from 'reselect'
import i18n from 'src/i18n'
import { RootState } from 'src/redux/reducers'
import { currentAccountSelector } from 'src/web3/selectors'

const inferCountryCode = () => {
const localizedCountry = new Countries(i18n.language).getCountryByCodeAlpha2(
Expand All @@ -27,6 +28,17 @@ export const pincodeTypeSelector = (state: RootState) => state.account.pincodeTy
export const promptFornoIfNeededSelector = (state: RootState) => state.account.promptFornoIfNeeded
export const isProfileUploadedSelector = (state: RootState) => state.account.profileUploaded
export const cUsdDailyLimitSelector = (state: RootState) => state.account.dailyLimitCusd

export const currentUserRecipientSelector = createSelector(
[currentAccountSelector, nameSelector, pictureSelector, userContactDetailsSelector],
(account, name, picture, contactDetails) => {
return {
address: account!,
name: name ?? undefined,
thumbnailPath: picture ?? contactDetails.thumbnailPath ?? undefined,
}
}
)
export const dailyLimitRequestStatusSelector = (state: RootState) =>
state.account.dailyLimitRequestStatus
export const recoveringFromStoreWipeSelector = (state: RootState) =>
Expand Down
5 changes: 2 additions & 3 deletions packages/mobile/src/analytics/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
import { PaymentMethod } from 'src/fiatExchanges/FiatExchangeOptions'
import { NotificationBannerCTATypes, NotificationBannerTypes } from 'src/home/NotificationBox'
import { LocalCurrencyCode } from 'src/localCurrency/consts'
import { RecipientKind } from 'src/recipients/recipient'

interface AppEventsProperties {
[AppEvents.app_launched]: {
Expand Down Expand Up @@ -479,7 +478,7 @@ interface EscrowEventsProperties {
interface SendEventsProperties {
[SendEvents.send_scan]: undefined
[SendEvents.send_select_recipient]: {
recipientKind: RecipientKind
// TODO: decide what recipient info to collect, now that RecipientKind doesn't exist
usedSearchBar: boolean
Comment on lines +481 to 482
Copy link
Member

Choose a reason for hiding this comment

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

}
[SendEvents.send_cancel]: undefined
Expand Down Expand Up @@ -549,7 +548,7 @@ interface RequestEventsProperties {
[RequestEvents.request_cancel]: undefined
[RequestEvents.request_scan]: undefined
[RequestEvents.request_select_recipient]: {
recipientKind: RecipientKind
// TODO: decide what recipient info to collect, now that RecipientKind doesn't exist
usedSearchBar: boolean
}
[RequestEvents.request_amount_continue]: {
Expand Down
3 changes: 2 additions & 1 deletion packages/mobile/src/apollo/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ export interface TransferItemFragment {
type: TokenTransactionType
hash: string
timestamp: number
address: string
address: string // wallet address (EOA)
account: string // account address (MTW)
Copy link
Contributor

Choose a reason for hiding this comment

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

This naming from the blockchain-api is really confusing 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

haha definitely, hopefully these comments help

comment: Maybe<string>
amount: {
__typename?: 'MoneyAmount'
Expand Down
28 changes: 14 additions & 14 deletions packages/mobile/src/components/Avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react'
import { Provider } from 'react-redux'
import * as renderer from 'react-test-renderer'
import Avatar from 'src/components/Avatar'
import { RecipientKind } from 'src/recipients/recipient'
import { createMockStore } from 'test/utils'

const mockName = 'mockName'
Expand All @@ -16,33 +15,34 @@ const store = createMockStore({
})

describe(Avatar, () => {
it('renders correctly with contact but without number', () => {
it('renders correctly with number and name', () => {
const tree = renderer.create(
<Provider store={store}>
<Avatar
iconSize={40}
recipient={{
kind: RecipientKind.Contact,
contactId: 'none',
displayName: mockName,
}}
/>
<Avatar recipient={{ name: mockName, e164PhoneNumber: mockNumber }} iconSize={40} />
</Provider>
)
expect(tree).toMatchSnapshot()
})
it('renders correctly with number but without contact', () => {
it('renders correctly with just number', () => {
const tree = renderer.create(
<Provider store={store}>
<Avatar iconSize={40} e164Number={mockNumber} />
<Avatar recipient={{ e164PhoneNumber: mockNumber }} iconSize={40} />
</Provider>
)
expect(tree).toMatchSnapshot()
})
it('renders correctly with address but without contact nor number', () => {
it('renders correctly with address and name but no number', () => {
const tree = renderer.create(
<Provider store={store}>
<Avatar iconSize={40} address={mockAccount} />
<Avatar recipient={{ name: mockName, address: mockAccount }} iconSize={40} />
</Provider>
)
expect(tree).toMatchSnapshot()
})
it('renders correctly with address but no name nor number', () => {
const tree = renderer.create(
<Provider store={store}>
<Avatar recipient={{ address: mockAccount }} iconSize={40} />
</Provider>
)
expect(tree).toMatchSnapshot()
Expand Down
34 changes: 7 additions & 27 deletions packages/mobile/src/components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,30 @@ import { defaultCountryCodeSelector } from 'src/account/selectors'
import ContactCircle from 'src/components/ContactCircle'
import { formatShortenedAddress } from 'src/components/ShortenedAddress'
import { Namespaces, withTranslation } from 'src/i18n'
import { getRecipientThumbnail, Recipient } from 'src/recipients/recipient'
import { getDisplayName, Recipient } from 'src/recipients/recipient'

const DEFAULT_ICON_SIZE = 40

interface OwnProps {
recipient?: Recipient
recipient: Recipient
e164Number?: string
address?: string
iconSize?: number
displayNameStyle?: TextStyle
}

type Props = OwnProps & WithTranslation

// When redesigning, consider using getDisplayName from recipient.ts
function getDisplayName({ recipient, e164Number, address, t }: Props) {
if (recipient && recipient.displayName) {
return recipient.displayName
}
if (getE164Number(e164Number, recipient)) {
return t('mobileNumber')
}
if (address) {
return t('walletAddress')
}
// Rare but possible, such as when a user skips onboarding flow (in dev mode) and then views their own avatar
return t('global:unknown')
}

export function getE164Number(e164Number?: string, recipient?: Recipient) {
return e164Number || (recipient && recipient.e164PhoneNumber)
}

export function Avatar(props: Props) {
const defaultCountryCode = useSelector(defaultCountryCodeSelector) ?? undefined
const { address, recipient, e164Number, iconSize = DEFAULT_ICON_SIZE, displayNameStyle } = props
const { recipient, e164Number, iconSize = DEFAULT_ICON_SIZE, displayNameStyle, t } = props

const name = getDisplayName(props)
const e164NumberToShow = getE164Number(e164Number, recipient)
const thumbnailPath = getRecipientThumbnail(recipient)
const name = getDisplayName(recipient, t)
const address = recipient.address
const e164NumberToShow = recipient.e164PhoneNumber || e164Number

return (
<View style={styles.container}>
<ContactCircle thumbnailPath={thumbnailPath} name={name} address={address} size={iconSize} />
<ContactCircle recipient={recipient} size={iconSize} />
<Text
style={[displayNameStyle || fontStyles.small500, styles.contactName]}
numberOfLines={1}
Expand Down
26 changes: 9 additions & 17 deletions packages/mobile/src/components/AvatarSelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react'
import { TextStyle } from 'react-native'
import { e164NumberSelector, nameSelector, userContactDetailsSelector } from 'src/account/selectors'
import Avatar from 'src/components/Avatar'
import { Recipient, RecipientKind } from 'src/recipients/recipient'
import { Recipient } from 'src/recipients/recipient'
import useSelector from 'src/redux/useSelector'
import { currentAccountSelector } from 'src/web3/selectors'

Expand All @@ -19,29 +19,21 @@ export function AvatarSelf({ iconSize, displayNameStyle }: Props) {
const account = useSelector(currentAccountSelector)

// Recipient refering to the wallet user, used for the avatar
let recipient: Recipient | undefined
if (displayName) {
let recipient: Recipient
if (displayName && e164PhoneNumber) {
recipient = {
kind: RecipientKind.Contact,
contactId: contactDetails.contactId || 'none',
thumbnailPath: contactDetails.thumbnailPath || undefined,
displayName,
name: displayName,
e164PhoneNumber,
address: account!,
}
} else if (account) {
} else {
recipient = {
kind: RecipientKind.Address,
address: account,
displayName: account,
address: account!,
name: displayName || undefined,
}
}

return (
<Avatar
recipient={recipient}
iconSize={iconSize}
displayNameStyle={displayNameStyle}
address={account ?? undefined}
/>
)
return <Avatar recipient={recipient} iconSize={iconSize} displayNameStyle={displayNameStyle} />
}
94 changes: 29 additions & 65 deletions packages/mobile/src/components/ContactCircle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,95 +5,59 @@ import { Provider } from 'react-redux'
import ContactCircle from 'src/components/ContactCircle'
import { createMockStore } from 'test/utils'

const testContact = {
recordID: '1',
displayName: 'Zahara Tests Jorge',
phoneNumbers: [],
thumbnailPath: '',
}

const mockAddress = '0x123456'
const mockName = 'Mock name'
const mockStore = createMockStore({
identity: {
addressToDisplayName: {
[mockAddress]: {
name: mockName,
},
},
},
})

const mockStore = createMockStore()

describe('ContactCircle', () => {
it('renders correctly', () => {
const tree = render(
<Provider store={mockStore}>
<ContactCircle size={30} name={'Jerry'} />
</Provider>
)
expect(tree).toMatchSnapshot()
})
describe('when given contact', () => {
it('uses contact name for initial', () => {
const { getByText } = render(
<Provider store={mockStore}>
<ContactCircle size={30} name={'Jerry'} contact={testContact} />
</Provider>
)
expect(getByText('Z')).toBeTruthy()
})
})
describe('when not given a contact', () => {
it('uses name for initial', () => {
const { getByText } = render(
describe('when given recipient with only address', () => {
it('uses DefaultAvatar svg', () => {
const wrapper = render(
<Provider store={mockStore}>
<ContactCircle size={30} name={'Jerry'} />
<ContactCircle
size={30}
recipient={{
address: mockAddress,
}}
/>
</Provider>
)
expect(getByText('J')).toBeTruthy()
expect(wrapper).toMatchSnapshot()
})
})
describe('when has a thumbnail', () => {
describe('when has a thumbnail and name', () => {
it('renders image', () => {
const mockThumbnnailPath = './test.jpg'
const { getByType } = render(
<Provider store={mockStore}>
<ContactCircle size={30} name={'Jerry'} thumbnailPath={mockThumbnnailPath} />
<ContactCircle
size={30}
recipient={{
name: mockName,
address: mockAddress,
thumbnailPath: mockThumbnnailPath,
}}
/>
</Provider>
)
expect(getByType(Image).props.source).toEqual({ uri: './test.jpg' })
})
})
describe('when has a saved name but no picture', () => {
describe('when has a name but no picture', () => {
it('renders initial', () => {
const { getByText } = render(
<Provider store={mockStore}>
<ContactCircle size={30} address={mockAddress} name={null} />
<ContactCircle
size={30}
recipient={{
name: mockName,
address: mockAddress,
}}
/>
</Provider>
)
expect(getByText(mockName[0])).toBeTruthy()
})
})
describe('when has a saved name and picture', () => {
it('renders picture', () => {
const mockImageUrl = 'https://somehost.com/test.jpg'
const { getByType } = render(
<Provider
store={createMockStore({
identity: {
addressToDisplayName: {
[mockAddress]: {
name: mockName,
imageUrl: mockImageUrl,
},
},
},
})}
>
<ContactCircle size={30} address={mockAddress} name={mockName} />
</Provider>
)
expect(getByType(Image).props.source).toEqual({ uri: mockImageUrl })
})
})
})
Loading