Added browser warning and minor layout and content improvements

This commit is contained in:
Marvin Sextro 2021-12-02 01:02:20 +01:00
parent 790bdf4494
commit 22c00b4052
16 changed files with 62 additions and 77 deletions

View File

@ -1,24 +1,22 @@
import {useTranslation} from 'next-i18next';
interface AlertProps { interface AlertProps {
onClose: () => void; onClose: () => void;
errorMessage: string; message: string;
isWarning: boolean;
} }
function Alert(props: AlertProps): JSX.Element { function Alert(props: AlertProps): JSX.Element {
const { t } = useTranslation(['index', 'errors']);
return ( return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 mt-5 rounded relative" role="alert"> <div className={`${props.isWarning ? "bg-yellow-100 border border-yellow-400 text-yellow-700" : "bg-red-100 border border-red-400 text-red-700"} px-4 py-3 mt-5 rounded-md relative flex justify-between items-center`} role="alert">
<span className="block sm:inline pr-6" id="message">{props.errorMessage}</span> <span className={`${props.isWarning ? "" : "pr-7"} block sm:inline text-lg`} id="message">{props.message}</span>
<span className="absolute top-0 bottom-0 right-0 px-4 py-3" onClick={props.onClose}> {
<svg className="fill-current h-6 w-6 text-red-500" role="button" xmlns="http://www.w3.org/2000/svg" !props.isWarning &&
viewBox="0 0 20 20"> <span className="absolute top-0 right-0 p-1 m-2" onClick={props.onClose}>
<title>{t('index:errorClose')}</title> <svg className="text-red-500 fill-current h-6 w-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path fill="currentColor"
d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/> d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z" />
</svg> </svg>
</span> </span>
}
</div> </div>
) )
} }

View File

@ -1,20 +1,16 @@
import {useTranslation} from 'next-i18next';
interface CheckProps { interface CheckProps {
text: string; text: string;
} }
function Check(props: CheckProps): JSX.Element { function Check(props: CheckProps): JSX.Element {
const { t } = useTranslation(["index"]); return (
<li className="flex flex-row space-x-4 items-center">
return ( <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mx-2 fill-current text-green-500" viewBox="0 0 20 20" fill="currentColor">
<li className="flex flex-row space-x-4 items-center"> <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mx-2 fill-current text-green-500" viewBox="0 0 20 20" fill="currentColor"> </svg>
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" /> {props.text}
</svg> </li>
{props.text} )
</li>
)
} }
export default Check; export default Check;

View File

