diff --git a/src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/index.tsx b/src/components/common/AccountShowcase/index.tsx similarity index 62% rename from src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/index.tsx rename to src/components/common/AccountShowcase/index.tsx index 68aa21aa..17409158 100644 --- a/src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/index.tsx +++ b/src/components/common/AccountShowcase/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { StyleProp, View, ViewStyle } from 'react-native'; +import { StyleProp, TextStyle, View, ViewStyle } from 'react-native'; -import { CustomCheckbox, Text, Touchable, UserIcon } from '@/components/common'; +import { Text, Touchable, UserIcon } from '@/components/common'; import { FontStyles } from '@/constants/theme'; import styles from './styles'; @@ -11,6 +11,9 @@ interface Props { subtitle?: string; icon?: string; selected: boolean; + right: React.ReactNode; + titleStyle?: StyleProp; + titleRight?: React.ReactNode; style?: StyleProp; onPress?: () => void; onLongPress?: () => void; @@ -22,6 +25,9 @@ function AccountShowcase({ subtitle, style, selected, + right, + titleStyle, + titleRight, onPress, onLongPress, }: Props) { @@ -31,12 +37,13 @@ function AccountShowcase({ - {title} + + {title} + {titleRight} + {subtitle} - - - + {right} diff --git a/src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/styles.ts b/src/components/common/AccountShowcase/styles.ts similarity index 86% rename from src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/styles.ts rename to src/components/common/AccountShowcase/styles.ts index 656fc150..2053ef27 100644 --- a/src/screens/tabs/Profile/modals/ExportPem/components/AccountShowcase/styles.ts +++ b/src/components/common/AccountShowcase/styles.ts @@ -23,4 +23,8 @@ export default StyleSheet.create({ alignItems: 'flex-end', marginRight: 8, }, + titleContainer: { + flexDirection: 'row', + alignItems: 'center', + }, }); diff --git a/src/components/common/EmptyState/index.js b/src/components/common/EmptyState/index.js deleted file mode 100644 index 02d12d8b..00000000 --- a/src/components/common/EmptyState/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { View } from 'react-native'; - -import Text from '../Text'; -import styles from './styles'; - -const EmptyState = ({ title, text, style, onTextPress }) => ( - - 🤔 - - {title} - - - {text} - - -); - -export default EmptyState; diff --git a/src/components/common/EmptyState/index.tsx b/src/components/common/EmptyState/index.tsx new file mode 100644 index 00000000..27fb2503 --- /dev/null +++ b/src/components/common/EmptyState/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { StyleProp, View, ViewStyle } from 'react-native'; + +import RainbowButton from '@/components/buttons/RainbowButton'; + +import Text from '../Text'; +import styles from './styles'; + +interface Props { + title: string; + text: string; + emoji?: string; + style?: StyleProp; + buttonTitle?: string; + buttonStyle?: StyleProp; + onTextPress?: () => void; + onButtonPress?: () => void; +} + +function EmptyState({ + title, + text, + style, + emoji = '🤔', + buttonTitle, + buttonStyle, + onTextPress, + onButtonPress, +}: Props) { + return ( + + {emoji} + + {title} + + + {text} + + {onButtonPress && buttonTitle && ( + + )} + + ); +} + +export default EmptyState; diff --git a/src/components/common/EmptyState/styles.js b/src/components/common/EmptyState/styles.ts similarity index 66% rename from src/components/common/EmptyState/styles.js rename to src/components/common/EmptyState/styles.ts index 149e4b78..1beeda05 100644 --- a/src/components/common/EmptyState/styles.js +++ b/src/components/common/EmptyState/styles.ts @@ -1,6 +1,7 @@ import { StyleSheet } from 'react-native'; import { Colors } from '@/constants/theme'; +import { fontMaker } from '@/utils/fonts'; export default StyleSheet.create({ container: { @@ -9,17 +10,17 @@ export default StyleSheet.create({ justifyContent: 'center', }, title: { - color: Colors.White.Primary, + ...fontMaker({ color: Colors.White.Primary }), marginTop: 11, marginBottom: 8, }, text: { - color: Colors.White.Secondary, + ...fontMaker({ color: Colors.White.Secondary }), textAlign: 'center', paddingHorizontal: 40, }, link: { - color: Colors.ActionBlue, + ...fontMaker({ color: Colors.ActionBlue }), }, emoji: { fontSize: 38, diff --git a/src/components/common/index.ts b/src/components/common/index.ts index d1c46982..a3aa182e 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -28,3 +28,4 @@ export { default as Touchable } from './Touchable'; export { default as UserIcon } from './UserIcon'; export { default as CustomCheckbox } from './CustomCheckbox'; export { default as Toast } from './Toast'; +export { default as AccountShowcase } from './AccountShowcase'; diff --git a/src/redux/slices/user.ts b/src/redux/slices/user.ts index d76476e8..2925f9f3 100644 --- a/src/redux/slices/user.ts +++ b/src/redux/slices/user.ts @@ -465,7 +465,6 @@ export const getCollectionInfo = createAsyncThunk( } ); -// eslint-disable-next-line no-spaced-func export const addCustomCollection = createAsyncThunk< Collection[], { diff --git a/src/screens/tabs/Profile/modals/Accounts/index.tsx b/src/screens/tabs/Profile/modals/Accounts/index.tsx index fd3d9e43..4135defc 100644 --- a/src/screens/tabs/Profile/modals/Accounts/index.tsx +++ b/src/screens/tabs/Profile/modals/Accounts/index.tsx @@ -5,14 +5,15 @@ import { ActivityIndicator, Alert, Platform, View } from 'react-native'; import { Modalize } from 'react-native-modalize'; import { + AccountShowcase, ActionSheet, - CommonItem, Header, Modal, Text, Touchable, } from '@/components/common'; import Icon from '@/components/icons'; +import { COMMON_HITSLOP } from '@/constants/general'; import { FontStyles } from '@/constants/theme'; import CopyIcon from '@/icons/material/Copy.svg'; import EditIcon from '@/icons/material/Edit.svg'; @@ -25,6 +26,7 @@ import { Row } from '@/layout'; import { useAppDispatch, useAppSelector } from '@/redux/hooks'; import { getICPPrice } from '@/redux/slices/icp'; import { removeAccount, setCurrentPrincipal } from '@/redux/slices/keyring'; +import animationScales from '@/utils/animationScales'; import shortAddress from '@/utils/shortAddress'; import CreateEditAccount from '../CreateEditAccount'; @@ -106,7 +108,7 @@ function Accounts({ modalRef }: Props) { addICNSRef.current?.open(); }; - const onLongPress = (account: Wallet) => { + const openAccountOptions = (account: Wallet) => { const isSelectedAccount = currentWallet?.principal === account.principal; const isImportedAccount = !account.type.includes('MNEMONIC'); @@ -159,9 +161,12 @@ function Accounts({ modalRef }: Props) { const renderAccountItem = (account: Wallet, index: number) => { const isSelectedAccount = currentWallet?.principal === account.principal; + const handleOpenAccountOptions = () => openAccountOptions(account); + const selectedAccountProps = { - nameStyle: styles.selectedAccount, - right: , + selected: true, + titleStyle: styles.selectedAccount, + titleRight: , }; const handleOnPress = () => { @@ -171,15 +176,24 @@ function Accounts({ modalRef }: Props) { }; return ( - onLongPress(account)} - onActionPress={() => onLongPress(account)} + selected={isSelectedAccount} + onLongPress={handleOpenAccountOptions} + subtitle={shortAddress(account.principal)} + title={account?.icnsData?.reverseResolvedName || account.name} + right={ + + + + + + } {...(isSelectedAccount && selectedAccountProps)} /> ); diff --git a/src/screens/tabs/Profile/modals/Accounts/styles.ts b/src/screens/tabs/Profile/modals/Accounts/styles.ts index 29a7e07f..8bda0ff3 100644 --- a/src/screens/tabs/Profile/modals/Accounts/styles.ts +++ b/src/screens/tabs/Profile/modals/Accounts/styles.ts @@ -4,8 +4,9 @@ import { Colors } from '@/constants/theme'; export default StyleSheet.create({ content: { - paddingHorizontal: 20, - paddingVertical: 20, + paddingHorizontal: 12, + paddingBottom: 20, + paddingTop: 10, zIndex: 0, }, loading: { @@ -17,11 +18,12 @@ export default StyleSheet.create({ ...StyleSheet.absoluteFillObject, }, row: { - marginBottom: 30, - marginTop: 10, + marginBottom: 20, + marginLeft: 10, + marginTop: 20, }, accountItem: { - marginBottom: 20, + marginBottom: 8, }, plusIcon: { marginRight: 8, @@ -29,4 +31,11 @@ export default StyleSheet.create({ selectedAccount: { color: Colors.ActionBlue, }, + threeDots: { + marginLeft: 'auto', + justifyContent: 'center', + }, + checkbox: { + marginLeft: 6, + }, }); diff --git a/src/screens/tabs/Profile/modals/ExportPem/index.tsx b/src/screens/tabs/Profile/modals/ExportPem/index.tsx index 6e5d2608..54aa22bb 100644 --- a/src/screens/tabs/Profile/modals/ExportPem/index.tsx +++ b/src/screens/tabs/Profile/modals/ExportPem/index.tsx @@ -7,6 +7,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import RainbowButton from '@/components/buttons/RainbowButton'; import { + AccountShowcase, ActionButton, CustomCheckbox, Header, @@ -21,7 +22,6 @@ import { useAppDispatch, useAppSelector } from '@/redux/hooks'; import { getPemFile, validatePassword } from '@/redux/slices/keyring'; import shortAddress from '@/utils/shortAddress'; -import AccountShowcase from './components/AccountShowcase'; import styles from './styles'; interface Props { @@ -113,13 +113,23 @@ function ExportPem({ modalRef }: Props) { const renderAccount = (account: Wallet) => { const { name, walletId, icon, principal } = account; + const selected = selectedWallet.walletId === walletId; + const handleSetAccount = () => setSelectedWallet(account); + return ( + } subtitle={shortAddress(principal)} - selected={selectedWallet.walletId === walletId} - onPress={() => setSelectedWallet(account)} + selected={selected} + onPress={handleSetAccount} title={account?.icnsData?.reverseResolvedName || name} /> ); diff --git a/src/screens/tabs/Profile/screens/Contacts/index.tsx b/src/screens/tabs/Profile/screens/Contacts/index.tsx index af14d870..1197cfba 100644 --- a/src/screens/tabs/Profile/screens/Contacts/index.tsx +++ b/src/screens/tabs/Profile/screens/Contacts/index.tsx @@ -7,6 +7,7 @@ import { Modalize } from 'react-native-modalize'; import CommonItem from '@/commonComponents/CommonItem'; import Touchable from '@/commonComponents/Touchable'; +import { EmptyState } from '@/components/common'; import ActionSheet, { Option } from '@/components/common/ActionSheet'; import Text from '@/components/common/Text'; import Icon from '@/components/icons'; @@ -32,8 +33,9 @@ function Contacts() { const addEditContactRef = useRef(null); const actionSheetRef = useRef(null); const [actionSheetData, setActionSheetData] = useState(); - const { contacts, contactsLoading } = useAppSelector(state => state.user); + const { contactsLoading, contacts } = useAppSelector(state => state.user); const dispatch = useAppDispatch(); + const showEmptyState = contacts.length === 0; const groupedContacts = useMemo( () => @@ -84,14 +86,17 @@ function Contacts() { return ( <> - - - - {t('contacts.addContact')} - - + {!showEmptyState && ( + + + + {t('contacts.addContact')} + + + )} }> - {groupedContacts.map(section => ( - - {section.letter} - {section.contacts.map(contact => { - const isICNS = validateICNSName(contact.id); - return ( - - onPress(contact)} - onActionPress={() => onPress(contact)} - disabled={contactsLoading} - /> - - ); - })} - - ))} + {showEmptyState ? ( + + ) : ( + groupedContacts.map(section => ( + + {section.letter} + {section.contacts.map(contact => { + const isICNS = validateICNSName(contact.id); + return ( + + onPress(contact)} + onActionPress={() => onPress(contact)} + disabled={contactsLoading} + /> + + ); + })} + + )) + )}