Compare commits
2 Commits
master
...
attestatio
Author | SHA1 | Date |
---|---|---|
LAB-MI | 6a5f269560 | |
LAB-MI | 86b15a4d6e |
|
@ -9,6 +9,7 @@ module.exports = {
|
|||
"no-console": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"no-var": 2,
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
|
42
CHANGELOG.md
|
@ -1,45 +1,5 @@
|
|||
# Changelog
|
||||
|
||||
## [1.0.13] - 2020-04-06
|
||||
## [1.0.0] - 2020-04-15
|
||||
### Added
|
||||
- first public release
|
||||
## [1.1.0] - 2020-04-08
|
||||
### Added
|
||||
- (#21, #23, #25, #26, #27, #28, #29) :wheelchair: improve A11Y support
|
||||
- adds github links in footer
|
||||
- (#19) clear localstorage
|
||||
- prevent sending personal data
|
||||
- 💚 Publish html as workflow asset and code in public repository
|
||||
- Add sitemap and tell robots.txt to scan the sitemap
|
||||
- Add Changelog
|
||||
### Changes
|
||||
- (#18) 📝 Update header for reasons section
|
||||
- (#3) ✏ Replace codiv by covid in package.json, README
|
||||
- changes start target
|
||||
- (#1) 🐛 Autocomplete birthday field only on keyup, not when deleting
|
||||
- (#1) 🎨 Improve regex control pattern for birhtday
|
||||
- :recycle: Move check update code to dedicated file
|
||||
- :recycle: Move dom utils in dedicated file
|
||||
- :sparkles: Notify user about newer version
|
||||
- :sparkles: Add cache with service workers
|
||||
- :recycle: Cleanup directory structure
|
||||
- :heavy_plus_sign: Avoid using env specific syntax in npm scripts
|
||||
- changes PWA display
|
||||
## [1.1.1] - 2020-04-09
|
||||
### Fixed
|
||||
- :wrench: Fix parcel-plugin-sw-cache configuration
|
||||
### Added
|
||||
- :pencil: add CONTRIBUTORS
|
||||
### Changes
|
||||
- :pencil: change LICENCE ( #16 )
|
||||
## [1.1.2] - 2020-04-10
|
||||
### Added
|
||||
- ♿ Increase contrast ratio hover link color (#29)
|
||||
- ♿ Add landmarks roles to header, main and footer sections (#43)
|
||||
- ♿ Add title to open stores link and add more explicit text (#44, #45)
|
||||
- ♿ Expose aria-invalid field assistance technologies (#24)
|
||||
- ✨ Add timestamp to generated pdf (#9)
|
||||
- 💄 Don't use autocompletion for release date and time (#31)
|
||||
- 💄 Add underline on hover links
|
||||
### Fixes
|
||||
- Fix Typo site.webmanifest (#52)
|
||||
|
|
21
CONTRIBUTORS
|
@ -1,20 +1,13 @@
|
|||
Ce générateur d'attestation de déplacement dérogatoire a été mis en place dans le cadre du confinement lié à la pandémie du virus COVID-19 de 2020.
|
||||
Ce service repose sur l'utilisation initale du projet covid-19-certificate <https://github.com/nesk/covid-19-certificate> de Johann Pardanaud <https://github.com/nesk>.
|
||||
Ce générateur d'attestation de déplacement international dérogatoire a été mis en place dans le cadre du confinement lié à la pandémie du virus COVID-19 de 2020.
|
||||
Ce service repose sur l'utilisation initale du projet covid-19-certificate <https://github.com/nesk/covid-19-certificate> de Johann Pardanaud <https://github.com/nesk> et de l'attestation de déplacement nationale dérogatoire <https://github.com/LAB-MI/deplacement-covid-19> du ministère de l'intérieur.
|
||||
Il a été enrichi par l'incubateur du ministère de l'intérieur : le LAB-MI <https://beta.interieur.gouv.fr>.
|
||||
|
||||
La liste qui suit mentionne les différents participants ayant contribué à rendre ce service utile à la fois à la population et aux forces de l'ordre :
|
||||
|
||||
Johann Pardanaud (https://github.com/nesk)
|
||||
|
||||
La liste qui suit mentionne les différents participants ayant contribué à rendre ce service utile à la fois à la population et aux forces de l'ordre :
|
||||
|
||||
Philippe Bron (https://github.com/PhilippeBron)
|
||||
Cristian (https://github.com/cristianpb)
|
||||
Stanislas Ormières (https://github.com/laruiss)
|
||||
Caroline Robillard (https://github.com/Carolinedanslesnuages)
|
||||
Joel Pagniez (https://github.com/JoelPagniez)
|
||||
Sophie GUERLAIS
|
||||
Philippe (https://github.com/pli01)
|
||||
Matthieu Bacconnier (https://github.com/Neamar)
|
||||
Hugo Cartigny (https://github.com/BlueskyFR)
|
||||
Sébastien Touzé (https://github.com/SebastienTouze)
|
||||
John Livingston (https://github.com/JohnXLivingston)
|
||||
David Libeau (https://github.com/DavidLibeau)
|
||||
Arnaud Delafosse (https://github.com/ArnaudDelafosse)
|
||||
Victor Journé (https://github.com/victorjourne)
|
||||
Philippe (https://github.com/pli01)
|
|
@ -1,4 +1,4 @@
|
|||
# Générateur de certificat de déplacement
|
||||
# Générateur: ATTESTATION DE DÉPLACEMENT INTERNATIONAL DÉROGATOIRE VERS LA FRANCE MÉTROPOLITAINE
|
||||
|
||||
## Développer
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# Attestation de déplacement international dérogatoire vers la France métropolitaine
|
||||
|
||||
## Fichiers pdf des attestations papier :
|
||||
|
||||
- version française : 07-04-20-Attestation-etranger-metropole-FR.pdf
|
||||
- version anglaise : Attestation_deplacement_International_EN-1.pdf
|
||||
|
||||
## Analyse de la structure du document
|
||||
|
||||
### Champs ajoutés :
|
||||
|
||||
- nationalité
|
||||
- typologie de nationalités : pays tiers ; eu ou assimilés ; française
|
||||
|
||||
### Champs supprimés :
|
||||
|
||||
- lieu de naissance
|
||||
- date de sortie
|
||||
- heure de sortie
|
||||
|
||||
### Remarques :
|
||||
|
||||
- Les motifs sont identiques pour les types tiers et eu.
|
||||
- Pas de motif pour les français.
|
||||
- Un seul motif possible défini en fonction du type de nationalité
|
||||
|
||||
## Structure des champs du QR Code
|
||||
|
||||
- **Cree le:** creationDate a creationHour;\n
|
||||
- **Nom:** `firstname`;\n
|
||||
- **Prenom:** `lastname`;\n
|
||||
- **Naissance:** `birthday` (`nationality`);\n
|
||||
- **Adresse:** `address` `zipcode` `town` `country`;\n
|
||||
- **Sortie:** N/A;\n
|
||||
- **Motifs:** `national`-`reason` (`reaseon` à vide pour les français)
|
||||
|
||||
### Correspondances formulaire/QR Code
|
||||
|
||||
Afin de pouvoir être sotckées dans le QR Code, à chaque choix du formulaire est associé un alias.
|
||||
|
||||
#### types de nationalités
|
||||
|
||||
| libellé formulaire | alias |
|
||||
|:-----|:-----|
|
||||
| Ressortissants de pays tiers | tiers |
|
||||
| Ressortissants de l’Union européenne et assimilés | eu |
|
||||
| Ressortissants de nationalité française | fr |
|
||||
|
||||
#### types de motifs
|
||||
|
||||
| libellé formulaire | alias |
|
||||
|:-----|:-----|
|
||||
| Personnes ayant leur résidence principale en France | residence |
|
||||
| Personnes transitant par la France pour rejoindre leur résidence | transit |
|
||||
| Professionnels de santé aux fins de lutter contre le Covid-19 | prof._sante |
|
||||
| Transporteurs de marchandises | marchandises |
|
||||
| Equipages et personnels exploitant des vols | equipage |
|
||||
| Personnels des missions diplomatiques et consulaires | diplomatique |
|
||||
| Travailleurs frontaliers | frontalier |
|
|
@ -0,0 +1,52 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script src="https://unpkg.com/pdf-lib@1.4.1"></script>
|
||||
<script src="https://unpkg.com/downloadjs@1.4.7"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<label for="file">Sélectionner le pdf</label>
|
||||
<input type="file" id="file" name="file" onchange="generatePdf()">
|
||||
|
||||
</body>
|
||||
|
||||
<script>
|
||||
|
||||
const { PDFDocument, StandardFonts, rgb } = PDFLib
|
||||
|
||||
async function generatePdf () {
|
||||
var pdfBase = document.getElementById("file").files[0];
|
||||
var buffer = await pdfBase.arrayBuffer();
|
||||
|
||||
const pdfDoc = await PDFDocument.load(buffer)
|
||||
|
||||
const page1 = pdfDoc.getPages()[0]
|
||||
|
||||
const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
||||
const drawText = (text, x, y, size = 11) => {
|
||||
page1.drawText(text, { x, y, size, font })
|
||||
}
|
||||
|
||||
var x;
|
||||
var y;
|
||||
for (x = 25; x < 1000; x += 25) {
|
||||
for (y = 25; y < 1000; y += 25) {
|
||||
|
||||
page1.drawText('.', { x: x, y: y, size: 11, font: font, color: rgb(0.95, 0.1, 0.1) })
|
||||
page1.drawText(`${x}`, { x: x+3, y: y, size: 7, font: font, color: rgb(0, 0, 0) })
|
||||
page1.drawText(`${y}`, { x: x+3, y: y-6, size: 7, font: font, color: rgb(0, 0, 0) })
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pdfDoc.addPage()
|
||||
|
||||
const pdfBytes = await pdfDoc.save()
|
||||
|
||||
// Trigger the browser to download the PDF document
|
||||
download(pdfBytes, "grid.pdf", "application/pdf");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "deplacement-covid-19",
|
||||
"name": "deplacement-vers-france-covid-19",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
|
|
25
package.json
|
@ -1,15 +1,16 @@
|
|||
{
|
||||
"name": "deplacement-covid-19",
|
||||
"name": "deplacement-vers-france-covid-19",
|
||||
"version": "0.0.1",
|
||||
"description": "Générateur d'attestation de déplacement dérogatoire'",
|
||||
"description": "Générateur d'attestation de déplacement international dérogatoire vers la France",
|
||||
"main": "certificate.js",
|
||||
"scripts": {
|
||||
"lint": "eslint ./*.js",
|
||||
"start": "cross-env VERSION=${VERSION:-localversion} parcel --public-url ${PUBLIC_URL:-/deplacement-covid-19} ./src/index.html",
|
||||
"lint": "eslint src/*.js",
|
||||
"format": "npm run lint -- --fix",
|
||||
"start": "cross-env VERSION=${VERSION:-localversion} parcel --public-url ${PUBLIC_URL:-/deplacement-vers-france-covid-19} ./src/index.html",
|
||||
"clean:dist": "rimraf dist",
|
||||
"prebuild": "run-s lint clean:dist",
|
||||
"build": "parcel build --public-url ${PUBLIC_URL:-/deplacement-covid-19} ./src/index.html ./src/robots.txt ./src/sitemap.xml",
|
||||
"postbuild": "PUBLIC_URL=${PUBLIC_URL:-/deplacement-covid-19} react-snap",
|
||||
"build": "parcel build --public-url ${PUBLIC_URL:-/deplacement-vers-france-covid-19} ./src/index.html ./src/index-en.html ./src/robots.txt ./src/sitemap.xml",
|
||||
"postbuild": "PUBLIC_URL=${PUBLIC_URL:-/deplacement-vers-france-covid-19} react-snap",
|
||||
"preserve": "npm run build",
|
||||
"serve": "serve dist",
|
||||
"serve:dist": "serve dist"
|
||||
|
@ -19,7 +20,7 @@
|
|||
"url": "git+https://github.com/lab-mi/deplacement-covid-19"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"author": "Ministère de l'Intérieur",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lab-mi/deplacement-covid-19/issues"
|
||||
|
@ -55,7 +56,8 @@
|
|||
"qrcode": "^1.4.4"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 5 versions"
|
||||
"last 5 versions",
|
||||
"ios_saf >= 7"
|
||||
],
|
||||
"reactSnap": {
|
||||
"source": "dist",
|
||||
|
@ -73,6 +75,9 @@
|
|||
"strategy": "default",
|
||||
"clearDist": false,
|
||||
"templatedURLs": {
|
||||
"./": ["index.html"]
|
||||
} }
|
||||
"./": [
|
||||
"index.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 900 600" style="enable-background:new 0 0 900 600;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#ED2939;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#002395;}
|
||||
</style>
|
||||
<rect y="0" class="st0" width="900" height="600"/>
|
||||
<rect y="0" class="st1" width="600" height="600"/>
|
||||
<rect y="0" class="st2" width="300" height="600"/>
|
||||
</svg>
|
After Width: | Height: | Size: 606 B |
|
@ -0,0 +1,328 @@
|
|||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
|
||||
import './main.css'
|
||||
|
||||
import { PDFDocument, StandardFonts } from 'pdf-lib'
|
||||
import QRCode from 'qrcode'
|
||||
import { library, dom } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faEye, faFilePdf } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import './check-updates'
|
||||
import { $, $$ } from './dom-utils'
|
||||
import pdfBase from './Attestation_deplacement_International_EN-1.pdf'
|
||||
|
||||
library.add(faEye, faFilePdf)
|
||||
|
||||
dom.watch()
|
||||
|
||||
$('#radio-language-fr').addEventListener('click', async event => {
|
||||
window.location.href = `${process.env.PUBLIC_URL === '/' ? '' : process.env.PUBLIC_URL}/index.html`
|
||||
})
|
||||
|
||||
const generateQR = async text => {
|
||||
try {
|
||||
const opts = {
|
||||
errorCorrectionLevel: 'M',
|
||||
type: 'image/png',
|
||||
quality: 0.92,
|
||||
margin: 1,
|
||||
}
|
||||
return await QRCode.toDataURL(text, opts)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
function saveProfile () {
|
||||
for (const field of $$('#form-profile input')) {
|
||||
localStorage.setItem(field.id.substring('field-'.length), field.value)
|
||||
}
|
||||
}
|
||||
|
||||
function getProfile () {
|
||||
const fields = {}
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const name = localStorage.key(i)
|
||||
fields[name] = localStorage.getItem(name)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
function idealFontSize (font, text, maxWidth, minSize, defaultSize) {
|
||||
let currentSize = defaultSize
|
||||
let textWidth = font.widthOfTextAtSize(text, defaultSize)
|
||||
|
||||
while (textWidth > maxWidth && currentSize > minSize) {
|
||||
textWidth = font.widthOfTextAtSize(text, --currentSize)
|
||||
}
|
||||
|
||||
return (textWidth > maxWidth) ? null : currentSize
|
||||
}
|
||||
|
||||
async function generatePdf (profile, typeNationality, reasons) {
|
||||
const creationDate = new Date().toLocaleDateString('fr-FR')
|
||||
const creationHour = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }).replace(':', 'h')
|
||||
|
||||
const { lastname, firstname, birthday, nationality, address, zipcode, town, country } = profile
|
||||
|
||||
const data = [
|
||||
`Cree le: ${creationDate} a ${creationHour}`,
|
||||
`Nom: ${lastname}`,
|
||||
`Prenom: ${firstname}`,
|
||||
`Naissance: ${birthday} (${nationality})`,
|
||||
`Adresse: ${address} ${zipcode} ${town} ${country}`,
|
||||
'Sortie: N/A',
|
||||
`Motifs: ${typeNationality}-${reasons}`,
|
||||
].join(';\n ')
|
||||
|
||||
const existingPdfBytes = await fetch(pdfBase).then(res => res.arrayBuffer())
|
||||
|
||||
const pdfDoc = await PDFDocument.load(existingPdfBytes)
|
||||
const page1 = pdfDoc.getPages()[0]
|
||||
|
||||
const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
||||
const drawText = (text, x, y, size = 11) => {
|
||||
page1.drawText(text, { x, y, size, font })
|
||||
}
|
||||
|
||||
drawText(`${firstname} ${lastname}`, 125, 590)
|
||||
drawText(birthday, 125, 567)
|
||||
drawText(nationality, 125, 545)
|
||||
drawText(`${address} ${zipcode}`, 127, 527)
|
||||
drawText(`${town}, ${country}`, 127, 505)
|
||||
|
||||
if (typeNationality === 'tiers') {
|
||||
if (reasons.includes('residence')) {
|
||||
drawText('x', 49, 449, 19)
|
||||
}
|
||||
if (reasons.includes('transit')) {
|
||||
drawText('x', 49, 412, 19)
|
||||
}
|
||||
if (reasons.includes('prof._sante')) {
|
||||
drawText('x', 49, 385, 19)
|
||||
}
|
||||
if (reasons.includes('marchandises')) {
|
||||
drawText('x', 49, 370, 19)
|
||||
}
|
||||
if (reasons.includes('equipage')) {
|
||||
drawText('x', 49, 354, 19)
|
||||
}
|
||||
if (reasons.includes('diplomatique')) {
|
||||
drawText('x', 49, 339, 19)
|
||||
}
|
||||
if (reasons.includes('frontalier')) {
|
||||
drawText('x', 49, 313, 19)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeNationality === 'eu') {
|
||||
if (reasons.includes('resident')) {
|
||||
drawText('x', 49, 276, 19)
|
||||
}
|
||||
if (reasons.includes('transit')) {
|
||||
drawText('x', 49, 263, 19)
|
||||
}
|
||||
if (reasons.includes('prof._sante')) {
|
||||
drawText('x', 49, 250, 19)
|
||||
}
|
||||
if (reasons.includes('marchandises')) {
|
||||
drawText('x', 49, 238, 19)
|
||||
}
|
||||
if (reasons.includes('equipage')) {
|
||||
drawText('x', 49, 225, 19)
|
||||
}
|
||||
if (reasons.includes('diplomatique')) {
|
||||
drawText('x', 49, 212, 19)
|
||||
}
|
||||
if (reasons.includes('frontalier')) {
|
||||
drawText('x', 49, 189, 19)
|
||||
}
|
||||
}
|
||||
if (typeNationality === 'fr') {
|
||||
drawText('x', 49, 162, 19)
|
||||
}
|
||||
let locationSize = idealFontSize(font, profile.town, 83, 7, 11)
|
||||
|
||||
if (!locationSize) {
|
||||
alert('Le nom de la ville risque de ne pas être affiché correctement en raison de sa longueur. ' +
|
||||
'Essayez d\'utiliser des abréviations ("Saint" en "St." par exemple) quand cela est possible.')
|
||||
locationSize = 7
|
||||
}
|
||||
|
||||
// Fait à :
|
||||
drawText(profile.town, 395, 142, locationSize)
|
||||
// Le
|
||||
drawText(`${new Date().toLocaleDateString('fr-FR', { month: 'numeric', day: 'numeric' })}`, 488, 142)
|
||||
|
||||
const generatedQR = await generateQR(data)
|
||||
|
||||
const qrImage = await pdfDoc.embedPng(generatedQR)
|
||||
|
||||
page1.drawImage(qrImage, {
|
||||
x: 450,
|
||||
y: 572,
|
||||
width: 100,
|
||||
height: 100,
|
||||
})
|
||||
|
||||
pdfDoc.addPage()
|
||||
const page2 = pdfDoc.getPages()[1]
|
||||
page2.drawImage(qrImage, {
|
||||
x: 50,
|
||||
y: page2.getHeight() - 350,
|
||||
width: 300,
|
||||
height: 300,
|
||||
})
|
||||
|
||||
const pdfBytes = await pdfDoc.save()
|
||||
|
||||
return new Blob([pdfBytes], { type: 'application/pdf' })
|
||||
}
|
||||
|
||||
function downloadBlob (blob, fileName) {
|
||||
const link = document.createElement('a')
|
||||
const url = URL.createObjectURL(blob)
|
||||
link.href = url
|
||||
link.download = fileName
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
}
|
||||
|
||||
function getAndSaveReasons () {
|
||||
const values = $$('input[name="field-reason"]:checked')
|
||||
.map(x => x.value)
|
||||
.join('-')
|
||||
localStorage.setItem('reasons', values)
|
||||
return values
|
||||
}
|
||||
|
||||
function getAndSaveTypeNationality () {
|
||||
const typeNationality = $$('input[name="field-type-nationality"]:checked')
|
||||
.map(x => x.value)
|
||||
.join('-')
|
||||
localStorage.setItem('typeNationality', typeNationality)
|
||||
|
||||
return typeNationality
|
||||
}
|
||||
|
||||
// see: https://stackoverflow.com/a/32348687/1513045
|
||||
function isFacebookBrowser () {
|
||||
const ua = navigator.userAgent || navigator.vendor || window.opera
|
||||
return ua.includes('FBAN') || ua.includes('FBAV')
|
||||
}
|
||||
|
||||
if (isFacebookBrowser()) {
|
||||
$('#alert-facebook').value = 'ATTENTION !! Vous utilisez actuellement le navigateur Facebook, ce générateur ne fonctionne pas correctement au sein de ce navigateur ! Merci d\'ouvrir Chrome sur Android ou bien Safari sur iOS.'
|
||||
$('#alert-facebook').classList.remove('d-none')
|
||||
}
|
||||
|
||||
function addSlash () {
|
||||
$('#field-birthday').value = $('#field-birthday').value.replace(/^(\d{2})$/g, '$1/')
|
||||
$('#field-birthday').value = $('#field-birthday').value.replace(/^(\d{2})\/(\d{2})$/g, '$1/$2/')
|
||||
$('#field-birthday').value = $('#field-birthday').value.replace(/\/\//g, '/')
|
||||
}
|
||||
|
||||
$('#field-birthday').onkeyup = function () {
|
||||
const key = event.keyCode || event.charCode
|
||||
if (key === 8 || key === 46) {
|
||||
return false
|
||||
} else {
|
||||
addSlash()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const snackbar = $('#snackbar')
|
||||
|
||||
$('#generate-btn').addEventListener('click', async event => {
|
||||
event.preventDefault()
|
||||
|
||||
saveProfile()
|
||||
const typeNationality = getAndSaveTypeNationality()
|
||||
let reasons
|
||||
if (typeNationality === 'fr') {
|
||||
reasons = 'N/A'
|
||||
} else {
|
||||
reasons = getAndSaveReasons()
|
||||
}
|
||||
|
||||
const pdfBlob = await generatePdf(getProfile(), typeNationality, reasons)
|
||||
localStorage.clear()
|
||||
const creationDate = new Date().toLocaleDateString('fr-CA')
|
||||
const creationHour = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }).replace(':', '-')
|
||||
downloadBlob(pdfBlob, `attestation-${creationDate}_${creationHour}.pdf`)
|
||||
|
||||
snackbar.classList.remove('d-none')
|
||||
setTimeout(() => snackbar.classList.add('show'), 100)
|
||||
|
||||
setTimeout(function () {
|
||||
snackbar.classList.remove('show')
|
||||
setTimeout(() => snackbar.classList.add('d-none'), 500)
|
||||
}, 6000)
|
||||
})
|
||||
|
||||
$$('input').forEach(input => {
|
||||
const exempleElt = input.parentNode.parentNode.querySelector('.exemple')
|
||||
if (input.placeholder && exempleElt) {
|
||||
input.addEventListener('input', (event) => {
|
||||
if (input.value) {
|
||||
exempleElt.innerHTML = 'ex. : ' + input.placeholder
|
||||
} else {
|
||||
exempleElt.innerHTML = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const conditions = {
|
||||
'#field-firstname': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-lastname': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-birthday': {
|
||||
condition: 'pattern',
|
||||
pattern: /^([0][1-9]|[1-2][0-9]|30|31)\/([0][1-9]|10|11|12)\/(19[0-9][0-9]|20[0-1][0-9]|2020)/g,
|
||||
},
|
||||
'#field-nationality': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-address': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-town': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-zipcode': {
|
||||
condition: 'lenght',
|
||||
},
|
||||
'#field-country': {
|
||||
condition: 'length',
|
||||
},
|
||||
}
|
||||
|
||||
Object.keys(conditions).forEach(field => {
|
||||
$(field).addEventListener('input', () => {
|
||||
if (conditions[field].condition === 'pattern') {
|
||||
const pattern = conditions[field].pattern
|
||||
if ($(field).value.match(pattern)) {
|
||||
$(field).setAttribute('aria-invalid', 'false')
|
||||
} else {
|
||||
$(field).setAttribute('aria-invalid', 'true')
|
||||
}
|
||||
}
|
||||
if (conditions[field].condition === 'length') {
|
||||
if ($(field).value.length > 0) {
|
||||
$(field).setAttribute('aria-invalid', 'false')
|
||||
} else {
|
||||
$(field).setAttribute('aria-invalid', 'true')
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function addVersion () {
|
||||
document.getElementById('version').innerHTML = `${new Date().getFullYear()} - ${process.env.VERSION}`
|
||||
}
|
||||
addVersion()
|
|
@ -9,17 +9,19 @@ import { faEye, faFilePdf } from '@fortawesome/free-solid-svg-icons'
|
|||
|
||||
import './check-updates'
|
||||
import { $, $$ } from './dom-utils'
|
||||
import pdfBase from './certificate.pdf'
|
||||
import pdfBase from './07-04-20-Attestation-etranger-metropole-FR.pdf'
|
||||
|
||||
library.add(faEye, faFilePdf)
|
||||
|
||||
dom.watch()
|
||||
|
||||
var year, month, day
|
||||
$('#radio-language-en').addEventListener('click', async event => {
|
||||
window.location.href = `${process.env.PUBLIC_URL === '/' ? '' : process.env.PUBLIC_URL}/index-en.html`
|
||||
})
|
||||
|
||||
const generateQR = async text => {
|
||||
try {
|
||||
var opts = {
|
||||
const opts = {
|
||||
errorCorrectionLevel: 'M',
|
||||
type: 'image/png',
|
||||
quality: 0.92,
|
||||
|
@ -31,39 +33,9 @@ const generateQR = async text => {
|
|||
}
|
||||
}
|
||||
|
||||
function pad (str) {
|
||||
return String(str).padStart(2, '0')
|
||||
}
|
||||
|
||||
function setDateNow (date) {
|
||||
year = date.getFullYear()
|
||||
month = pad(date.getMonth() + 1) // Les mois commencent à 0
|
||||
day = pad(date.getDate())
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', setReleaseDateTime)
|
||||
|
||||
function setReleaseDateTime () {
|
||||
const loadedDate = new Date()
|
||||
setDateNow(loadedDate)
|
||||
const releaseDateInput = document.querySelector('#field-datesortie')
|
||||
releaseDateInput.value = `${year}-${month}-${day}`
|
||||
|
||||
const hour = pad(loadedDate.getHours())
|
||||
const minute = pad(loadedDate.getMinutes())
|
||||
|
||||
const releaseTimeInput = document.querySelector('#field-heuresortie')
|
||||
releaseTimeInput.value = `${hour}:${minute}`
|
||||
}
|
||||
|
||||
function saveProfile () {
|
||||
for (const field of $$('#form-profile input')) {
|
||||
if (field.id === 'field-datesortie') {
|
||||
var dateSortie = field.value.split('-')
|
||||
localStorage.setItem(field.id.substring('field-'.length), `${dateSortie[2]}/${dateSortie[1]}/${dateSortie[0]}`)
|
||||
} else {
|
||||
localStorage.setItem(field.id.substring('field-'.length), field.value)
|
||||
}
|
||||
localStorage.setItem(field.id.substring('field-'.length), field.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,23 +59,21 @@ function idealFontSize (font, text, maxWidth, minSize, defaultSize) {
|
|||
return (textWidth > maxWidth) ? null : currentSize
|
||||
}
|
||||
|
||||
async function generatePdf (profile, reasons) {
|
||||
async function generatePdf (profile, typeNationality, reasons) {
|
||||
const creationDate = new Date().toLocaleDateString('fr-FR')
|
||||
const creationHour = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }).replace(':', 'h')
|
||||
|
||||
const { lastname, firstname, birthday, lieunaissance, address, zipcode, town, datesortie, heuresortie } = profile
|
||||
const releaseHours = String(heuresortie).substring(0, 2)
|
||||
const releaseMinutes = String(heuresortie).substring(3, 5)
|
||||
const { lastname, firstname, birthday, nationality, address, zipcode, town, country } = profile
|
||||
|
||||
const data = [
|
||||
`Cree le: ${creationDate} a ${creationHour}`,
|
||||
`Nom: ${lastname}`,
|
||||
`Prenom: ${firstname}`,
|
||||
`Naissance: ${birthday} a ${lieunaissance}`,
|
||||
`Adresse: ${address} ${zipcode} ${town}`,
|
||||
`Sortie: ${datesortie} a ${releaseHours}h${releaseMinutes}`,
|
||||
`Motifs: ${reasons}`,
|
||||
].join('; ')
|
||||
`Naissance: ${birthday} (${nationality})`,
|
||||
`Adresse: ${address} ${zipcode} ${town} ${country}`,
|
||||
'Sortie: N/A',
|
||||
`Motifs: ${typeNationality}-${reasons}`,
|
||||
].join(';\n ')
|
||||
|
||||
const existingPdfBytes = await fetch(pdfBase).then(res => res.arrayBuffer())
|
||||
|
||||
|
@ -115,31 +85,61 @@ async function generatePdf (profile, reasons) {
|
|||
page1.drawText(text, { x, y, size, font })
|
||||
}
|
||||
|
||||
drawText(`${firstname} ${lastname}`, 123, 686)
|
||||
drawText(birthday, 123, 661)
|
||||
drawText(lieunaissance, 92, 638)
|
||||
drawText(`${address} ${zipcode} ${town}`, 134, 613)
|
||||
drawText(`${firstname} ${lastname}`, 125, 590)
|
||||
drawText(birthday, 125, 567)
|
||||
drawText(nationality, 125, 545)
|
||||
drawText(`${address} ${zipcode}`, 127, 527)
|
||||
drawText(`${town}, ${country}`, 127, 505)
|
||||
|
||||
if (reasons.includes('travail')) {
|
||||
drawText('x', 76, 527, 19)
|
||||
if (typeNationality === 'tiers') {
|
||||
if (reasons.includes('residence')) {
|
||||
drawText('x', 49, 449, 19)
|
||||
}
|
||||
if (reasons.includes('transit')) {
|
||||
drawText('x', 49, 412, 19)
|
||||
}
|
||||
if (reasons.includes('prof._sante')) {
|
||||
drawText('x', 49, 385, 19)
|
||||
}
|
||||
if (reasons.includes('marchandises')) {
|
||||
drawText('x', 49, 370, 19)
|
||||
}
|
||||
if (reasons.includes('equipage')) {
|
||||
drawText('x', 49, 354, 19)
|
||||
}
|
||||
if (reasons.includes('diplomatique')) {
|
||||
drawText('x', 49, 328, 19)
|
||||
}
|
||||
if (reasons.includes('frontalier')) {
|
||||
drawText('x', 49, 302, 19)
|
||||
}
|
||||
}
|
||||
if (reasons.includes('courses')) {
|
||||
drawText('x', 76, 478, 19)
|
||||
|
||||
if (typeNationality === 'eu') {
|
||||
if (reasons.includes('resident')) {
|
||||
drawText('x', 49, 265, 19)
|
||||
}
|
||||
if (reasons.includes('transit')) {
|
||||
drawText('x', 49, 249, 19)
|
||||
}
|
||||
if (reasons.includes('prof._sante')) {
|
||||
drawText('x', 49, 234, 19)
|
||||
}
|
||||
if (reasons.includes('marchandises')) {
|
||||
drawText('x', 49, 218, 19)
|
||||
}
|
||||
if (reasons.includes('equipage')) {
|
||||
drawText('x', 49, 202, 19)
|
||||
}
|
||||
if (reasons.includes('diplomatique')) {
|
||||
drawText('x', 49, 177, 19)
|
||||
}
|
||||
if (reasons.includes('frontalier')) {
|
||||
drawText('x', 49, 150, 19)
|
||||
}
|
||||
}
|
||||
if (reasons.includes('sante')) {
|
||||
drawText('x', 76, 436, 19)
|
||||
}
|
||||
if (reasons.includes('famille')) {
|
||||
drawText('x', 76, 400, 19)
|
||||
}
|
||||
if (reasons.includes('sport')) {
|
||||
drawText('x', 76, 345, 19)
|
||||
}
|
||||
if (reasons.includes('judiciaire')) {
|
||||
drawText('x', 76, 298, 19)
|
||||
}
|
||||
if (reasons.includes('missions')) {
|
||||
drawText('x', 76, 260, 19)
|
||||
if (typeNationality === 'fr') {
|
||||
drawText('x', 49, 127, 19)
|
||||
}
|
||||
let locationSize = idealFontSize(font, profile.town, 83, 7, 11)
|
||||
|
||||
|
@ -149,26 +149,18 @@ async function generatePdf (profile, reasons) {
|
|||
locationSize = 7
|
||||
}
|
||||
|
||||
drawText(profile.town, 111, 226, locationSize)
|
||||
|
||||
if (reasons !== '') {
|
||||
// Date sortie
|
||||
drawText(`${profile.datesortie}`, 92, 200)
|
||||
drawText(releaseHours, 200, 201)
|
||||
drawText(releaseMinutes, 220, 201)
|
||||
}
|
||||
|
||||
// Date création
|
||||
drawText('Date de création:', 464, 150, 7)
|
||||
drawText(`${creationDate} à ${creationHour}`, 455, 144, 7)
|
||||
// Fait à :
|
||||
drawText(profile.town, 388, 107, locationSize)
|
||||
// Le
|
||||
drawText(`${new Date().toLocaleDateString('fr-FR', { month: 'numeric', day: 'numeric' })}`, 488, 107)
|
||||
|
||||
const generatedQR = await generateQR(data)
|
||||
|
||||
const qrImage = await pdfDoc.embedPng(generatedQR)
|
||||
|
||||
page1.drawImage(qrImage, {
|
||||
x: page1.getWidth() - 170,
|
||||
y: 155,
|
||||
x: 450,
|
||||
y: 572,
|
||||
width: 100,
|
||||
height: 100,
|
||||
})
|
||||
|
@ -189,7 +181,7 @@ async function generatePdf (profile, reasons) {
|
|||
|
||||
function downloadBlob (blob, fileName) {
|
||||
const link = document.createElement('a')
|
||||
var url = URL.createObjectURL(blob)
|
||||
const url = URL.createObjectURL(blob)
|
||||
link.href = url
|
||||
link.download = fileName
|
||||
document.body.appendChild(link)
|
||||
|
@ -204,6 +196,15 @@ function getAndSaveReasons () {
|
|||
return values
|
||||
}
|
||||
|
||||
function getAndSaveTypeNationality () {
|
||||
const typeNationality = $$('input[name="field-type-nationality"]:checked')
|
||||
.map(x => x.value)
|
||||
.join('-')
|
||||
localStorage.setItem('typeNationality', typeNationality)
|
||||
|
||||
return typeNationality
|
||||
}
|
||||
|
||||
// see: https://stackoverflow.com/a/32348687/1513045
|
||||
function isFacebookBrowser () {
|
||||
const ua = navigator.userAgent || navigator.vendor || window.opera
|
||||
|
@ -237,12 +238,19 @@ $('#generate-btn').addEventListener('click', async event => {
|
|||
event.preventDefault()
|
||||
|
||||
saveProfile()
|
||||
const reasons = getAndSaveReasons()
|
||||
const pdfBlob = await generatePdf(getProfile(), reasons)
|
||||
const typeNationality = getAndSaveTypeNationality()
|
||||
let reasons
|
||||
if (typeNationality === 'fr') {
|
||||
reasons = 'N/A'
|
||||
} else {
|
||||
reasons = getAndSaveReasons()
|
||||
}
|
||||
|
||||
const pdfBlob = await generatePdf(getProfile(), typeNationality, reasons)
|
||||
localStorage.clear()
|
||||
const creationDate = new Date().toLocaleDateString('fr-CA')
|
||||
const creationHour = new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }).replace(':', '-')
|
||||
downloadBlob(pdfBlob, `attestation-${creationDate}_${creationHour}.pdf`)
|
||||
downloadBlob(pdfBlob, `attestation-${creationDate}_${creationHour}.pdf`)
|
||||
|
||||
snackbar.classList.remove('d-none')
|
||||
setTimeout(() => snackbar.classList.add('show'), 100)
|
||||
|
@ -275,9 +283,9 @@ const conditions = {
|
|||
},
|
||||
'#field-birthday': {
|
||||
condition: 'pattern',
|
||||
pattern: /^([0][1-9]|[1-2][0-9]|30|31)\/([0][1-9]|10|11|12)\/(19[0-9][0-9]|20[0-1][0-9]|2020)/g
|
||||
pattern: /^([0][1-9]|[1-2][0-9]|30|31)\/([0][1-9]|10|11|12)\/(19[0-9][0-9]|20[0-1][0-9]|2020)/g,
|
||||
},
|
||||
'#field-lieunaissance': {
|
||||
'#field-nationality': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-address': {
|
||||
|
@ -287,34 +295,28 @@ const conditions = {
|
|||
condition: 'length',
|
||||
},
|
||||
'#field-zipcode': {
|
||||
condition: 'pattern',
|
||||
pattern: /\d{5}/g
|
||||
condition: 'lenght',
|
||||
},
|
||||
'#field-datesortie': {
|
||||
condition: 'pattern',
|
||||
pattern: /\d{4}-\d{2}-\d{2}/g
|
||||
'#field-country': {
|
||||
condition: 'length',
|
||||
},
|
||||
'#field-heuresortie': {
|
||||
condition: 'pattern',
|
||||
pattern: /\d{2}:\d{2}/g
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(conditions).forEach(field => {
|
||||
$(field).addEventListener('input', () => {
|
||||
if (conditions[field].condition == 'pattern') {
|
||||
const pattern = conditions[field].pattern;
|
||||
if (conditions[field].condition === 'pattern') {
|
||||
const pattern = conditions[field].pattern
|
||||
if ($(field).value.match(pattern)) {
|
||||
$(field).setAttribute('aria-invalid', "false");
|
||||
$(field).setAttribute('aria-invalid', 'false')
|
||||
} else {
|
||||
$(field).setAttribute('aria-invalid', "true");
|
||||
$(field).setAttribute('aria-invalid', 'true')
|
||||
}
|
||||
}
|
||||
if (conditions[field].condition == 'length') {
|
||||
if (conditions[field].condition === 'length') {
|
||||
if ($(field).value.length > 0) {
|
||||
$(field).setAttribute('aria-invalid', "false");
|
||||
$(field).setAttribute('aria-invalid', 'false')
|
||||
} else {
|
||||
$(field).setAttribute('aria-invalid', "true");
|
||||
$(field).setAttribute('aria-invalid', 'true')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 1.1 KiB |
|
@ -14,26 +14,6 @@
|
|||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "apple-touch-icon.png",
|
||||
"sizes": "180x180",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "apple-touch-icon-precomposed.png",
|
||||
"sizes": "180x180",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "apple-touch-icon-120x120.png",
|
||||
"sizes": "120x120",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "apple-touch-icon-120x120-precomposed.png",
|
||||
"sizes": "120x120",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"orientation": "portrait-primary",
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="flag_EN" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 207 133.5" style="enable-background:new 0 0 207 133.5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#EDEDED;}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#CE0100;}
|
||||
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#1E359B;}
|
||||
.st3{fill:#EDEDED;}
|
||||
.st4{fill:#CC0B1B;}
|
||||
.st5{fill:#2C4DB5;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="9.7" y="38.3" class="st0" width="138.6" height="92.4"/>
|
||||
<polygon class="st1" points="148.3,76.8 148.3,92.3 85.8,92.3 85.8,130.7 72.2,130.7 72.2,92.3 9.7,92.3 9.7,76.8 72.2,76.8
|
||||
72.2,38.3 85.8,38.3 85.8,76.8 "/>
|
||||
<path class="st2" d="M22.5,38.3h46.2v30.5L22.5,38.3z M89.3,38.3h46.2L89.3,68.8V38.3z M148.3,47.8l-37.6,24.8h37.6V47.8z
|
||||
M110.7,96.5h37.6v24.8L110.7,96.5z M135.6,130.7l-46.2-30.5v30.5H135.6z M9.7,96.5h37.6L9.7,121.3V96.5z M68.7,100.3l-46.2,30.5
|
||||
h46.2V100.3z M47.3,72.6L9.7,47.8v24.8H47.3z"/>
|
||||
<g>
|
||||
<polygon class="st1" points="52.3,72.6 9.7,44.5 9.7,38.8 61,72.6 "/>
|
||||
<polygon class="st1" points="68.7,97.2 17.8,130.7 9.7,130.7 9.7,130.4 61.1,96.5 68.7,96.5 "/>
|
||||
<polygon class="st1" points="148.3,39 97.4,72.6 89.3,72.6 89.3,72.1 140.7,38.3 148.3,38.3 "/>
|
||||
<polygon class="st1" points="148.3,130 97.4,96.5 106.1,96.5 148.3,124.3 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="64" y="4.4" class="st3" width="138.6" height="92.4"/>
|
||||
<path class="st4" d="M64,89.7h138.6v7.1H64V89.7z M64,4.4h138.6v7.1H64V4.4z M64,18.6h138.6v7.1H64V18.6z M64,32.9h138.6V40H64
|
||||
V32.9z M64,47.1h138.6v7.1H64V47.1z M64,61.3h138.6v7.1H64V61.3z M64,75.5h138.6v7.1H64V75.5z"/>
|
||||
<rect x="64" y="4.4" class="st5" width="70.2" height="49.8"/>
|
||||
<path class="st3" d="M128.9,18.4l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2l-0.6-2l1.7-1.2H128.9z M71.1,9.7l1.7-1.2h-2.1
|
||||
l-0.6-2l-0.6,2h-2.1L69,9.7l-0.6,2l1.7-1.2l1.7,1.2L71.1,9.7z M82.7,9.7l1.7-1.2h-2.1l-0.6-2l-0.6,2H79l1.7,1.2l-0.6,2l1.7-1.2
|
||||
l1.7,1.2L82.7,9.7z M94.3,9.7L96,8.5H94l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L94.3,9.7z M106,9.7l1.7-1.2h-2.1
|
||||
l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L106,9.7z M77.2,44.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2
|
||||
l1.7,1.2L77.2,44.4z M77,34.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L77,34.7z M77,25l1.7-1.2h-2.1
|
||||
l-0.6-2l-0.6,2h-2.1L75,25l-0.6,2l1.7-1.2l1.7,1.2L77,25z M117.6,9.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2
|
||||
l1.7,1.2L117.6,9.7z M129.3,9.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L129.3,9.7z M88.7,25l1.7-1.2h-2.1
|
||||
l-0.6-2l-0.6,2h-2.1l1.7,1.2L86,27l1.7-1.2l1.7,1.2L88.7,25z M88.6,34.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2
|
||||
l1.7,1.2L88.6,34.7z M88.8,44.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L88.8,44.4z M100.5,44.4l1.7-1.2
|
||||
h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L100.5,44.4z M100.3,34.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2
|
||||
l1.7-1.2l1.7,1.2L100.3,34.7z M100.3,25l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L100.3,25z M76.9,14.7
|
||||
l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L76.9,14.7z M88.5,14.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2
|
||||
l-0.6,2l1.7-1.2l1.7,1.2L88.5,14.7z M112,25l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L112,25z M111.9,34.7
|
||||
l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L111.9,34.7z M112.1,44.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1
|
||||
l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L112.1,44.4z M123.8,44.4l1.7-1.2h-2.1l-0.6-2l-0.6,2H120l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2
|
||||
L123.8,44.4z M123.5,34.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L123.5,34.7z M123.6,25l1.7-1.2h-2.1
|
||||
l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L123.6,25z M100.2,14.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2
|
||||
l1.7-1.2l1.7,1.2L100.2,14.7z M111.8,14.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L111.8,14.7z
|
||||
M123.5,14.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L123.5,14.7z M71.4,49.4l1.7-1.2H71l-0.6-2l-0.6,2
|
||||
h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L71.4,49.4z M71.1,39.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2
|
||||
L71.1,39.7z M71.2,30l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L71.2,30z M82.8,30l1.7-1.2h-2.1l-0.6-2
|
||||
l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L82.8,30z M82.8,39.7l1.7-1.2h-2.1l-0.6-2l-0.6,2H79l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2
|
||||
L82.8,39.7z M83,49.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L83,49.4z M94.7,49.4l1.7-1.2h-2.1l-0.6-2
|
||||
l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L94.7,49.4z M94.4,39.7l1.7-1.2H94l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2
|
||||
L94.4,39.7z M94.5,30l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L94.5,30z M71.1,19.7l1.7-1.2h-2.1l-0.6-2
|
||||
l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L71.1,19.7z M82.7,19.7l1.7-1.2h-2.1l-0.6-2l-0.6,2H79l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2
|
||||
L82.7,19.7z M106.1,30l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L106.1,30z M106.1,39.7l1.7-1.2h-2.1l-0.6-2
|
||||
l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L106.1,39.7z M106.3,49.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2
|
||||
l1.7,1.2L106.3,49.4z M117.9,49.4l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L117.9,49.4z M129.6,49.4
|
||||
l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L129.6,49.4z M117.7,39.7l1.7-1.2h-2.1l-0.6-2l-0.6,2H114l1.7,1.2
|
||||
l-0.6,2l1.7-1.2l1.7,1.2L117.7,39.7z M129.4,39.7l1.7-1.2H129l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L129.4,39.7z
|
||||
M117.8,30l1.7-1.2h-2.1l-0.6-2l-0.6,2H114l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L117.8,30z M129.4,30l1.7-1.2H129l-0.6-2l-0.6,2h-2.1
|
||||
l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L129.4,30z M94.3,19.7l1.7-1.2H94l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L94.3,19.7z
|
||||
M106,19.7l1.7-1.2h-2.1l-0.6-2l-0.6,2h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L106,19.7z M117.6,19.7l1.7-1.2h-2.1l-0.6-2l-0.6,2
|
||||
h-2.1l1.7,1.2l-0.6,2l1.7-1.2l1.7,1.2L117.6,19.7z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1,378 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="msapplication-TileColor" content="#603cba">
|
||||
<meta name="msapplication-config" content="./favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="title" content="international travel certificate to mainland France - COVID-19">
|
||||
<meta name="description" content="Ce service officiel génère une version numérique de l’attestation déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.">
|
||||
<meta name="keywords" content="covid19, covid-19, certificate, travel, international, official, government">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="language" content="English">
|
||||
<meta property="og:title" content="Generator of international travel certificate to mainland France - 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 l’attestation 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/deplacement-vers-france-covid-19/" />
|
||||
<meta property="og:url" content="https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/" />
|
||||
<meta property="og:site_name" content="Generator of international travel certificate to mainland France - COVID-19" />
|
||||
<script type='application/ld+json'>{"@context":"http://www.schema.org","@type":"GovernmentOrganization","name":"Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine - COVID-19","description":"Ce service officiel génère une version numérique de l’attestation déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.","address":{"@type":"PostalAddress","addressCountry":"France"}}</script>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./favicons/favicon-16x16.png">
|
||||
<link rel="manifest" href="./favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="./favicons/safari-pinned-tab.svg" color="#21bf73">
|
||||
|
||||
<title>COVID-19 – Generator of international travel certificate to mainland France</title>
|
||||
</head>
|
||||
<body>
|
||||
<header role="banner" class="wrapper">
|
||||
<ul class="flex-justify">
|
||||
<img class="logo" src="/MIN_Interieur_RVB.svg" alt="Ministère de l'intérieur. Liberté, égalité, fraternité.">
|
||||
<fieldset class="form-language">
|
||||
<legend class="legend-language">Select your language</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-language" id="radio-language-en" value="en" checked>
|
||||
<label class="form-check-label" for="radio-language-en">ENGLISH</label>
|
||||
<img class="flags" src="flag EN.svg">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-language" id="radio-language-fr" value="fr">
|
||||
<label class="form-check-label" for="radio-language-fr">FRANCAIS</label>
|
||||
<img class="flags" src="Flag_of_France.svg">
|
||||
</div>
|
||||
</fieldset>
|
||||
</ul>
|
||||
<div>
|
||||
<h1 class="flex flex-wrap">
|
||||
<span class="covid-title">
|
||||
COVID-19
|
||||
</span>
|
||||
<span class="covid-subtitle">
|
||||
Generator of international travel certificate to mainland France
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p class="text-alert">
|
||||
Filled in data is exclusively stored on your mobile phone or computer.
|
||||
No information is collected by the Ministry of the Interior.
|
||||
The generated pdf certificate has a QR Code.
|
||||
This visual barcode makes it possible to read the information on your certificate at the time it was entered.
|
||||
It is readable with all generic QR code readers.
|
||||
</p>
|
||||
<p>
|
||||
This certificate must be presented to transportation companies, before boarding, by passengers travelling to
|
||||
mainland France. It must also be presented to border control authorities, for any type of border:
|
||||
|
||||
<ul>
|
||||
<li>European external borders of France (air, maritime, land including railway connections).</li>
|
||||
<li>European internal borders of France.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
<main role="main">
|
||||
<p class="alert alert-danger d-none" role="alert" id="alert-facebook"></p>
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<form id="form-profile" accept-charset="UTF-8">
|
||||
<h2 class="titre-2">Fill online your digital certificate :</h2>
|
||||
<p class="text-alert">All fields are mandatory.</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-firstname" id="field-firstname-label">First name</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-firstname"
|
||||
name="firstname"
|
||||
autocomplete="given-name"
|
||||
placeholder="Jean"
|
||||
required
|
||||
aria-invalid="true"
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-lastname" id="field-lastname-label">Surname</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-lastname"
|
||||
name="lastname"
|
||||
autocomplete="family-name"
|
||||
placeholder="Dupont"
|
||||
aria-invalid="true"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-birthday" id="field-birthday-label">Date of birth (dd/mm/yyyy)</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
pattern="^([0][1-9]|[1-2][0-9]|30|31)\/([0][1-9]|10|11|12)\/(19[0-9][0-9]|20[0-1][0-9]|2020)"
|
||||
inputmode="numeric"
|
||||
class="form-control"
|
||||
id="field-birthday"
|
||||
name="birthday"
|
||||
aria-invalid="true"
|
||||
autocomplete="bday"
|
||||
placeholder="01/01/1970"
|
||||
maxlength="10"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-nationality" id="field-nationality-label">Nationality</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-nationality"
|
||||
name="nationality"
|
||||
autocomplete="country-name"
|
||||
aria-invalid="true"
|
||||
placeholder="Belgian"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-address" id="field-address-label">Address</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-address"
|
||||
name="address"
|
||||
aria-invalid="true"
|
||||
autocomplete="address-line1"
|
||||
placeholder="999 avenue de Belgique"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-town" id="field-town-label">City</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-town"
|
||||
name="town"
|
||||
autocomplete="address-level1"
|
||||
aria-invalid="true"
|
||||
placeholder="Brussels"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-zipcode" id="field-zipcode-label" >Zip code</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-zipcode"
|
||||
name="zipcode"
|
||||
aria-invalid="true"
|
||||
autocomplete="postal-code"
|
||||
placeholder="1000"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-country" id="field-country-label">Country</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-country"
|
||||
name="country"
|
||||
autocomplete="country-name"
|
||||
aria-invalid="true"
|
||||
placeholder="Belgium"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<fieldset class="control">
|
||||
<legend class="titre-3">You are : </legend>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-tiers" value="tiers">
|
||||
<label class="form-nationality-label" for="radio-tiers">Third country nationals.</label>
|
||||
|
||||
<fieldset class='conditional'>
|
||||
<legend class="titre-4">Choose the reason :</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-residence-tiers" value="residence">
|
||||
<label class="form-check-label" for="radio-residence-tiers">Individuals having their primary residence in France or in the European Union or assimilated countries<a href="#footnote1">[1]</a>, who are holders of a French or European residence permit or valid long-stay visa, accompanied by their spouse and
|
||||
children.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-transit-tiers" value="transit">
|
||||
<label class="form-check-label" for="radio-transit-tiers">Individuals in transit to reach their country of origin who are holders of a travel document to their country of origin and remaining in the international area with no intention to enter the national territory.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-prof._sante-tiers" value="prof._sante">
|
||||
<label class="form-check-label" for="radio-prof._sante-tiers">Healthcare workers supporting the fight against Covid-19.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-marchandises-tiers" value="marchandises">
|
||||
<label class="form-check-label" for="radio-marchandises-tiers">Goods carriers, including seamen.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-equipage-tiers" value="equipage">
|
||||
<label class="form-check-label" for="radio-equipage-tiers">Flight and cargo crews, or travelling as a passenger to their departure base.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-diplomatique-tiers" value="diplomatique">
|
||||
<label class="form-check-label" for="radio-diplomatique-tiers">Diplomatic mission staff, or international organisations staff working in headquarters or offices located in France, who are holders of a special residence permit or a type D promae visa.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-frontalier-tiers" value="frontalier">
|
||||
<label class="form-check-label" for="radio-frontalier-tiers">Cross-border workers at internal land borders.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-eu" value="eu">
|
||||
<label class="form-nationality-label" for="radio-eu">European Union or assimilated countries nationals<a href="#footnote2">[2]</a>.</label>
|
||||
|
||||
<fieldset class='conditional'>
|
||||
<legend class="titre-4">Choose the reason :</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-residence-eu" value="residence">
|
||||
<label class="form-check-label" for="radio-residence-eu">Individuals having their primary residence in France, accompanied by their spouse and children.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-transit-eu" value="transit">
|
||||
<label class="form-check-label" for="radio-transit-eu">Individuals transiting through France to reach their residence, accompanied by their spouse and children.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-prof._sante-eu" value="prof._sante">
|
||||
<label class="form-check-label" for="radio-prof._sante-eu">Healthcare workers supporting the fight against Covid-19.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-marchandises-eu" value="marchandises">
|
||||
<label class="form-check-label" for="radio-marchandises-eu">Goods carriers, including seamen.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-equipage-eu" value="equipage">
|
||||
<label class="form-check-label" for="radio-equipage-eu">Flight and cargo crews, or travelling as a passenger to their departure base.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-diplomatique-eu" value="diplomatique">
|
||||
<label class="form-check-label" for="radio-diplomatique-eu">Diplomatic mission staff, or international organisations staff working in headquarters or offices located in France,
|
||||
who are hold ers of a special residence permit or a type D promae visa.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-frontalier" value="frontalier">
|
||||
<label class="form-check-label" for="radio-frontalier">Cross-border workers at internal land borders.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-fr" value="fr">
|
||||
<label class="form-nationality-label" for="radio-fr">French nationals, accompanied by their spouse and children.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<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> Generate my certificate</span></button>
|
||||
</p>
|
||||
|
||||
<div class="bg-primary d-none" id="snackbar">
|
||||
The certificate is downloaded on your terminal.
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="">
|
||||
<p id="footnotes">
|
||||
<span id="footnote1">[1] United Kingdom, Iceland, Liechtenstein, Norway, Andorra, Monaco, Switzerland, San Marino, Holy See.</span><br>
|
||||
<span id="footnote2">[2] European Union, United Kingdom, Iceland, Liechtenstein, Norway, Andorra, Monaco, Switzerland, San Marino and Holy See nationals (2004/38/CE directive).</span>
|
||||
</p>
|
||||
|
||||
<p class="github">
|
||||
The source code of this service is available for consultation on <a href="https://github.com/LAB-MI/deplacement-covid-19" class="github-link">GitHub</a>.
|
||||
</p>
|
||||
<p class="label-mi">
|
||||
Ministry of the Interior - DNUM - SDIT
|
||||
</p>
|
||||
<img class="center" src="/logo_dnum.svg" alt="logo dnum">
|
||||
</div>
|
||||
</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">Privacy policy</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">Legal notices</a>
|
||||
<a href="https://www.gouvernement.fr/info-coronavirus" title="Informations du gouvernement sur le Covid-19 - nouvelle page" target="_blank" class="footer-line footer-link">Government information on COVID-19</a>
|
||||
<div class="footer-line" >For more information, call <a class="num-08" href="tel:0800130000">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">
|
||||
A new version is available. Click on the button to get it.
|
||||
<p class="text-right">
|
||||
<button id="reload-btn" class="btn btn-info">Update</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="./certificate-en.js"></script>
|
||||
</body>
|
||||
</html>
|
266
src/index.html
|
@ -6,19 +6,19 @@
|
|||
<meta name="msapplication-TileColor" content="#603cba">
|
||||
<meta name="msapplication-config" content="./favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="title" content="Générateur d'attestation de déplacement dérogatoire - COVID-19">
|
||||
<meta name="title" content="Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine - COVID-19">
|
||||
<meta name="description" content="Ce service officiel génère une version numérique de l’attestation déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.">
|
||||
<meta name="keywords" content="covid19, covid-19, attestation, déplacement, officielle, gouvernement">
|
||||
<meta name="keywords" content="covid19, covid-19, attestation, déplacement, international, officielle, gouvernement">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="language" content="French">
|
||||
<meta property="og:title" content="Générateur d'attestation de déplacement dérogatoire - COVID-19" />
|
||||
<meta property="og:title" content="Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine - 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 l’attestation 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/deplacement-covid-19/" />
|
||||
<meta property="og:url" content="https://media.interieur.gouv.fr/deplacement-covid-19/" />
|
||||
<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 l’attestation déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.","address":{"@type":"PostalAddress","addressCountry":"France"}}</script>
|
||||
<link rel="canonical" href="https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/" />
|
||||
<meta property="og:url" content="https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/" />
|
||||
<meta property="og:site_name" content="Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine - COVID-19" />
|
||||
<script type='application/ld+json'>{"@context":"http://www.schema.org","@type":"GovernmentOrganization","name":"Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine - COVID-19","description":"Ce service officiel génère une version numérique de l’attestation déplacement covid-19 à présenter aux forces de sécurité lors d’un contrôle.","address":{"@type":"PostalAddress","addressCountry":"France"}}</script>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./favicons/favicon-32x32.png">
|
||||
|
@ -26,30 +26,50 @@
|
|||
<link rel="manifest" href="./favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="./favicons/safari-pinned-tab.svg" color="#21bf73">
|
||||
|
||||
<title>COVID-19 – Générateur d'attestation de déplacement dérogatoire</title>
|
||||
<title>COVID-19 – Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine</title>
|
||||
</head>
|
||||
<body>
|
||||
<header role="banner" class="wrapper">
|
||||
<img class="logo" src="/MIN_Interieur_RVB.svg" alt="Ministère de l'intérieur. Liberté, égalité, fraternité.">
|
||||
<ul class="flex-justify">
|
||||
<img class="logo" src="/MIN_Interieur_RVB.svg" alt="Ministère de l'intérieur. Liberté, égalité, fraternité.">
|
||||
<fieldset class="form-language">
|
||||
<legend class="legend-language">Choisissez votre langue</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-language" id="radio-language-en" value="en">
|
||||
<label class="form-check-label" for="radio-language-en">ENGLISH</label>
|
||||
<img class="flags" src="flag EN.svg">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-language" id="radio-language-fr" value="fr" checked>
|
||||
<label class="form-check-label" for="radio-language-fr">FRANCAIS</label>
|
||||
<img class="flags" src="Flag_of_France.svg">
|
||||
</div>
|
||||
</fieldset>
|
||||
</ul>
|
||||
<div>
|
||||
<h1 class="flex flex-wrap">
|
||||
<span class="covid-title">
|
||||
COVID-19
|
||||
</span>
|
||||
<span class="covid-subtitle">
|
||||
Générateur d'attestation de déplacement dérogatoire
|
||||
Générateur d'attestation de déplacement international dérogatoire vers la France métropolitaine
|
||||
</span>
|
||||
</h1>
|
||||
<p class="text-alert important">
|
||||
Cette application est <a href="#source">dérivée de l'application développée par le Ministère de l'Intérieur</a>.
|
||||
Elle est hébergé sur un serveur qui n'a <b>aucun lien avec les pouvoirs publics</b> et ne stocke aucune information (contrairement aux pratiques habituelles, les requêtes ne sont pas stockées dans les journaux du serveur).
|
||||
Elle est mise à votre disposition sans aucune garantie de bon fonctionnement !
|
||||
</p>
|
||||
|
||||
<p class="text-alert">
|
||||
Les données saisies sont stockées exclusivement sur votre téléphone ou votre ordinateur. Aucune information n'est collectée par le Ministère de l'Intérieur.
|
||||
L'attestation pdf générée contient un QR Code. Ce code-barres graphique permet de lire les informations portées dans votre attestation au moment de leur saisie.
|
||||
Il peut être déchiffré à l'aide de tout type de lecteur de QR code générique.
|
||||
</p>
|
||||
<p>
|
||||
Cette attestation est à présenter aux compagnies de transport, avant l’utilisation du titre de transport, par les
|
||||
passagers qui souhaitent voyager à destination de la France métropolitaine. Elle sera aussi présentée aux autorités en
|
||||
charge du contrôle frontières, pour tout type de frontière :
|
||||
<ul>
|
||||
<li>Aux frontières extérieures de la France (liaisons aériennes, maritimes, terrestres, dont les liaisons ferroviaires).</li>
|
||||
<li>Aux frontières intérieures de la France.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
<main role="main">
|
||||
|
@ -60,7 +80,7 @@
|
|||
<form id="form-profile" accept-charset="UTF-8">
|
||||
<h2 class="titre-2">Remplissez en ligne votre attestation numérique :</h2>
|
||||
<p class="text-alert">Tous les champs sont obligatoires.</p>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-firstname" id="field-firstname-label">Prénom</label>
|
||||
<div class="input-group align-items-center">
|
||||
|
@ -72,14 +92,13 @@
|
|||
autocomplete="given-name"
|
||||
placeholder="Jean"
|
||||
required
|
||||
autofocus
|
||||
aria-invalid="true"
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-lastname" id="field-lastname-label">Nom</label>
|
||||
<div class="input-group align-items-center">
|
||||
|
@ -92,13 +111,12 @@
|
|||
placeholder="Dupont"
|
||||
aria-invalid="true"
|
||||
required
|
||||
autofocus
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-birthday" id="field-birthday-label">Date de naissance (au format jj/mm/aaaa)</label>
|
||||
<div class="input-group align-items-center">
|
||||
|
@ -119,24 +137,25 @@
|
|||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-lieunaissance" id="field-lieunaissance-label">Lieu de naissance</label>
|
||||
<label for="field-nationality" id="field-nationality-label">Nationalité</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-lieunaissance"
|
||||
name="lieunaissance"
|
||||
id="field-nationality"
|
||||
name="nationality"
|
||||
autocomplete="country-name"
|
||||
aria-invalid="true"
|
||||
placeholder="Lyon"
|
||||
placeholder="Belge"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-address" id="field-address-label">Adresse</label>
|
||||
<div class="input-group align-items-center">
|
||||
|
@ -146,15 +165,15 @@
|
|||
id="field-address"
|
||||
name="address"
|
||||
aria-invalid="true"
|
||||
autocomplete="address-line1"
|
||||
placeholder="999 avenue de france"
|
||||
autocomplete="address-line1"
|
||||
placeholder="999 avenue de Belgique"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-town" id="field-town-label">Ville</label>
|
||||
<div class="input-group align-items-center">
|
||||
|
@ -165,91 +184,151 @@
|
|||
name="town"
|
||||
autocomplete="address-level1"
|
||||
aria-invalid="true"
|
||||
placeholder="Paris"
|
||||
placeholder="Bruxelles"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-zipcode" id="field-zipcode-label" >Code Postal</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9]{5}"
|
||||
min="00000"
|
||||
max="99999"
|
||||
class="form-control"
|
||||
id="field-zipcode"
|
||||
name="zipcode"
|
||||
aria-invalid="true"
|
||||
autocomplete="postal-code"
|
||||
minlength="4"
|
||||
maxlength="5"
|
||||
placeholder="75001"
|
||||
autocomplete="postal-code"
|
||||
placeholder="1000"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<legend class="title-3">Choisissez le ou les motif(s) de sortie</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-travail" value="travail">
|
||||
<label class="form-check-label" for="checkbox-travail">Déplacements entre le domicile et le lieu d’exercice de l’activité professionnelle, lorsqu'ils sont indispensables à l'exercice d’activités ne pouvant être organisées sous forme de télétravail ou déplacements professionnels ne pouvant être différés.</label>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-country" id="field-country-label">Pays</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="field-country"
|
||||
name="country"
|
||||
autocomplete="country-name"
|
||||
aria-invalid="true"
|
||||
placeholder="Belgique"
|
||||
required
|
||||
>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
|
||||
<p class="exemple"></p>
|
||||
</div>
|
||||
|
||||
<fieldset class="control">
|
||||
<legend class="titre-3">Vous êtes : </legend>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-courses" value="courses">
|
||||
<label class="form-check-label" for="checkbox-courses">Déplacements pour effectuer des achats de fournitures nécessaires à l’activité professionnelle et des achats de première nécessité dans des établissements dont les activités demeurent autorisées (<a href="https://www.service-public.fr/particuliers/actualites/A13921" class="stores-link" title="Liste des commerces et établissements qui restent ouverts - nouvelle page" target="_blank">liste des commerces et établissements qui restent ouverts</a>).</label>
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-tiers" value="tiers">
|
||||
<label class="form-nationality-label" for="radio-tiers">Ressortissant de pays tiers.</label>
|
||||
|
||||
<fieldset class='conditional'>
|
||||
<legend class="titre-4">Choisissez le motif :</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-residence-tiers" value="residence">
|
||||
<label class="form-check-label" for="radio-residence-tiers">Personnes ayant leur résidence principale en France ou dans l’Union européenne et pays assimilés<a href="#footnote1">[1]</a>, titulaires d’un titre de séjour ou d’un visa de long séjour français ou européen en cours de validité, ainsi que leurs conjoints et leurs enfants.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-transit-tiers" value="transit">
|
||||
<label class="form-check-label" for="radio-transit-tiers">Personnes en transit pour rejoindre leur pays d’origine, présentant le titre de voyage vers leur pays d’origine et
|
||||
restant en zone internationale sans entrer sur le territoire national.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-prof._sante-tiers" value="prof._sante">
|
||||
<label class="form-check-label" for="radio-prof._sante-tiers">Professionnels de santé aux fins de lutter contre le Covid-19.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-marchandises-tiers" value="marchandises">
|
||||
<label class="form-check-label" for="radio-marchandises-tiers">Transporteurs de marchandises, dont les marins.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-equipage-tiers" value="equipage">
|
||||
<label class="form-check-label" for="radio-equipage-tiers">Équipages et personnels exploitant des vols passagers et cargo, ou voyageant comme passagers pour se positionner sur leur base de départ.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-diplomatique-tiers" value="diplomatique">
|
||||
<label class="form-check-label" for="radio-diplomatique-tiers">Personnels des missions diplomatiques et consulaires, ainsi que des organisations internationales ayant leur siège
|
||||
ou un bureau en France, titulaires d’un titre de séjour spécial ou d’un visa D promae.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-frontalier-tiers" value="frontalier">
|
||||
<label class="form-check-label" for="radio-frontalier-tiers">Travailleurs frontaliers aux frontières intérieures terrestres.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-sante" value="sante">
|
||||
<label class="form-check-label" for="checkbox-sante">Consultations et soins ne pouvant être assurés à distance et ne pouvant être différés ; consultations et soins des patients atteints d'une affection de longue durée.</label>
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-eu" value="eu">
|
||||
<label class="form-nationality-label" for="radio-eu">Ressortissant de l’Union européenne et assimilés<a href="#footnote2">[2]</a>.</label>
|
||||
|
||||
<fieldset class='conditional'>
|
||||
<legend class="titre-4">Choisissez le motif</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-residence-eu" value="residence">
|
||||
<label class="form-check-label" for="radio-residence-eu">Personnes ayant leur résidence principale en France, ainsi que leurs conjoints et leurs enfants.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-transit-eu" value="transit">
|
||||
<label class="form-check-label" for="radio-transit-eu">Personnes transitant par la France pour rejoindre leur résidence, ainsi que leurs conjoints et leurs enfants.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-prof._sante-eu" value="prof._sante">
|
||||
<label class="form-check-label" for="radio-prof._sante-eu">Professionnels de santé aux fins de lutter contre le Covid-19.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-marchandises-eu" value="marchandises">
|
||||
<label class="form-check-label" for="radio-marchandises-eu">Transporteurs de marchandises, dont les marins.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-equipage-eu" value="equipage">
|
||||
<label class="form-check-label" for="radio-equipage-eu">Équipages et personnels exploitant des vols passagers et cargo, ou voyageant comme passagers pour se positionner sur leur base de départ.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-diplomatique-eu" value="diplomatique">
|
||||
<label class="form-check-label" for="radio-diplomatique-eu">Personnels des missions diplomatiques et consulaires, ainsi que des organisations internationales ayant leur siège
|
||||
ou un bureau en France, titulaires d’un titre de séjour spécial ou d’un visa D promae.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="field-reason" id="radio-frontalier" value="frontalier">
|
||||
<label class="form-check-label" for="radio-frontalier">Travailleurs frontaliers aux frontières intérieures terrestres.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-famille" value="famille">
|
||||
<label class="form-check-label" for="checkbox-famille">Déplacements pour motif familial impérieux, pour l’assistance aux personnes vulnérables ou la garde d’enfants.</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-sport" value="sport">
|
||||
<label class="form-check-label" for="checkbox-sport">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>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-judiciaire" value="judiciaire">
|
||||
<label class="form-check-label" for="checkbox-judiciaire">Convocation judiciaire ou administrative.</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="field-reason" id="checkbox-missions" value="missions">
|
||||
<label class="form-check-label" for="checkbox-missions">Participation à des missions d’intérêt général sur demande de l’autorité administrative.</label>
|
||||
<input class="form-check-input" type="radio" name="field-type-nationality" id="radio-fr" value="fr">
|
||||
<label class="form-nationality-label" for="radio-fr">Ressortissant de nationalité française, ainsi que votre conjoint et enfants.</label>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-datesortie">Date de sortie</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input type="date" class="form-control" id="field-datesortie" name="datesortie" autocomplete="off" placeholder="JJ/MM/YYYY" aria-invalid="true" required>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="field-heuresortie">Heure de sortie</label>
|
||||
<div class="input-group align-items-center">
|
||||
<input type="time" class="form-control" id="field-heuresortie" name="heure" autocomplete="off" aria-invalid="true" required>
|
||||
<span class="validity" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<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>
|
||||
|
@ -258,14 +337,21 @@
|
|||
L'attestation est téléchargée sur votre appareil.
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="">
|
||||
<p class="github" id="source">
|
||||
Le code source de ce service est dérivé de celui qui a été développé par le ministère de l'intérieur. La version d'origine est consultable sur <a href="https://github.com/LAB-MI/deplacement-covid-19" class="github-link">Github (Microsoft)</a>. La version dérivée est consultable sur <a href="https://gitea.dyomedea.com/vdv/deplacement-covid-19" class="github-link">Gitea (Open Source)</a>. L'application est hébergée dans un container Docker dont le source est également <a href="https://gitea.dyomedea.com/vdv/docker-deplacement-covid-19" class="github-link">public</a>.
|
||||
<p id="footnotes">
|
||||
<span id="footnote1">[1] Royaume-Uni, Islande, Liechtenstein, Norvège, Andorre, Monaco, Suisse, Saint-Marin, Saint Siège.</span><br>
|
||||
<span id="footnote2">[2] Ressortissants de l’Union européenne et ressortissants britanniques, ainsi que les ressortissants islandais, liechtensteinois, norvégiens, andorrans, monégasques, suisses, saint-marinais, citoyens du Saint Siège (directive 2004/38/CE).</span>
|
||||
</p>
|
||||
|
||||
<p class="github">
|
||||
Le code source de ce service est consultable sur <a href="https://github.com/LAB-MI/deplacement-covid-19" class="github-link">Github</a>.
|
||||
</p>
|
||||
<p class="label-mi">
|
||||
Ministère de l'Intérieur - DNUM - SDIT
|
||||
</p>
|
||||
</p>
|
||||
<img class="center" src="/logo_dnum.svg" alt="logo dnum">
|
||||
</div>
|
||||
</main>
|
||||
|
@ -273,11 +359,11 @@
|
|||
<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>
|
||||
<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">0 800 130 000</a></div>
|
||||
<p class="footer-line" id="version"></p>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
||||
|
||||
<div class="alert alert-info d-none" id="update-alert">
|
||||
Une nouvelle version est disponible. Cliquer sur le bouton pour l'obtenir.
|
||||
|
|
66
src/main.css
|
@ -29,14 +29,14 @@ h1 {
|
|||
}
|
||||
|
||||
/* Small devices (landscape phones, 576px and up) */
|
||||
@media (min-width: 576px) {
|
||||
@media (min-width: 576px) {
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Medium devices (tablets, 768px and up) */
|
||||
@media (min-width: 768px) {
|
||||
@media (min-width: 768px) {
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
@ -46,6 +46,14 @@ svg {
|
|||
height: 1em;
|
||||
}
|
||||
|
||||
ul.flex-justify {
|
||||
display: -webkit-flex; /* Safari */
|
||||
-webkit-align-items: center; /* Safari 7.0+ */
|
||||
justify-content:space-between;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1.flex.flex-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -83,6 +91,11 @@ a {
|
|||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
#form-profile .form-nationality-label {
|
||||
font-weight: 800;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
#form-generate .form-check {
|
||||
margin: 10px;
|
||||
}
|
||||
|
@ -155,6 +168,27 @@ input:valid+span:after {
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
fieldset .form-language {
|
||||
display: flex;
|
||||
align-items: right;
|
||||
}
|
||||
|
||||
.legend-language {
|
||||
text-align: left;
|
||||
font-size: 1rem;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.form-language .form-check-label {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.flags {
|
||||
width: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.covid-title {
|
||||
display: flex;
|
||||
|
@ -185,11 +219,10 @@ input:valid+span:after {
|
|||
|
||||
.text-alert{
|
||||
text-align: left;
|
||||
font-style: italic;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.btn-attestation {
|
||||
padding: 0.9em;
|
||||
font-size: 1.2em;
|
||||
|
@ -204,7 +237,7 @@ input:valid+span:after {
|
|||
}
|
||||
|
||||
.github {
|
||||
font-size: 1em;
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
color: #000000;
|
||||
|
||||
|
@ -308,13 +341,13 @@ input:valid+span:after {
|
|||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
em {
|
||||
font-size: .8rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.titre-2 {
|
||||
text-align: left;
|
||||
font-size: 1.5rem;
|
||||
|
@ -402,6 +435,21 @@ input:valid+span:after {
|
|||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.important {
|
||||
font-style: italic;
|
||||
.control:not(:checked) ~ .conditional,
|
||||
#radio-fr:not(:checked) ~ .conditional,
|
||||
#radio-eu:not(:checked) ~ .conditional,
|
||||
#radio-tiers:not(:checked) ~ .conditional {
|
||||
clip: rect(0 0 0 0);
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
[id^="footnote"] {
|
||||
margin: 30px auto;
|
||||
max-width: 400px;
|
||||
font-size: 0.8em;
|
||||
color: #000000;
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Sitemap: https://media.interieur.gouv.fr/deplacement-covid-19/sitemap.xml
|
||||
Sitemap: https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/sitemap.xml
|
||||
|
|
|
@ -8,20 +8,20 @@
|
|||
|
||||
|
||||
<url>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-covid-19/</loc>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/</loc>
|
||||
<lastmod>2020-04-06T04:22:03+00:00</lastmod>
|
||||
<priority>1.00</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-covid-19/confidentialite.html</loc>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/confidentialite.html</loc>
|
||||
<lastmod>2020-04-06T04:22:03+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-covid-19/index.html</loc>
|
||||
<loc>https://media.interieur.gouv.fr/deplacement-vers-france-covid-19/index.html</loc>
|
||||
<lastmod>2020-04-06T04:22:03+00:00</lastmod>
|
||||
<priority>0.64</priority>
|
||||
</url>
|
||||
|
||||
|
||||
</urlset>
|
||||
</urlset>
|
||||
|
|