Commit 3c31bebb authored by Yoan VALLET's avatar Yoan VALLET
Browse files

Merge branch 'dev' into 'master'

Merge master into dev - v0.1.6

See merge request web-et-numerique/llle_project/ecolyo!58
parents fec77b2c 5734d926
......@@ -9,7 +9,8 @@
"name": "Enedis",
"type": "ELECTRICITY",
"oauth": true,
"slug": "enedisgrandlyon"
"slug": "enedisgrandlyon",
"cron": "0 30 8 * * *"
},
"siteLink": "https://mon-compte-client.enedis.fr/"
},
......@@ -22,7 +23,8 @@
"name": "Eau du Grand Lyon",
"type": "WATER",
"oauth": false,
"slug": "eglgrandlyon"
"slug": "eglgrandlyon",
"cron": "0 30 8 * * *"
},
"siteLink": "https://agence.eaudugrandlyon.com/inscription.aspx"
},
......@@ -35,7 +37,8 @@
"name": "GRDF",
"type": "GAS",
"oauth": false,
"slug": "grdfgrandlyon"
"slug": "grdfgrandlyon",
"cron": "0 30 8 * * *"
},
"siteLink": "https://monespace.grdf.fr/monespace/connexion"
}
......
......@@ -3,7 +3,7 @@
"slug": "ecolyo",
"icon": "icon.svg",
"categories": ["energy"],
"version": "0.1.4",
"version": "0.1.6",
"licence": "AGPL-3.0",
"editor": "Métropole de Lyon",
"default_locale": "fr",
......
{
"name": "ecolyo",
"version": "0.1.4",
"version": "0.1.6",
"scripts": {
"tx": "tx pull --all || true",
"lint": "yarn lint:js && yarn lint:styles",
......
......@@ -45,6 +45,9 @@ const BaseButton = withStyles({
fontSize: '1rem',
lineHeight: '120%',
},
disabled: {
opacity: '0.4',
},
})(MuiButton)
const PrimaryButton = withStyles({
......@@ -55,6 +58,9 @@ const PrimaryButton = withStyles({
color: 'var(--textBlack)',
fontWeight: 'bold',
},
disabled: {
background: 'var(--blueBackground) !important',
},
})(BaseButton)
const SecondaryButton = withStyles({
......
......@@ -9,12 +9,10 @@ import { FluidType } from 'enum/fluid.enum'
const CardBase = withStyles({
root: {
background: 'linear-gradient(180deg, #323339 0%, #25262B 100%)',
border: '1px solid',
boxSizing: 'border-box',
boxShadow: '0px 4px 8px rgba(0, 0, 0, 0.75)',
borderRadius: '4px',
margin: '10px 0px 20px 0px',
//maxWidth: '155px',
},
})(CardActionArea)
......
......@@ -4,31 +4,31 @@ import { translate } from 'cozy-ui/react/I18n'
import StyledCard from 'components/CommonKit/Card/StyledCard'
import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
import LegalIcon from 'assets/icons/ico/legal.svg'
import LegalNoticeIcon from 'assets/icons/ico/legal-notice.svg'
interface LegalContainerProps {
interface LegalNoticeContainerProps {
t: Function
}
const LegalContainer: React.FC<LegalContainerProps> = ({
const LegalNoticeContainer: React.FC<LegalNoticeContainerProps> = ({
t,
}: LegalContainerProps) => {
}: LegalNoticeContainerProps) => {
return (
<div className="legal-root">
<div className="legal-content">
<div className="legal-header text-14-normal-uppercase">
<div className="legal-notice-root">
<div className="legal-notice-content">
<div className="legal-notice-header text-14-normal-uppercase">
{t('LEGAL.TITLE_LEGAL')}
</div>
<NavLink className="legal-card-link" to="parameters/Legal">
<NavLink className="legal-notice-card-link" to="parameters/legalnotice">
<StyledCard>
<div className="legal-card">
<div className="legal-card-content">
<div className="legal-notice-card">
<div className="legal-notice-card-content">
<StyledIcon
className="legal-card-content-icon"
icon={LegalIcon}
className="legal-notice-card-content-icon"
icon={LegalNoticeIcon}
size={50}
/>
<div className="legal-card-content-title">
<div className="legal-notice-card-content-title">
{t('LEGAL.READ_LEGAL')}
</div>
</div>
......@@ -40,4 +40,4 @@ const LegalContainer: React.FC<LegalContainerProps> = ({
)
}
export default translate()(LegalContainer)
export default translate()(LegalNoticeContainer)
......@@ -13,6 +13,8 @@ import { Client, withClient } from 'cozy-client'
import StyledButtonValid from 'components/CommonKit/Button/StyledButtonValid'
import { ScreenType } from 'enum/screen.enum'
import AvailableChallengeIcon from 'assets/png/badges/available-big.png'
import ConsumptionDataManager from 'services/consumptionDataManagerService'
import { DateTime } from 'luxon'
interface AvailableChallengeDetailsViewProps {
location: any
......@@ -27,11 +29,16 @@ const AvailableChallengeDetailsViewContainer: React.FC<AvailableChallengeDetails
const t = props.t
const client = props.client
const challengeManager = new ChallengeManager(client)
const { refreshCurrentChallenge, screenType } = useContext(AppContext)
const { refreshCurrentChallenge, screenType, fluidTypes } = useContext(
AppContext
)
const [redirect, setRedirect] = useState(false)
const [challenge, setChallenge] = useState<ChallengeType | null>(null)
const [userChallenge, setUserChallenge] = useState<UserChallenge | null>(null)
const [headerHeight, setHeaderHeight] = useState<number>(0)
const [lackOfDataForChallenge, setLackOfDataForChallenge] = useState<boolean>(
false
)
const defineHeaderHeight = (height: number) => {
setHeaderHeight(height)
......@@ -41,7 +48,7 @@ const AvailableChallengeDetailsViewContainer: React.FC<AvailableChallengeDetails
if (challenge) {
const data = await challengeManager.startChallenge(
challenge,
[0, 1, 2],
fluidTypes,
challenge.availableEcogestures
)
const chal = await challengeManager.getCurrentChallenge()
......@@ -69,9 +76,40 @@ const AvailableChallengeDetailsViewContainer: React.FC<AvailableChallengeDetails
}
useEffect(() => {
let subscribed = true
const lag = challengeManager.getLagDays(fluidTypes)
const timePeriod = {
startDate: DateTime.local()
.plus({ days: -6 })
.startOf('day'),
endDate: DateTime.local()
.plus({ days: -lag })
.endOf('day'),
}
async function checkPreviousData() {
const cdm = new ConsumptionDataManager(client)
const fetchedPerformanceIndicators = await cdm.getPerformanceIndicators(
timePeriod,
20,
fluidTypes
)
if (fetchedPerformanceIndicators && subscribed) {
fetchedPerformanceIndicators.forEach(element => {
!element.value ? setLackOfDataForChallenge(true) : null
})
} else {
setLackOfDataForChallenge(true)
}
}
checkPreviousData()
if (props.location.state) {
setChallenge(props && props.location.state.challenge)
}
return () => {
subscribed = false
}
}, [])
return (
......@@ -114,6 +152,7 @@ const AvailableChallengeDetailsViewContainer: React.FC<AvailableChallengeDetails
</div>
<div className="cp-right-button">
<StyledButtonValid
disabled={lackOfDataForChallenge}
color="primary"
onClick={handleStartClick}
>
......@@ -122,6 +161,11 @@ const AvailableChallengeDetailsViewContainer: React.FC<AvailableChallengeDetails
</StyledButtonValid>
</div>
</div>
<div className="lack-of-data-challenge">
{lackOfDataForChallenge
? t('CHALLENGE.LACK_OF_DATA')
: null}
</div>
</div>
</div>
</div>
......
......@@ -34,7 +34,7 @@ const FinishedChallengeDetailsViewContainer: React.FC<FinishedChallengeDetailsVi
const [challenge, setChallenge] = useState<UserChallenge | null>(null)
const [headerHeight, setHeaderHeight] = useState<number>(0)
const [badgeIcon, setBadgeIcon] = useState<any | null>(null)
const { screenType } = useContext(AppContext)
const { screenType, toggleBackgroundScroll } = useContext(AppContext)
async function importRightBadge(id: string, badgeStatus: number) {
// Les png doivent être au format idchallenge-badgestate.png
......@@ -56,10 +56,12 @@ const FinishedChallengeDetailsViewContainer: React.FC<FinishedChallengeDetailsVi
const handleClick = (index: number) => {
setChallengeEcogesture(index)
setOpenEcogestureModal(true)
toggleBackgroundScroll()
}
const handleCloseClick = () => {
setOpenEcogestureModal(false)
toggleBackgroundScroll()
}
useEffect(() => {
......@@ -164,6 +166,7 @@ const FinishedChallengeDetailsViewContainer: React.FC<FinishedChallengeDetailsVi
opened={openEcogestureModal}
ecogesture={challenge.selectedEcogestures[challengeEcogesture]}
handleCloseClick={handleCloseClick}
unlockedEcogesture={true}
/>
</>
)}
......
import React, { useState, useContext } from 'react'
import React, { useState, useContext, useEffect } from 'react'
import StyledSpinner from 'components/CommonKit/Spinner/StyledSpinner'
import CozyBar from 'components/ContainerComponents/CozyBar/CozyBar'
import Header from 'components/ContainerComponents/Header/Header'
......@@ -12,9 +12,12 @@ import ChallengeCardContainer from 'components/ContainerComponents/ChallengeCard
import KonnectorViewerContainer from 'components/ContainerComponents/KonnectorViewerContainer/KonnectorViewerContainer'
const HomeViewContainer: React.FC = () => {
const { fluidTypes, previousTimeStep, setPreviousTimeStep } = useContext(
AppContext
)
const {
fluidTypes,
previousTimeStep,
setPreviousTimeStep,
chartIsLoaded,
} = useContext(AppContext)
const [timeStep, setTimeStep] = useState<TimeStep>(
previousTimeStep && previousTimeStep !== TimeStep.HALF_AN_HOUR
? previousTimeStep
......@@ -65,24 +68,32 @@ const HomeViewContainer: React.FC = () => {
/>
</Header>
<Content height={headerHeight}>
{(isChartLoading || isIndicatorsLoading) && (
{(isChartLoading || isIndicatorsLoading || !chartIsLoaded) && (
<div className="content-view-loading">
<StyledSpinner size="5em" />
</div>
)}
<FluidContainer
timeStep={timeStep}
fluidTypes={fluidTypes}
resetReferenceDate={resetRefenceDate}
multiFluid={true}
handleClickTimeStep={handleClickTimeStepForFluidContainer}
setChartLoaded={setChartLoaded}
/>
<MultliFluidIndicatorsContainer
timeStep={timeStep}
setIndicatorsLoaded={setIndicatorsLoaded}
/>
<ChallengeCardContainer />
<div
className={`${
isChartLoading || isIndicatorsLoading || !chartIsLoaded
? 'chart-indicator-none'
: 'chart-indicator-block'
}`}
>
<FluidContainer
timeStep={timeStep}
fluidTypes={fluidTypes}
resetReferenceDate={resetRefenceDate}
multiFluid={true}
handleClickTimeStep={handleClickTimeStepForFluidContainer}
setChartLoaded={setChartLoaded}
/>
<MultliFluidIndicatorsContainer
timeStep={timeStep}
setIndicatorsLoaded={setIndicatorsLoaded}
/>
<ChallengeCardContainer />
</div>
</Content>
</>
) : (
......
import React, { useState } from 'react'
import CozyBar from 'components/ContainerComponents/CozyBar/CozyBar'
import Header from 'components/ContainerComponents/Header/Header'
import Content from 'components/ContainerComponents/Content/Content'
const LegalNoticeViewContainer: React.FC = () => {
const [headerHeight, setHeaderHeight] = useState<number>(0)
const defineHeaderHeight = (height: number) => {
setHeaderHeight(height)
}
const url = window.location.hostname
return (
<React.Fragment>
<CozyBar titleKey={'COMMON.APP_LEGAL_TITLE'} displayBackArrow={true} />
<Header
setHeaderHeight={defineHeaderHeight}
desktopTitleKey={'COMMON.APP_LEGAL_TITLE'}
displayBackArrow={true}
></Header>
<Content height={headerHeight}>
<div className="legal-notice-root">
<div className="legal-notice-content">
<h2>Mentions légales de Ecolyo</h2>
<p>Site du service Ecolyo : {url}</p>
<p>
Métropole de Lyon - 20, rue du Lac – CS 33569 - 69505 Lyon cedex
03{' '}
</p>
<p>Tél : (33) 4 78 63 40 40</p>{' '}
<p className="ln-contact">contact(at)grandlyon.com </p>
<div className="text-16-normal">
<div className="legal-notice-oneline">
<span className="text-16-bold">Directeur de publication</span> :
Blandine MELAY
</div>{' '}
<div className="legal-notice-oneline">
<span className="text-16-bold">
Animation éditoriale, gestion et mise à jour
</span>{' '}
: Marion BERTHOLON, Maria Inés LEAL
</div>{' '}
<div className="legal-notice-oneline">
<span className="text-16-bold">Photographies</span> : sauf
mention contraire, les photos sont la propriété de la Métropole
de Lyon
</div>{' '}
<div className="legal-notice-oneline">
<span className="text-16-bold">
Conception et Charte graphique
</span>{' '}
: Florent Dufier -{' '}
<a
href="https://florentdufier.myportfolio.com/"
target="_blank"
rel="noopener noreferrer"
>
https://florentdufier.myportfolio.com/
</a>
</div>
<div className="legal-notice-oneline">
<span className="text-16-bold">Réalisation technique</span> :
Métropole de Lyon, Sopra Steria, Cozy Cloud, Clever Age
</div>
<div className="legal-notice-oneline">
<span className="text-16-bold">Maintenance technique</span> :
Délégation Développement économique, emploi & savoirs -
Innovation numérique & systèmes d’information - Usages et
services numériques - Développement des services numériques
</div>{' '}
<div className="legal-notice-part">
<h3>Crédits</h3>
<p>
Ce site est le résultat de développements spécifiques réalisés
dans les langages Go, TypeScript, HTML et Sass. Les
développements s’appuient sur plusieurs bibliothèques et
frameworks libres : axios, cozy-bar, cozy-client,
cozy-harvest-lib, cozy-scripts, cozy-ui, d3, detect-browser,
eslint-config-cozy-app, global, lodash, luxon, moment,
moment-timezone, node-sass, object-hash, react, react-dom,
react-lottie, react-router-dom, react-swipeable-views,
sass-loader. La pile technique intègre également les
applications Cozy stack, Yarn, Docker, ACH. Les déploiements
sont réalisés sur le registre hébergé chez Cozy. L’équipe de
réalisation utilise au quotidien les applications GitLab,
IceScrum, RocketChat, Sonarqube.
</p>
</div>
<div className="legal-notice-part">
<h3>
Traitement des données personnelles et droit d’accès, de
modification et de suppression
</h3>
<p>
Conformément à la réglementation en vigueur en matière de
protection des données personnelles, le service Ecolyo a fait
l’objet d’une inscription au registre des traitements de la
Métropole de Lyon. Ecolyo fait partie de l’écosystème de
services orientés « self data » déployés par la Métropole de
Lyon avec l’ambition d’offrir aux usagers métropolitains les
outils et les services leur permettant d’exercer directement
leur droit à la portabilité, dans un cadre apte à garantir
aussi bien la transparence et le contrôle sur l’usage de leurs
données personnelles que l’exploitation directe du contenu de
ces données selon leurs libres choix. Le self data est en
effet selon la Fondation Internet Nouvelle Génération (FING)
« “la production, l’exploitation et le partage de données
personnelles par les individus, sous leur contrôle et à leurs
propres fins ». Au sein de cet environnement self data, la
gestion des données s’appuie sur l’organisation suivante des
rôles et responsabilités associées :
</p>
<ul>
<li>
Les partenaires du service Ecolyo – Enedis, GRDF et Eau du
Grand Lyon sont responsable exclusivements des selis
traitements de Données Personnelles relatifs à la collecte
des données de consommation de l’usager et à leur
transmission sur la plateforme de cloud personnel, après
consentement de l’usager ;
</li>
<li>
La Métropole de Lyon est responsable de traitement sur le
périmètre du service Ecolyo qu’elle propose à l’usager,
ainsi que les traitements nécessaires à la fourniture de la
plateforme de cloud personnel qu’elle met à disposition de
l’usager pour accéder au service Ecolyo. En sa qualité de
responsable de ces traitements, elle collecte et traite :
<ul>
<li>
Les données de compte de l’usager sur la plateforme de
cloud personnel à des fins de gestion du compte et de
communication avec l’usager ;
</li>
<li>
Les données privées de consommation d’énergie dont la
récupération, la sauvegarde, le stockage, la
synchronisation et le partage sur la plateforme de cloud
personnel sont initiés par l’usager sans visibilité de
la Métropole de Lyon sur leur contenu.
</li>
</ul>
</li>
<li>
L’usager, seul décisionnaire des finalités d’utilisation
qu’il souhaite définir pour le traitement de ses données
personnelles, à la suite de leur transmission par les
partenaires du service Ecolyo sur son cloud personnel.
</li>
</ul>
</div>
<div className="legal-notice-part">
<p>
Ainsi, dans le cadre de l’utilisation d’Ecolyo, l’usager ne
recevra les données des partenaires du service : Enedis, GRDF
et Eau du Grand Lyon seulement qu’à sa demande expresse après
la saisie de ses identifiants.
</p>
<p>L’utilisateur est donc le seul à accéder :</p>
<ul>
<li>
À ses données de consommation d’électricité horaires,
journalières, hebdomadaires, mensuelles et annuelles.
</li>
<li>
À ses données de consommation de gaz journalières,
hebdomadaires, mensuelles et annuelles.
</li>
<li>
À ses données de consommation eau journalières,
hebdomadaires, mensuelles et annuelles.
</li>
</ul>
<p>
Les engagements et responsabilités de la Métropole de Lyon
concernant la protection des données et la confidentialité des
données Ecolyo sont précisés dans les Mentions légales et les
conditions d’utilisation du cloud personnel Grand Lyon qui
accueille aujourd’hui le service Ecolyo et sans lequel le
service ne peut pas fonctionner. Conformément à la loi 78-17
du 6 janvier 1978 modifiée relative à l’information, aux
fichiers et aux libertés, vous disposez d’un droit d’accès, de
rectification et d’opposition au traitement de vos données à
caractère personnel. Votre cloud personnel vous permet
d’exercer ces droits directement dans cet espace sur vos
données de compte et sur vos données privées de consommation
dans le cadre de votre utilisation du service Ecolyo.
</p>
<p>
Vous pouvez également si vous avez des questions à ce sujet,
vous adresser par courrier postal à :
</p>
<p>
Métropole de Lyon - Direction des Affaires Juridiques et de la
Commande Publique - 20, rue du Lac – CS 33569 - 69505 Lyon
Cedex 03.
</p>
<p>
L’exercice des droits d’accès et de rectification de vos
données nominatives auprès de la Métropole de Lyon concerne
exclusivement celles de « Ecolyo ».
</p>
</div>
<div className="legal-notice-part">
<h3>Dispositions légales</h3>
<p>
Les divers éléments du site web (la forme, la mise en page, le
fonds, la structure …) sont protégés par le droit des dessins
et modèles, le droit d’auteur, le droit des marques ainsi que
le droit à l’image et ils ne peuvent être copiés ou imités en
tout ou partie sauf autorisation expresse de la Métropole de
Lyon.
</p>{' '}
<p>
Toute personne ne respectant pas les dispositions légales
applicables se rend coupable du délit de contrefaçon et est
passible des sanctions pénales prévues par la loi.
</p>
</div>
<div className="legal-notice-part">
<h3>Droits d’auteurs</h3>
<p>
Les photographies, textes, logos, pictogrammes, ainsi que
toutes œuvres intégrées dans le site sont la propriété de la
&quot;Métropole de Lyon&quot; ou de tiers ayant autorisé la
&quot;Métropole de Lyon&quot; à les utiliser.
</p>
<p>