Skip to content

Commit

Permalink
Merge pull request #131 from ZeroGachis/task/add-badge-component
Browse files Browse the repository at this point in the history
Task/add badge component
  • Loading branch information
AdrienCasta authored Dec 4, 2023
2 parents 34e2fba + c6a9310 commit c50bf2f
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 21 deletions.
1 change: 1 addition & 0 deletions Storybook/.ondevice/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ try {
const getStories = () => {
return {
"./components/ActionCard/ActionCard.stories.tsx": require("../components/ActionCard/ActionCard.stories.tsx"),
"./components/Badge/Badge.stories.tsx": require("../components/Badge/Badge.stories.tsx"),
"./components/BottomSheet/BottomSheet.stories.tsx": require("../components/BottomSheet/BottomSheet.stories.tsx"),
"./components/Button/Button.stories.tsx": require("../components/Button/Button.stories.tsx"),
"./components/Card/Card.stories.tsx": require("../components/Card/Card.stories.tsx"),
Expand Down
31 changes: 31 additions & 0 deletions Storybook/components/Badge/Badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Badge } from 'smartway-react-native-ui';
import type { ComponentMeta, ComponentStory } from '@storybook/react-native';
import React from 'react';
import { StyleSheet, View } from 'react-native';

export default {
title: 'components/Badge',
component: Badge,
decorators: [
(Story) => {
const styles = StyleSheet.create({
container: { paddingTop: 16 },
});
return (
<View style={styles.container}>
<Story />
</View>
);
},
],
} as ComponentMeta<typeof Badge>;

export const Base: ComponentStory<typeof Badge> = () => <Badge number={1500} />;

export const NotTruncated: ComponentStory<typeof Badge> = () => (
<Badge number={1500} maxDigits={4} />
);

export const Truncated: ComponentStory<typeof Badge> = () => (
<Badge number={1500} maxDigits={3} />
);
41 changes: 41 additions & 0 deletions src/__tests__/components/Badge.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { render, screen } from '@testing-library/react-native';

import { ThemeProvider } from '../../styles/themes';
import { Badge } from '../../components/badge/Badge';

describe('MODULE | Badge', () => {
describe('Given a `number`', () => {
it('should display it', () => {
render(
<ThemeProvider>
<Badge number={100} />
</ThemeProvider>,
);

expect(screen.getByText('100')).toBeDefined();
});
});
describe("Given a `number` and a `maxDigits` greater than number's total digit", () => {
it('should display a truncated `number`', () => {
render(
<ThemeProvider>
<Badge number={100} maxDigits={2} />
</ThemeProvider>,
);

expect(screen.getByText('99+')).toBeDefined();
});
});
describe("Given a `number` and a `maxDigits` smaller or equal than number's total digit'", () => {
it('should display the entire `number`', () => {
render(
<ThemeProvider>
<Badge number={88} maxDigits={2} />
</ThemeProvider>,
);

expect(screen.getByText('88')).toBeDefined();
});
});
});
14 changes: 9 additions & 5 deletions src/components/Screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import React from 'react';
import { SafeAreaView, ViewStyle, StatusBar, StyleSheet } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTheme } from '../styles/themes';
import type { WithTestID } from 'src/shared/type';

type Props = {
type Props = WithTestID<{
children?: React.ReactNode;
style?: ViewStyle;
testID?: string;
statusBarColor?: string;
};
}>;

export const Screen = ({ children, style, testID, statusBarColor }: Props) => {
const theme = useTheme();
Expand All @@ -29,8 +29,12 @@ export const Screen = ({ children, style, testID, statusBarColor }: Props) => {
<SafeAreaView style={styles.screen} testID={testID}>
<StatusBar
translucent
backgroundColor={statusBarColor ? statusBarColor : theme.sw.colors.neutral[50]}
barStyle="dark-content"
backgroundColor={
statusBarColor
? statusBarColor
: theme.sw.colors.neutral[50]
}
barStyle='dark-content'
/>
{children}
</SafeAreaView>
Expand Down
48 changes: 48 additions & 0 deletions src/components/badge/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { StyleSheet, ViewStyle } from 'react-native';

import { Body } from '../typography/Body';
import { ThemType, useTheme } from '../../styles/themes';
import type { WithTestID } from 'src/shared/type';

type BadgeProps = WithTestID<{
number: number;
maxDigits?: number;
style?: ViewStyle;
}>;

const createStyle = (theme: ThemType, style?: ViewStyle) => {
return StyleSheet.create({
badge: {
backgroundColor: theme.sw.colors.neutral[700],
color: theme.sw.colors.neutral[50],
paddingHorizontal: theme.sw.spacing.xs,
paddingVertical: theme.sw.spacing.xxs,
alignSelf: 'flex-start',
borderRadius: 8,
...style,
},
});
};

export const Badge = ({ number, maxDigits, testID, style }: BadgeProps) => {
const theme = useTheme();

const displayText = maxDigits
? getTruncatedNumber(number, maxDigits)
: number;

const badgeStyle = createStyle(theme, style).badge;

return (
<Body size='B2' weight='semi-bold' style={badgeStyle} testID={testID}>
{displayText}
</Body>
);
};

function getTruncatedNumber(number: number, maxDigits: number): string {
const maxNumber = Math.pow(10, maxDigits) - 1;
const isTruncated = number > maxNumber;
return isTruncated ? `${maxNumber}+` : `${number}`;
}
2 changes: 2 additions & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Label } from './label/Label';
import { Product } from './product/Product';
import { Divider } from './divider/Divider';
import { LineChart } from './charts/LineChart';
import { Badge } from './badge/Badge';

export {
Body,
Expand Down Expand Up @@ -56,4 +57,5 @@ export {
Product,
Divider,
LineChart,
Badge,
};
18 changes: 13 additions & 5 deletions src/components/keyboard/DeleteButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Pressable, StyleSheet, View } from 'react-native';
import { useTheme } from '../../styles/themes';
import { Icon } from '../icons/Icon';
import type { KeyboardActions } from './Keyboard';
import type { WithTestID } from 'src/shared/type';

interface Props {
type Props = WithTestID<{
onPress: (action: KeyboardActions) => void;
testID?: string;
}
}>;

export const DeleteButton = ({ onPress, testID }: Props) => {
const theme = useTheme();
Expand All @@ -25,9 +25,17 @@ export const DeleteButton = ({ onPress, testID }: Props) => {
});

return (
<Pressable testID={testID} style={[styles.button]} onPress={() => onPress('delete')}>
<Pressable
testID={testID}
style={[styles.button]}
onPress={() => onPress('delete')}
>
<View style={styles.icon}>
<Icon name={'backspace'} color={theme.sw.colors.neutral[500]} size={24} />
<Icon
name={'backspace'}
color={theme.sw.colors.neutral[500]}
size={24}
/>
</View>
</Pressable>
);
Expand Down
18 changes: 13 additions & 5 deletions src/components/keyboard/SubmitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Pressable, StyleSheet, View } from 'react-native';
import { useTheme } from '../../styles/themes';
import { Icon } from '../icons/Icon';
import type { KeyboardActions } from './Keyboard';
import type { WithTestID } from 'src/shared/type';

interface Props {
type Props = WithTestID<{
onPress: (action: KeyboardActions) => void;
testID?: string;
}
}>;

export const SubmitButton = ({ onPress, testID }: Props) => {
const theme = useTheme();
Expand All @@ -26,9 +26,17 @@ export const SubmitButton = ({ onPress, testID }: Props) => {
});

return (
<Pressable testID={testID} style={[styles.button]} onPress={() => onPress('submit')}>
<Pressable
testID={testID}
style={[styles.button]}
onPress={() => onPress('submit')}
>
<View style={styles.icon}>
<Icon name={'validate'} color={theme.sw.colors.primary.main} size={24} />
<Icon
name={'validate'}
color={theme.sw.colors.primary.main}
size={24}
/>
</View>
</Pressable>
);
Expand Down
24 changes: 18 additions & 6 deletions src/components/topAppBar/TopAppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useTheme } from '../../styles/themes';
import { StyleSheet, type ViewStyle } from 'react-native';
import { Headline } from '../typography/Headline';
import type { IconSource } from 'react-native-paper/lib/typescript/components/Icon';
import type { WithTestID } from 'src/shared/type';

