Skip to content
Snippets Groups Projects
Commit 7c5ab6ed authored by Guilhem CARRON's avatar Guilhem CARRON
Browse files

Merge branch 'dev' of...

Merge branch 'dev' of https://forge.grandlyon.com/web-et-numerique/llle_project/ecolyo into features/US337-review-quiz
parents 0637086a 2d57e0ec
No related branches found
No related tags found
1 merge request!180Features/us337 review quiz
import React, { useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { Client, useClient } from 'cozy-client'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import { useDispatch, useSelector } from 'react-redux'
......@@ -23,6 +23,7 @@ import { UserDuelState } from 'enum/userDuel.enum'
import classNames from 'classnames'
import { AppStore } from 'store'
import { UserQuizState } from 'enum/userQuiz.enum'
import ChallengeNoFluidModal from './ChallengeNoFluidModal'
interface ChallengeCardOnGoingProps {
userChallenge: UserChallenge
......@@ -34,11 +35,14 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({
const { t } = useI18n()
const dispatch = useDispatch()
const history = useHistory()
const [isOneFluidUp, setIsOneFluidUp] = useState(true)
const [challengeIcon, setChallengeIcon] = useState(defaultIcon)
const [isDone, setisDone] = useState(false)
const { currentDataload } = useSelector(
(state: AppStore) => state.ecolyo.challenge
)
const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global)
//To be removed when action and missions will be done
const winStars = async () => {
const challengeService = new ChallengeService(client)
......@@ -55,17 +59,24 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({
)
dispatch(updateUserChallengeList(updatedChallenge))
}
const toggleNoFluidModal = useCallback(() => {
setIsOneFluidUp(prev => !prev)
}, [])
const goDuel = async () => {
if (userChallenge.duel.state !== UserDuelState.ONGOING) {
const challengeService = new ChallengeService(client)
const updatedChallenge = await challengeService.updateUserChallenge(
userChallenge,
UserChallengeUpdateFlag.DUEL_UPDATE_THRESHOLD
)
dispatch(updateUserChallengeList(updatedChallenge))
//Check if at least one fluid is up
if (fluidTypes.length !== 0) {
if (userChallenge.duel.state !== UserDuelState.ONGOING) {
const challengeService = new ChallengeService(client)
const updatedChallenge = await challengeService.updateUserChallenge(
userChallenge,
UserChallengeUpdateFlag.DUEL_UPDATE_THRESHOLD
)
dispatch(updateUserChallengeList(updatedChallenge))
}
history.push('/challenges/duel')
} else {
toggleNoFluidModal()
}
history.push('/challenges/duel')
}
const goQuiz = async () => {
if (userChallenge.quiz.state !== UserQuizState.ONGOING) {
......@@ -223,6 +234,10 @@ const ChallengeCardOnGoing: React.FC<ChallengeCardOnGoingProps> = ({
<StyledIcon className="duelLocked" icon={duelLocked} size={60} />
</div>
)}
<ChallengeNoFluidModal
open={!isOneFluidUp}
handleCloseClick={toggleNoFluidModal}
></ChallengeNoFluidModal>
</div>
)
}
......
......@@ -13,7 +13,6 @@ import defaultDuelIcon from 'assets/icons/visu/challenge/CHALLENGE0001.svg'
import defaultIcon from 'assets/icons/visu/duel/default.svg'
import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
import StyledStopButton from 'components/CommonKit/Button/StyledStopButton'
import ChallengeNoFluidModal from 'components/Challenge/ChallengeNoFluidModal'
import { UserChallengeUpdateFlag } from 'enum/userChallenge.enum'
interface DuelUnlockedProps {
userChallenge: UserChallenge
......@@ -27,7 +26,6 @@ const DuelUnlocked: React.FC<DuelUnlockedProps> = ({
const { t } = useI18n()
const [duelIcon, setDuelIcon] = useState(defaultIcon)
const [openNoFluidModal, setopenNoFluidModal] = useState(false)
const { fluidTypes } = useSelector((state: AppStore) => state.ecolyo.global)
const average: string = formatNumberValues(
userChallenge.duel.threshold
......@@ -37,25 +35,17 @@ const DuelUnlocked: React.FC<DuelUnlockedProps> = ({
average
)
const toggleNoFluidModal = useCallback(() => {
setopenNoFluidModal(prev => !prev)
}, [])
const launchDuel = useCallback(async () => {
if (fluidTypes.length > 0) {
const challengeService = new ChallengeService(client)
const updatedChallenge = await challengeService.updateUserChallenge(
userChallenge,
UserChallengeUpdateFlag.DUEL_START
)
const dataloads = await challengeService.getUserChallengeDataload(
updatedChallenge
)
dispatch(setChallengeConsumption(updatedChallenge, dataloads))
} else {
return toggleNoFluidModal()
}
}, [client, dispatch, userChallenge, fluidTypes, toggleNoFluidModal])
const challengeService = new ChallengeService(client)
const updatedChallenge = await challengeService.updateUserChallenge(
userChallenge,
UserChallengeUpdateFlag.DUEL_START
)
const dataloads = await challengeService.getUserChallengeDataload(
updatedChallenge
)
dispatch(setChallengeConsumption(updatedChallenge, dataloads))
}, [client, dispatch, userChallenge, fluidTypes])
useEffect(() => {
importIconbyId(userChallenge.id, 'challenge').then(icon => {
......@@ -83,11 +73,6 @@ const DuelUnlocked: React.FC<DuelUnlockedProps> = ({
{t('duel.start_button')}
</StyledStopButton>
</div>
<ChallengeNoFluidModal
open={openNoFluidModal}
handleCloseClick={toggleNoFluidModal}
></ChallengeNoFluidModal>
</div>
</>
)
......
......@@ -50,9 +50,6 @@ describe('FeedbackModal functionnalities', () => {
'\n' +
'Description:\n' +
'La description\n' +
'\n' +
'Email: \n' +
'_______________\n' +
'Ecolyo\n' +
'v0.0.0\n' +
'\n' +
......@@ -89,8 +86,6 @@ describe('FeedbackModal functionnalities', () => {
const wrapper = shallow(
<FeedbackModal open={true} handleCloseClick={handleFeedbackModalClose} />
)
const mockElement = { style: { overflowY: 'style' } }
jest.spyOn(document, 'querySelector').mockReturnValue(mockElement)
wrapper
.find('#idFeedbackDescription')
.simulate('change', { target: { value: 'La description' } })
......
......@@ -35,7 +35,6 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({
const client = useClient()
const [type, setType] = useState<string>('bug')
const [description, setDescription] = useState<string>('')
const [email, setEmail] = useState<string>('')
const [sending, setSending] = useState<boolean>(false)
const [sent, setSent] = useState<boolean>(false)
const [error, setError] = useState<string>('')
......@@ -43,7 +42,6 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({
const resetInputs = () => {
setType('bug')
setDescription('')
setEmail('')
setSent(false)
setError('')
}
......@@ -76,9 +74,7 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({
t('feedback.type_' + type) +
'\n\nDescription:\n' +
description +
'\n\nEmail: ' +
email +
'\n_______________\n' +
'\n' +
envInfo
const mailData = {
......@@ -212,19 +208,6 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({
}
value={description}
></textarea>
<div className="fb-label text-15-normal">{t('feedback.email')}</div>
<input
id="idFeedbackEmail"
type="text"
className="fb-form fb-input"
aria-describedby="Feedbacks email"
placeholder={t('feedback.email_placeholder')}
name="email"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setEmail(e.target.value)
}
value={email}
/>
<StyledButton
className="fb-button"
color="primary"
......
......@@ -88,21 +88,6 @@ exports[`FeedbackModal component should render the component 1`] = `
placeholder="feedback.description_placeholder"
value=""
/>
<div
className="fb-label text-15-normal"
>
feedback.email
</div>
<input
aria-describedby="Feedbacks email"
className="fb-form fb-input"
id="idFeedbackEmail"
name="email"
onChange={[Function]}
placeholder="feedback.email_placeholder"
type="text"
value=""
/>
<StyledButton
className="fb-button"
color="primary"
......
......@@ -2,6 +2,7 @@
.fb-root {
overflow-y: auto;
min-width: 70%;
.fb-header {
color: $gold-shadow;
padding: 1.5rem 1.5rem 0rem 1.5rem;
......
......@@ -275,8 +275,6 @@
"type": "Motif du retour :",
"description": "Description :",
"description_placeholder": "Vos remarques",
"email": "Si vous souhaitez un suivi de vos retours, inscrivez votre email :",
"email_placeholder": "Email (optionnel)",
"send": "Envoyer",
"ok": "Ok",
"type_bug": "Bug",
......
......@@ -325,6 +325,7 @@ describe('Challenge service', () => {
duration: Duration.fromObject({ day: 3 }),
threshold: 200,
userConsumption: 199,
startDate: DateTime.local().minus({ days: 5 }),
},
}
const dataloads = graphData.actualData
......@@ -334,14 +335,14 @@ describe('Challenge service', () => {
userChallenge,
dataloads
)
expect(result).toEqual({ isDone: true, isWin: true })
expect(result).toEqual({ isDone: true, isWin: true, isEmpty: false })
})
it('should return isDone = true and isWin = false when threshold < consumption ', async () => {
const updatedUserChallenge = {
...userChallenge,
duel: {
...userChallenge.duel,
threshold: 200,
threshold: 100,
userConsumption: 200,
},
}
......@@ -349,7 +350,7 @@ describe('Challenge service', () => {
updatedUserChallenge,
dataloads
)
expect(result).toEqual({ isDone: true, isWin: false })
expect(result).toEqual({ isDone: true, isWin: false, isEmpty: false })
})
it('should return isDone = false and isWin = true with last dataload = -1', async () => {
const updatedDataloads = [...dataloads]
......@@ -359,7 +360,7 @@ describe('Challenge service', () => {
userChallenge,
updatedDataloads
)
expect(result).toEqual({ isDone: false, isWin: true })
expect(result).toEqual({ isDone: true, isWin: true, isEmpty: true })
})
it('should return isDone = false and isWin = false with dataload not complete', async () => {
const updatedUserChallenge = {
......@@ -373,7 +374,7 @@ describe('Challenge service', () => {
updatedUserChallenge,
dataloads
)
expect(result).toEqual({ isDone: false, isWin: false })
expect(result).toEqual({ isDone: false, isWin: false, isEmpty: false })
})
})
})
import { QueryResult } from 'cozy-client'
import { FluidType } from 'enum/fluid.enum'
import { UserDuelState } from 'enum/userDuel.enum'
import { DateTime } from 'luxon'
import { DateTime, Duration } from 'luxon'
import { UserDuel, DuelEntity } from 'models'
import {
duelData,
......@@ -24,6 +24,7 @@ jest.mock('./fluid.service', () => {
const mockGetPerformanceIndicators = jest.fn()
const mockGetGraphData = jest.fn()
jest.mock('./consumption.service', () => {
return jest.fn(() => {
return {
......@@ -160,6 +161,30 @@ describe('Duel service', () => {
const result = await duelService.updateUserDuelThreshold(duelData)
expect(result).toEqual(mockUpdatedDuel)
})
it('should return the userDuel with the state to NO_REF_PERIOD_VALID', async () => {
mockGetGraphData.mockResolvedValueOnce(graphData)
mockGetFluidStatus.mockResolvedValueOnce(fluidStatusData)
mockGetPerformanceIndicators.mockResolvedValueOnce([])
const aggregatePerformanceIndicators = {
value: 55,
compareValue: null,
percentageVariation: null,
}
mockAggregatePerformanceIndicators.mockReturnValue(
aggregatePerformanceIndicators
)
const mockUpdatedDuel: UserDuel = {
...duelData,
state: UserDuelState.NO_REF_PERIOD_VALID,
duration: Duration.fromObject({ years: 99 }),
}
const falseDuelData: UserDuel = {
...duelData,
duration: Duration.fromObject({ years: 99 }),
}
const result = await duelService.updateUserDuelThreshold(falseDuelData)
expect(result).toEqual(mockUpdatedDuel)
})
})
describe('getDuelfromDuelEntities method', () => {
......
......@@ -5,7 +5,7 @@ import { DateTime, Duration } from 'luxon'
import FluidService from './fluid.service'
import ConsumptionService from './consumption.service'
import PerformanceService from './performanceIndicator.service'
import { FluidType } from 'enum/fluid.enum'
import { FluidState, FluidType } from 'enum/fluid.enum'
import { TimeStep } from 'enum/timeStep.enum'
import {
UserDuel,
......@@ -17,6 +17,8 @@ import {
} from 'models'
import { FluidStatus } from 'models'
import { getRoundFloat } from 'utils/math'
import { useSelector } from 'react-redux'
import { AppStore } from 'store'
export default class DuelService {
private readonly _client: Client
......@@ -33,6 +35,7 @@ export default class DuelService {
*/
private async getValidPeriod(
fluidStatus: FluidStatus[],
fluidTypes: FluidType[],
userDuel: UserDuel
): Promise<TimePeriod | false> {
let lastDate: DateTime = DateTime.local().setZone('utc', {
......@@ -52,7 +55,7 @@ export default class DuelService {
}
validPeriod = await this.isPeriodComplete(
validPeriod,
userDuel.fluidTypes,
fluidTypes,
userDuel.duration
)
return validPeriod
......@@ -156,6 +159,18 @@ export default class DuelService {
}
return updatedUserDuel
}
private getFluidTypesFromStatus(fluidStatus: FluidStatus[]): FluidType[] {
const fluidTypes: FluidType[] = []
fluidStatus.forEach(fluid => {
if (
fluid.status !== FluidState.KONNECTOR_NOT_FOUND &&
fluid.status !== FluidState.NOT_CONNECTED
) {
fluidTypes.push(fluid.fluidType)
}
})
return fluidTypes.sort()
}
/**
* Return duel with updated thrshold and fluidTypes
......@@ -172,15 +187,11 @@ export default class DuelService {
const configuredFluid: FluidType[] = []
// Retrieve actual configured fluids
const fluidStatus = await fluidService.getFluidStatus()
fluidStatus.forEach(fluid => {
if (fluid.status) {
configuredFluid.push(fluid.fluidType)
}
})
configuredFluid.sort()
const fluidTypes: FluidType[] = this.getFluidTypesFromStatus(fluidStatus)
// Get last period with all days known
const period: TimePeriod | false = await this.getValidPeriod(
fluidStatus,
fluidTypes,
userDuel
)
if (period !== false) {
......@@ -188,7 +199,7 @@ export default class DuelService {
const fetchLastValidData: PerformanceIndicator[] = await consumptionService.getPerformanceIndicators(
period,
TimeStep.DAY,
configuredFluid
fluidTypes
)
const maxData: PerformanceIndicator = performanceService.aggregatePerformanceIndicators(
fetchLastValidData
......@@ -202,9 +213,9 @@ export default class DuelService {
}
updatedUserDuel = {
...userDuel,
state: !period ? UserDuelState.NO_REF_PERIOD_VALID : userDuel.state,
state: userDuel.state,
threshold: updatedThreshold,
fluidTypes: configuredFluid,
fluidTypes: fluidTypes,
}
} else {
updatedUserDuel = {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment