Skip to content

Commit

Permalink
Enregistrer et restaurer automatiquement les données du formulaire
Browse files Browse the repository at this point in the history
- raw copy from LAB-MI#58
- simplify text
- fix genrated time to out time
  • Loading branch information
Quentin Dunand authored and fatpat committed Nov 2, 2020
1 parent 4151ba2 commit d655270
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 13,646 deletions.
13,591 changes: 32 additions & 13,559 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"prebuild:ci": "run-p lint clean:dist",
"build:ci": "cross-env npm run build:simple",
"postbuild:ci": "cross-env-shell react-snap",
"build:dev": "cross-env PUBLIC_URL='/' npm run build:simple",
"build:dev": "cross-env PUBLIC_URL='/covid19' npm run build:simple",
"preserve": "npm run build",
"serve": "serve dist",
"serve:dist": "serve dist"
Expand Down Expand Up @@ -62,7 +62,8 @@
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"bootstrap": "^4.5.3",
"pdf-lib": "^1.11.2",
"qrcode": "^1.4.4"
"qrcode": "^1.4.4",
"secure-ls": "^1.2.6"
},
"browserslist": [
"last 5 versions"
Expand Down
12 changes: 10 additions & 2 deletions src/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ p {
transform: translateY(-2px);
}

#form-profile #formgroup-storedata {
user-select: none;
}

@media (prefers-color-scheme: dark) {
#form-profile .form-radio-label .form-check-label {
color: #ddd;
Expand Down Expand Up @@ -352,6 +356,10 @@ input[type=number] {
border-radius: 0.5em;
}

.delete-data-link {
text-align: center;
}

.btn-attestation:hover {
background-color: #3031C1;
}
Expand Down Expand Up @@ -581,7 +589,7 @@ input[type=number] {
}
}

#snackbar {
#snackbar, #snackbar-cleardata {
min-width: 250px;
color: #fff;
text-align: center;
Expand All @@ -598,7 +606,7 @@ input[type=number] {
transition: all 0.5s ease-in-out;
}

#snackbar.show {
#snackbar.show, #snackbar-cleardata.show {
opacity: 1;
}

Expand Down
18 changes: 9 additions & 9 deletions src/form-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,39 +103,39 @@
"items": [
{
"code": "travail",
"label": "Déplacements entre le domicile et le lieu d’exercice de l’activité professionnelle ou un établissement d’enseignement ou de formation, déplacements professionnels ne pouvant être différés <a class=\"footnote\" href=\"#footnote2\">[2]</a> , déplacements pour un concours ou un examen."
"label": "Travail"
},
{
"code": "achats",
"label": "Déplacements pour effectuer des achats de fournitures nécessaires à l'activité professionnelle, des achats de première nécessité <a class=\"footnote\" href=\"#footnote3\">[3]</a> dans des établissements dont les activités demeurent autorisées, le retrait de commande et les livraisons à domicile ;"
"label": "Courses"
},
{
"code": "sante",
"label": "Consultations, examens et soins ne pouvant être assurés à distance et l’achat de médicaments ;"
"label": "Sante"
},
{
"code": "famille",
"label": " Déplacements pour motif familial impérieux, pour l'assistance aux personnes vulnérables et précaires ou la garde d'enfants ;"
"label": "Famille"
},
{
"code": "handicap",
"label": "Déplacement des personnes en situation de handicap et leur accompagnant ;"
"label": "Handicap"
},
{
"code": "sport_animaux",
"label": "Déplacements brefs, dans la limite d'une heure quotidienne et dans un rayon maximal d'un kilomètre autour du domicile, liés soit à l'activité physique individuelle des personnes, à l'exclusion de toute pratique sportive collective et de toute proximité avec d'autres personnes, soit à la promenade avec les seules personnes regroupées dans un même domicile, soit aux besoins des animaux de compagnie ;"
"label": "Sport"
},
{
"code": "convocation",
"label": " Convocation judiciaire ou administrative et pour se rendre dans un service public ;"
"label": "Convocation"
},
{
"code": "missions",
"label": " Participation à des missions d'intérêt général sur demande de l'autorité administrative ;"
"label": "Mission d'intérêt Général"
},
{
"code": "enfants",
"label": "Déplacement pour chercher les enfants à l’école et à l’occasion de leurs activités périscolaires ;"
"label": "Enfants"
}
]
}
Expand Down
68 changes: 22 additions & 46 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
<meta property="og:title" content="Générateur d'attestation de déplacement dérogatoire - COVID-19" />
<meta property="og:locale" content="fr_FR" />
<meta property="og:description" content="Ce service officiel génère une version numérique de la déclaration de déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle." />
<link rel="canonical" href="https://media.interieur.gouv.fr{{ PUBLIC_URL || '/deplacement-covid-19' }}" />
<meta property="og:url" content="https://media.interieur.gouv.fr{{ PUBLIC_URL || '/deplacement-covid-19' }}" />
<link rel="canonical" href="https://fatpat.github.io/covid19/" />
<meta property="og:url" content="https://fatpat.github.io/covid19/" />
<meta property="og:site_name" content="Générateur d'attestation de déplacement dérogatoire - COVID-19" />
<script type='application/ld+json'>{"@context":"http://www.schema.org","@type":"GovernmentOrganization","name":"Générateur d'attestation de déplacement dérogatoire - COVID-19","description":"Ce service officiel génère une version numérique de la déclaration de déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.","address":{"@type":"PostalAddress","addressCountry":"France"}}</script>

