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

Component/4233 account picker #4689

Merged
merged 2 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const TEST_ACCOUNT_ADDRESS =
'0x2990079bcdEe240329a520d2444386FC119da21a';
export const TEST_ACCOUNT_NAME = 'Orangefox.eth';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable no-console */
import React from 'react';
import { Alert } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import PickerAccount from './PickerAccount';
import {
TEST_ACCOUNT_ADDRESS,
TEST_ACCOUNT_NAME,
} from './PickerAccount.constants';
import { AccountAvatarType } from '../AccountAvatar';

storiesOf('Component Library / PickerAccount', module).add('Default', () => (
<PickerAccount
accountAddress={TEST_ACCOUNT_ADDRESS}
accountName={TEST_ACCOUNT_NAME}
accountAvatarType={AccountAvatarType.JazzIcon}
onPress={() => Alert.alert('Pressed account picker!')}
/>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { StyleSheet, ViewStyle } from 'react-native';
import { PickerAccountStyleSheetVars } from './PickerAccount.types';
import { Theme } from '../../../util/theme/models';

/**
* Style sheet function for PickerAccount component.
*
* @param params Style sheet params.
* @param params.theme App theme from ThemeContext.
* @param params.vars Inputs that the style sheet depends on.
* @returns StyleSheet object.
*/
const styleSheet = (params: {
theme: Theme;
vars: PickerAccountStyleSheetVars;
}) => {
const { vars, theme } = params;
const { colors } = theme;
const { style } = vars;
return StyleSheet.create({
base: Object.assign({} as ViewStyle, style) as ViewStyle,
accountAvatar: {
marginRight: 16,
},
accountAddressLabel: {
color: colors.text.alternative,
},
cellAccount: {
flex: 1,
flexDirection: 'row',
marginVertical: 16,
},
});
};

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { shallow } from 'enzyme';
import PickerAccount from './PickerAccount';
import {
TEST_ACCOUNT_ADDRESS,
TEST_ACCOUNT_NAME,
} from './PickerAccount.constants';
import { AccountAvatarType } from '../AccountAvatar';

describe('PickerAccount', () => {
it('should render correctly', () => {
const wrapper = shallow(
<PickerAccount
accountAddress={TEST_ACCOUNT_ADDRESS}
accountName={TEST_ACCOUNT_NAME}
accountAvatarType={AccountAvatarType.JazzIcon}
onPress={jest.fn}
/>,
);
expect(wrapper).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { View } from 'react-native';
import { useStyles } from '../../hooks';
import AccountAvatar from '../AccountAvatar';
import BaseText, { BaseTextVariant } from '../BaseText';
import PickerItem from '../PickerItem';
import styleSheet from './PickerAccount.styles';
import { PickerAccountProps } from './PickerAccount.types';
import { BaseAvatarSize } from '../BaseAvatar';
import { formatAddress } from '../../../util/address';

const PickerAccount = ({
style,
accountAddress,
accountName,
accountAvatarType,
...props
}: PickerAccountProps) => {
const { styles } = useStyles(styleSheet, { style });
const shortenedAddress = formatAddress(accountAddress, 'short');

const renderCellAccount = () => (
<View style={styles.cellAccount}>
<AccountAvatar
type={accountAvatarType}
accountAddress={accountAddress}
size={BaseAvatarSize.Md}
style={styles.accountAvatar}
/>
<View>
<BaseText variant={BaseTextVariant.lHeadingSMRegular}>
{accountName}
</BaseText>
<BaseText
variant={BaseTextVariant.lBodyMD}
style={styles.accountAddressLabel}
>
{shortenedAddress}
</BaseText>
</View>
</View>
);

return (
<PickerItem style={styles.base} {...props}>
{renderCellAccount()}
</PickerItem>
);
};

export default PickerAccount;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { StyleProp, TouchableOpacityProps, ViewStyle } from 'react-native';
import { AccountAvatarType } from '../AccountAvatar';

/**
* PickerAccount component props.
*/
export interface PickerAccountProps extends TouchableOpacityProps {
/**
* Callback to trigger when pressed.
*/
onPress: () => void;
/**
* An Ethereum wallet address.
*/
accountAddress: string;
/**
* AccountAvatar variants.
*/
accountAvatarType: AccountAvatarType;
/**
* Name of the account.
*/
accountName: string;
/**
* Escape hatch for applying extra styles. Only use if absolutely necessary.
*/
style?: StyleProp<ViewStyle>;
}

/**
* Style sheet input parameters.
*/
export type PickerAccountStyleSheetVars = Pick<PickerAccountProps, 'style'>;
39 changes: 39 additions & 0 deletions app/component-library/components/PickerAccount/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# PickerAccount

PickerAccount is a component used for accessing account selection.

## Props

This component extends `TouchableOpacityProps` from React Native's [TouchableOpacityProps Component](https://reactnative.dev/docs/touchableOpacity).

### `onPress`

Callback to trigger when pressed.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| function | Yes |

### `accountAddress`

An Ethereum wallet address.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| string | Yes |

### `accountName`

Name of the account.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| string | Yes |

### `children`

Content to wrap in PickerAccount.

| <span style="color:gray;font-size:14px">TYPE</span> | <span style="color:gray;font-size:14px">REQUIRED</span> |
| :-------------------------------------------------- | :------------------------------------------------------ |
| ReactNode | Yes |
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PickerAccount should render correctly 1`] = `
<PickerItem
onPress={[Function]}
style={Object {}}
>
<View
style={
Object {
"flex": 1,
"flexDirection": "row",
"marginVertical": 16,
}
}
>
<AccountAvatar
accountAddress="0x2990079bcdEe240329a520d2444386FC119da21a"
size="32"
style={
Object {
"marginRight": 16,
}
}
type="JazzIcon"
/>
<View>
<BaseText
variant="lHeadingSMRegular"
>
Orangefox.eth
</BaseText>
<BaseText
style={
Object {
"color": "#535A61",
}
}
variant="lBodyMD"
>
0x2990...a21a
</BaseText>
</View>
</View>
</PickerItem>
`;
1 change: 1 addition & 0 deletions app/component-library/components/PickerAccount/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './PickerAccount';
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable no-console */
import React from 'react';
import { Alert, StyleSheet, View } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import PickerItem from './PickerItem';
import { mockTheme } from '../../../util/theme';
import BaseText, { BaseTextVariant } from '../BaseText';

const styles = StyleSheet.create({
wrappedContent: {
height: 50,
flex: 1,
backgroundColor: mockTheme.colors.background.alternative,
alignItems: 'center',
justifyContent: 'center',
},
});

storiesOf('Component Library / PickerItem', module).add('Default', () => (
<PickerItem onPress={() => Alert.alert('Pressed picker!')}>
<View style={styles.wrappedContent}>
<BaseText variant={BaseTextVariant.sBodySM}>{'Wrapped Content'}</BaseText>
</View>
</PickerItem>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { StyleSheet, ViewStyle } from 'react-native';
import { PickerItemStyleSheetVars } from './PickerItem.types';
import { Theme } from '../../../util/theme/models';

/**
* Style sheet function for PickerItem component.
*
* @param params Style sheet params.
* @param params.theme App theme from ThemeContext.
* @param params.vars Inputs that the style sheet depends on.
* @returns StyleSheet object.
*/
const styleSheet = (params: {
theme: Theme;
vars: PickerItemStyleSheetVars;
}) => {
const { vars, theme } = params;
const { colors } = theme;
const { style } = vars;
return StyleSheet.create({
base: Object.assign(
{
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
borderWidth: 1,
borderColor: colors.border.default,
borderRadius: 4,
backgroundColor: colors.background.default,
} as ViewStyle,
style,
) as ViewStyle,
dropdownIcon: {
marginLeft: 16,
},
});
};

export default styleSheet;
15 changes: 15 additions & 0 deletions app/component-library/components/PickerItem/PickerItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { View } from 'react-native';
import { shallow } from 'enzyme';
import PickerItem from './PickerItem';

describe('PickerItem', () => {
it('should render correctly', () => {
const wrapper = shallow(
<PickerItem onPress={jest.fn}>
<View />
</PickerItem>,
);
expect(wrapper).toMatchSnapshot();
});
});
30 changes: 30 additions & 0 deletions app/component-library/components/PickerItem/PickerItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { TouchableOpacity } from 'react-native';
import { useStyles } from '../../hooks';
import Icon, { IconName, IconSize } from '../Icon';
import styleSheet from './PickerItem.styles';
import { PickerItemProps } from './PickerItem.types';

const PickerItem: React.FC<PickerItemProps> = ({
style,
children,
...props
}) => {
const { styles, theme } = useStyles(styleSheet, { style });
const { colors } = theme;

return (
<TouchableOpacity style={styles.base} {...props}>
{children}
<Icon
size={IconSize.Md}
color={colors.icon.alternative}
name={IconName.ArrowDownOutline}
style={styles.dropdownIcon}
/>
</TouchableOpacity>
);
};

export default PickerItem;
24 changes: 24 additions & 0 deletions app/component-library/components/PickerItem/PickerItem.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { StyleProp, TouchableOpacityProps, ViewStyle } from 'react-native';

/**
* PickerItem component props.
*/
export interface PickerItemProps extends TouchableOpacityProps {
/**
* Callback to trigger when pressed.
*/
onPress: () => void;
/**
* Escape hatch for applying extra styles. Only use if absolutely necessary.
*/
style?: StyleProp<ViewStyle>;
/**
* Content to wrap for multiselect.
*/
children: React.ReactNode;
}

/**
* Style sheet input parameters.
*/
export type PickerItemStyleSheetVars = Pick<PickerItemProps, 'style'>;
Loading