@ -59,6 +59,21 @@ function Form(): JSX.Element {
}); });
} }
}, [inputFile]) }, [inputFile])
// Whether Safari is used or not
let [isSafari, setIsSafari] = useState<boolean>(false);
// Check if Safari is used
useEffect(() => {
const navigator = window.navigator;
setIsSafari(
navigator.vendor &&
navigator.vendor.indexOf('Apple') > -1 &&
navigator.userAgent &&
navigator.userAgent.indexOf('CriOS') == -1 &&
navigator.userAgent.indexOf('FxiOS') == -1
)
}, []);
// Show file Dialog // Show file Dialog
async function showFileDialog() { async function showFileDialog() {
@ -102,7 +117,7 @@ function Form(): JSX.Element {
// Start decoding from video device // Start decoding from video device
await codeReader.decodeFromVideoDevice(undefined, await codeReader.decodeFromVideoDevice(undefined,
previewElem, previewElem,
(result, error, controls) => { (result, _error, controls) => {
if (result !== undefined) { if (result !== undefined) {
setQrCode(result); setQrCode(result);
setFile(undefined); setFile(undefined);
@ -113,9 +128,6 @@ function Form(): JSX.Element {
setGlobalControls(undefined); setGlobalControls(undefined);
setIsCameraOpen(false); setIsCameraOpen(false);
} }
if (error !== undefined) {
setErrorMessage(error.message);
}
} }
) )
); );
@ -164,6 +176,9 @@ function Form(): JSX.Element {
return ( return (
<div> <div>
<form className="space-y-5" id="form" onSubmit={addToWallet}> <form className="space-y-5" id="form" onSubmit={addToWallet}>
{
!isSafari && <Alert isWarning={true} message={t('iosHint')} onClose={() => {}}/>
}
<Card step="1" heading={t('index:selectCertificate')} content={ <Card step="1" heading={t('index:selectCertificate')} content={
<div className="space-y-5"> <div className="space-y-5">
<p>{t('index:selectCertificateDescription')}</p> <p>{t('index:selectCertificateDescription')}</p>
@ -171,13 +186,13 @@ function Form(): JSX.Element {
<button <button
type="button" type="button"
onClick={isCameraOpen ? hideCameraView : showCameraView} onClick={isCameraOpen ? hideCameraView : showCameraView}
className="focus:outline-none h-20 bg-gray-500 hover:bg-gray-700 text-white font-semibold rounded-md"> className="focus:outline-none h-20 bg-gray-400 dark:bg-gray-600 hover:bg-gray-500 text-white font-semibold rounded-md">
{isCameraOpen ? t('index:stopCamera') : t('index:startCamera')} {isCameraOpen ? t('index:stopCamera') : t('index:startCamera')}
</button> </button>
<button <button
type="button" type="button"
onClick={showFileDialog} onClick={showFileDialog}
className="focus:outline-none h-20 bg-gray-500 hover:bg-gray-700 text-white font-semibold rounded-md"> className="focus:outline-none h-20 bg-gray-400 dark:bg-gray-600 hover:bg-gray-500 text-white font-semibold rounded-md">
{t('index:openFile')} {t('index:openFile')}
</button> </button>
</div> </div>
@ -195,7 +210,7 @@ function Form(): JSX.Element {
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<svg className="h-4 w-4 text-green-600" fill="none" viewBox="0 0 24 24" <svg className="h-4 w-4 text-green-600" fill="none" viewBox="0 0 24 24"
stroke="currentColor"> stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7"/> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M9 5l7 7-7 7"/>
</svg> </svg>
<span className="w-full truncate"> <span className="w-full truncate">
{ {
@ -264,7 +279,7 @@ function Form(): JSX.Element {
</form> </form>
<canvas id="canvas" style={{display: "none"}}/> <canvas id="canvas" style={{display: "none"}}/>
{ {
errorMessage && <Alert errorMessage={errorMessage} onClose={() => setErrorMessage(undefined)}/> errorMessage && <Alert isWarning={false} message={errorMessage} onClose={() => setErrorMessage(undefined)}/>
} }
</div> </div>
) )

View File

@ -24,7 +24,7 @@ function Page(props: PageProps): JSX.Element {
{props.content} {props.content}
<footer> <footer>
<nav className="nav flex pt-4 flex-row space-x-4 justify-center text-md font-bold flex-wrap"> <nav className="nav flex flex-row space-x-4 justify-center text-md font-bold flex-wrap">
<a href="https://ko-fi.com/marvinsxtr" className="hover:underline">{t('common:donate')}</a> <a href="https://ko-fi.com/marvinsxtr" className="hover:underline">{t('common:donate')}</a>
<a href="https://github.com/marvinsxtr/covidpass" className="hover:underline">{t('common:gitHub')}</a> <a href="https://github.com/marvinsxtr/covidpass" className="hover:underline">{t('common:gitHub')}</a>
<Link href="/privacy"><a className="hover:underline">{t('common:privacyPolicy')}</a></Link> <Link href="/privacy"><a className="hover:underline">{t('common:privacyPolicy')}</a></Link>

View File

@ -12,14 +12,10 @@ function Imprint(): JSX.Element {
<Card step="§" heading={t('common:imprint')} content={ <Card step="§" heading={t('common:imprint')} content={
<div className="space-y-3"> <div className="space-y-3">
<p className="font-bold">{t('imprint:heading')}</p> <p className="font-bold">{t('imprint:heading')}</p>
<p> <p>Marvin Sextro</p>
Marvin Sextro<br />
Wilhelm-Busch-Str. 8A<br />
30167 Hannover<br />
</p>
<p className="font-bold">{t('imprint:contact')}</p> <p className="font-bold">{t('imprint:contact')}</p>
<p> <p>
<a href="mailto:marvin.sextro@gmail.com" className="underline">marvin.sextro@gmail.com</a> <a href="mailto:covidpass@marvinsextro.de" className="underline">covidpass@marvinsextro.de</a>
</p> </p>
<p className="font-bold">{t('imprint:euDisputeResolution')}</p> <p className="font-bold">{t('imprint:euDisputeResolution')}</p>
<p>{t('imprint:euDisputeResolutionParagraph')}</p> <p>{t('imprint:euDisputeResolutionParagraph')}</p>

View File

@ -40,9 +40,8 @@ function Index(): JSX.Element {
<Page content={ <Page content={
<div className="space-y-5"> <div className="space-y-5">
<Card content={ <Card content={
<p>{t('common:subtitle')}&nbsp;{t('index:iosHint')}</p> <p>{t('common:subtitle')}</p>
}/> }/>
<Form/> <Form/>
</div> </div>
}/> }/>

View File

@ -49,12 +49,11 @@ function Privacy(): JSX.Element {
</div> </div>
<p className="font-bold">{t('privacy:contact')}</p> <p className="font-bold">{t('privacy:contact')}</p>
<p> <p>
Marvin Sextro<br/> Marvin Sextro
Wilhelm-Busch-Str. 8A<br/> <br/>
30167 Hannover<br/>
{t('privacy:email')}: {t('privacy:email')}:
&nbsp; &nbsp;
<a href="mailto:marvin.sextro@gmail.com">marvin.sextro@gmail.com</a> <a href="mailto:covidpass@marvinsextro.de" className="underline">covidpass@marvinsextro.de</a>
<br/> <br/>
{t('privacy:website')}: {t('privacy:website')}:
&nbsp; &nbsp;
@ -137,9 +136,9 @@ function Privacy(): JSX.Element {
</a> </a>
</li> </li>
<li> <li>
PayPal: Ko-fi:
&nbsp; &nbsp;
<a href="https://www.paypal.com/de/webapps/mpp/ua/privacy-full?locale.x=en_EN" className="underline"> <a href="https://more.ko-fi.com/privacy" className="underline">
{t('common:privacyPolicy')} {t('common:privacyPolicy')}
</a> </a>
</li> </li>

View File

@ -1,9 +1,7 @@
iosHint: Bitte verwende unter iOS den Safari Browser. iosHint: Bitte verwende unter iOS den Safari Browser.
errorClose: Schließen errorClose: Schließen
selectCertificate: Zertifikat auswählen selectCertificate: Zertifikat auswählen
selectCertificateDescription: | selectCertificateDescription: Scanne den QR-Code auf Deinem Zertifikat oder wähle einen Screenshot oder eine PDF-Datei mit dem QR-Code.
Scanne den QR-Code auf Deinem Zertifikat oder wähle einen Screenshot oder eine PDF-Datei mit dem QR-Code.
Bitte beachte, dass die Auswahl einer Datei direkt von der Kamera nicht unterstützt wird.
stopCamera: Kamera stoppen stopCamera: Kamera stoppen
startCamera: Kamera starten startCamera: Kamera starten
openFile: Datei auswählen openFile: Datei auswählen

View File

@ -1,9 +1,7 @@
iosHint: Στο iOS, παρακαλώ χρησιμοποιήστε τον περιηγητή Safari. iosHint: Στο iOS, παρακαλώ χρησιμοποιήστε τον περιηγητή Safari.
errorClose: Κλείσιμο errorClose: Κλείσιμο
selectCertificate: Επιλογή Πιστοποιητικού selectCertificate: Επιλογή Πιστοποιητικού
selectCertificateDescription: | selectCertificateDescription: Παρακαλώ σαρώστε τον κωδικό QR του πιστοποιητικού σας ή επιλέξτε ένα στιγμιότυπο οθόνης ή την σελίδα PDF με τον κωδικό QR.
Παρακαλώ σαρώστε τον κωδικό QR του πιστοποιητικού σας ή επιλέξτε ένα στιγμιότυπο οθόνης ή την σελίδα PDF με τον κωδικό QR.
Λάβετε υπόψη πως η απευθείας επιλογή κάποιου αρχείου μέσω της κάμερας, δεν υποστηρίζεται.
stopCamera: Τερματισμός Κάμερας stopCamera: Τερματισμός Κάμερας
startCamera: Εκκίνηση Κάμερας startCamera: Εκκίνηση Κάμερας
openFile: Επιλογή Αρχείου openFile: Επιλογή Αρχείου

View File

@ -1,9 +1,7 @@
iosHint: On iOS, please use the Safari Browser. iosHint: On iOS, please use the Safari Browser.
errorClose: Close errorClose: Close
selectCertificate: Select Certificate selectCertificate: Select Certificate
selectCertificateDescription: | selectCertificateDescription: Please scan the QR code on your certificate or select a screenshot or PDF page with the QR code.
Please scan the QR code on your certificate or select a screenshot or PDF page with the QR code.
Note that selecting a file directly from camera is not supported.
stopCamera: Stop Camera stopCamera: Stop Camera
startCamera: Start Camera startCamera: Start Camera
openFile: Select File openFile: Select File

View File

@ -1,9 +1,7 @@
iosHint: En iOS, Por favor use el navegador Safari. iosHint: En iOS, Por favor use el navegador Safari.
errorClose: Cerrar errorClose: Cerrar
selectCertificate: Seleccione Certificado selectCertificate: Seleccione Certificado
selectCertificateDescription: | selectCertificateDescription: Escanee el código QR de su certificado, o seleccione una captura de pantalla o un PDF que contenga el código QR.
Escanee el código QR de su certificado, o seleccione una captura de pantalla o un PDF que contenga el código QR.
Tenga en cuenta que no se admite la selección de un archivo directamente desde la cámara.
stopCamera: Detener Cámara stopCamera: Detener Cámara
startCamera: Iniciar Cámara startCamera: Iniciar Cámara
openFile: Seleccione archivo openFile: Seleccione archivo

View File

@ -1,9 +1,7 @@
iosHint: Käytä iOS:ssä Safari-selainta. iosHint: Käytä iOS:ssä Safari-selainta.
errorClose: Sulje errorClose: Sulje
selectCertificate: Valitse todistus selectCertificate: Valitse todistus
selectCertificateDescription: | selectCertificateDescription: Skannaa todistuksessa oleva QR-koodi tai valitse kuvakaappaus tai PDF-sivu, jossa on QR-koodi.
Skannaa todistuksessa oleva QR-koodi tai valitse kuvakaappaus tai PDF-sivu, jossa on QR-koodi.
Huomaa, että tiedoston valitsemista suoraan kamerasta ei tueta.
stopCamera: Lopeta Kamera stopCamera: Lopeta Kamera
startCamera: Käynnistä Kamera startCamera: Käynnistä Kamera
openFile: Valitse Tiedosto openFile: Valitse Tiedosto

View File

@ -1,9 +1,7 @@
iosHint: Sur iOS, veuillez utiliser le navigateur Safari. iosHint: Sur iOS, veuillez utiliser le navigateur Safari.
errorClose: Fermez errorClose: Fermez
selectCertificate: Sélectionner le certificat selectCertificate: Sélectionner le certificat
selectCertificateDescription: | selectCertificateDescription: Veuillez scanner le QR Code de votre certificat ou sélectionner une capture d'écran ou une page PDF avec le QR Code.
Veuillez scanner le QR Code de votre certificat ou sélectionner une capture d'écran ou une page PDF avec le QR Code.
Notez que la sélection d'un fichier directement à partir de l'appareil photo n'est pas prise en charge.
stopCamera: Arrêter l'appareil photo stopCamera: Arrêter l'appareil photo
startCamera: Démarrer l'appareil photo startCamera: Démarrer l'appareil photo
openFile: Sélectionner un fichier openFile: Sélectionner un fichier

View File

@ -1,9 +1,7 @@
iosHint: Su iOS, si prega di utilizzare il browser Safari. iosHint: Su iOS, si prega di utilizzare il browser Safari.
errorClose: Chiudi errorClose: Chiudi
selectCertificate: Seleziona il certificato selectCertificate: Seleziona il certificato
selectCertificateDescription: | selectCertificateDescription: Scannerizza il codice QR sul tuo certificato o seleziona uno screenshot o una pagina PDF con il codice QR.
Scannerizza il codice QR sul tuo certificato o seleziona uno screenshot o una pagina PDF con il codice QR.
Nota che la selezione di un file direttamente dalla fotocamera non è supportata.
stopCamera: Blocca Fotocamera stopCamera: Blocca Fotocamera
startCamera: Avvia Fotocamera startCamera: Avvia Fotocamera
openFile: Seleziona un File openFile: Seleziona un File

View File

@ -1,9 +1,7 @@
iosHint: På iOS, vennligst bruk Safari nettleseren. iosHint: På iOS, vennligst bruk Safari nettleseren.
errorClose: Lukk errorClose: Lukk
selectCertificate: Velg Sertifikat selectCertificate: Velg Sertifikat
selectCertificateDescription: | selectCertificateDescription: Skann QR-koden på sertifikatet ditt, eller velg et skjermbilde eller en PDF med QR-koden.
Skann QR-koden på sertifikatet ditt, eller velg et skjermbilde eller en PDF med QR-koden.
Vær oppmerksom på at det ikke støttes å velge en fil direkte fra kameraet.
stopCamera: Stopp Kamera stopCamera: Stopp Kamera
startCamera: Start Kamera startCamera: Start Kamera
openFile: Velg Fil openFile: Velg Fil

View File

@ -1,9 +1,7 @@
iosHint: Gebruik op iOS de Safari-browser. iosHint: Gebruik op iOS de Safari-browser.
errorClose: Sluiten errorClose: Sluiten
selectCertificate: Selecteer Certificaat selectCertificate: Selecteer Certificaat
selectCertificateDescription: | selectCertificateDescription: Scan de QR-code op uw certificaat of selecteer een screenshot of pdf-pagina met de QR-code.
Scan de QR-code op uw certificaat of selecteer een screenshot of pdf-pagina met de QR-code.
Merk op dat het rechtstreeks vanaf de camera selecteren van een bestand niet wordt ondersteund.
stopCamera: Stop Camera stopCamera: Stop Camera
startCamera: Start Camera startCamera: Start Camera
openFile: Selecteer Bestand openFile: Selecteer Bestand