Expand All @@ -30,12 +30,6 @@
</head>
<body>
<header role="banner" class="wrapper">
<picture>
<source srcset="/MIN_Interieur_RVB_dark.svg" media="(prefers-color-scheme: dark)">
<img src="/MIN_Interieur_RVB.svg" alt="Ministère de l'intérieur. Liberté, égalité, fraternité."
class="logo" role="presentation" aria-hidden="true">
</picture>

<div>
<h1 class="flex flex-wrap">
<span class="covid-title">
Expand All @@ -45,11 +39,6 @@ <h1 class="flex flex-wrap">
Attestation de déplacement dérogatoire
</span>
</h1>
<p class="text-desc">
En application du décret n°2020-1310 du 29 octobre 2020 prescrivant les mesures générales
nécessaires pour faire face à l'épidémie de Covid19 dans le cadre de l'état d'urgence sanitaire
</p>

</div>
</header>
<main role="main">
Expand All @@ -59,48 +48,35 @@ <h1 class="flex flex-wrap">
id="alert-facebook"
></p>

<div class="wrapper">
<form id="form-profile" accept-charset="UTF-8"></form>
<p class="text-center mt-5">
<button type="button" id="generate-btn" class="btn btn-primary btn-attestation"><span ><i class="fa fa-file-pdf inline-block mr-1"></i> Générer mon attestation</span></button>
</p>
<div class="wrapper">
<form id="form-profile" accept-charset="UTF-8"></form>
<p class="text-center mt-5">
<button type="button" id="generate-btn" class="btn btn-primary btn-attestation">
<span>
<i class="fa fa-file-pdf inline-block mr-1"></i>
Générer mon attestation
</span>
</button>
</p>

<div class="bg-primary d-none" id="snackbar">
L'attestation est téléchargée sur votre appareil.
</div>
</div>

<div id="footnotes">
<p id="footnote1">
[1] Les personnes souhaitant bénéficier de l'une de ces exceptions doivent se munir s'il y a lieu, lors de leurs déplacements hors de leur domicile, d'un document leur permettant de justifier que le déplacement considéré entre dans le champ de l'une de ces exceptions.
</p>
<p id="footnote2">
[2] A utiliser par les travailleurs non salariés, lorsqu'ils ne peuvent disposer d'un justificatif de déplacement établi par leur employeur.
</p>
<p id="footnote3">
[3] Y compris les acquisitions à titre gratuit (distribution de denrées alimentaires...) et les déplacements liés à la perception de prestations sociales et au retrait d'espèces.
</p>
<a id="cleardata"
class="center delete-data-link"
href="javascript:void(0)">Effacer les données du formulaire</a>
<div class="bg-primary d-none"
id="snackbar-cleardata">
Les données du formulaire ont été effacées.
</div>
</div>


