From 9b6b757f6516a8c1d7e4994da2110c5aa412df18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marl=C3=A8ne=20SIMONDANT?= <msimondant@grandlyon.com> Date: Thu, 7 Jul 2022 09:09:43 +0000 Subject: [PATCH] feat : add management of the end of all available challenges (modal + card) --- src/assets/icons/visu/challenge/ecolyo.svg | 6 +++ src/assets/icons/visu/duel/star.svg | 9 ++++ src/components/Challenge/ChallengeCard.tsx | 12 +++-- .../Challenge/ChallengeCardLast.spec.tsx | 34 +++++++++++++ .../Challenge/ChallengeCardLast.tsx | 49 ++++++++++++++++++ .../Challenge/ChallengeCardOnGoing.tsx | 2 +- src/components/Challenge/ChallengeView.tsx | 32 +++++++++++- .../ChallengeCardLast.spec.tsx.snap | 3 ++ .../__snapshots__/ChallengeView.spec.tsx.snap | 6 +++ .../Challenge/challengeCardLast.scss | 41 +++++++++++++++ src/components/Duel/DuelOngoing.tsx | 30 +++++++++-- src/components/Duel/DuelView.spec.tsx | 24 ++++++++- src/components/Duel/DuelView.tsx | 18 +++++-- .../__snapshots__/lastDuelModal.spec.tsx.snap | 3 ++ src/components/Duel/lastDuelModal.scss | 29 +++++++++++ src/components/Duel/lastDuelModal.spec.tsx | 27 ++++++++++ src/components/Duel/lastDuelModal.tsx | 51 +++++++++++++++++++ src/locales/fr.json | 12 +++++ src/styles/components/_dialog.scss | 3 ++ 19 files changed, 374 insertions(+), 17 deletions(-) create mode 100644 src/assets/icons/visu/challenge/ecolyo.svg create mode 100644 src/assets/icons/visu/duel/star.svg create mode 100644 src/components/Challenge/ChallengeCardLast.spec.tsx create mode 100644 src/components/Challenge/ChallengeCardLast.tsx create mode 100644 src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap create mode 100644 src/components/Challenge/challengeCardLast.scss create mode 100644 src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap create mode 100644 src/components/Duel/lastDuelModal.scss create mode 100644 src/components/Duel/lastDuelModal.spec.tsx create mode 100644 src/components/Duel/lastDuelModal.tsx diff --git a/src/assets/icons/visu/challenge/ecolyo.svg b/src/assets/icons/visu/challenge/ecolyo.svg new file mode 100644 index 000000000..504f722c6 --- /dev/null +++ b/src/assets/icons/visu/challenge/ecolyo.svg @@ -0,0 +1,6 @@ +<svg width="62" height="62" viewBox="0 0 62 62" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M30.9999 58.3539C57.4593 48.0072 55.4028 33.2974 54.0319 11.3573C45.532 10.9834 37.9918 8.36552 30.9999 4.00244C24.0081 8.36552 16.4679 10.9834 7.96801 11.3573C6.59706 33.2974 4.54064 48.0072 30.9999 58.3539Z" fill="#1B1C22"/> +<path d="M31 0L29.2075 1.11858C22.6524 5.20911 15.6717 7.61771 7.81931 7.96319L4.77457 8.09716L4.58414 11.1446C4.52759 12.0496 4.46881 12.95 4.41037 13.8451C3.78152 23.4778 3.1917 32.5124 5.83816 40.2978C8.88926 49.2736 15.9673 56.1216 29.7672 61.5179L31 62V58.3535C5.57809 48.4124 6.4797 34.4437 7.80541 13.9043C7.85951 13.0662 7.91431 12.2171 7.96806 11.3569C16.4679 10.9829 24.0082 8.36507 31 4.00199V0Z" fill="#FFC600"/> +<path d="M31 0L32.7925 1.11858C39.3476 5.20911 46.3283 7.61771 54.1807 7.96319L57.2254 8.09716L57.4159 11.1446C57.4724 12.0496 57.5312 12.95 57.5896 13.8451C58.2185 23.4778 58.8083 32.5124 56.1618 40.2978C53.1107 49.2736 46.0327 56.1216 32.2328 61.5179L31 62V58.3535C56.4219 48.4124 55.5203 34.4437 54.1946 13.9043C54.1405 13.0662 54.0857 12.2171 54.0319 11.3569C45.5321 10.9829 37.9918 8.36507 31 4.00199V0Z" fill="#DB8300"/> +<path d="M22.639 21.3672H23.8419C24.3222 21.3672 24.783 21.5561 25.1226 21.8925C25.4623 22.2289 25.6532 22.6851 25.6532 23.1608V41.3684H20.8277V23.1608C20.8277 22.6851 21.0185 22.2289 21.3582 21.8925C21.6979 21.5561 22.1586 21.3672 22.639 21.3672ZM30.9965 30.2331H32.1993C32.6797 30.2331 33.1404 30.4221 33.4801 30.7585C33.8198 31.0948 34.0107 31.5511 34.0107 32.0268V41.3684H29.1852V32.0268C29.1852 31.5511 29.376 31.0948 29.7157 30.7585C30.0554 30.4221 30.5161 30.2331 30.9965 30.2331ZM39.8521 26.8035H41.055C41.5353 26.8035 41.9961 26.9925 42.3358 27.3288C42.6754 27.6652 42.8663 28.1214 42.8663 28.5971V41.3684H38.0408V28.5971C38.0408 28.1214 38.2316 27.6652 38.5713 27.3288C38.911 26.9925 39.3717 26.8035 39.8521 26.8035Z" fill="#FFC600"/> +</svg> diff --git a/src/assets/icons/visu/duel/star.svg b/src/assets/icons/visu/duel/star.svg new file mode 100644 index 000000000..59414adf1 --- /dev/null +++ b/src/assets/icons/visu/duel/star.svg @@ -0,0 +1,9 @@ +<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M46.4486 17.7627L32.0591 15.7204L25.6267 2.98519C25.451 2.6365 25.1619 2.35424 24.8049 2.18266C23.9094 1.75096 22.8213 2.11071 22.3736 2.98519L15.9411 15.7204L1.55164 17.7627C1.15492 17.818 0.792211 18.0007 0.514509 18.2774C0.178784 18.6144 -0.00621659 19.0678 0.000159514 19.5379C0.00653562 20.008 0.203766 20.4564 0.548513 20.7846L10.9595 30.6972L8.49984 44.6943C8.44216 45.0199 8.47906 45.3548 8.60634 45.6609C8.73363 45.9671 8.94621 46.2323 9.21999 46.4265C9.49376 46.6207 9.81777 46.7361 10.1553 46.7596C10.4928 46.7831 10.8303 46.7137 11.1295 46.5595L24.0001 39.9511L36.8707 46.5595C37.2221 46.7421 37.6302 46.803 38.0212 46.7366C39.0073 46.5705 39.6704 45.6573 39.5004 44.6943L37.0407 30.6972L47.4517 20.7846C47.7351 20.5134 47.9221 20.1592 47.9788 19.7718C48.1318 18.8032 47.4404 17.9066 46.4486 17.7627Z" fill="url(#paint0_linear_12656_82845)"/> +<defs> +<linearGradient id="paint0_linear_12656_82845" x1="23.175" y1="2" x2="23.175" y2="46.764" gradientUnits="userSpaceOnUse"> +<stop stop-color="#61F0F2"/> +<stop offset="1" stop-color="#48C2C4"/> +</linearGradient> +</defs> +</svg> diff --git a/src/components/Challenge/ChallengeCard.tsx b/src/components/Challenge/ChallengeCard.tsx index 852f3395f..6336cc75b 100644 --- a/src/components/Challenge/ChallengeCard.tsx +++ b/src/components/Challenge/ChallengeCard.tsx @@ -6,13 +6,15 @@ import ChallengeCardLocked from './ChallengeCardLocked' import ChallengeCardOnGoing from './ChallengeCardOnGoing' import ChallengeCardUnlocked from './ChallengeCardUnlocked' import './challengeCard.scss' +import ChallengeCardLast from './ChallengeCardLast' interface ChallengeCardProps { - userChallenge: UserChallenge + userChallenge?: UserChallenge indexSlider: number index: number cardWidth: number cardHeight: number + isChallengeCardLast: boolean moveToSlide: (slideIndex: number) => void } @@ -22,10 +24,12 @@ const ChallengeCard: React.FC<ChallengeCardProps> = ({ index, cardWidth, cardHeight, + isChallengeCardLast, moveToSlide, }: ChallengeCardProps) => { - const renderCard = (state: UserChallengeState) => { - switch (state) { + const renderCard = (userChallenge: UserChallenge | undefined) => { + if (!userChallenge || isChallengeCardLast) return <ChallengeCardLast /> + switch (userChallenge.state) { case UserChallengeState.LOCKED: return <ChallengeCardLocked userChallenge={userChallenge} /> case UserChallengeState.UNLOCKED: @@ -50,7 +54,7 @@ const ChallengeCard: React.FC<ChallengeCardProps> = ({ height: `${cardHeight}px`, }} > - {renderCard(userChallenge.state)} + {renderCard(userChallenge)} </div> ) } diff --git a/src/components/Challenge/ChallengeCardLast.spec.tsx b/src/components/Challenge/ChallengeCardLast.spec.tsx new file mode 100644 index 000000000..68b0c6814 --- /dev/null +++ b/src/components/Challenge/ChallengeCardLast.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import { mount } from 'enzyme' +import ChallengeCardLast from './ChallengeCardLast' +import { Provider } from 'react-redux' +import configureStore from 'redux-mock-store' +import { globalStateData } from '../../../tests/__mocks__/globalStateData.mock' + +jest.mock('cozy-ui/transpiled/react/I18n', () => { + return { + useI18n: jest.fn(() => { + return { + t: (str: string) => str, + } + }), + } +}) + +const mockStore = configureStore([]) + +describe('ChallengeCardLast component', () => { + it('should be rendered correctly', () => { + const store = mockStore({ + ecolyo: { + global: globalStateData, + }, + }) + const wrapper = mount( + <Provider store={store}> + <ChallengeCardLast /> + </Provider> + ) + expect(wrapper).toMatchSnapshot() + }) +}) diff --git a/src/components/Challenge/ChallengeCardLast.tsx b/src/components/Challenge/ChallengeCardLast.tsx new file mode 100644 index 000000000..345753b96 --- /dev/null +++ b/src/components/Challenge/ChallengeCardLast.tsx @@ -0,0 +1,49 @@ +import React from 'react' +import './challengeCardLast.scss' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import ecolyoIcon from 'assets/icons/visu/challenge/ecolyo.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' +import { Button } from '@material-ui/core' +import { updateModalIsFeedbacksOpen } from 'store/modal/modal.actions' +import { useDispatch } from 'react-redux' + +interface ChallengeCardLastProps {} + +const ChallengeCardLast: React.FC = () => { + const { t } = useI18n() + const dispatch = useDispatch() + + const handleClickFeedbacks = (): void => { + dispatch(updateModalIsFeedbacksOpen(true)) + } + + return ( + <div className="cardLast"> + <StyledIcon icon={ecolyoIcon} size={62} /> + <div className="content"> + <div className="text-22-bold title-last"> + {t('challenge.card_last.title')} + </div> + <div className="text-18-normal message"> + {t('challenge.card_last.message1')} + </div> + <div className="text-18-normal message"> + {t('challenge.card_last.message2')} + </div> + </div> + <Button + aria-label={t('challenge.card_last.button')} + onClick={handleClickFeedbacks} + className="btn1" + classes={{ + root: 'btn-secondary-negative btn_lastCard', + label: 'text-15-bold', + }} + > + {t('challenge.card_last.button')} + </Button> + </div> + ) +} + +export default ChallengeCardLast diff --git a/src/components/Challenge/ChallengeCardOnGoing.tsx b/src/components/Challenge/ChallengeCardOnGoing.tsx index e1d7fc859..25388104f 100644 --- a/src/components/Challenge/ChallengeCardOnGoing.tsx +++ b/src/components/Challenge/ChallengeCardOnGoing.tsx @@ -65,7 +65,7 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({ dispatch(updateUserChallengeList(updatedChallenge)) } setIsLoading(false) - history.push('/challenges/duel') + history.push('/challenges/duel?id=' + userChallenge.id) } else { setIsLoading(false) toggleNoFluidModal() diff --git a/src/components/Challenge/ChallengeView.tsx b/src/components/Challenge/ChallengeView.tsx index 585f18b1b..aaa1b27e4 100644 --- a/src/components/Challenge/ChallengeView.tsx +++ b/src/components/Challenge/ChallengeView.tsx @@ -31,6 +31,7 @@ const ChallengeView: React.FC = () => { const [touchEnd, setTouchEnd] = useState<number>() const [index, setindex] = useState<number>(0) const [lastChallengeIndex, setlastChallengeIndex] = useState<number>(0) + const [isLastDuelDone, setIsLastDuelDone] = useState<boolean>(false) const [containerTranslation, setcontainerTranslation] = useState<number>(marginPx) const defineHeaderHeight = (height: number) => { @@ -44,7 +45,10 @@ const ChallengeView: React.FC = () => { } const moveSliderRight = useCallback(() => { - if (index < userChallengeList.length - 1) { + if ( + index < userChallengeList.length - 1 || + (isLastDuelDone && index < userChallengeList.length) + ) { if (index === 0) setcontainerTranslation( (prev: number) => prev - cardWitdh - marginPx * 1.2 @@ -123,10 +127,22 @@ const ChallengeView: React.FC = () => { 0 - cardWitdh * lastChallengeIndex - marginPx * 1.2 ) } + if (isLastDuelDone) { + setlastChallengeIndex(i + 1) + } setindex(i) } }) - }, [userChallengeList, lastChallengeIndex, cardWitdh]) + }, [userChallengeList, lastChallengeIndex, cardWitdh, isLastDuelDone]) + + useEffect(() => { + if ( + userChallengeList[userChallengeList.length - 1].state == + UserChallengeState.DONE + ) { + setIsLastDuelDone(true) + } + }, [userChallengeList]) return ( <> @@ -160,9 +176,21 @@ const ChallengeView: React.FC = () => { index={i} cardWidth={cardWitdh} cardHeight={cardHeight} + isChallengeCardLast={false} moveToSlide={moveToSlide} /> ))} + + {isLastDuelDone && ( + <ChallengeCard + indexSlider={index} + index={5} + cardWidth={cardWitdh} + cardHeight={cardHeight} + isChallengeCardLast={true} + moveToSlide={moveToSlide} + /> + )} </div> </div> <div className="sliderButtons"> diff --git a/src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap b/src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap new file mode 100644 index 000000000..efa516743 --- /dev/null +++ b/src/components/Challenge/__snapshots__/ChallengeCardLast.spec.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChallengeCardLast component should be rendered correctly 1`] = `ReactWrapper {}`; diff --git a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap index 2aeb64067..80f37a2cb 100644 --- a/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap +++ b/src/components/Challenge/__snapshots__/ChallengeView.spec.tsx.snap @@ -47,6 +47,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={0} indexSlider={3} + isChallengeCardLast={false} key="0" moveToSlide={[Function]} userChallenge={ @@ -198,6 +199,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={1} indexSlider={3} + isChallengeCardLast={false} key="1" moveToSlide={[Function]} userChallenge={ @@ -349,6 +351,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={2} indexSlider={3} + isChallengeCardLast={false} key="2" moveToSlide={[Function]} userChallenge={ @@ -500,6 +503,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={3} indexSlider={3} + isChallengeCardLast={false} key="3" moveToSlide={[Function]} userChallenge={ @@ -651,6 +655,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={4} indexSlider={3} + isChallengeCardLast={false} key="4" moveToSlide={[Function]} userChallenge={ @@ -802,6 +807,7 @@ exports[`ChallengeView component should be rendered correctly 1`] = ` cardWidth={285} index={5} indexSlider={3} + isChallengeCardLast={false} key="5" moveToSlide={[Function]} userChallenge={ diff --git a/src/components/Challenge/challengeCardLast.scss b/src/components/Challenge/challengeCardLast.scss new file mode 100644 index 000000000..a33b5213e --- /dev/null +++ b/src/components/Challenge/challengeCardLast.scss @@ -0,0 +1,41 @@ +@import '../../styles/base/typo-variables'; +@import '../../styles/base/color'; + +.cardLast { + width: 100%; + height: inherit; + box-sizing: border-box; + padding: 5%; + transition: all 300ms ease; + border: 1px solid $grey-bright; + border-radius: 4px; + align-items: center; + text-align: center; + display: flex; + flex-direction: column; + .content { + max-height: 350px; + flex-direction: column; + display: flex; + } + svg { + max-height: 150px; + } + .title-last { + padding: 1rem 2.3rem 1.5rem; + } + .message { + margin: 0 0 0.7rem; + } + .btn_lastCard { + padding: 8px; + max-height: 33px; + } + .content, + .title-last, + .message, + .btn_lastCard, + svg { + flex: 1; + } +} diff --git a/src/components/Duel/DuelOngoing.tsx b/src/components/Duel/DuelOngoing.tsx index 9dd80796d..892af50ca 100644 --- a/src/components/Duel/DuelOngoing.tsx +++ b/src/components/Duel/DuelOngoing.tsx @@ -21,8 +21,10 @@ import CaptionIncomingIcon from 'assets/icons/visu/duel/captionIncoming.svg' import ChallengeService from 'services/challenge.service' import DuelChart from 'components/Duel/DuelChart' import DuelResultModal from 'components/Duel/DuelResultModal' +import LastDuelModal from 'components/Duel/lastDuelModal' import UsageEventService from 'services/usageEvent.service' import { UsageEventType } from 'enum/usageEvent.enum' +import { UserDuelState } from 'enum/userDuel.enum' interface DuelOngoingProps { userChallenge: UserChallenge @@ -40,9 +42,13 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ const history = useHistory() const [resultModal, setResultModal] = useState<boolean>(false) const [winChallenge, setWinChallenge] = useState<boolean>(false) + const [isLastDuel, setIsLastDuel] = useState<boolean>(false) const [width, setWidth] = useState<number>(0) const [height, setHeight] = useState<number>(0) const chartContainer = useRef<HTMLDivElement>(null) + const { userChallengeList } = useSelector( + (state: AppStore) => state.ecolyo.challenge + ) const duel: UserDuel = userChallenge.duel const title: string = duel.title @@ -78,8 +84,25 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ dispatch(unlockNextUserChallenge(updatedChallenge)) dispatch(toggleChallengeDuelNotification(false)) + if ( + userChallenge.id == userChallengeList[userChallengeList.length - 1].id + ) { + setIsLastDuel(true) + } else { + history.push('/challenges') + } + }, [ + client, + userChallenge, + winChallenge, + dispatch, + userChallengeList, + history, + ]) + + const setLastResult = useCallback(async () => { history.push('/challenges') - }, [client, dispatch, userChallenge, history, winChallenge]) + }, [history]) useEffect(() => { function handleResize() { @@ -129,13 +152,13 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ <div className="duel-goal text-18-normal"> {t('duel.goal1', { durationInDays, - // eslint-disable-next-line @typescript-eslint/camelcase + smart_count: durationInDays, })} <span> </span> {t('duel.goal2', { title, - // eslint-disable-next-line @typescript-eslint/camelcase + smart_count: title, })} </div> @@ -183,6 +206,7 @@ const DuelOngoing: React.FC<DuelOngoingProps> = ({ win={winChallenge} handleCloseClick={setResult} /> + <LastDuelModal open={isLastDuel} handleCloseClick={setLastResult} /> </> ) } diff --git a/src/components/Duel/DuelView.spec.tsx b/src/components/Duel/DuelView.spec.tsx index f1fa4c7f1..da088b854 100644 --- a/src/components/Duel/DuelView.spec.tsx +++ b/src/components/Duel/DuelView.spec.tsx @@ -16,6 +16,16 @@ jest.mock('components/Content/Content', () => 'mock-content') const mockUseSelector = jest.spyOn(reactRedux, 'useSelector') +const mockHistoryGoBack = jest.fn() +jest.mock('react-router-dom', () => ({ + useLocation: () => ({ + search: '?id=CHALLENGE0002', + }), + useHistory: () => ({ + goBack: mockHistoryGoBack, + }), +})) + describe('DuelView component', () => { it('should be rendered with DuelError component when no current challenge', () => { mockUseSelector.mockReturnValue(challengeStateData) @@ -23,7 +33,7 @@ describe('DuelView component', () => { expect(wrapper.find(DuelError).exists()).toBeTruthy() }) - it('should be rendered with DuelError component when current challenge with state = duel and duel state = done', () => { + it('should be rendered with DuelOngoing component when current challenge with state = duel and duel state = done', () => { const updatedUserChallenge = { ...userChallengeData[1], state: UserChallengeState.DUEL, @@ -31,11 +41,13 @@ describe('DuelView component', () => { } const updatedChallengeState = { ...challengeStateData, + userChallengeList: userChallengeData, currentChallenge: updatedUserChallenge, } + updatedChallengeState.userChallengeList[1] = updatedUserChallenge mockUseSelector.mockReturnValue(updatedChallengeState) const wrapper = shallow(<DuelView />) - expect(wrapper.find(DuelError).exists()).toBeTruthy() + expect(wrapper.find(DuelOngoing).exists()).toBeTruthy() }) it('should be rendered with DuelError component when current challenge with state = duel and duel state = locked', () => { @@ -46,8 +58,10 @@ describe('DuelView component', () => { } const updatedChallengeState = { ...challengeStateData, + userChallengeList: userChallengeData, currentChallenge: updatedUserChallenge, } + updatedChallengeState.userChallengeList[1] = updatedUserChallenge mockUseSelector.mockReturnValue(updatedChallengeState) const wrapper = shallow(<DuelView />) expect(wrapper.find(DuelError).exists()).toBeTruthy() @@ -60,8 +74,10 @@ describe('DuelView component', () => { } const updatedChallengeState = { ...challengeStateData, + userChallengeList: userChallengeData, currentChallenge: updatedUserChallenge, } + updatedChallengeState.userChallengeList[1] = updatedUserChallenge mockUseSelector.mockReturnValue(updatedChallengeState) const wrapper = shallow(<DuelView />) expect(wrapper.find(DuelError).exists()).toBeTruthy() @@ -75,8 +91,10 @@ describe('DuelView component', () => { } const updatedChallengeState = { ...challengeStateData, + userChallengeList: userChallengeData, currentChallenge: updatedUserChallenge, } + updatedChallengeState.userChallengeList[1] = updatedUserChallenge mockUseSelector.mockReturnValue(updatedChallengeState) const wrapper = shallow(<DuelView />) expect(wrapper.find(DuelUnlocked).exists()).toBeTruthy() @@ -90,8 +108,10 @@ describe('DuelView component', () => { } const updatedChallengeState = { ...challengeStateData, + userChallengeList: userChallengeData, currentChallenge: updatedUserChallenge, } + updatedChallengeState.userChallengeList[1] = updatedUserChallenge mockUseSelector.mockReturnValue(updatedChallengeState) const wrapper = shallow(<DuelView />) expect(wrapper.find(DuelOngoing).exists()).toBeTruthy() diff --git a/src/components/Duel/DuelView.tsx b/src/components/Duel/DuelView.tsx index 006f90215..f5c410ca8 100644 --- a/src/components/Duel/DuelView.tsx +++ b/src/components/Duel/DuelView.tsx @@ -12,13 +12,18 @@ import { UserDuelState } from 'enum/userDuel.enum' import { UserChallenge } from 'models' import DuelOngoing from './DuelOngoing' import DuelEmptyValueModal from './DuelEmptyValueModal' -import { useHistory } from 'react-router-dom' +import { useHistory, useLocation } from 'react-router-dom' const DuelView: React.FC = () => { const [headerHeight, setHeaderHeight] = useState<number>(0) - const { currentChallenge } = useSelector( + const { userChallengeList } = useSelector( (state: AppStore) => state.ecolyo.challenge ) + const id = new URLSearchParams(useLocation().search).get('id') + const challengeToDisplay: UserChallenge | undefined = userChallengeList.find( + challenge => challenge.id === id + ) + const history = useHistory() const defineHeaderHeight = useCallback((height: number) => { setHeaderHeight(height) @@ -32,6 +37,8 @@ const DuelView: React.FC = () => { return <DuelUnlocked userChallenge={challenge} /> case UserDuelState.ONGOING: return <DuelOngoing userChallenge={challenge} /> + case UserDuelState.DONE: + return <DuelOngoing userChallenge={challenge} /> case UserDuelState.NO_REF_PERIOD_VALID: return ( <DuelEmptyValueModal @@ -58,9 +65,10 @@ const DuelView: React.FC = () => { ></Header> <Content height={headerHeight}> <div> - {currentChallenge && - currentChallenge.state === UserChallengeState.DUEL ? ( - renderDuel(currentChallenge) + {challengeToDisplay && + (challengeToDisplay.state === UserChallengeState.DUEL || + challengeToDisplay.state === UserChallengeState.DONE) ? ( + renderDuel(challengeToDisplay) ) : ( <DuelError /> )} diff --git a/src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap b/src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap new file mode 100644 index 000000000..2b0bc89e8 --- /dev/null +++ b/src/components/Duel/__snapshots__/lastDuelModal.spec.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lastDuelModal component should render correctly 1`] = `ReactWrapper {}`; diff --git a/src/components/Duel/lastDuelModal.scss b/src/components/Duel/lastDuelModal.scss new file mode 100644 index 000000000..16e4bafe7 --- /dev/null +++ b/src/components/Duel/lastDuelModal.scss @@ -0,0 +1,29 @@ +@import '../../styles/base/color'; + +.duel-last-modal-root { + text-align: center; + .closeIcon { + float: right; + cursor: pointer; + } + .icon { + margin: 2rem 0 0; + } + .title { + margin: 1rem 0 1rem; + } + .subtitle { + color: $blue-light; + margin: 1rem 0 0.5rem; + } + .content { + margin: 0.5rem 0; + } + button.btn-secondary-negative { + margin: 2rem 0.25rem 0.5rem; + } +} + +#accessibility-title { + display: none; +} diff --git a/src/components/Duel/lastDuelModal.spec.tsx b/src/components/Duel/lastDuelModal.spec.tsx new file mode 100644 index 000000000..10c378316 --- /dev/null +++ b/src/components/Duel/lastDuelModal.spec.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { mount } from 'enzyme' +import { act } from 'react-dom/test-utils' +import LastDuelModal from './lastDuelModal' + +jest.mock('cozy-ui/transpiled/react/I18n', () => { + return { + useI18n: jest.fn(() => { + return { + t: (str: string) => str, + } + }), + } +}) + +describe('lastDuelModal component', () => { + it('should render correctly', async () => { + const wrapper = mount( + <LastDuelModal open={true} handleCloseClick={jest.fn()} /> + ) + await act(async () => { + await new Promise(resolve => setTimeout(resolve)) + wrapper.update() + }) + expect(wrapper).toMatchSnapshot() + }) +}) diff --git a/src/components/Duel/lastDuelModal.tsx b/src/components/Duel/lastDuelModal.tsx new file mode 100644 index 000000000..5ebd3f2e8 --- /dev/null +++ b/src/components/Duel/lastDuelModal.tsx @@ -0,0 +1,51 @@ +import React, { useEffect, useState } from 'react' +import './lastDuelModal.scss' +import { useI18n } from 'cozy-ui/transpiled/react/I18n' +import Dialog from '@material-ui/core/Dialog' +import star from 'assets/icons/visu/duel/star.svg' +import CloseIcon from 'assets/icons/ico/close.svg' +import StyledIcon from 'components/CommonKit/Icon/StyledIcon' + +interface LastDuelModalProps { + open: boolean + handleCloseClick: () => void +} + +const LastDuelModal: React.FC<LastDuelModalProps> = ({ + open, + handleCloseClick, +}: LastDuelModalProps) => { + const { t } = useI18n() + + return ( + <Dialog + open={open} + onClose={handleCloseClick} + aria-labelledby={'accessibility-title'} + classes={{ + root: 'modal-root', + paper: 'modal-paper blue-light-border', + }} + > + <div id={'accessibility-title'}>{t('last_duel_modal.title')}</div> + <div className="duel-last-modal-root"> + <div onClick={handleCloseClick}> + <StyledIcon className="closeIcon" icon={CloseIcon} size={16} /> + </div> + <StyledIcon className="icon" icon={star} size={48} /> + <div className="text-28-bold title">{t('last_duel_modal.title')}</div> + <div className="text-22-bold subtitle"> + {t('last_duel_modal.subtitle')} + </div> + <div className="text-18-normal content"> + {t('last_duel_modal.message1')} + </div> + <div className="text-18-normal content"> + {t('last_duel_modal.message2')} + </div> + </div> + </Dialog> + ) +} + +export default LastDuelModal diff --git a/src/locales/fr.json b/src/locales/fr.json index 40093127f..6ae0498f9 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -234,6 +234,12 @@ "get_in": "obtenues en ", "final_defi": "sur le duel final" }, + "card_last": { + "title": " Tous les défis ont été terminés", + "message1": "Nous travaillons actuellement à vous proposer de nouveaux défis.", + "message2": "Vous pouvez donner votre avis sur ce que vous aimeriez", + "button": "Suggérer une idée de défi" + }, "card_unlocked": { "button_launch": "Lancer le challenge" }, @@ -346,6 +352,12 @@ "button_validate": "Valider" } }, + "last_duel_modal": { + "title": "Félicitations !", + "subtitle": "Vous avez terminé tous les défis !", + "message1": "Nous travaillons actuellement à vous proposer de nouveaux défis.", + "message2": "Vous pouvez donner votre avis sur ce que vous aimeriez en cliquant sur la bulle jaune." + }, "duel_empty_value_modal": { "title": "Oups !", "message": "Impossible de lancer le duel. Il nous manque en effet certaines de vos données de consommation pour vous proposer un duel à votre hauteur.", diff --git a/src/styles/components/_dialog.scss b/src/styles/components/_dialog.scss index 46650413d..c5e3008f1 100644 --- a/src/styles/components/_dialog.scss +++ b/src/styles/components/_dialog.scss @@ -35,6 +35,9 @@ div.modal-paper { &.blue-border { border: 1px solid $blue-40; } + &.blue-light-border { + border: 1px solid $blue-light; + } &.yellow-border { border: 1px solid $gold-40; } -- GitLab