Commit 8d36b536 authored by Hugo SUBTIL's avatar Hugo SUBTIL
Browse files

Merge branch 'fix/CGU-page-to-Modal' into 'dev'

Fix/cgu page to modal

See merge request web-et-numerique/llle_project/ecolyo!395
parents fd9f6bca 6302799b
......@@ -10,12 +10,10 @@
text-align: left;
padding: 0 2rem;
.gcu-content-wrapper {
width: 36rem;
max-width: 36rem;
margin: 2rem 0;
color: $grey-bright;
@media #{$large-phone} {
width: 100%;
}
width: 100%;
.version {
color: $soft-grey;
text-align: center;
......
......@@ -14,7 +14,8 @@
margin-bottom: 1.25rem;
}
.legal-notice-content {
width: 45.75rem;
max-width: 45.75rem;
width: 100%;
@media #{$large-phone} {
width: 100%;
}
......
......@@ -44,7 +44,7 @@
.ln-contact {
color: $multi-color;
}
width: 45.75rem;
max-width: 45.75rem;
@media #{$large-phone} {
width: 100%;
}
......
import React, { Suspense, lazy } from 'react'
import { Route, Switch, Redirect } from 'react-router-dom'
import { FluidType } from 'enum/fluid.enum'
import ChallengeView from 'components/Challenge/ChallengeView'
import DuelView from 'components/Duel/DuelView'
import QuizView from 'components/Quiz/QuizView'
import ExplorationView from 'components/Exploration/ExplorationView'
import ActionView from 'components/Action/ActionView'
import UnSubscribe from 'components/Options/UnSubscribe'
const HomeView = lazy(() => import('components/Home/HomeView'))
const SingleFluidView = lazy(() =>
import('components/SingleFluid/SingleFluidView')
)
const EcogestureView = lazy(() =>
import('components/Ecogesture/EcogestureView')
)
const OptionsView = lazy(() => import('components/Options/OptionsView'))
const FAQView = lazy(() => import('components/FAQ/FAQView'))
const LegalNoticeView = lazy(() =>
import('components/LegalNotice/LegalNoticeView')
)
const GCUView = lazy(() => import('components/GCU/GCUView'))
const AnalysisView = lazy(() => import('components/Analysis/AnalysisView'))
const ProfileTypeView = lazy(() =>
import('components/ProfileType/ProfileTypeView')
)
const TermsView = lazy(() => import('components/Terms/TermsView'))
const LegalNoticePublic = lazy(() =>
import('components/Terms/LegalNoticePublic')
)
const CGUPublic = lazy(() => import('components/Terms/CGUPublic'))
interface RouteProps {
isLastTermAccepted: boolean
}
const Routes: React.FC<RouteProps> = ({ isLastTermAccepted }: RouteProps) => {
return (
<Suspense fallback={<div></div>}>
<Switch>
{!isLastTermAccepted && (
<>
<Route path="/terms" component={TermsView} />
<Redirect from="*" to="/terms" />
</>
)}
<Route path="/legal" component={LegalNoticePublic} />
<Route path="/cgu" component={CGUPublic} />
<Route
path="/consumption"
render={({ match: { url } }) => (
<>
<Route path={`${url}/electricité`} exact>
<SingleFluidView fluidType={FluidType.ELECTRICITY} />
</Route>
<Route path={`${url}/eau`} exact>
<SingleFluidView fluidType={FluidType.WATER} />
</Route>
<Route path={`${url}/gaz`} exact>
<SingleFluidView fluidType={FluidType.GAS} />
</Route>
<Route path={`${url}/`} component={HomeView} exact />
</>
)}
/>
<Route
path="/challenges"
render={({ match: { url } }) => (
<>
<Route path={`${url}/duel`} component={DuelView} />
<Route path={`${url}/quiz`} component={QuizView} />
<Route path={`${url}/exploration`} component={ExplorationView} />
<Route path={`${url}/action`} exact component={ActionView} />
<Route path={`${url}/`} component={ChallengeView} exact />
</>
)}
/>
<Route path="/ecogestures" component={EcogestureView} />
<Route path={'/options/FAQ'} component={FAQView} />
<Route path={`/options/legalnotice`} component={LegalNoticeView} />
<Route path={`/options/gcu`} component={GCUView} />
<Route path={'/options/:connectParam'} exact component={OptionsView} />
<Route path={'/options'} exact component={OptionsView} />
<Route path="/analysis" component={AnalysisView} />
<Route path="/profiletype" component={ProfileTypeView} />
<Route path="/unsubscribe" component={UnSubscribe} />
<Redirect from="/" to="/consumption" />
<Redirect from="*" to="/consumption" />
</Switch>
</Suspense>
)
}
export default Routes
import React, { Suspense, lazy } from 'react'
import { Route, Switch, Redirect } from 'react-router-dom'
import { FluidType } from 'enum/fluid.enum'
import ChallengeView from 'components/Challenge/ChallengeView'
import DuelView from 'components/Duel/DuelView'
import QuizView from 'components/Quiz/QuizView'
import ExplorationView from 'components/Exploration/ExplorationView'
import ActionView from 'components/Action/ActionView'
import UnSubscribe from 'components/Options/UnSubscribe'
import TermsView from 'components/Terms/TermsView'
const HomeView = lazy(() => import('components/Home/HomeView'))
const SingleFluidView = lazy(() =>
import('components/SingleFluid/SingleFluidView')
)
const EcogestureView = lazy(() =>
import('components/Ecogesture/EcogestureView')
)
const OptionsView = lazy(() => import('components/Options/OptionsView'))
const FAQView = lazy(() => import('components/FAQ/FAQView'))
const LegalNoticeView = lazy(() =>
import('components/LegalNotice/LegalNoticeView')
)
const GCUView = lazy(() => import('components/GCU/GCUView'))
const AnalysisView = lazy(() => import('components/Analysis/AnalysisView'))
const ProfileTypeView = lazy(() =>
import('components/ProfileType/ProfileTypeView')
)
interface RouteProps {
isLastTermAccepted: boolean
}
const Routes: React.FC<RouteProps> = ({ isLastTermAccepted }: RouteProps) => {
return (
<Suspense fallback={<div></div>}>
<Switch>
{isLastTermAccepted && <Redirect from="/terms" to="/consumption" />}
<Route path="/terms" component={TermsView} />
{!isLastTermAccepted && (
<>
<Redirect from="*" to="/terms" />
<Redirect from="/" to="/terms" />
</>
)}
<Route
path="/consumption"
render={({ match: { url } }) => (
<>
<Route path={`${url}/electricité`} exact>
<SingleFluidView fluidType={FluidType.ELECTRICITY} />
</Route>
<Route path={`${url}/eau`} exact>
<SingleFluidView fluidType={FluidType.WATER} />
</Route>
<Route path={`${url}/gaz`} exact>
<SingleFluidView fluidType={FluidType.GAS} />
</Route>
<Route path={`${url}/`} component={HomeView} exact />
</>
)}
/>
<Route
path="/challenges"
render={({ match: { url } }) => (
<>
<Route path={`${url}/duel`} component={DuelView} />
<Route path={`${url}/quiz`} component={QuizView} />
<Route path={`${url}/exploration`} component={ExplorationView} />
<Route path={`${url}/action`} exact component={ActionView} />
<Route path={`${url}/`} component={ChallengeView} exact />
</>
)}
/>
<Route path="/ecogestures" component={EcogestureView} />
<Route path={'/options/FAQ'} component={FAQView} />
<Route path={`/options/legalnotice`} component={LegalNoticeView} />
<Route path={`/options/gcu`} component={GCUView} />
<Route path={'/options/:connectParam'} exact component={OptionsView} />
<Route path={'/options'} exact component={OptionsView} />
<Route path="/analysis" component={AnalysisView} />
<Route path="/profiletype" component={ProfileTypeView} />
<Route path="/unsubscribe" component={UnSubscribe} />
<Redirect from="/" to="/consumption" />
<Redirect from="*" to="/consumption" />
</Switch>
</Suspense>
)
}
export default Routes
import GCUContent from 'components/GCU/GCUContent'
import React from 'react'
import './termsView.scss'
import Dialog from '@material-ui/core/Dialog'
import { Button, IconButton } from '@material-ui/core'
import Icon from 'cozy-ui/transpiled/react/Icon'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import CloseIcon from 'assets/icons/ico/close.svg'
interface CGUModalProps {
open: boolean
handleCloseClick: () => void
}
const CGUModal: React.FC<CGUModalProps> = ({
open,
handleCloseClick,
}: CGUModalProps) => {
const { t } = useI18n()
return (
<Dialog
open={open}
onClose={handleCloseClick}
aria-labelledby={'accessibility-title'}
classes={{
root: 'modal-root',
paper: 'modal-paper',
}}
>
<div id={'accessibility-title'}>
{t('feedback.accessibility.window_title')}
</div>
<IconButton
aria-label={t('feedback.accessibility.button_close')}
className="modal-paper-close-button"
onClick={handleCloseClick}
>
<Icon icon={CloseIcon} size={16} />
</IconButton>
<GCUContent />
<Button
aria-label={t('gcu_modal.accessibility.button_accept')}
onClick={handleCloseClick}
className="gcu-modal-button"
classes={{
root: 'btn-profile-next rounded',
label: 'text-16-bold',
}}
>
{t('legal.accessibility.button_close')}
</Button>
</Dialog>
)
}
export default CGUModal
import React from 'react'
import { mount } from 'enzyme'
import CGUPublic from './CGUPublic'
import CGUModal from './CGUModal'
jest.mock('cozy-ui/transpiled/react/I18n', () => {
return {
......@@ -12,9 +12,11 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => {
}
})
describe('CGUPublic component', () => {
describe('CGUModal component', () => {
it('should be rendered correctly', () => {
const component = mount(<CGUPublic />).getElement()
const component = mount(
<CGUModal open={true} handleCloseClick={jest.fn()} />
).getElement()
expect(component).toMatchSnapshot()
})
})
import GCUContent from 'components/GCU/GCUContent'
import React from 'react'
import './termsView.scss'
const CGUPublic: React.FC = () => {
return (
<div className="terms-wrapper">
<div className="terms-content">
<GCUContent />
</div>
</div>
)
}
export default CGUPublic
......@@ -16,8 +16,6 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => {
})
const mockStore = configureStore([])
const mockDecoreText = jest.fn()
describe('DataShareConsentContent component', () => {
it('should be rendered correctly with first connexion text', () => {
const store = mockStore({
......@@ -27,12 +25,12 @@ describe('DataShareConsentContent component', () => {
})
const component = mount(
<Provider store={store}>
<DataShareConsentContent decoreText={mockDecoreText} />
<DataShareConsentContent />
</Provider>
).getElement()
expect(component).toMatchSnapshot()
})
it('should be rendered correctly with first connexion text', () => {
it('should be rendered correctly without first connexion text', () => {
profileData.isFirstConnection = false
const store = mockStore({
ecolyo: {
......@@ -41,7 +39,7 @@ describe('DataShareConsentContent component', () => {
})
const component = mount(
<Provider store={store}>
<DataShareConsentContent decoreText={mockDecoreText} />
<DataShareConsentContent />
</Provider>
)
expect(
......
......@@ -34,7 +34,7 @@ const DataShareConsentContent: React.FC = () => {
</ul>
<p className="text-14-normal">{t('dataShare.part4')}</p>
<p className="text-14-normal">{t('dataShare.part5')}</p>
<p className="text-14-normal">{t('dataShare.part6')}</p>
<p className="text-14-normal">{decoreText(t('dataShare.part6'))}</p>
<p className="text-14-normal">{t('dataShare.part7')}</p>
<p className="text-14-normal">{t('dataShare.part8')}</p>
<span className="text-14-normal">{t('dataShare.part9')}</span>
......
import React from 'react'
import { mount } from 'enzyme'
import LegalNoticePublic from './LegalNoticePublic'
import LegalNoticeModal from './LegalNoticeModal'
jest.mock('cozy-ui/transpiled/react/I18n', () => {
return {
......@@ -12,9 +12,11 @@ jest.mock('cozy-ui/transpiled/react/I18n', () => {
}
})
describe('LegalNoticePublic component', () => {
describe('LegalNoticeModal component', () => {
it('should be rendered correctly', () => {
const component = mount(<LegalNoticePublic />).getElement()
const component = mount(
<LegalNoticeModal open={true} handleCloseClick={jest.fn()} />
).getElement()
expect(component).toMatchSnapshot()
})
})
import React from 'react'
import LegalNoticeContent from 'components/LegalNotice/LegalNoticeContent'
import './termsView.scss'
import Dialog from '@material-ui/core/Dialog'
import { Button, IconButton } from '@material-ui/core'
import Icon from 'cozy-ui/transpiled/react/Icon'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import CloseIcon from 'assets/icons/ico/close.svg'
interface LegalNoticeModalProps {
open: boolean
handleCloseClick: () => void
}
const LegalNoticeModal: React.FC<LegalNoticeModalProps> = ({
open,
handleCloseClick,
}: LegalNoticeModalProps) => {
const { t } = useI18n()
return (
<Dialog
open={open}
onClose={handleCloseClick}
aria-labelledby={'accessibility-title'}
classes={{
root: 'modal-root',
paper: 'modal-paper',
}}
>
<div id={'accessibility-title'}>{t('legal.title_legal')}</div>
<IconButton
aria-label={t('feedback.accessibility.button_close')}
className="modal-paper-close-button"
onClick={handleCloseClick}
>
<Icon icon={CloseIcon} size={16} />
</IconButton>
<LegalNoticeContent />
<Button
aria-label={t('gcu_modal.accessibility.button_accept')}
onClick={handleCloseClick}
className="gcu-modal-button"
classes={{
root: 'btn-profile-next rounded',
label: 'text-16-bold',
}}
>
{t('legal.accessibility.button_close')}
</Button>
</Dialog>
)
}
export default LegalNoticeModal
import LegalNoticeContent from 'components/LegalNotice/LegalNoticeContent'
import React from 'react'
import './termsView.scss'
const LegalNoticePublic: React.FC = () => {
return (
<div className="terms-wrapper">
<div className="terms-content">
<LegalNoticeContent />
</div>
</div>
)
}
export default LegalNoticePublic
......@@ -10,6 +10,8 @@ import './termsView.scss'
import { useHistory } from 'react-router-dom'
import { decoreText } from 'utils/decoreText'
import { updateTermValidation } from 'store/global/global.actions'
import CGUModal from './CGUModal'
import LegalNoticeModal from './LegalNoticeModal'
const TermsView: React.FC = () => {
const { t } = useI18n()
......@@ -20,6 +22,19 @@ const TermsView: React.FC = () => {
const [dataConsentValidation, setDataConsentValidation] = useState<boolean>(
false
)
const [openCGUModal, setOpenCGUModal] = useState<boolean>(false)
const [openLegalNoticeModal, setOpenLegalNoticeModal] = useState<boolean>(
false
)
const toggleCGUModal = () => {
setOpenCGUModal(prev => !prev)
}
const toggleLegalNoticeModal = () => {
setOpenLegalNoticeModal(prev => !prev)
}
const handleGCUValidate = useCallback(() => {
setGCUValidation(prev => !prev)
}, [])
......@@ -65,8 +80,10 @@ const TermsView: React.FC = () => {
checked={GCUValidation}
/>
<span>
{decoreText(t('dataShare.validCGU'))}
{decoreText(t('dataShare.validLegal'))}
{decoreText(t('dataShare.validCGU'), () => toggleCGUModal())}
{decoreText(t('dataShare.validLegal'), () =>
toggleLegalNoticeModal()
)}
</span>
</label>
</div>
......@@ -87,6 +104,11 @@ const TermsView: React.FC = () => {
{t('tutorial_welcome.accessibility.finish')}
</Button>
</div>
<CGUModal open={openCGUModal} handleCloseClick={toggleCGUModal} />
<LegalNoticeModal
open={openLegalNoticeModal}
handleCloseClick={toggleLegalNoticeModal}
/>
</div>
)
}
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CGUPublic component should be rendered correctly 1`] = `<CGUPublic />`;
......@@ -13,8 +13,6 @@ exports[`DataShareConsentContent component should be rendered correctly with fir
}
}
>
<DataShareConsentContent
decoreText={[MockFunction]}
/>
<DataShareConsentContent />
</Provider>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LegalNoticeModal component should be rendered correctly 1`] = `
<LegalNoticeModal
handleCloseClick={[MockFunction]}
open={true}
/>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LegalNoticePublic component should be rendered correctly 1`] = `<LegalNoticePublic />`;
......@@ -89,3 +89,12 @@
}
}
}
button.action {
appearance: none;
cursor: pointer;
display: contents;
background: transparent;
border: none;
padding: 0;
color: $gold-shadow;
}
......@@ -397,15 +397,15 @@
"item3": "De l’évolution de vos consommations, des nouveautés et de la qualité du service via une lettre mensuelle. Vous pouvez à tout moment vous désinscrire de cette lettre via la page Options du service.",
"part4": "Vos données privées de consommation d’énergie et d’eau sont récupérées, sauvegardées et stockées dans votre cloud personnel à votre initiative sans visibilité de la Métropole de Lyon sur leur contenu.",
"part5": "Il en est de même pour les données privées de composition du logement et du foyer, fournies par vos soins. Elles restent également sans visibilité de la Métropole de Lyon sur leur contenu. ",
"part6": "Dans le cadre de l’évaluation et de l’amélioration du service, des données d’utilisation anonymisées seront remontées à des fins d’exploitation statistiques. La récupération de ces statistiques anonymisées nous permettra de s’assurer du bon fonctionnement technique de la connexion à vos données de consommation ainsi que d’évaluer l’impact global en termes de baisse des consommations énergétiques de notre service (Plus d’informations sur la manière dont votre anonymat est bien préservé dans ce processus ici).",
"part6": "Dans le cadre de l’évaluation et de l’amélioration du service, des données d’utilisation anonymisées seront remontées à des fins d’exploitation statistiques. La récupération de ces statistiques anonymisées nous permettra de s’assurer du bon fonctionnement technique de la connexion à vos données de consommation ainsi que d’évaluer l’impact global en termes de baisse des consommations énergétiques de notre service (Plus d’informations sur la manière dont votre anonymat est bien préservé dans ce processus <a href=\"https://ecolyo.com/cloud_statistiques.html\">ici</a>).",
"part7": "Au sein de votre cloud personnel, vous pouvez à tout moment exercer vos droits d’accès, de rectification, de portabilité, de limitation et d’opposition. ",
"part8": "Vous pouvez également exercer vos droits d’accès, de rectification, de limitation, d’opposition et d’effacement de vos données personnelles en contactant directement le Délégué à la Protection des Données par courrier en écrivant à l’adresse :",
"part9": "Métropole de Lyon – Délégué à la Protection des Données - Direction des Affaires Juridiques et de la Commande Publique - 20, rue du Lac - BP 33569 - 69505 Lyon Cedex 03 ",
"part10": "ou en ligne, au moyen du formulaire disponible à l'adresse suivante : ",
"link1": "<a href=\"https://demarches.toodego.com/sve/proteger-mes-donnees-personnelles/\">https://demarches.toodego.com/sve/proteger-mes-donnees-personnelles/</a>",
"validDataConsent": "Je consens au traitement de mes données tel que décrit ci-dessus.",
"validCGU": "Je valide les <a href=\"#/cgu\">Conditions Générales d’Utilisation</a> ",
"validLegal": " du service et ai pris connaissance des <a href=\"#/legal\"> Mentions Légales </a> de celui-ci."
"validCGU": "Je valide les <span class=\"action\">Conditions Générales d’Utilisation</span> ",
"validLegal": " du service et ai pris connaissance des <span class=\"action\"> Mentions Légales </span> de celui-ci."
},
"gcu": {
"title": "Conditions générales d’utilisation du service",
......@@ -595,7 +595,10 @@
"part8": "Les liens hypertextes mis en œuvre au sein du site en direction d’autres sites et/ou de pages personnelles et d’une manière générale vers toutes ressources existantes sur internet ne sauraient engager la responsabilité de la Métropole de Lyon quant aux liens qu’ils contiennent ou aux changements ou mises à jour qui leur sont apportés.",
"title9": "Mise en garde générale",
"part9-1": "Nos services mettent tout en œuvre pour offrir aux visiteurs de ce site web des informations fiables et vérifiées. Cependant, malgré tous les soins apportés, le site peut comporter des inexactitudes, des défauts de mise à jour ou des erreurs.",
"part9-2": "Nous remercions les utilisateurs du site de nous faire part d’éventuelles omissions, erreurs ou corrections par mail sur la boite aux lettres du webmestre ou directement via le formulaire proposé dans le service."
"part9-2": "Nous remercions les utilisateurs du site de nous faire part d’éventuelles omissions, erreurs ou corrections par mail sur la boite aux lettres du webmestre ou directement via le formulaire proposé dans le service.",
"accessibility": {
"button_close": "Fermer la fenêtre"
}
},
"navigation": {
"consumption": "Conso",
......