<p class="github">
Le code source de ce service est consultable sur <a href="https://github.com/LAB-MI/attestation-deplacement-derogatoire-q4-2020" class="github-link">GitHub</a>.
Le code source de ce service est consultable sur <a href="https://github.com/fatpat/attestation-deplacement-derogatoire-q4-2020" class="github-link">GitHub</a>.
</p>
<p class="label-mi">
Ministère de l'Intérieur - DNUM - SDIT
</p>
<picture class="center">
<source srcset="/logo_dnum_dark.svg" media="(prefers-color-scheme: dark)">
<img class="center" src="/logo_dnum.svg" alt="logo dnum">
</picture>
</main>
<footer role="contentinfo" class="main-footer">
<div class="footer-links">
<a href="./confidentialite.html" title="Confidentialité - nouvelle page" target="_blank" class="footer-line footer-link">Confidentialité</a>
<a href="https://www.interieur.gouv.fr/Infos-du-site/Mentions-legales" title="Mentions légales - nouvelle page" target="_blank" class="footer-line footer-link">Mentions légales</a>
<a href="https://www.gouvernement.fr/info-coronavirus" title="Information du gouvernement sur le Covid-19 - nouvelle page" target="_blank" class="footer-line footer-link">Informations du gouvernement sur le Covid-19</a>
<div class="footer-line" >Plus d’infos au <a class="num-08" href="tel:0800130000" title="Numéro vert - appel gratuit depuis un poste fixe en France">0 800 130 000</a></div>
<p class="footer-line" id="version"></p>
</div>
</footer>

<div class="alert alert-info d-none" id="update-alert">
Une nouvelle version est disponible. Cliquer sur le bouton pour l'obtenir.
Expand Down
85 changes: 82 additions & 3 deletions src/js/form-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { $, $$, downloadBlob } from './dom-utils'
import { addSlash, getFormattedDate } from './util'
import pdfBase from '../certificate.pdf'
import { generatePdf } from './pdf-util'
import SecureLS from 'secure-ls'

const secureLS = new SecureLS({ encodingType: 'aes' })
const clearDataSnackbar = $('#snackbar-cleardata')

