Skip to content

Commit

Permalink
merged juip-128 carousel component and solved conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
christian97dd committed Oct 25, 2023
2 parents 13b98b9 + 78eae85 commit 9b65d67
Show file tree
Hide file tree
Showing 11 changed files with 660 additions and 2 deletions.
1 change: 1 addition & 0 deletions .ondevice/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ try {
const getStories = () => {
return {
'./storybook/stories/Avatar/Avatar.stories.js': require('../storybook/stories/Avatar/Avatar.stories.js'),
'./storybook/stories/Carousel/Carousel.stories.js': require('../storybook/stories/Carousel/Carousel.stories.js'),
'./storybook/stories/CheckBox/CheckBox.stories.js': require('../storybook/stories/CheckBox/CheckBox.stories.js'),
'./storybook/stories/DesignStystem/Colors.stories.js': require('../storybook/stories/DesignStystem/Colors.stories.js'),
'./storybook/stories/DesignStystem/Icons.stories.js': require('../storybook/stories/DesignStystem/Icons.stories.js'),
Expand Down
66 changes: 66 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"prepare": "husky install",
"validate:code": "npm run lint -- --fix && tsc --noEmit && npm t",
"test:commit": "jest --colors --bail --findRelatedTests",
"test:coverage": "tsc --noEmit && jest --collectCoverage",
"test:coverage": "tsc --noEmit && jest --collectCoverage --detectOpenHandles",
"build": "rm -rf dist && tsc && cp -r android ios dist",
"storybook": "react-native-storybook-server",
"storybook-watcher": "sb-rn-watcher --config-path .ondevice",
Expand Down Expand Up @@ -61,6 +61,7 @@
"@storybook/react": "^6.5.4",
"@storybook/react-native": "^6.5.4",
"@storybook/react-native-server": "^6.5.4",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/react-native": "^7.2.0",
"@types/jest": "^25.2.3",
"@types/react": "^17.0.2",
Expand Down
1 change: 1 addition & 0 deletions setupTest/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ jest.mock('react', () => {
...react,
useState: jest.fn(react.useState),
useEffect: jest.fn(react.useEffect),
useRef: jest.fn(react.useRef),
};
});

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

const validPages = [<Text>Page1</Text>, <Text>Page2</Text>, <Text>Page3</Text>];
const validProps = {
pages: validPages,
isLoop: true,
autoplay: true,
intervalTime: 4000,
customWidth: 360,
callback: {},
};

const scrollTo = jest.fn();
const setActivePage = jest.fn();
const spyUseEffect = jest.spyOn(React, 'useEffect');
const spyUseState = jest.spyOn(React, 'useState');
const spyUseRef = jest.spyOn(React, 'useRef');

describe('Carousel component', () => {
it('it is rendered correctly', async () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const CarouselComp = create(<Carousel pages={validProps.pages} />).toJSON();
await expect(CarouselComp).toBeTruthy();
});

it('it returns null when page is not comming', async () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const CarouselComp = create(<Carousel pages={[]} />).toJSON();
await expect(CarouselComp).toBe(null);
});

describe('chage page when', () => {
it('scroll it', () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(<Carousel pages={validProps.pages} />);

const [ScrollComp] = root.findAllByType(ScrollView);
ScrollComp.props.onScroll({
nativeEvent: {contentOffset: {x: 360, layoutMeasurement: {width: 360}}},
});

expect(root).toBeTruthy();
});
});

describe('go preview page', () => {
it('using goPrev option on callback without isLoop', () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const CarouselComp = create(
<Carousel
pages={validProps.pages}
buttonsCallback={(params) => {
params.goPrev();
params.goPrev();
}}
/>
).toJSON();
expect(CarouselComp).toBeTruthy();
});

it('using goPrev option on callback with isLoop', () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(
<Carousel
pages={validProps.pages}
isLoop={validProps.isLoop}
buttonsCallback={(params) => {
params.goPrev();
params.goPrev();
}}
/>
);
expect(root).toBeTruthy();
});

it('using goPrev option on callback with isLoop & active page is not zero', () => {
spyUseState.mockReturnValueOnce([1, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(
<Carousel
pages={validProps.pages}
isLoop={validProps.isLoop}
buttonsCallback={(params) => {
params.goPrev();
params.goPrev();
}}
/>
);
expect(root).toBeTruthy();
});
});

describe('go next page', () => {
it('using goNext option on callback without isLoop & active page is not last page', () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(
<Carousel
pages={validProps.pages}
buttonsCallback={(params) => {
params.goNext();
}}
/>
);
expect(root).toBeTruthy();
});

it('using goNext option on callback with isLoop & active page is last page', () => {
spyUseState.mockReturnValueOnce([2, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(
<Carousel
pages={validProps.pages}
isLoop={validProps.isLoop}
buttonsCallback={(params) => {
params.goNext();
}}
/>
);
expect(root).toBeTruthy();
});

it('using goNext option on callback with isLoop & active page is not last page', () => {
spyUseState.mockReturnValueOnce([0, setActivePage]);
spyUseRef.mockReturnValueOnce({current: {scrollTo}});
spyUseEffect.mockImplementation((f) => f());

const {root} = create(
<Carousel
pages={validProps.pages}
isLoop={validProps.isLoop}
buttonsCallback={(params) => {
params.goNext();
}}
/>
);
expect(root).toBeTruthy();
});
});
});
74 changes: 74 additions & 0 deletions src/components/Carousel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, {FC} from 'react';
import {ScrollView, StyleSheet, View} from 'react-native';
import useCarouselControls from './utils';

export interface CarouselProps {
pages: React.ReactNode[];
isLoop?: boolean;
autoplay?: boolean;
autoPlayReverse?: boolean;
intervalTime?: number;
customWidth?: number;
buttonsCallback?: (params: {goPrev: () => void; goNext: () => void}) => void | null;
pagesCallback?: (params: {activePage: number; pagesLength: number}) => void | null;
}

const Carousel: FC<CarouselProps> = ({
pages,
isLoop = false,
autoplay = false,
autoPlayReverse = false,
intervalTime = 4000,
customWidth,
buttonsCallback,
pagesCallback,
...props
}) => {
if (!pages || !pages?.length) {
return null;
}

const carouselParams = {
pages,
isLoop,
autoplay,
autoPlayReverse,
intervalTime,
customWidth,
buttonsCallback,
pagesCallback,
};
// eslint-disable-next-line react-hooks/rules-of-hooks
const {slider, width, onPageChange} = useCarouselControls(carouselParams);

const styles = StyleSheet.create({
page: {
width,
alignItems: 'center',
},
});

return (
<View>
<ScrollView
ref={slider}
snapToInterval={width}
decelerationRate="fast"
pagingEnabled
onScroll={onPageChange}
scrollEventThrottle={16}
horizontal
showsHorizontalScrollIndicator={false}
{...props}>
{pages.length &&
pages.map((page, index) => (
<View key={`${index}`} style={styles.page}>
{page}
</View>
))}
</ScrollView>
</View>
);
};

export default Carousel;

0 comments on commit 9b65d67

Please sign in to comment.