interface Icon {
name: IconSource;
Expand All @@ -15,16 +16,22 @@ export interface Title {
onPress?: () => void;
}

export interface Props {
export type Props = WithTestID<{
size?: 'small' | 'medium' | 'large' | 'center-aligned';
title: Title;
icon?: Icon;
onBack?: () => void;
style?: ViewStyle;
testID?: string;
}
}>;

export const TopAppBar = ({ size = 'small', title, icon, onBack, style, testID }: Props) => {
export const TopAppBar = ({
size = 'small',
title,
icon,
onBack,
style,
testID,
}: Props) => {
const theme = useTheme();
const styles = StyleSheet.create({
button: {
Expand All @@ -47,7 +54,12 @@ export const TopAppBar = ({ size = 'small', title, icon, onBack, style, testID }
return theme.sw.colors.neutral[600];
};
return (
<Appbar.Header mode={size} style={styles.header} statusBarHeight={0} testID={testID}>
<Appbar.Header
mode={size}
style={styles.header}
statusBarHeight={0}
testID={testID}
>
{onBack !== undefined && (
<Appbar.BackAction
style={styles.button}
Expand All @@ -58,7 +70,7 @@ export const TopAppBar = ({ size = 'small', title, icon, onBack, style, testID }
<Appbar.Content
title={
typeof title.value === 'string' ? (
<Headline size="h2">{title.value}</Headline>
<Headline size='h2'>{title.value}</Headline>
) : (
title.value
)
Expand Down
2 changes: 2 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
Product,
Divider,
LineChart,
Badge,
} from './components';

import { ThemeProvider, useTheme } from './styles/themes';
Expand Down Expand Up @@ -61,4 +62,5 @@ export {
Product,
Divider,
LineChart,
Badge
};
1 change: 1 addition & 0 deletions src/shared/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type WithTestID<Props> = Props & { testID?: string };

0 comments on commit c50bf2f

Please sign in to comment.