version 1 ready
This commit is contained in:
parent
3cc37c2d34
commit
08faec5e16
5 changed files with 539 additions and 0 deletions
193
.gitignore
vendored
Normal file
193
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
css/
|
||||||
|
js/qr-creator.js
|
||||||
|
js/qr-creator.min.js
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/linux,windows,macos,direnv,vim,webstorm+all
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=linux,windows,macos,direnv,vim,webstorm+all
|
||||||
|
|
||||||
|
### direnv ###
|
||||||
|
.direnv
|
||||||
|
.envrc
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### macOS Patch ###
|
||||||
|
# iCloud generated files
|
||||||
|
*.icloud
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
!*.svg # comment out if you don't need vector files
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
Sessionx.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
### WebStorm+all ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### WebStorm+all Patch ###
|
||||||
|
# Ignore everything but code style settings and run configurations
|
||||||
|
# that are supposed to be shared within teams.
|
||||||
|
|
||||||
|
.idea/*
|
||||||
|
|
||||||
|
!.idea/codeStyles
|
||||||
|
!.idea/runConfigurations
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/linux,windows,macos,direnv,vim,webstorm+all
|
||||||
20
Makefile
Normal file
20
Makefile
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
.PHONY: bulma
|
||||||
|
bulma:
|
||||||
|
curl -Ls https://github.com/jgthms/bulma/releases/download/1.0.2/bulma-1.0.2.zip -o bulma.zip
|
||||||
|
unzip bulma.zip
|
||||||
|
mkdir -p css
|
||||||
|
|
||||||
|
js/qr-create.min.js:
|
||||||
|
curl -Ls https://cdn.jsdelivr.net/npm/qr-creator/dist/qr-creator.min.js -o js/qr-creator.min.js
|
||||||
|
|
||||||
|
js/qr-create.js:
|
||||||
|
curl -Ls https://raw.githubusercontent.com/nimiq/qr-creator/refs/heads/master/src/qr-creator.js -o js/qr-creator.js
|
||||||
|
|
||||||
|
css/bulma.css: bulma
|
||||||
|
mv bulma/css/bulma.css css/bulma.css
|
||||||
|
|
||||||
|
css/bulma.css.map: bulma
|
||||||
|
mv bulma/css/bulma.css.map css/bulma.css.map
|
||||||
|
|
||||||
|
css/bulma.min.css: bulma
|
||||||
|
mv bulma/css/bulma.min.css css/bulma.min.css
|
||||||
43
README.md
Normal file
43
README.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# BezahlBrudi
|
||||||
|
|
||||||
|
In an effort to reduce the usage of Paypal, I created this simple web app. It can generate GiroCodes that can be used to easily transfer money between friends by showing a QR code that can be scanned by most banking apps. It will import all neccessary infos for a normal SEPA bank transfer. No third parties involved, only the banks of the friends who want to exchange money.
|
||||||
|
|
||||||
|
# How to use
|
||||||
|
|
||||||
|
Simple visit the webpage, and put in the details. The QR code will be generated automatically. You can choose to save your details in a cookie, so you don't have to input your bank details everytime. The cookie will be store on your device.
|
||||||
|
|
||||||
|
# Data privacy
|
||||||
|
|
||||||
|
The web app doesn't store any data of the sender, the receiver or the transaction. Everything runs locally in your browser.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
## Content of a Girocode
|
||||||
|
|
||||||
|
| Line | Example | Note |
|
||||||
|
| ---- | ----------- | ---- |
|
||||||
|
| 1 | BCD | Service Tag |
|
||||||
|
| 2 | 002 | Version (001 oder 002) |
|
||||||
|
| 3 | 2 | Encoding (1 = UTF-8, 2 = ISO 8859-1, 3 = ISO 8859-2, 4 = ISO 8859-4, 5 = ISO 8859-5, 6 = ISO 8859-7, 7 = ISO 8859-10, 8 = ISO 8859-15) |
|
||||||
|
| 4 | SCT | SEPA Credit Transfer |
|
||||||
|
| 5 | XXXXXXXXXXX | BIC of receiver bank (optional in EWR) |
|
||||||
|
| 6 | Max Muster | Name of receiver (max 70 chars) |
|
||||||
|
| 7 | DEXXXXXXXXXXXXXXXXXXXX | IBAN of receiver |
|
||||||
|
| 8 | EUR13.37 | Amount (Format `EUR#.##`) |
|
||||||
|
| 9 | CHAR | Reason (4 letter code, optional) |
|
||||||
|
| 10 | RF366 | Reference (structured code (ISO 11649 RF Creditor Reference) |
|
||||||
|
| 11 | Pizza | Purpose (unstructured text, max 140 chars) |
|
||||||
|
| 12 | Foobar | Note to user (optional) |
|
||||||
|
|
||||||
|
_The app will skip lines 9, 10 and 12._
|
||||||
|
|
||||||
|
## Valid chars for SEPA "Verwendungszweck"
|
||||||
|
|
||||||
|
```
|
||||||
|
a-zA-Z0-9/?:\(\).,'\+-[:space:]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Build with ❤️ and 🍝.
|
||||||
|
|
||||||
86
index.html
Normal file
86
index.html
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>BezahlBrudi</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/bulma.min.css">
|
||||||
|
<script src="js/qr-creator.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">BezahlBrudi</h1>
|
||||||
|
<p class="subtitle">Transfer money without any 3rd parties</p>
|
||||||
|
<p>The QR code can be scanned by most banking apps. Give it a try!</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column">
|
||||||
|
<div id="name" class="field">
|
||||||
|
<label for="input-name" class="label">Receiver Name</label>
|
||||||
|
<div class="control has-icons-right">
|
||||||
|
<input id="input-name" class="input" type="text" placeholder="Receiver Name" value="" maxlength="70" required>
|
||||||
|
<span class="icon is-small is-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="iban" class="field">
|
||||||
|
<label for="input-iban" class="label">Receiver IBAN</label>
|
||||||
|
<div class="control has-icons-right">
|
||||||
|
<input id="input-iban" class="input" type="text" placeholder="Receiver IBAN" value="" required>
|
||||||
|
<span class="icon is-small is-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="bic" class="field">
|
||||||
|
<label for="input-bic" class="label">Receiver BIC</label>
|
||||||
|
<div class="control has-icons-right">
|
||||||
|
<input id="input-bic" class="input" type="text" placeholder="Receiver BIC" value="" required>
|
||||||
|
<span class="icon is-small is-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="amount" class="field">
|
||||||
|
<label for="input-amount" class="label">Amount</label>
|
||||||
|
<div class="control has-icons-left has-icons-right">
|
||||||
|
<input id="input-amount" class="input" type="number" min="0.00" step="0.01" value="0.00" pattern="[0-9]+.[0-9]{2}" required>
|
||||||
|
<span class="icon is-small is-left">€</span>
|
||||||
|
<span class="icon is-small is-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="purpose" class="field">
|
||||||
|
<label for="input-purpose" class="label">Purpose</label>
|
||||||
|
<div class="control has-icons-right">
|
||||||
|
<input id="input-purpose" class="input" type="text" placeholder="Purpose" value="" maxlength="140" required>
|
||||||
|
<span class="icon is-small is-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input id="rememberme" type="checkbox" />
|
||||||
|
Remember me
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column">
|
||||||
|
<figure class="image is-square">
|
||||||
|
<div id="qr-code"></div>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
197
js/index.js
Normal file
197
js/index.js
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
getCookie = (key) => {
|
||||||
|
let name = key + "=";
|
||||||
|
let decodedCookie = decodeURIComponent(document.cookie);
|
||||||
|
let ca = decodedCookie.split(';');
|
||||||
|
for(let i = 0; i <ca.length; i++) {
|
||||||
|
let c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') {
|
||||||
|
c = c.substring(1);
|
||||||
|
}
|
||||||
|
if (c.indexOf(name) === 0) {
|
||||||
|
return c.substring(name.length, c.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
setCookie = () => {
|
||||||
|
const d = new Date();
|
||||||
|
d.setTime(d.getTime() + (180*24*60*60*1000)); // 180 days
|
||||||
|
document.cookie = `name=${document.querySelector("#name input").value};iban=${document.querySelector("#iban input").value};bic=${document.querySelector("#bic input").value};expires=${d.toUTCString()};path=/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in form from cookie
|
||||||
|
const cookieName = getCookie("name");
|
||||||
|
if (cookieName !== "") {
|
||||||
|
document.querySelector("#name input").value = cookieName;
|
||||||
|
}
|
||||||
|
const cookieIban = getCookie("iban");
|
||||||
|
if (cookieIban !== "") {
|
||||||
|
document.querySelector("#iban input").value = cookieIban;
|
||||||
|
}
|
||||||
|
const cookieBic = getCookie("bic");
|
||||||
|
if (cookieBic !== "") {
|
||||||
|
document.querySelector("#bic input").value = cookieBic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field data checks
|
||||||
|
|
||||||
|
validateName = (target) => {
|
||||||
|
if (target.value.length > 0 && target.value.length <= 70) {
|
||||||
|
target.classList.remove("is-danger")
|
||||||
|
document.querySelector("#name div span").innerHTML = "✅";
|
||||||
|
if (document.querySelector("#name p")) {
|
||||||
|
document.querySelector("#name p").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
regenerate();
|
||||||
|
} else {
|
||||||
|
target.classList.add("is-danger")
|
||||||
|
document.querySelector("#name div span").innerHTML = "❌";
|
||||||
|
|
||||||
|
if (!document.querySelector("#name p")) {
|
||||||
|
const help = document.createElement("p");
|
||||||
|
help.classList.add("help", "is-danger");
|
||||||
|
help.textContent = "Name can only have 70 characters.";
|
||||||
|
document.querySelector("#name").appendChild(help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateBic = (target) => {
|
||||||
|
const re = /^[a-z]{6}[2-9a-z][0-9a-np-z]([a-z0-9]{3}|x{3})?$/i;
|
||||||
|
|
||||||
|
if (re.test(target.value)) {
|
||||||
|
target.classList.remove("is-danger")
|
||||||
|
document.querySelector("#bic div span").innerHTML = "✅";
|
||||||
|
if (document.querySelector("#bic p")) {
|
||||||
|
document.querySelector("#bic p").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
regenerate();
|
||||||
|
} else {
|
||||||
|
target.classList.add("is-danger")
|
||||||
|
document.querySelector("#bic div span").innerHTML = "❌";
|
||||||
|
|
||||||
|
if (!document.querySelector("#bic p")) {
|
||||||
|
const help = document.createElement("p");
|
||||||
|
help.classList.add("help", "is-danger");
|
||||||
|
help.textContent = "BIC is invalid";
|
||||||
|
document.querySelector("#bic").appendChild(help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateIban = (target) => {
|
||||||
|
// IBANs are fucking complicated. this is a hugely simplified check
|
||||||
|
const re = /^[a-z]{2}[0-9]{20}$/i;
|
||||||
|
|
||||||
|
if (re.test(target.value)) {
|
||||||
|
target.classList.remove("is-danger")
|
||||||
|
document.querySelector("#iban div span").innerHTML = "✅";
|
||||||
|
if (document.querySelector("#iban p")) {
|
||||||
|
document.querySelector("#iban p").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
regenerate();
|
||||||
|
} else {
|
||||||
|
target.classList.add("is-danger")
|
||||||
|
document.querySelector("#iban div span").innerHTML = "❌";
|
||||||
|
|
||||||
|
if (!document.querySelector("#iban p")) {
|
||||||
|
const help = document.createElement("p");
|
||||||
|
help.classList.add("help", "is-danger");
|
||||||
|
help.textContent = "IBAN is invalid";
|
||||||
|
document.querySelector("#iban").appendChild(help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validatePurpose = (target) => {
|
||||||
|
if (target.value.length > 0 && target.value.length <= 140) {
|
||||||
|
target.classList.remove("is-danger")
|
||||||
|
document.querySelector("#purpose div span").innerHTML = "✅";
|
||||||
|
if (document.querySelector("#purpose p")) {
|
||||||
|
document.querySelector("#purpose p").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
regenerate();
|
||||||
|
} else {
|
||||||
|
target.classList.add("is-danger")
|
||||||
|
document.querySelector("#name div span").innerHTML = "❌";
|
||||||
|
|
||||||
|
if (!document.querySelector("#purpose p")) {
|
||||||
|
const help = document.createElement("p");
|
||||||
|
help.classList.add("help", "is-danger");
|
||||||
|
help.textContent = "Purpose can only have 140 characters.";
|
||||||
|
document.querySelector("#purpose").appendChild(help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector("#name input").addEventListener("input", (event) => {
|
||||||
|
validateName(event.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector("#iban input").addEventListener("input", (event) => {
|
||||||
|
validateIban(event.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector("#bic input").addEventListener("input", (event) => {
|
||||||
|
validateBic(event.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector("#purpose input").addEventListener("input", (event) => {
|
||||||
|
validatePurpose(event.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remember inputs
|
||||||
|
document.querySelector("#rememberme").addEventListener("change", (event) => {
|
||||||
|
if (event.target.checked) {
|
||||||
|
console.log("Save Name, IBAN and BIC to cookie..");
|
||||||
|
setCookie();
|
||||||
|
} else {
|
||||||
|
console.log("Remove Cookie..");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// qr code generator
|
||||||
|
regenerate = () => {
|
||||||
|
if (document.querySelector("#name input").classList.contains("is-danger")
|
||||||
|
|| document.querySelector("#iban input").classList.contains("is-danger")
|
||||||
|
|| document.querySelector("#bic input").classList.contains("is-danger")) {
|
||||||
|
console.log("Error in inputs")
|
||||||
|
} else {
|
||||||
|
document.querySelector('#qr-code').innerHTML = "";
|
||||||
|
QrCreator.render({
|
||||||
|
text: `BCD
|
||||||
|
002
|
||||||
|
1
|
||||||
|
SCT
|
||||||
|
${document.querySelector("#bic input").value.toUpperCase()}
|
||||||
|
${document.querySelector("#name input").value}
|
||||||
|
${document.querySelector("#iban input").value.toUpperCase()}
|
||||||
|
EUR${document.querySelector("#amount input").value}
|
||||||
|
|
||||||
|
|
||||||
|
${document.querySelector("#purpose input").value}
|
||||||
|
`,
|
||||||
|
radius: 0.25,
|
||||||
|
ecLevel: "H",
|
||||||
|
fill: "#fff",
|
||||||
|
background: null,
|
||||||
|
size: 512
|
||||||
|
}, document.querySelector('#qr-code'));
|
||||||
|
|
||||||
|
if (document.querySelector("#rememberme").checked) {
|
||||||
|
setCookie()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate qr code on first visit
|
||||||
|
validateName(document.querySelector("#name input"));
|
||||||
|
validateIban(document.querySelector("#iban input"));
|
||||||
|
validateBic(document.querySelector("#bic input"));
|
||||||
|
validatePurpose(document.querySelector("#purpose input"));
|
||||||
|
regenerate();
|
||||||
Loading…
Reference in a new issue