diff --git a/src/components/Seasons/SeasonCard.tsx b/src/components/Seasons/SeasonCard.tsx index 5f918353a6fefc9efef3fdb84a8392966605d78c..576d61806c39fb22c75275cdd39e6be8cce86a7a 100644 --- a/src/components/Seasons/SeasonCard.tsx +++ b/src/components/Seasons/SeasonCard.tsx @@ -1,6 +1,6 @@ import React from 'react' import SeasonCardUnlocked from './SeasonCardUnlocked' - +import './_Seasons.scss' interface Season { saison: number name: string diff --git a/src/components/Seasons/SeasonCardLocked.tsx b/src/components/Seasons/SeasonCardLocked.tsx index b4ca33e5dc8174b787da674aea7794bbfebba78f..b0ab9d798a8d3746027160d47a34645a8dc35794 100644 --- a/src/components/Seasons/SeasonCardLocked.tsx +++ b/src/components/Seasons/SeasonCardLocked.tsx @@ -1,4 +1,5 @@ import React from 'react' +import './_Seasons.scss' const SeasonCardLocked: React.FC = () => { return <></> diff --git a/src/components/Seasons/SeasonCardOnGoing.tsx b/src/components/Seasons/SeasonCardOnGoing.tsx index 71f13f4d1a9d9058a0dbf1b516f84123fd7d989b..8f564d75025f14bc860be8efa9bac46dc70d2ffa 100644 --- a/src/components/Seasons/SeasonCardOnGoing.tsx +++ b/src/components/Seasons/SeasonCardOnGoing.tsx @@ -1,4 +1,5 @@ import React from 'react' +import './_Seasons.scss' const SeasonCardOnGoing: React.FC = () => { return <></> diff --git a/src/components/Seasons/SeasonCardUnlocked.tsx b/src/components/Seasons/SeasonCardUnlocked.tsx index 1b7e2ff5a05b4c0e6b9703dd8db44328aeb8d0ed..4a6f5ecd0419aac6a0e4fbeadda3a4de6d1c7d00 100644 --- a/src/components/Seasons/SeasonCardUnlocked.tsx +++ b/src/components/Seasons/SeasonCardUnlocked.tsx @@ -1,4 +1,5 @@ import React from 'react' +import './_Seasons.scss' interface Season { saison: number diff --git a/src/components/Seasons/SeasonView.spec.tsx b/src/components/Seasons/SeasonView.spec.tsx new file mode 100644 index 0000000000000000000000000000000000000000..30ce0e6e3654336700ccc87b8a891819f3b0c906 --- /dev/null +++ b/src/components/Seasons/SeasonView.spec.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { shallow } from 'enzyme' +import SeasonView from 'components/Seasons/SeasonView' + +const mockaHandleTouchStart = jest.fn() +const mockaHandleTouchMove = jest.fn() +const mockaHandleTouchEnd = jest.fn() + +describe('SeasonView component', () => { + it('should be rendered correctly', () => { + const component = shallow(<SeasonView />).getElement() + expect(component).toMatchSnapshot() + }) + it('should detect user swipe on slider', () => { + const wrapper = shallow(<SeasonView />) + // TODO how to simulate Touch event in jest + wrapper.find('.seasonSlider').simulate('touchStart', { + targetTouches: [ + { + clientX: 50, + }, + ], + }) + mockaHandleTouchStart.mockReturnValueOnce({ nativeEvent: '' }) + + expect(mockaHandleTouchStart).toBeCalledTimes(1) + }) +}) diff --git a/src/components/Seasons/SeasonView.tsx b/src/components/Seasons/SeasonView.tsx index 8c66ce98fabb0b5dabf93a0d870d97237b550d92..3f9a09914b09dd544a80a586c062944851c1ae3a 100644 --- a/src/components/Seasons/SeasonView.tsx +++ b/src/components/Seasons/SeasonView.tsx @@ -1,17 +1,23 @@ -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import SeasonCard from './SeasonCard' import CozyBar from 'components/Header/CozyBar' import Content from 'components/Content/Content' import Header from 'components/Header/Header' -const SeasonView: React.FC = () => { - const [headerHeight, setHeaderHeight] = useState<number>(0) - const [touchStart, setTouchStart] = React.useState(0) - const [touchEnd, setTouchEnd] = React.useState(0) - const [index, setindex] = useState(0) - const [containerTranslation, setcontainerTranslation] = useState<any>(0) +import StyledIconbutton from 'components/CommonKit/IconButton/StyledIconButton' +import LeftArrowIcon from 'assets/icons/ico/left-arrow.svg' +import RightArrowIcon from 'assets/icons/ico/right-arrow.svg' +import './_Seasons.scss' +const SeasonView: React.FC = () => { const cardWitdh = 285 const marginPx = 16 + const [headerHeight, setHeaderHeight] = useState<number>(0) + const [touchStart, setTouchStart] = useState<number>() + const [touchEnd, setTouchEnd] = useState<number>() + const [index, setindex] = useState<number>(0) + const [containerTranslation, setcontainerTranslation] = useState<number>( + marginPx + ) const defineHeaderHeight = (height: number) => { setHeaderHeight(height) @@ -29,10 +35,19 @@ const SeasonView: React.FC = () => { { saison: 4, name: 'saison4' }, { saison: 5, name: 'saison5' }, ]) + const resetValues = () => { + //Method used to cancel a swipe on a simple click + setTouchEnd(0) + setTouchStart(0) + } const moveSliderRight = () => { if (index < seasonList.length - 1) { - if (index >= 1) + if (index === 0) + setcontainerTranslation( + (prev: number) => prev - cardWitdh - marginPx * 1.2 + ) + else if (index >= 1) setcontainerTranslation((prev: number) => prev - cardWitdh - marginPx) else setcontainerTranslation((prev: number) => prev - cardWitdh) setindex(prev => prev + 1) @@ -46,27 +61,36 @@ const SeasonView: React.FC = () => { setindex(prev => prev - 1) } if (index <= 1) { - setcontainerTranslation(0) + setcontainerTranslation(marginPx) } } - const handleTouchStart = (e: React.TouchEvent) => { - setTouchStart(e.targetTouches[0].clientX) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const handleClickOrTouchStart = (e: any) => { + if (e.nativeEvent instanceof TouchEvent) + setTouchStart(e.targetTouches[0].clientX) + if (e.nativeEvent instanceof MouseEvent) setTouchStart(e.clientX) } - const handleTouchEnd = () => { - //Change the following value in order to change the swipe sensibilyy - if (touchStart - touchEnd > 75) { - //If swipe left move slider right and add positive translation - moveSliderRight() - } - if (touchStart - touchEnd < -75) { - //If swipe right move slider left and add negative translation - moveSliderLeft() + const handleClickOrTouchEnd = () => { + //if the swipe is too small and can be taken for a touch + if (touchStart && touchEnd) { + if (touchStart - touchEnd < 5 && -5 < touchStart - touchEnd) return + //Change the following value in order to change the swipe sensibilyy + if (touchStart - touchEnd > 75) { + //If swipe left move slider right and add positive translation + moveSliderRight() + } + if (touchStart - touchEnd < -75) { + //If swipe right move slider left and add negative translation + moveSliderLeft() + } } } - - const handleTouchMove = (e: React.TouchEvent) => { - setTouchEnd(e.targetTouches[0].clientX) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const handleClickOrTouchMove = (e: any) => { + if (e.nativeEvent instanceof TouchEvent) + setTouchEnd(e.targetTouches[0].clientX) + if (e.nativeEvent instanceof MouseEvent) setTouchEnd(e.clientX) } return ( @@ -79,19 +103,37 @@ const SeasonView: React.FC = () => { <Content height={headerHeight}> <div className="seasonSlider" - onTouchStart={handleTouchStart} - onTouchMove={handleTouchMove} - onTouchEnd={handleTouchEnd} + onClick={resetValues} + onTouchStart={handleClickOrTouchStart} + onTouchMove={handleClickOrTouchMove} + onTouchEnd={handleClickOrTouchEnd} + onMouseDown={handleClickOrTouchStart} + onMouseMove={handleClickOrTouchMove} + onMouseUp={handleClickOrTouchEnd} > <div className="container" - style={{ transform: `translateX(${containerTranslation}px)` }} + style={{ + transform: `translateX(${containerTranslation}px)`, + }} > {seasonList.map(season => ( <SeasonCard key={season.saison} season={season} index={index} /> ))} </div> </div> + <div className="sliderButtons"> + <StyledIconbutton + onClick={moveSliderLeft} + icon={LeftArrowIcon} + size={16} + /> + <StyledIconbutton + onClick={moveSliderRight} + icon={RightArrowIcon} + size={16} + /> + </div> </Content> </> ) diff --git a/src/styles/components/_seasons.scss b/src/components/Seasons/_Seasons.scss similarity index 77% rename from src/styles/components/_seasons.scss rename to src/components/Seasons/_Seasons.scss index fa6f6bc7c5ed66ad26885d7ed66e961fe8be6a38..c888e246ff166331b3bfbb808e80a875577225ed 100644 --- a/src/styles/components/_seasons.scss +++ b/src/components/Seasons/_Seasons.scss @@ -1,9 +1,19 @@ +@import '../../styles/base/typography'; + .seasonSlider { min-height: inherit; margin-top: -2rem; overflow-x: hidden; padding: 2rem; position: relative; + max-width: 850px; + user-select: none; + @media all and (min-width: $width-tablet) { + margin: auto; + margin-top: 2rem; + min-height: 0; + } + .container { min-height: inherit; width: 100%; @@ -49,3 +59,11 @@ } } } +.sliderButtons { + text-align: center; + margin: auto; + margin-top: 1.5rem; + @media all and (max-width: $width-tablet) { + display: none; + } +} diff --git a/src/components/Seasons/__snapshots__/SeasonView.spec.tsx.snap b/src/components/Seasons/__snapshots__/SeasonView.spec.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..3cc771eb9e56f251dadd77096ad8acdbb09e87ec --- /dev/null +++ b/src/components/Seasons/__snapshots__/SeasonView.spec.tsx.snap @@ -0,0 +1,104 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SeasonView component should be rendered correctly 1`] = ` +<React.Fragment> + <CozyBar + titleKey="COMMON.APP_OPTIONS_TITLE" + /> + <Header + desktopTitleKey="COMMON.APP_OPTIONS_TITLE" + setHeaderHeight={[Function]} + /> + <Content + height={0} + > + <div + className="seasonSlider" + onMouseDown={[Function]} + onMouseMove={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} + > + <div + className="container" + style={ + Object { + "transform": "translateX(16px)", + } + } + > + <SeasonCard + index={0} + season={ + Object { + "name": "saison0", + "saison": 0, + } + } + /> + <SeasonCard + index={0} + season={ + Object { + "name": "saison1", + "saison": 1, + } + } + /> + <SeasonCard + index={0} + season={ + Object { + "name": "saison2", + "saison": 2, + } + } + /> + <SeasonCard + index={0} + season={ + Object { + "name": "saison3", + "saison": 3, + } + } + /> + <SeasonCard + index={0} + season={ + Object { + "name": "saison4", + "saison": 4, + } + } + /> + <SeasonCard + index={0} + season={ + Object { + "name": "saison5", + "saison": 5, + } + } + /> + </div> + </div> + <div + className="sliderButtons" + > + <StyledIconButton + icon="test-file-stub" + onClick={[Function]} + size={16} + /> + <StyledIconButton + icon="test-file-stub" + onClick={[Function]} + size={16} + /> + </div> + </Content> +</React.Fragment> +`; diff --git a/src/styles/index.scss b/src/styles/index.scss index 06daec7f0665ff62467335eb0e3fc111db8472e7..adfc221e369b29010fb46791a4d60a018c731962 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -23,7 +23,6 @@ @import 'components/faq'; @import 'components/legalnotice'; @import 'components/splash'; -@import 'components/seasons'; @import 'components/auth'; @import 'components/feedback'; @import 'components/version';