From 23b973c641583bdcfa134059607f32d38d9823eb Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Tue, 28 May 2024 00:58:45 +0200 Subject: [PATCH 1/6] add File for Mneomic String Generation --- fe1-web/src/core/functions/Mnemonic.ts | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 fe1-web/src/core/functions/Mnemonic.ts diff --git a/fe1-web/src/core/functions/Mnemonic.ts b/fe1-web/src/core/functions/Mnemonic.ts new file mode 100644 index 0000000000..754e2170d6 --- /dev/null +++ b/fe1-web/src/core/functions/Mnemonic.ts @@ -0,0 +1,64 @@ +import * as crypto from 'crypto'; + +import base64url from 'base64url'; +import * as bip39 from 'bip39'; + +import { Base64UrlData } from 'core/objects'; + +function hashCode(a: Buffer): number { + if (a === null) { + return 0; + } + let result = 1; + for (let element of a) { + if (element >= 2 ** 7) { + element -= 2 ** 8; + } + result = 31 * result + (element == null ? 0 : element); + result %= 2 ** 32; + if (result >= 2 ** 31) { + result -= 2 ** 32; + } + if (result < -(2 ** 31)) { + result += 2 ** 32; + } + } + return result; +} + +function generateMnemonic(data: Buffer): string[] { + try { + const digest = crypto.createHash('sha256').update(data).digest(); + let mnemonic = ''; + bip39.setDefaultWordlist('english'); + mnemonic = bip39.entropyToMnemonic(digest); + return mnemonic.split(' ').filter((word) => word.length > 0); + } catch (e) { + console.error( + `Error generating the mnemonic for the base64 string ${base64url.encode(data)}`, + e, + ); + return []; + } +} + +function generateMnemonicFromBase64(data: Buffer, numberOfWords: number): string { + // Generate the mnemonic words from the input data + const mnemonicWords = generateMnemonic(data); + if (mnemonicWords.length === 0) { + return 'none'; + } + + let result = ''; + const hc = hashCode(data); + for (let i = 0; i < numberOfWords; i += 1) { + const wordIndex = Math.abs(hc + i) % mnemonicWords.length; + result = `${result} ${mnemonicWords[wordIndex]}`; + } + + return result.substring(1, result.length); +} + +export const generateMnemonicWordFromBase64 = (input: string, numberOfWords: number): string => { + return generateMnemonicFromBase64(new Base64UrlData(input).toBuffer(), numberOfWords); +}; From ff7dd1e344653e59480861daf9b84dc4714352a3 Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Tue, 11 Jun 2024 20:58:34 +0200 Subject: [PATCH 2/6] finish username generator, fix linting and add tests --- fe1-web/src/core/functions/Mnemonic.ts | 60 +++- .../core/functions/__tests__/Mnemonic.test.ts | 19 ++ .../screens/SendReceive/SendReceive.tsx | 3 +- .../__snapshots__/SendReceive.test.tsx.snap | 8 +- .../rollCall/components/AttendeeList.tsx | 7 +- .../ViewSingleRollCall.test.tsx.snap | 288 ++++++++++++++++++ .../features/social/components/ChirpCard.tsx | 5 +- .../features/social/components/Profile.tsx | 9 +- .../social/components/UserListItem.tsx | 3 +- .../__snapshots__/ChirpCard.test.tsx.snap | 30 +- .../__snapshots__/Profile.test.tsx.snap | 26 +- .../__snapshots__/UserListItem.test.tsx.snap | 2 +- .../SocialTopChirps.test.tsx.snap | 18 +- fe1-web/src/resources/strings.ts | 7 +- 14 files changed, 429 insertions(+), 56 deletions(-) create mode 100644 fe1-web/src/core/functions/__tests__/Mnemonic.test.ts diff --git a/fe1-web/src/core/functions/Mnemonic.ts b/fe1-web/src/core/functions/Mnemonic.ts index 754e2170d6..0b4f90b5cf 100644 --- a/fe1-web/src/core/functions/Mnemonic.ts +++ b/fe1-web/src/core/functions/Mnemonic.ts @@ -1,16 +1,22 @@ -import * as crypto from 'crypto'; +import { randomInt, createHash } from 'crypto'; import base64url from 'base64url'; import * as bip39 from 'bip39'; import { Base64UrlData } from 'core/objects'; -function hashCode(a: Buffer): number { - if (a === null) { +/** + * This function computes the hashcode of a buffer according to the + * Java Arrays.hashcode(bytearray) function to get the same results as in fe2. + * @param buf + * @returns computed hash code as a number + */ +function hashCode(buf: Buffer): number { + if (buf === null) { return 0; } let result = 1; - for (let element of a) { + for (let element of buf) { if (element >= 2 ** 7) { element -= 2 ** 8; } @@ -26,9 +32,14 @@ function hashCode(a: Buffer): number { return result; } +/** + * This function converts a buffer into mnemomic words from the english dictionary. + * @param data buffer containing a base64 string + * @returns array containing the mnemonic words + */ function generateMnemonic(data: Buffer): string[] { try { - const digest = crypto.createHash('sha256').update(data).digest(); + const digest = createHash('sha256').update(data).digest(); let mnemonic = ''; bip39.setDefaultWordlist('english'); mnemonic = bip39.entropyToMnemonic(digest); @@ -42,6 +53,17 @@ function generateMnemonic(data: Buffer): string[] { } } +/** + * This function converts a buffer of a base64 string into a given number of mnemonic words. + * + * Disclaimer: there's no guarantee that different base64 inputs map to 2 different words. The + * reason is that the representation space is limited. However, since the amount of messages is + * low is practically improbable to have conflicts + * + * @param data Buffer of a base64 string + * @param numberOfWords number of mnemonic words we want to generate + * @return given number of mnemonic words concatenated with ' ' + */ function generateMnemonicFromBase64(data: Buffer, numberOfWords: number): string { // Generate the mnemonic words from the input data const mnemonicWords = generateMnemonic(data); @@ -59,6 +81,28 @@ function generateMnemonicFromBase64(data: Buffer, numberOfWords: number): string return result.substring(1, result.length); } -export const generateMnemonicWordFromBase64 = (input: string, numberOfWords: number): string => { - return generateMnemonicFromBase64(new Base64UrlData(input).toBuffer(), numberOfWords); -}; +/** + * This function filters all non digits characters and returns the first nbDigits + * @param b64 base64 string containing numbers + * @param nbDigits numbers of digitis to extract from input + * @return string containing all the extracted numbers + */ +function getFirstNumberDigits(b64: string, nbDigits: number): string { + const digits = b64.replace(/\D/g, ''); + return digits.slice(0, nbDigits).padStart(nbDigits, '0'); +} + +/** + * This function generates a unique and memorable username from a base64 string. + * + * @param input base64 string. + * @return a username composed of truncated mnemonic words and a numerical suffix. + */ +export function generateUsernameFromBase64(input: string): string { + const words = generateMnemonicFromBase64(new Base64UrlData(input).toBuffer(), 2).split(' '); + if (words.length < 2) { + return `defaultUsername${randomInt(0, 10000000).toString().padStart(4, '0')}`; + } + const number = getFirstNumberDigits(input, 4); + return `${words[0]}${words[1]}${number}`; +} diff --git a/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts b/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts new file mode 100644 index 0000000000..13f4b163e3 --- /dev/null +++ b/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts @@ -0,0 +1,19 @@ +import { generateUsernameFromBase64 } from '../Mnemonic'; + +test('generateUsernameFromBase64 should generate the correct username for the token: d_xeXEsurEnyWOp04mrrMxC3m4cS-3jK_9_Aw-UYfww=', () => { + const popToken = 'd_xeXEsurEnyWOp04mrrMxC3m4cS-3jK_9_Aw-UYfww='; + const result = 'spoonissue0434'; + expect(generateUsernameFromBase64(popToken)).toBe(result); +}); + +test('generateUsernameFromBase64 should generate the correct username for the token: e5YJ5Q6x39u_AIK78_puEE2X5wy7Y7iYZLeuZx1lnZI=', () => { + const popToken = 'e5YJ5Q6x39u_AIK78_puEE2X5wy7Y7iYZLeuZx1lnZI='; + const result = 'bidtrial5563'; + expect(generateUsernameFromBase64(popToken)).toBe(result); +}); + +test('generateUsernameFromBase64 should generate the correct username for the token: Y5ZAd_7Ba31uu4EUIYbG2AVnthR623-NdPyYhtyechE=', () => { + const popToken = 'Y5ZAd_7Ba31uu4EUIYbG2AVnthR623-NdPyYhtyechE='; + const result = 'figuredevote5731'; + expect(generateUsernameFromBase64(popToken)).toBe(result); +}); diff --git a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx index e96591a5b3..fda8f72959 100644 --- a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx +++ b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx @@ -21,6 +21,7 @@ import { } from 'core/components'; import ModalHeader from 'core/components/ModalHeader'; import ScreenWrapper from 'core/components/ScreenWrapper'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { KeyPairStore } from 'core/keypair'; import { AppParamList } from 'core/navigation/typing/AppParamList'; import { DigitalCashParamList } from 'core/navigation/typing/DigitalCashParamList'; @@ -95,7 +96,7 @@ const SendReceive = () => { } return (rollCall?.attendees || []) - .map((key) => key.toString()) + .map((key) => generateUsernameFromBase64(key.valueOf())) .filter((key) => key.startsWith(beneficiary)); }, [beneficiary, beneficiaryFocused, rollCall]); diff --git a/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap b/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap index 2a41bc9627..3ec88d0541 100644 --- a/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap +++ b/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap @@ -385,7 +385,7 @@ exports[`SendReceive renders correctly 1`] = ` } } > - You can send cash by entering the public key of the beneficiary below and choosing the amount of cash you would like to transfer. To receive money you canshow your PoP token to the sender. To access the QR code of your PoP token, tab the QRcode icon in the top right of this screen. + You can send cash by entering the username of the beneficiary below and choosing the amount of cash you would like to transfer. To receive money you canshow your PoP token to the sender. To access the QR code of your PoP token, tab the QRcode icon in the top right of this screen. - You can send cash by entering the public key of the beneficiary below and choosing the amount of cash you would like to transfer. To receive money you canshow your PoP token to the sender. To access the QR code of your PoP token, tab the QRcode icon in the top right of this screen. + You can send cash by entering the username of the beneficiary below and choosing the amount of cash you would like to transfer. To receive money you canshow your PoP token to the sender. To access the QR code of your PoP token, tab the QRcode icon in the top right of this screen. { numberOfLines={1} testID={`attendee_${idx}`} selectable> - {token.valueOf()} + {generateUsernameFromBase64(token.valueOf())} + + {STRINGS.popToken} {token.valueOf()} + ); diff --git a/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap b/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap index 2b21c92f4e..5e5017eb36 100644 --- a/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap +++ b/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap @@ -874,6 +874,24 @@ exports[`EventRollCall render correctly no duplicate attendees opened roll calls } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -1021,6 +1039,24 @@ exports[`EventRollCall render correctly no duplicate attendees opened roll calls } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -1918,6 +1954,24 @@ exports[`EventRollCall render correctly no duplicate attendees re-opened roll ca } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -2065,6 +2119,24 @@ exports[`EventRollCall render correctly no duplicate attendees re-opened roll ca } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -2805,6 +2877,24 @@ exports[`EventRollCall render correctly non organizers closed roll calls 1`] = ` } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -2952,6 +3042,24 @@ exports[`EventRollCall render correctly non organizers closed roll calls 1`] = ` } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -4275,6 +4383,24 @@ exports[`EventRollCall render correctly non organizers opened roll calls 1`] = ` } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -4422,6 +4548,24 @@ exports[`EventRollCall render correctly non organizers opened roll calls 1`] = ` } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -5319,6 +5463,24 @@ exports[`EventRollCall render correctly non organizers re-opened roll calls 1`] } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -5466,6 +5628,24 @@ exports[`EventRollCall render correctly non organizers re-opened roll calls 1`] } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -6206,6 +6386,24 @@ exports[`EventRollCall render correctly organizers closed roll calls 1`] = ` } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -6353,6 +6551,24 @@ exports[`EventRollCall render correctly organizers closed roll calls 1`] = ` } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -7651,6 +7867,24 @@ exports[`EventRollCall render correctly organizers opened roll calls 1`] = ` } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -7798,6 +8032,24 @@ exports[`EventRollCall render correctly organizers opened roll calls 1`] = ` } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 @@ -8662,6 +8914,24 @@ exports[`EventRollCall render correctly organizers re-opened roll calls 1`] = ` } testID="attendee_0" > + bestdespair0001 + + + PoP token: + attendee1 @@ -8809,6 +9079,24 @@ exports[`EventRollCall render correctly organizers re-opened roll calls 1`] = ` } testID="attendee_1" > + bestdespair0002 + + + PoP token: + attendee2 diff --git a/fe1-web/src/features/social/components/ChirpCard.tsx b/fe1-web/src/features/social/components/ChirpCard.tsx index a538db8040..30d16001ca 100644 --- a/fe1-web/src/features/social/components/ChirpCard.tsx +++ b/fe1-web/src/features/social/components/ChirpCard.tsx @@ -11,6 +11,7 @@ import TimeAgo from 'react-timeago'; import { ProfileIcon, ConfirmModal } from 'core/components'; import PoPIconButton from 'core/components/PoPIconButton'; import PoPTouchableOpacity from 'core/components/PoPTouchableOpacity'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { AppParamList } from 'core/navigation/typing/AppParamList'; import { LaoParamList } from 'core/navigation/typing/LaoParamList'; import { SocialParamList } from 'core/navigation/typing/social'; @@ -49,6 +50,7 @@ type NavigationProps = CompositeScreenProps< const styles = StyleSheet.create({ profileIcon: { alignSelf: 'flex-start', + width: '165px', } as ViewStyle, senderPrefix: { marginTop: Spacing.x05, @@ -197,13 +199,12 @@ const ChirpCard = ({ chirp, isFirstItem, isLastItem }: IPropTypes) => { Typography.base, Typography.small, Typography.inactive, - Typography.centered, Typography.code, styles.senderPrefix, ]} numberOfLines={1} selectable> - {chirp.sender.valueOf().slice(0, 4)} + {generateUsernameFromBase64(chirp.sender.valueOf())} diff --git a/fe1-web/src/features/social/components/Profile.tsx b/fe1-web/src/features/social/components/Profile.tsx index 0e2de3b37d..644fdf97cc 100644 --- a/fe1-web/src/features/social/components/Profile.tsx +++ b/fe1-web/src/features/social/components/Profile.tsx @@ -5,8 +5,10 @@ import { FlatList } from 'react-native-gesture-handler'; import { useSelector } from 'react-redux'; import { ProfileIcon } from 'core/components'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { PublicKey } from 'core/objects'; import { Border, Color, List, Spacing, Typography } from 'core/styles'; +import STRINGS from 'resources/strings'; import { SocialHooks } from '../hooks'; import { Chirp } from '../objects'; @@ -51,9 +53,12 @@ const Profile = ({ publicKey }: IPropTypes) => { - {publicKey.toString()} + {generateUsernameFromBase64(publicKey.valueOf())} - {`${userChirpList.length} ${ + + {STRINGS.popToken} {publicKey.toString()} + + {`${userChirpList.length} ${ userChirpList.length === 1 ? 'chirp' : 'chirps' }`} diff --git a/fe1-web/src/features/social/components/UserListItem.tsx b/fe1-web/src/features/social/components/UserListItem.tsx index f80505605d..04dc464afd 100644 --- a/fe1-web/src/features/social/components/UserListItem.tsx +++ b/fe1-web/src/features/social/components/UserListItem.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { StyleSheet, View, ViewStyle } from 'react-native'; import { ProfileIcon } from 'core/components'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { AppParamList } from 'core/navigation/typing/AppParamList'; import { LaoParamList } from 'core/navigation/typing/LaoParamList'; import { SocialParamList } from 'core/navigation/typing/social/SocialParamList'; @@ -68,7 +69,7 @@ const UserListItem = ({ publicKey, isFirstItem, isLastItem }: IPropTypes) => { - {publicKey.valueOf()} + {generateUsernameFromBase64(publicKey.valueOf())} diff --git a/fe1-web/src/features/social/components/__tests__/__snapshots__/ChirpCard.test.tsx.snap b/fe1-web/src/features/social/components/__tests__/__snapshots__/ChirpCard.test.tsx.snap index 0179c26528..5fe3e844e1 100644 --- a/fe1-web/src/features/social/components/__tests__/__snapshots__/ChirpCard.test.tsx.snap +++ b/fe1-web/src/features/social/components/__tests__/__snapshots__/ChirpCard.test.tsx.snap @@ -374,6 +374,7 @@ exports[`ChirpCard for deletion render correct for a deleted chirp 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -397,9 +398,6 @@ exports[`ChirpCard for deletion render correct for a deleted chirp 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -409,7 +407,7 @@ exports[`ChirpCard for deletion render correct for a deleted chirp 1`] = ` ] } > - Joke + pilotmusic0000 @@ -971,6 +969,7 @@ exports[`ChirpCard for deletion renders correctly for non-sender 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -994,9 +993,6 @@ exports[`ChirpCard for deletion renders correctly for non-sender 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -1006,7 +1002,7 @@ exports[`ChirpCard for deletion renders correctly for non-sender 1`] = ` ] } > - Doug + clickbetter0000 @@ -1779,6 +1775,7 @@ exports[`ChirpCard for deletion renders correctly for sender 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -1802,9 +1799,6 @@ exports[`ChirpCard for deletion renders correctly for sender 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -1814,7 +1808,7 @@ exports[`ChirpCard for deletion renders correctly for sender 1`] = ` ] } > - Doug + clickbetter0000 @@ -2643,6 +2637,7 @@ exports[`ChirpCard for reaction renders correctly with reaction 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -2666,9 +2661,6 @@ exports[`ChirpCard for reaction renders correctly with reaction 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -2678,7 +2670,7 @@ exports[`ChirpCard for reaction renders correctly with reaction 1`] = ` ] } > - Doug + clickbetter0000 @@ -3451,6 +3443,7 @@ exports[`ChirpCard for reaction renders correctly without reaction 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -3474,9 +3467,6 @@ exports[`ChirpCard for reaction renders correctly without reaction 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -3486,7 +3476,7 @@ exports[`ChirpCard for reaction renders correctly without reaction 1`] = ` ] } > - Doug + clickbetter0000 diff --git a/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap b/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap index 7094ecc897..59a552c559 100644 --- a/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap +++ b/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap @@ -36,9 +36,33 @@ exports[`Profile renders correctly 1`] = ` ] } > + daughterscrub0000 + + + PoP token: + PublicKey - + 0 chirps diff --git a/fe1-web/src/features/social/components/__tests__/__snapshots__/UserListItem.test.tsx.snap b/fe1-web/src/features/social/components/__tests__/__snapshots__/UserListItem.test.tsx.snap index b0539ece61..c066bc0055 100644 --- a/fe1-web/src/features/social/components/__tests__/__snapshots__/UserListItem.test.tsx.snap +++ b/fe1-web/src/features/social/components/__tests__/__snapshots__/UserListItem.test.tsx.snap @@ -480,7 +480,7 @@ exports[`UserListItem renders correctly 1`] = ` } testID="listItemTitle" > - PublicKey + daughterscrub0000 - Doug + clickbetter0000 @@ -890,6 +888,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -919,9 +918,6 @@ exports[`SocialTopChirps renders correctly 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -931,7 +927,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` ] } > - Gand + limitroad0000 @@ -1370,6 +1366,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` }, { "alignSelf": "flex-start", + "width": "165px", }, ] } @@ -1399,9 +1396,6 @@ exports[`SocialTopChirps renders correctly 1`] = ` { "color": "#8E8E8E", }, - { - "textAlign": "center", - }, { "fontFamily": "Courier New", }, @@ -1411,7 +1405,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` ] } > - Doug + clickbetter0000 diff --git a/fe1-web/src/resources/strings.ts b/fe1-web/src/resources/strings.ts index 8b715c66e8..cf4ed288fc 100644 --- a/fe1-web/src/resources/strings.ts +++ b/fe1-web/src/resources/strings.ts @@ -483,7 +483,7 @@ namespace STRINGS { 'You as the organizer can create money out of thin air 🧙‍♂️'; export const digital_cash_wallet_transaction_description = - 'You can send cash by entering the public key of the beneficiary below and ' + + 'You can send cash by entering the username of the beneficiary below and ' + 'choosing the amount of cash you would like to transfer. To receive money you can' + 'show your PoP token to the sender. To access the QR code of your PoP token, tab the QR' + 'code icon in the top right of this screen.'; @@ -497,8 +497,7 @@ namespace STRINGS { export const digital_cash_wallet_send_transaction = 'Send Transaction'; export const digital_cash_wallet_beneficiary = 'Beneficiary (-ies)'; - export const digital_cash_wallet_beneficiary_placeholder = - 'QVGlyoTAEYWxq3hSBuawE-lo3sHEyfIv8uizjQTzsIU='; + export const digital_cash_wallet_beneficiary_placeholder = 'defuser1234'; export const digital_cash_wallet_amount = 'Amount'; export const digital_cash_wallet_amount_placeholder = '42'; @@ -573,6 +572,8 @@ namespace STRINGS { 'porta orci auctor, a vulputate felis suscipit. Aenean vulputate ligula ac commodo ornare.'; export const unused = 'unused'; + + export const popToken = 'PoP token:'; } export default STRINGS; From 34ce5b26efa540dc843ec5f4fead25587961e416 Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Wed, 26 Jun 2024 16:17:53 +0200 Subject: [PATCH 3/6] update when to show username in transaction history --- .../components/TransactionHistory.tsx | 4 +++- .../screens/SendReceive/SendReceive.tsx | 16 ++++++++++++++-- fe1-web/src/resources/strings.ts | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx index df4ab6bf24..102be0e4a2 100644 --- a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx +++ b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx @@ -12,6 +12,8 @@ import STRINGS from 'resources/strings'; import { DigitalCashHooks } from '../hooks'; import { Transaction, TransactionState } from '../objects/transaction'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; +import { getCurrentLao } from 'features/lao/functions'; /** * UI for the transactions history given roll call tokens of the user in the lao. @@ -135,7 +137,7 @@ const TransactionHistory = ({ laoId, rollCallTokens }: IPropTypes) => { - {input.script.publicKey.valueOf()} + { input.script.publicKey.valueOf() === getCurrentLao().organizer.valueOf() ? input.script.publicKey.valueOf() + ' ' + '(organizer)' : generateUsernameFromBase64(input.script.publicKey.valueOf())} {input.txOutHash.valueOf() === COINBASE_HASH && diff --git a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx index fda8f72959..3ef47527d5 100644 --- a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx +++ b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx @@ -84,11 +84,24 @@ const SendReceive = () => { const selectedRollCall = DigitalCashHooks.useRollCallById(selectedRollCallId); - const [beneficiary, setBeneficiary] = useState(''); + const [beneficiary, setBeneficiaryState] = useState(''); const [beneficiaryFocused, setBeneficiaryFocused] = useState(false); const [amount, setAmount] = useState(''); const [error, setError] = useState(''); + const setBeneficiary = (newBeneficiary: string) => { + if(rollCall?.attendees) { + for (let i=0; i < rollCall!.attendees!.length; i++) { + let username = generateUsernameFromBase64(rollCall!.attendees![i].valueOf()); + if (username == newBeneficiary) { + setBeneficiaryState(rollCall!.attendees![i].valueOf()); + return; + } + } + } + setBeneficiaryState(newBeneficiary); + }; + const suggestedBeneficiaries = useMemo(() => { // do not show any suggestions if no text has been entered if (!beneficiaryFocused && beneficiary.trim().length === 0) { @@ -180,7 +193,6 @@ const SendReceive = () => { if (!rollCallToken) { throw new Error('The roll call token is not defined'); } - return requestSendTransaction( rollCallToken.token, new PublicKey(beneficiary), diff --git a/fe1-web/src/resources/strings.ts b/fe1-web/src/resources/strings.ts index cf4ed288fc..1e8c322886 100644 --- a/fe1-web/src/resources/strings.ts +++ b/fe1-web/src/resources/strings.ts @@ -497,7 +497,8 @@ namespace STRINGS { export const digital_cash_wallet_send_transaction = 'Send Transaction'; export const digital_cash_wallet_beneficiary = 'Beneficiary (-ies)'; - export const digital_cash_wallet_beneficiary_placeholder = 'defuser1234'; + export const digital_cash_wallet_beneficiary_placeholder = + 'QVGlyoTAEYWxq3hSBuawE-lo3sHEyfIv8uizjQTzsIU='; export const digital_cash_wallet_amount = 'Amount'; export const digital_cash_wallet_amount_placeholder = '42'; From 5c49217722f601e184b8485b06934d2eb994f383 Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Wed, 26 Jun 2024 16:33:54 +0200 Subject: [PATCH 4/6] fix linting --- .../components/TransactionHistory.tsx | 9 ++++--- .../screens/SendReceive/SendReceive.tsx | 26 ++++++++++--------- .../__snapshots__/SendReceive.test.tsx.snap | 4 +-- fe1-web/src/resources/strings.ts | 1 + 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx index 102be0e4a2..1faec1a8c6 100644 --- a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx +++ b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx @@ -5,15 +5,15 @@ import { Modal, View } from 'react-native'; import { ScrollView, TouchableWithoutFeedback } from 'react-native-gesture-handler'; import ModalHeader from 'core/components/ModalHeader'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { Hash, RollCallToken } from 'core/objects'; import { List, ModalStyles, Typography } from 'core/styles'; +import { getCurrentLao } from 'features/lao/functions'; import { COINBASE_HASH } from 'resources/const'; import STRINGS from 'resources/strings'; import { DigitalCashHooks } from '../hooks'; import { Transaction, TransactionState } from '../objects/transaction'; -import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; -import { getCurrentLao } from 'features/lao/functions'; /** * UI for the transactions history given roll call tokens of the user in the lao. @@ -137,7 +137,10 @@ const TransactionHistory = ({ laoId, rollCallTokens }: IPropTypes) => { - { input.script.publicKey.valueOf() === getCurrentLao().organizer.valueOf() ? input.script.publicKey.valueOf() + ' ' + '(organizer)' : generateUsernameFromBase64(input.script.publicKey.valueOf())} + {input.script.publicKey.valueOf() === getCurrentLao().organizer.valueOf() + ? input.script.publicKey.valueOf() + + STRINGS.digital_cash_wallet_transaction_history_organizer + : generateUsernameFromBase64(input.script.publicKey.valueOf())} {input.txOutHash.valueOf() === COINBASE_HASH && diff --git a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx index 3ef47527d5..1d0b1be5b8 100644 --- a/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx +++ b/fe1-web/src/features/digital-cash/screens/SendReceive/SendReceive.tsx @@ -1,7 +1,7 @@ import { CompositeScreenProps, useNavigation, useRoute } from '@react-navigation/core'; import { StackScreenProps } from '@react-navigation/stack'; import * as Clipboard from 'expo-clipboard'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Modal, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'; import { ScrollView, @@ -89,18 +89,20 @@ const SendReceive = () => { const [amount, setAmount] = useState(''); const [error, setError] = useState(''); - const setBeneficiary = (newBeneficiary: string) => { - if(rollCall?.attendees) { - for (let i=0; i < rollCall!.attendees!.length; i++) { - let username = generateUsernameFromBase64(rollCall!.attendees![i].valueOf()); - if (username == newBeneficiary) { - setBeneficiaryState(rollCall!.attendees![i].valueOf()); - return; + const setBeneficiary = useCallback( + (newBeneficiary: string) => { + if (rollCall?.attendees) { + for (let i = 0; i < rollCall!.attendees!.length; i += 1) { + if (generateUsernameFromBase64(rollCall!.attendees![i].valueOf()) === newBeneficiary) { + setBeneficiaryState(rollCall!.attendees![i].valueOf()); + return; + } } } - } - setBeneficiaryState(newBeneficiary); - }; + setBeneficiaryState(newBeneficiary); + }, + [rollCall], + ); const suggestedBeneficiaries = useMemo(() => { // do not show any suggestions if no text has been entered @@ -137,7 +139,7 @@ const SendReceive = () => { if (scannedPoPToken) { setBeneficiary(scannedPoPToken); } - }, [scannedPoPToken]); + }, [scannedPoPToken, setBeneficiary]); const checkBeneficiaryValidity = (): boolean => { if (!isCoinbase && beneficiary === '') { diff --git a/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap b/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap index 3ec88d0541..fa9523bb18 100644 --- a/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap +++ b/fe1-web/src/features/digital-cash/screens/SendReceive/__tests__/__snapshots__/SendReceive.test.tsx.snap @@ -448,7 +448,7 @@ exports[`SendReceive renders correctly 1`] = ` editable={true} onChangeText={[Function]} onFocus={[Function]} - placeholder="defuser1234" + placeholder="QVGlyoTAEYWxq3hSBuawE-lo3sHEyfIv8uizjQTzsIU=" placeholderTextColor="#8E8E8E" style={ [ @@ -1101,7 +1101,7 @@ exports[`SendReceive renders correctly with passed scanned pop token 1`] = ` editable={true} onChangeText={[Function]} onFocus={[Function]} - placeholder="defuser1234" + placeholder="QVGlyoTAEYWxq3hSBuawE-lo3sHEyfIv8uizjQTzsIU=" placeholderTextColor="#8E8E8E" style={ [ diff --git a/fe1-web/src/resources/strings.ts b/fe1-web/src/resources/strings.ts index 1e8c322886..2945d37457 100644 --- a/fe1-web/src/resources/strings.ts +++ b/fe1-web/src/resources/strings.ts @@ -517,6 +517,7 @@ namespace STRINGS { export const digital_cash_wallet_issue_all_attendees = 'All attendees of roll call'; export const digital_cash_wallet_issue_to_every_participants = 'Issue to every attendee of this roll call'; + export const digital_cash_wallet_transaction_history_organizer = ' (organizer)'; export const digital_cash_infinity = '∞'; export const digital_cash_error_rollcall_not_defined = From 0bc8b3ae2a381c9a1b8d17afc7784f827543068a Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Fri, 28 Jun 2024 22:50:14 +0200 Subject: [PATCH 5/6] fix dependency issue --- fe1-web/src/features/digital-cash/__tests__/utils.ts | 3 ++- .../digital-cash/components/TransactionHistory.tsx | 5 +++-- .../src/features/digital-cash/hooks/DigitalCashHooks.ts | 5 +++++ fe1-web/src/features/digital-cash/index.ts | 1 + .../src/features/digital-cash/interface/Configuration.ts | 7 +++++++ fe1-web/src/features/digital-cash/interface/Feature.ts | 1 + fe1-web/src/features/index.ts | 1 + 7 files changed, 20 insertions(+), 3 deletions(-) diff --git a/fe1-web/src/features/digital-cash/__tests__/utils.ts b/fe1-web/src/features/digital-cash/__tests__/utils.ts index bb0066a9a9..739c899bec 100644 --- a/fe1-web/src/features/digital-cash/__tests__/utils.ts +++ b/fe1-web/src/features/digital-cash/__tests__/utils.ts @@ -1,4 +1,4 @@ -import { mockKeyPair, mockLaoId } from '__tests__/utils'; +import { mockKeyPair, mockLao, mockLaoId } from '__tests__/utils'; import { Hash, PopToken, RollCallToken } from 'core/objects'; import { COINBASE_HASH, SCRIPT_TYPE } from 'resources/const'; @@ -26,6 +26,7 @@ export const mockDigitalCashContextValue = (isOrganizer: boolean) => ({ }), useRollCallTokensByLaoId: () => [mockRollCallToken], useRollCallTokenByRollCallId: () => mockRollCallToken, + useCurrentLao: () => mockLao, } as DigitalCashReactContext, }); diff --git a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx index 1faec1a8c6..34c7ecdc9d 100644 --- a/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx +++ b/fe1-web/src/features/digital-cash/components/TransactionHistory.tsx @@ -8,7 +8,6 @@ import ModalHeader from 'core/components/ModalHeader'; import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { Hash, RollCallToken } from 'core/objects'; import { List, ModalStyles, Typography } from 'core/styles'; -import { getCurrentLao } from 'features/lao/functions'; import { COINBASE_HASH } from 'resources/const'; import STRINGS from 'resources/strings'; @@ -26,6 +25,8 @@ const TransactionHistory = ({ laoId, rollCallTokens }: IPropTypes) => { const [selectedTransaction, setSelectedTransaction] = useState(null); const [showModal, setShowModal] = useState(false); + const currentLao = DigitalCashHooks.useCurrentLao(); + // If we want to show all transactions, just use DigitalCashHooks.useTransactions(laoId) const transactions: Transaction[] = DigitalCashHooks.useTransactionsByRollCallTokens( laoId, @@ -137,7 +138,7 @@ const TransactionHistory = ({ laoId, rollCallTokens }: IPropTypes) => { - {input.script.publicKey.valueOf() === getCurrentLao().organizer.valueOf() + {input.script.publicKey.valueOf() === currentLao.organizer.valueOf() ? input.script.publicKey.valueOf() + STRINGS.digital_cash_wallet_transaction_history_organizer : generateUsernameFromBase64(input.script.publicKey.valueOf())} diff --git a/fe1-web/src/features/digital-cash/hooks/DigitalCashHooks.ts b/fe1-web/src/features/digital-cash/hooks/DigitalCashHooks.ts index 2825ef8f41..5ec94bb11b 100644 --- a/fe1-web/src/features/digital-cash/hooks/DigitalCashHooks.ts +++ b/fe1-web/src/features/digital-cash/hooks/DigitalCashHooks.ts @@ -64,6 +64,11 @@ export namespace DigitalCashHooks { export const useRollCallsByLaoId = (laoId: Hash) => useDigitalCashContext().useRollCallsByLaoId(laoId); + /** + * Gets the current lao , throws an error if there is none + */ + export const useCurrentLao = () => useDigitalCashContext().useCurrentLao(); + /** * Gets the list of all transactions that happened in this LAO * To use only in a React component diff --git a/fe1-web/src/features/digital-cash/index.ts b/fe1-web/src/features/digital-cash/index.ts index c8001125ba..be1898ae7d 100644 --- a/fe1-web/src/features/digital-cash/index.ts +++ b/fe1-web/src/features/digital-cash/index.ts @@ -31,6 +31,7 @@ export function compose( useRollCallById: configuration.useRollCallById, useCurrentLaoId: configuration.useCurrentLaoId, useConnectedToLao: configuration.useConnectedToLao, + useCurrentLao: configuration.useCurrentLao, useIsLaoOrganizer: configuration.useIsLaoOrganizer, useRollCallTokensByLaoId: configuration.useRollCallTokensByLaoId, useRollCallTokenByRollCallId: configuration.useRollCallTokenByRollCallId, diff --git a/fe1-web/src/features/digital-cash/interface/Configuration.ts b/fe1-web/src/features/digital-cash/interface/Configuration.ts index 9819a3c73e..eb4e362788 100644 --- a/fe1-web/src/features/digital-cash/interface/Configuration.ts +++ b/fe1-web/src/features/digital-cash/interface/Configuration.ts @@ -91,6 +91,12 @@ export interface DigitalCashCompositionConfiguration { * @returns the RollCallToken or undefined if not found in the roll call */ useRollCallTokenByRollCallId: (laoId: Hash, rollCallId?: Hash) => RollCallToken | undefined; + + /** + * Gets the current lao + * @returns The current lao + */ + useCurrentLao: () => DigitalCashFeature.Lao; } /** @@ -102,6 +108,7 @@ export type DigitalCashReactContext = Pick< | 'useCurrentLaoId' | 'useIsLaoOrganizer' | 'useConnectedToLao' + | 'useCurrentLao' /* roll call */ | 'useRollCallById' diff --git a/fe1-web/src/features/digital-cash/interface/Feature.ts b/fe1-web/src/features/digital-cash/interface/Feature.ts index ae6083e2f5..0e7f01cbeb 100644 --- a/fe1-web/src/features/digital-cash/interface/Feature.ts +++ b/fe1-web/src/features/digital-cash/interface/Feature.ts @@ -5,6 +5,7 @@ import { Hash, PopToken, PublicKey } from 'core/objects'; export namespace DigitalCashFeature { export interface Lao { id: Hash; + organizer: PublicKey; } export interface LaoScreen extends NavigationDrawerScreen { diff --git a/fe1-web/src/features/index.ts b/fe1-web/src/features/index.ts index 6a2b5a914c..3d2a4d3f0c 100644 --- a/fe1-web/src/features/index.ts +++ b/fe1-web/src/features/index.ts @@ -94,6 +94,7 @@ export function configureFeatures() { useConnectedToLao: laoConfiguration.hooks.useConnectedToLao, useIsLaoOrganizer: laoConfiguration.hooks.useIsLaoOrganizer, getLaoOrganizer: laoConfiguration.functions.getLaoOrganizer, + useCurrentLao: laoConfiguration.hooks.useCurrentLao, useRollCallById: rollCallConfiguration.hooks.useRollCallById, useRollCallsByLaoId: rollCallConfiguration.hooks.useRollCallsByLaoId, useRollCallTokensByLaoId: rollCallConfiguration.hooks.useRollCallTokensByLaoId, From 489d25ea834aebd0ac225f46e8a007c70fae5e1c Mon Sep 17 00:00:00 2001 From: ljankoschek Date: Sun, 30 Jun 2024 15:57:44 +0200 Subject: [PATCH 6/6] make first letter of words upper case, add username to Token page --- fe1-web/src/core/functions/Mnemonic.ts | 4 +- .../core/functions/__tests__/Mnemonic.test.ts | 6 +-- .../ViewSingleRollCall.test.tsx.snap | 32 ++++++------- .../__snapshots__/ChirpCard.test.tsx.snap | 10 ++-- .../__snapshots__/Profile.test.tsx.snap | 2 +- .../__snapshots__/UserListItem.test.tsx.snap | 2 +- .../SocialTopChirps.test.tsx.snap | 6 +-- .../wallet/screens/WalletSingleRollCall.tsx | 10 +++- .../WalletSingleRollCall.test.tsx.snap | 46 ++++++++++++++++++- 9 files changed, 85 insertions(+), 33 deletions(-) diff --git a/fe1-web/src/core/functions/Mnemonic.ts b/fe1-web/src/core/functions/Mnemonic.ts index 0b4f90b5cf..c798465034 100644 --- a/fe1-web/src/core/functions/Mnemonic.ts +++ b/fe1-web/src/core/functions/Mnemonic.ts @@ -104,5 +104,7 @@ export function generateUsernameFromBase64(input: string): string { return `defaultUsername${randomInt(0, 10000000).toString().padStart(4, '0')}`; } const number = getFirstNumberDigits(input, 4); - return `${words[0]}${words[1]}${number}`; + const word1 = words[0].charAt(0).toUpperCase() + words[0].slice(1); + const word2 = words[1].charAt(0).toUpperCase() + words[1].slice(1); + return `${word1}${word2}${number}`; } diff --git a/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts b/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts index 13f4b163e3..745e1899f1 100644 --- a/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts +++ b/fe1-web/src/core/functions/__tests__/Mnemonic.test.ts @@ -2,18 +2,18 @@ import { generateUsernameFromBase64 } from '../Mnemonic'; test('generateUsernameFromBase64 should generate the correct username for the token: d_xeXEsurEnyWOp04mrrMxC3m4cS-3jK_9_Aw-UYfww=', () => { const popToken = 'd_xeXEsurEnyWOp04mrrMxC3m4cS-3jK_9_Aw-UYfww='; - const result = 'spoonissue0434'; + const result = 'SpoonIssue0434'; expect(generateUsernameFromBase64(popToken)).toBe(result); }); test('generateUsernameFromBase64 should generate the correct username for the token: e5YJ5Q6x39u_AIK78_puEE2X5wy7Y7iYZLeuZx1lnZI=', () => { const popToken = 'e5YJ5Q6x39u_AIK78_puEE2X5wy7Y7iYZLeuZx1lnZI='; - const result = 'bidtrial5563'; + const result = 'BidTrial5563'; expect(generateUsernameFromBase64(popToken)).toBe(result); }); test('generateUsernameFromBase64 should generate the correct username for the token: Y5ZAd_7Ba31uu4EUIYbG2AVnthR623-NdPyYhtyechE=', () => { const popToken = 'Y5ZAd_7Ba31uu4EUIYbG2AVnthR623-NdPyYhtyechE='; - const result = 'figuredevote5731'; + const result = 'FigureDevote5731'; expect(generateUsernameFromBase64(popToken)).toBe(result); }); diff --git a/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap b/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap index 5e5017eb36..ba471fdccf 100644 --- a/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap +++ b/fe1-web/src/features/rollCall/screens/__tests__/__snapshots__/ViewSingleRollCall.test.tsx.snap @@ -874,7 +874,7 @@ exports[`EventRollCall render correctly no duplicate attendees opened roll calls } testID="attendee_0" > - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - bestdespair0001 + BestDespair0001 - bestdespair0002 + BestDespair0002 - pilotmusic0000 + PilotMusic0000 @@ -1002,7 +1002,7 @@ exports[`ChirpCard for deletion renders correctly for non-sender 1`] = ` ] } > - clickbetter0000 + ClickBetter0000 @@ -1808,7 +1808,7 @@ exports[`ChirpCard for deletion renders correctly for sender 1`] = ` ] } > - clickbetter0000 + ClickBetter0000 @@ -2670,7 +2670,7 @@ exports[`ChirpCard for reaction renders correctly with reaction 1`] = ` ] } > - clickbetter0000 + ClickBetter0000 @@ -3476,7 +3476,7 @@ exports[`ChirpCard for reaction renders correctly without reaction 1`] = ` ] } > - clickbetter0000 + ClickBetter0000 diff --git a/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap b/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap index 59a552c559..26231780a8 100644 --- a/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap +++ b/fe1-web/src/features/social/components/__tests__/__snapshots__/Profile.test.tsx.snap @@ -36,7 +36,7 @@ exports[`Profile renders correctly 1`] = ` ] } > - daughterscrub0000 + DaughterScrub0000 - daughterscrub0000 + DaughterScrub0000 - clickbetter0000 + ClickBetter0000 @@ -927,7 +927,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` ] } > - limitroad0000 + LimitRoad0000 @@ -1405,7 +1405,7 @@ exports[`SocialTopChirps renders correctly 1`] = ` ] } > - clickbetter0000 + ClickBetter0000 diff --git a/fe1-web/src/features/wallet/screens/WalletSingleRollCall.tsx b/fe1-web/src/features/wallet/screens/WalletSingleRollCall.tsx index 55e1f02283..bad0591749 100644 --- a/fe1-web/src/features/wallet/screens/WalletSingleRollCall.tsx +++ b/fe1-web/src/features/wallet/screens/WalletSingleRollCall.tsx @@ -6,6 +6,7 @@ import { StyleSheet, Text, TextStyle, View } from 'react-native'; import { PoPTextButton, QRCode } from 'core/components'; import ScreenWrapper from 'core/components/ScreenWrapper'; +import { generateUsernameFromBase64 } from 'core/functions/Mnemonic'; import { AppParamList } from 'core/navigation/typing/AppParamList'; import { WalletParamList } from 'core/navigation/typing/WalletParamList'; import { ScannablePopToken } from 'core/objects/ScannablePopToken'; @@ -19,10 +20,14 @@ type NavigationProps = CompositeScreenProps< const styles = StyleSheet.create({ publicKey: { - marginVertical: Spacing.x2, + marginTop: Spacing.x05, + marginBottom: Spacing.x1, color: Color.inactive, textAlign: 'center', } as TextStyle, + username: { + marginTop: Spacing.x2, + } as TextStyle, }); /** @@ -41,6 +46,9 @@ const WalletSingleRollCall = () => { /> + + {generateUsernameFromBase64(rollCallTokenPublicKey)} + {rollCallTokenPublicKey} diff --git a/fe1-web/src/features/wallet/screens/__tests__/__snapshots__/WalletSingleRollCall.test.tsx.snap b/fe1-web/src/features/wallet/screens/__tests__/__snapshots__/WalletSingleRollCall.test.tsx.snap index 12048ac916..e8b768b1fd 100644 --- a/fe1-web/src/features/wallet/screens/__tests__/__snapshots__/WalletSingleRollCall.test.tsx.snap +++ b/fe1-web/src/features/wallet/screens/__tests__/__snapshots__/WalletSingleRollCall.test.tsx.snap @@ -425,6 +425,26 @@ exports[`ViewSingleRollCallScreenHeader renders correctly 1`] = ` + + LoyalBorrow3877 + + + LoyalBorrow3877 +