const conditions = {
'#field-firstname': {
Expand Down Expand Up @@ -53,6 +57,45 @@ function validateAriaFields () {
.includes(true)
}

function updateSecureLS (formInputs, reasonInputs) {
if (wantDataToBeStored() === true) {
secureLS.set('profile', getProfile(formInputs))
secureLS.set('reason', getReasonsObject(reasonInputs))
} else {
clearSecureLS()
}
}

function clearSecureLS () {
secureLS.clear()
}

function clearForm () {
const formProfile = $('#form-profile')
formProfile.reset()
}

function setCurrentDate (releaseDateInput, releaseTimeInput) {
const currentDate = new Date()

releaseDateInput.value = getFormattedDate(currentDate)
releaseTimeInput.value = currentDate.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
}

function showSnackbar (snackbarToShow, showDuration = 6000) {
snackbarToShow.classList.remove('d-none')
setTimeout(() => snackbarToShow.classList.add('show'), 100)

setTimeout(function () {
snackbarToShow.classList.remove('show')
setTimeout(() => snackbarToShow.classList.add('d-none'), 500)
}, showDuration)
}

export function wantDataToBeStored () {
return true
}

export function setReleaseDateTime (releaseDateInput) {
const loadedDate = new Date()
releaseDateInput.value = getFormattedDate(loadedDate)
Expand All @@ -78,8 +121,36 @@ export function getReasons (reasonInputs) {
return reasons
}

export function prepareInputs (formInputs, reasonInputs, reasonFieldset, reasonAlert, snackbar) {
export function getReasonsObject (reasonInputs) {
return reasonInputs
.filter((reason) => reason.checked)
.reduce((map, reason) => {
map[reason.value] = reason.checked
return map
}, {})
}

export function prepareInputs (formInputs, reasonInputs, reasonFieldset, reasonAlert, snackbar, releaseDateInput, releaseTimeInput) {
const lsProfile = secureLS.get('profile')
const lsReason = secureLS.get('reason')
const currentDate = new Date()
const formattedDate = getFormattedDate(currentDate)
const formattedTime = currentDate.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })

formInputs.forEach((input) => {
switch (input.name) {
case 'datesortie':
input.value = formattedDate
break
case 'heuresortie':
input.value = formattedTime
break
case 'field-reason':
if (lsReason) input.checked = lsReason[input.value]
break
default:
if (lsProfile) input.value = lsProfile[input.name]
}
const exempleElt = input.parentNode.parentNode.querySelector('.exemple')
const validitySpan = input.parentNode.parentNode.querySelector('.validity')
if (input.placeholder && exempleElt) {
Expand Down Expand Up @@ -111,6 +182,13 @@ export function prepareInputs (formInputs, reasonInputs, reasonFieldset, reasonA
})
})

$('#cleardata').addEventListener('click', () => {
clearSecureLS()
clearForm()
setCurrentDate(releaseDateInput, releaseTimeInput)
showSnackbar(clearDataSnackbar, 1200)
})

$('#generate-btn').addEventListener('click', async (event) => {
event.preventDefault()

Expand All @@ -127,7 +205,7 @@ export function prepareInputs (formInputs, reasonInputs, reasonFieldset, reasonA
return
}

console.log(getProfile(formInputs), reasons)
updateSecureLS(formInputs, reasonInputs)

const pdfBlob = await generatePdf(getProfile(formInputs), reasons, pdfBase)

Expand Down Expand Up @@ -156,6 +234,7 @@ export function prepareForm () {
const reasonFieldset = $('#reason-fieldset')
const reasonAlert = reasonFieldset.querySelector('.msg-alert')
const releaseDateInput = $('#field-datesortie')
const releaseTimeInput = $('#field-heuresortie')
setReleaseDateTime(releaseDateInput)
prepareInputs(formInputs, reasonInputs, reasonFieldset, reasonAlert, snackbar)
prepareInputs(formInputs, reasonInputs, reasonFieldset, reasonAlert, snackbar, releaseDateInput, releaseTimeInput)
}
18 changes: 1 addition & 17 deletions src/js/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ const createTitle = () => {
const p = createElement('p', { className: 'msg-info', innerHTML: 'Tous les champs sont obligatoires.' })
return [h2, p]
}
// createElement('div', { className: 'form-group' })

const getCurrentTime = () => {
const date = new Date();
return date.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
}

const createFormGroup = ({
autocomplete = false,
Expand Down Expand Up @@ -60,10 +54,6 @@ const createFormGroup = ({

const input = createElement('input', inputAttrs)

if (name === 'heuresortie') {
input.value = getCurrentTime()
}

const validityAttrs = {
className: 'validity',
}
Expand Down Expand Up @@ -120,15 +110,9 @@ const createReasonFieldset = (reasonsData) => {
const textAlertAttrs = { className: 'msg-alert hidden', innerHTML: 'Veuillez choisir un motif' }
const textAlert = createElement('p', textAlertAttrs)

const textSubscribeReasonAttrs = {
innerHTML: 'certifie que mon déplacement est lié au motif suivant (cocher la case) autorisé par le décret n°2020-1310 du 29 octobre 2020 prescrivant les mesures générales nécessaires pour faire face à l\'épidémie de Covid19 dans le cadre de l\'état d\'urgence sanitaire <a class="footnote" href="#footnote1">[1]</a>&nbsp;:',
}

const textSubscribeReason = createElement('p', textSubscribeReasonAttrs)

const reasonsFields = reasonsData.items.map(createReasonField)

appendToFieldset([legend, textAlert, textSubscribeReason, ...reasonsFields])
appendToFieldset([legend, textAlert, ...reasonsFields])
// Créer un form-checkbox par motif
return fieldset
}
Expand Down
4 changes: 1 addition & 3 deletions src/js/pdf-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ const ys = {
export async function generatePdf (profile, reasons, pdfBase) {
const creationInstant = new Date()
const creationDate = creationInstant.toLocaleDateString('fr-FR')
const creationHour = creationInstant
.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
.replace(':', 'h')
const creationHour = profile.heuresortie.replace(':', 'h')

const {
lastname,
Expand Down
2 changes: 1 addition & 1 deletion src/robots.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Sitemap: https://media.interieur.gouv.fr/deplacement-covid-19/sitemap.xml
Sitemap: https://fatpat.github.io/covid19/sitemap.xml
Loading

0 comments on commit d655270

Please sign in to comment.