first commit

This commit is contained in:
Colin-Joel Scupin
2026-08-05 01:29:39 +02:00
commit 86d4bcdc37
85 changed files with 7706 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
const resource = typeof GetParentResourceName === 'function'
? GetParentResourceName()
: 'devx_banking';
const app = document.querySelector('#app');
const form = document.querySelector('#transferForm');
const transactions = document.querySelector('#transactions');
const errorEl = document.querySelector('#error');
const format = new Intl.NumberFormat('de-DE');
async function post(event, data = {}) {
const response = await fetch(`https://${resource}/${event}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
body: JSON.stringify(data)
});
return response.json();
}
function showError(text = '') {
errorEl.textContent = text;
errorEl.classList.toggle('hidden', !text);
}
function render(overview) {
const account = overview.account;
document.querySelector('#accountName').textContent = account.accountName;
document.querySelector('#accountNumber').textContent = account.accountNumber;
document.querySelector('#balance').textContent = `${format.format(account.balance)} $`;
transactions.innerHTML = '';
for (const entry of overview.transactions || []) {
const row = document.createElement('div');
row.className = 'transaction';
const sign = entry.direction === 'credit' ? '+' : '';
row.innerHTML = `
<div><strong>${escapeHtml(entry.reference)}</strong><br>
<small>${escapeHtml(entry.counterparty || '')} · ${escapeHtml(String(entry.createdAt))}</small></div>
<strong class="${entry.direction}">${sign}${format.format(entry.amount)} $</strong>`;
transactions.appendChild(row);
}
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, char => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;'
}[char]));
}
document.querySelector('#close').addEventListener('click', () => post('close'));
document.addEventListener('keyup', event => {
if (event.key === 'Escape') post('close');
});
form.addEventListener('submit', async event => {
event.preventDefault();
showError('');
const result = await post('transfer', Object.fromEntries(new FormData(form)));
if (!result.ok) {
showError(result.error || 'Überweisung fehlgeschlagen.');
return;
}
form.reset();
const refreshed = await post('refresh');
if (refreshed.ok) render(refreshed.overview);
});
window.addEventListener('message', event => {
const data = event.data;
if (data.action === 'open') app.classList.remove('hidden');
if (data.action === 'close') app.classList.add('hidden');
if (data.action === 'overview') render(data.overview);
if (data.action === 'error') showError(data.message);
});
@@ -0,0 +1,44 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main id="app" class="hidden">
<section class="bank">
<header>
<div>
<p>LOS SANTOS FINANCIAL</p>
<h1>Banking</h1>
</div>
<button id="close" aria-label="Schließen">×</button>
</header>
<div id="error" class="error hidden"></div>
<section class="account">
<div><span>KONTO</span><strong id="accountName"></strong></div>
<div><span>KONTONUMMER</span><strong id="accountNumber"></strong></div>
<div class="balance"><span>VERFÜGBAR</span><strong id="balance">0 $</strong></div>
</section>
<section class="columns">
<form id="transferForm">
<h2>Überweisung</h2>
<label>Empfängerkonto<input name="destination" placeholder="LS0000000000" required></label>
<label>Betrag<input name="amount" type="number" min="1" step="1" required></label>
<label>Verwendungszweck<input name="reference" maxlength="140" value="Überweisung"></label>
<button type="submit">Überweisen</button>
</form>
<div>
<h2>Letzte Buchungen</h2>
<div id="transactions" class="transactions"></div>
</div>
</section>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
@@ -0,0 +1,47 @@
:root { font-family: Inter, Arial, sans-serif; color: #f7f8fb; }
* { box-sizing: border-box; }
body { margin: 0; overflow: hidden; background: transparent; }
.hidden { display: none !important; }
#app {
min-height: 100vh; display: grid; place-items: center;
background: rgba(2,5,9,.55); backdrop-filter: blur(5px);
}
.bank {
width: min(980px, 92vw); max-height: 86vh; overflow: auto;
background: #10151e; border: 1px solid rgba(255,255,255,.1);
border-radius: 22px; padding: 28px; box-shadow: 0 30px 100px rgba(0,0,0,.55);
}
header { display: flex; justify-content: space-between; align-items: flex-start; }
header p, .account span { color: #8f9aae; font-size: 11px; letter-spacing: .15em; }
h1 { margin: 4px 0 22px; font-size: 38px; }
h2 { font-size: 18px; }
#close { background: transparent; color: white; border: 0; font-size: 32px; cursor: pointer; }
.account {
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px;
background: linear-gradient(135deg, #2857dd, #1e3e98);
border-radius: 16px; padding: 20px;
}
.account div { display: grid; gap: 7px; }
.account .balance strong { font-size: 28px; }
.columns { display: grid; grid-template-columns: .8fr 1.2fr; gap: 24px; margin-top: 22px; }
form { display: grid; gap: 12px; align-content: start; }
label { display: grid; gap: 6px; color: #aeb7c7; font-size: 13px; }
input {
border: 1px solid rgba(255,255,255,.11); background: #0a0e15;
color: white; border-radius: 10px; padding: 12px;
}
button[type=submit] {
border: 0; background: #416cf5; color: white; font-weight: 800;
border-radius: 10px; padding: 12px; cursor: pointer;
}
.transaction {
display: grid; grid-template-columns: 1fr auto; gap: 6px;
padding: 12px 0; border-bottom: 1px solid rgba(255,255,255,.08);
}
.transaction small { color: #8f9aae; }
.credit { color: #6ee7a5; }
.debit { color: #ff8592; }
.error { background: rgba(180,45,65,.28); padding: 12px; border-radius: 10px; margin-bottom: 14px; }
@media (max-width: 760px) {
.account, .columns { grid-template-columns: 1fr; }
}