Skip to content

Commit

Permalink
Component/4233 account picker (#4689)
Browse files Browse the repository at this point in the history
* Create PickerItem component

* Create picker account component
  • Loading branch information
Cal-L authored Jul 19, 2022
1 parent f563bfc commit efb8b98
Show file tree
Hide file tree
Showing 18 changed files with 443 additions and 1 deletion.
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();
});
});
52 changes: 52 additions & 0 deletions app/component-library/components/PickerAccount/PickerAccount.tsx
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';
25 changes: 25 additions & 0 deletions app/component-library/components/PickerItem/PickerItem.stories.tsx
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>
));
39 changes: 39 additions & 0 deletions app/component-library/components/PickerItem/PickerItem.styles.ts
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

0 comments on commit efb8b98

Please sign in to comment.