Praxissofttware/views/setup/index.ejs
2026-03-27 16:39:28 +00:00

219 lines
5.9 KiB
Plaintext

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<title><%= title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: Arial, sans-serif;
background: #f0f2f5;
padding: 40px 20px;
min-height: 100vh;
display: flex;
align-items: flex-start;
justify-content: center;
}
.card {
width: 100%;
max-width: 580px;
background: white;
padding: 32px;
border-radius: 14px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
}
.card h2 {
margin: 0 0 6px 0;
font-size: 22px;
color: #111827;
}
.card p {
margin: 0 0 24px 0;
color: #6b7280;
font-size: 14px;
}
.badge-update {
display: inline-block;
background: #fef3c7;
color: #92400e;
font-size: 12px;
font-weight: 600;
padding: 3px 10px;
border-radius: 20px;
margin-bottom: 16px;
border: 1px solid #fcd34d;
}
label {
display: block;
margin-top: 16px;
margin-bottom: 5px;
font-weight: 600;
font-size: 13px;
color: #374151;
}
input {
width: 100%;
padding: 10px 12px;
border-radius: 8px;
border: 1px solid #d1d5db;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
input:focus {
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37,99,235,0.12);
}
.row {
display: flex;
gap: 12px;
}
.row > div { flex: 1; }
.btn-row {
display: flex;
gap: 10px;
margin-top: 24px;
flex-wrap: wrap;
}
button {
padding: 10px 18px;
border: 0;
border-radius: 10px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: opacity 0.2s;
}
button:hover { opacity: 0.88; }
.btn-primary { background: #2563eb; color: white; flex: 1; }
.btn-secondary { background: #111827; color: white; }
.msg {
margin-top: 14px;
padding: 12px 14px;
border-radius: 10px;
font-size: 14px;
display: none;
}
.msg.ok { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
.msg.bad { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
.msg.pending { background: #eff6ff; color: #1d4ed8; border: 1px solid #93c5fd; }
.divider {
border: none;
border-top: 1px solid #e5e7eb;
margin: 24px 0;
}
</style>
</head>
<body>
<div class="card">
<h2>🛠️ <%= title %></h2>
<% if (typeof isUpdate !== 'undefined' && isUpdate) { %>
<span class="badge-update">⚠️ Bestehende Konfiguration wird überschrieben</span>
<% } %>
<p>DB-Verbindungsdaten eingeben. Die Verbindung wird vor dem Speichern geprüft.</p>
<form method="POST" action="/setup" id="setupForm">
<div class="row">
<div>
<label for="host">DB Host</label>
<input
id="host"
name="host"
placeholder="85.215.63.122"
value="<%= defaults.host %>"
required
/>
</div>
<div style="max-width:110px">
<label for="port">Port</label>
<input
id="port"
name="port"
placeholder="3306"
value="<%= defaults.port %>"
required
/>
</div>
</div>
<label for="user">DB Benutzer</label>
<input
id="user"
name="user"
placeholder="praxisuser"
value="<%= defaults.user %>"
required
/>
<label for="password">DB Passwort</label>
<input
id="password"
name="password"
type="password"
placeholder="<%= typeof isUpdate !== 'undefined' && isUpdate ? '(unverändert lassen = leer lassen)' : '' %>"
/>
<label for="name">DB Name</label>
<input
id="name"
name="name"
placeholder="praxissoftware"
value="<%= defaults.name %>"
required
/>
<hr class="divider" />
<div class="btn-row">
<button type="button" class="btn-secondary" onclick="testConnection()">
🔍 Verbindung testen
</button>
<button type="submit" class="btn-primary">
✅ Speichern & abschließen
</button>
</div>
<div id="msg" class="msg"></div>
</form>
</div>
<script>
async function testConnection() {
const msg = document.getElementById("msg");
msg.className = "msg pending";
msg.style.display = "block";
msg.textContent = "⏳ Teste Verbindung...";
// Felder einzeln auslesen (sicherer als FormData bei doppelten Namen)
const body = {
host: document.getElementById("host").value.trim(),
port: document.getElementById("port").value.trim(),
user: document.getElementById("user").value.trim(),
password: document.getElementById("password").value,
name: document.getElementById("name").value.trim(),
};
try {
const res = await fetch("/setup/test", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const json = await res.json();
msg.className = "msg " + (json.ok ? "ok" : "bad");
msg.textContent = json.message;
} catch (e) {
msg.className = "msg bad";
msg.textContent = "❌ Netzwerkfehler: " + e.message;
}
}
</script>
</body>
</html>