Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/JUIP-101-creacion-componente-loa…
Browse files Browse the repository at this point in the history
…ding'
  • Loading branch information
christian97dd committed Aug 2, 2023
2 parents 6472c11 + c468503 commit c82eb87
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .ondevice/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ global.STORIES = [
directory: "./storybook/stories",
files: "**/*.stories.?(ts|tsx|js|jsx)",
importPathMatcher:
"^\\.[\\\\/](?:storybook[\\\\/]stories(?:[\\\\/](?!\\.)(?:(?:(?!(?:^|[\\\\/])\\.).)*?)[\\\\/]|[\\\\/]|$)(?!\\.)(?=.)[^\\\\/]*?\\.stories\\.(?:ts|tsx|js|jsx)?)$",
"^\\.[\\\\/](?:storybook\\/stories(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.(?:ts|tsx|js|jsx)?)$",
},
];

Expand Down Expand Up @@ -50,6 +50,7 @@ const getStories = () => {
"./storybook/stories/Avatar/Avatar.stories.js": require("../storybook/stories/Avatar/Avatar.stories.js"),
"./storybook/stories/CheckBox/CheckBox.stories.js": require("../storybook/stories/CheckBox/CheckBox.stories.js"),
"./storybook/stories/Image/Image.stories.js": require("../storybook/stories/Image/Image.stories.js"),
"./storybook/stories/Loading/Loading.stories.js": require("../storybook/stories/Loading/Loading.stories.js"),
"./storybook/stories/Text/Text.stories.js": require("../storybook/stories/Text/Text.stories.js"),
};
};
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added component Text
- Added slack notification on each release
- Added storybook web
- Added component Loading

### Changed

Expand Down
97 changes: 97 additions & 0 deletions src/components/Loading/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import {create} from 'react-test-renderer';
import {Animated, Text, View} from 'react-native';
import Loading from './';

jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
jest.spyOn(React, 'useEffect').mockImplementation((f) => f());

const validProps = {
color: 'red',
isLoading: true,
duration: 2000,
children: <Text>Valid Children</Text>,
};
const defaultProps = {
color: '#2979FF',
duration: 1000,
children: null,
};

describe('Loading component', () => {
describe('render correctly', () => {
it('when is loading is true', () => {
const {toJSON} = create(
<Loading
color={validProps.color}
isLoading={validProps.isLoading}
duration={validProps.duration}
children={validProps.children}
/>
);
expect(toJSON()).toBeTruthy();
});

it('children component when it exist', () => {
const {root} = create(
<Loading
color={validProps.color}
isLoading={validProps.isLoading}
duration={validProps.duration}
children={validProps.children}
/>
);
const TextComponent = root.findByType(Text);
const {children} = TextComponent.props;

expect(children).toBe('Valid Children');
});
});

describe('default value of', () => {
it('color when it is not exist', () => {
const {root} = create(
<Loading
isLoading={validProps.isLoading}
duration={validProps.duration}
children={validProps.children}
/>
);
const ViewComponent = root.findByType(Animated.View);
const {borderBottomColor, borderLeftColor, borderRightColor} = ViewComponent.props.style;

expect(borderBottomColor).toBe(defaultProps.color);
expect(borderLeftColor).toBe(defaultProps.color);
expect(borderRightColor).toBe(defaultProps.color);
});

it('duration when it is not exist', () => {
const {toJSON} = create(
<Loading isLoading={validProps.isLoading} children={validProps.children} />
);
expect(toJSON()).toBeTruthy();
});

it('children when it is not exist', () => {
const {root} = create(<Loading isLoading={validProps.isLoading} />);

const ViewComponent = root.findByType(View);
const [, ChildrenText] = ViewComponent.props.children;

expect(ChildrenText).toBeNull();
});
});
describe('returns null', () => {
it('when is loading is false', () => {
const {toJSON} = create(
<Loading
isLoading={false}
color={validProps.color}
duration={validProps.duration}
children={validProps.children}
/>
);
expect(toJSON()).not.toBeTruthy();
});
});
});
91 changes: 91 additions & 0 deletions src/components/Loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, {useEffect, useRef, FC} from 'react';
import {StyleSheet, View, Animated, Easing, ColorValue} from 'react-native';
import {primary, white} from '../../theme/palette';

interface Params {
duration: number;
rotationDegree: Animated.Value;
timingAnimation: (value: number) => number;
}
interface Props {
isLoading: boolean;
color?: ColorValue;
size?: number;
duration?: number;
children?: React.ReactNode | null;
}

const startRotationAnimation = ({duration, rotationDegree, timingAnimation}: Params): void =>
Animated.loop(
Animated.timing(rotationDegree, {
duration,
toValue: 360,
easing: timingAnimation,
useNativeDriver: true,
})
).start();

const Loading: FC<Props> = ({
isLoading,
color = primary.main,
size = 64,
duration = 1000,
children = null,
...props
}) => {
const rotationDegree = useRef(new Animated.Value(0)).current;

const styles = StyleSheet.create({
container: {
position: 'relative',
justifyContent: 'center',
alignItems: 'center',
width: size,
height: size,
},
spinner: {
position: 'absolute',
width: size,
height: size,
borderTopColor: white.dark,
borderLeftColor: color,
borderRightColor: color,
borderBottomColor: color,
borderRadius: size / 2,
borderWidth: 3.5,
},
});
const animationSpinnerStyle = {
transform: [
{
rotateZ: rotationDegree.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg'],
}),
},
],
};

useEffect(() => {
if (isLoading) {
startRotationAnimation({
duration,
rotationDegree,
timingAnimation: Easing.linear,
});
}
}, [isLoading, duration, rotationDegree]);

if (!isLoading) {
return <></>;
}

return (
<View style={styles.container} {...props}>
<Animated.View style={{...styles.spinner, ...animationSpinnerStyle}} />
{children}
</View>
);
};

export default Loading;
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ import Text from './components/Text';
import Avatar from './components/Avatar';
import CheckBox from './components/CheckBox';
import Image from './components/Image';
import Loading from './components/Loading';

export {Text, Avatar, CheckBox, Image};
export {Text, Avatar, CheckBox, Image, Loading};
24 changes: 24 additions & 0 deletions storybook/stories/Loading/Loading.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import {Text} from 'react-native';
import Loading from '../../../src/components/Loading/';

export default {
title: 'Loading',
argTypes: {
color: {
control: {type: 'color'},
},
},
};

export const DefaultProps = (props) => <Loading {...props} />;

DefaultProps.storyName = 'with text children';

DefaultProps.args = {
isLoading: true,
color: '#2979FF',
size: 64,
duration: 1000,
children: <Text>Loading</Text>,
};

0 comments on commit c82eb87

Please sign in to comment.