Skip to content

Commit

Permalink
✨ Add badge component
Browse files Browse the repository at this point in the history
  • Loading branch information
tuxtoby authored and Adrien Castagliola committed Dec 1, 2023
1 parent c805725 commit 836e369
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 0 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();
});
});
});
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,
};
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 836e369

Please sign in to comment.