Äanderungen der Sidebars und design
This commit is contained in:
parent
10e83f53da
commit
860b41ab28
@ -88,7 +88,7 @@ async function postCreateUser(req, res) {
|
|||||||
password,
|
password,
|
||||||
role,
|
role,
|
||||||
fachrichtung,
|
fachrichtung,
|
||||||
arztnummer
|
arztnummer,
|
||||||
);
|
);
|
||||||
|
|
||||||
req.session.flash = {
|
req.session.flash = {
|
||||||
@ -159,7 +159,7 @@ async function resetUserPassword(req, res) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
res.redirect("/admin/users");
|
res.redirect("/admin/users");
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ async function showInvoiceOverview(req, res) {
|
|||||||
GROUP BY p.id
|
GROUP BY p.id
|
||||||
ORDER BY total DESC
|
ORDER BY total DESC
|
||||||
`,
|
`,
|
||||||
[`%${search}%`]
|
[`%${search}%`],
|
||||||
);
|
);
|
||||||
|
|
||||||
res.render("admin/admin_invoice_overview", {
|
res.render("admin/admin_invoice_overview", {
|
||||||
@ -266,6 +266,7 @@ async function showInvoiceOverview(req, res) {
|
|||||||
search,
|
search,
|
||||||
fromYear,
|
fromYear,
|
||||||
toYear,
|
toYear,
|
||||||
|
view, // ✅ WICHTIG: damit EJS weiß welche Tabelle angezeigt wird
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"dashboard": "Dashboard"
|
"dashboard": "Dashboard",
|
||||||
|
"year": "Jahr",
|
||||||
|
"month": "Monat"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"patients": "Patienten",
|
"patients": "Patienten",
|
||||||
@ -22,5 +24,17 @@
|
|||||||
"adminSidebar": {
|
"adminSidebar": {
|
||||||
"users": "Userverwaltung",
|
"users": "Userverwaltung",
|
||||||
"database": "Datenbankverwaltung"
|
"database": "Datenbankverwaltung"
|
||||||
|
},
|
||||||
|
"adminInvoice": {
|
||||||
|
"annualSales": "Jahresumsatz",
|
||||||
|
"quarterlySales": "Quartalsumsatz.",
|
||||||
|
"monthSales": "Monatsumsatz",
|
||||||
|
"patientsSales": "Umsatz pro Patient",
|
||||||
|
"doctorSales": "Umsatz pro Arzt",
|
||||||
|
"filter": "Filtern",
|
||||||
|
"invoiceOverview": "Rechnungsübersicht",
|
||||||
|
"search": "Suchen",
|
||||||
|
"patient": "Patient",
|
||||||
|
"searchPatient": "Patienten suchen"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"reset": "Resetear",
|
"reset": "Resetear",
|
||||||
"dashboard": "Panel"
|
"dashboard": "Panel",
|
||||||
|
"year": "Ano",
|
||||||
|
"month": "mes"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"patients": "Pacientes",
|
"patients": "Pacientes",
|
||||||
@ -23,5 +25,17 @@
|
|||||||
"adminSidebar": {
|
"adminSidebar": {
|
||||||
"users": "Administración de usuarios",
|
"users": "Administración de usuarios",
|
||||||
"database": "Administración de base de datos"
|
"database": "Administración de base de datos"
|
||||||
|
},
|
||||||
|
"adminInvoice": {
|
||||||
|
"annualSales": "facturación anual",
|
||||||
|
"quarterlySales": "ingresos trimestrales.",
|
||||||
|
"monthSales": "facturación mensual",
|
||||||
|
"patientsSales": "Ingresos por paciente",
|
||||||
|
"doctorSales": "Facturación por médico",
|
||||||
|
"filter": "filtro",
|
||||||
|
"invoiceOverview": "Resumen de facturas",
|
||||||
|
"search": "buscar",
|
||||||
|
"patient": "paciente",
|
||||||
|
"searchPatient": "Buscar pacientes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
public/js/flash_auto_hide.js
Normal file
16
public/js/flash_auto_hide.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const alerts = document.querySelectorAll(".auto-hide-flash");
|
||||||
|
|
||||||
|
if (!alerts.length) return;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
alerts.forEach((el) => {
|
||||||
|
el.classList.add("flash-hide");
|
||||||
|
|
||||||
|
// nach der Animation aus dem DOM entfernen
|
||||||
|
setTimeout(() => {
|
||||||
|
el.remove();
|
||||||
|
}, 700);
|
||||||
|
});
|
||||||
|
}, 3000); // ✅ 3 Sekunden
|
||||||
|
});
|
||||||
124
public/js/patients_sidebar.js
Normal file
124
public/js/patients_sidebar.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const radios = document.querySelectorAll(".patient-radio");
|
||||||
|
|
||||||
|
const sidebarPatientInfo = document.getElementById("sidebarPatientInfo");
|
||||||
|
|
||||||
|
const sbOverview = document.getElementById("sbOverview");
|
||||||
|
const sbHistory = document.getElementById("sbHistory");
|
||||||
|
const sbEdit = document.getElementById("sbEdit");
|
||||||
|
const sbMeds = document.getElementById("sbMeds");
|
||||||
|
|
||||||
|
const sbWaitingRoomWrapper = document.getElementById("sbWaitingRoomWrapper");
|
||||||
|
const sbActiveWrapper = document.getElementById("sbActiveWrapper");
|
||||||
|
|
||||||
|
const sbUploadForm = document.getElementById("sbUploadForm");
|
||||||
|
const sbUploadInput = document.getElementById("sbUploadInput");
|
||||||
|
const sbUploadBtn = document.getElementById("sbUploadBtn");
|
||||||
|
|
||||||
|
if (
|
||||||
|
!radios.length ||
|
||||||
|
!sidebarPatientInfo ||
|
||||||
|
!sbOverview ||
|
||||||
|
!sbHistory ||
|
||||||
|
!sbEdit ||
|
||||||
|
!sbMeds ||
|
||||||
|
!sbWaitingRoomWrapper ||
|
||||||
|
!sbActiveWrapper ||
|
||||||
|
!sbUploadForm ||
|
||||||
|
!sbUploadInput ||
|
||||||
|
!sbUploadBtn
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Sicherheit: Upload blocken falls nicht aktiv
|
||||||
|
sbUploadForm.addEventListener("submit", (e) => {
|
||||||
|
if (!sbUploadForm.action || sbUploadForm.action.endsWith("#")) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
radios.forEach((radio) => {
|
||||||
|
radio.addEventListener("change", () => {
|
||||||
|
const id = radio.dataset.id;
|
||||||
|
const firstname = radio.dataset.firstname;
|
||||||
|
const lastname = radio.dataset.lastname;
|
||||||
|
|
||||||
|
const waiting = radio.dataset.waiting === "1";
|
||||||
|
const active = radio.dataset.active === "1";
|
||||||
|
|
||||||
|
// ✅ Patient Info
|
||||||
|
sidebarPatientInfo.innerHTML = `
|
||||||
|
<div class="patient-name">
|
||||||
|
<strong>${firstname} ${lastname}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="patient-meta text-muted">
|
||||||
|
ID: ${id}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// ✅ Übersicht
|
||||||
|
sbOverview.href = "/patients/" + id;
|
||||||
|
sbOverview.classList.remove("disabled");
|
||||||
|
|
||||||
|
// ✅ Verlauf
|
||||||
|
sbHistory.href = "/patients/" + id + "/overview";
|
||||||
|
sbHistory.classList.remove("disabled");
|
||||||
|
|
||||||
|
// ✅ Bearbeiten
|
||||||
|
sbEdit.href = "/patients/edit/" + id;
|
||||||
|
sbEdit.classList.remove("disabled");
|
||||||
|
|
||||||
|
// ✅ Medikamente
|
||||||
|
sbMeds.href = "/patients/" + id + "/medications";
|
||||||
|
sbMeds.classList.remove("disabled");
|
||||||
|
|
||||||
|
// ✅ Wartezimmer (NUR wenn Patient aktiv ist)
|
||||||
|
if (!active) {
|
||||||
|
sbWaitingRoomWrapper.innerHTML = `
|
||||||
|
<div class="nav-item disabled">
|
||||||
|
<i class="bi bi-door-open"></i> Ins Wartezimmer (Patient inaktiv)
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else if (waiting) {
|
||||||
|
sbWaitingRoomWrapper.innerHTML = `
|
||||||
|
<div class="nav-item disabled">
|
||||||
|
<i class="bi bi-hourglass-split"></i> Wartet bereits
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
sbWaitingRoomWrapper.innerHTML = `
|
||||||
|
<form method="POST" action="/patients/waiting-room/${id}" style="margin:0;">
|
||||||
|
<button type="submit" class="nav-item nav-btn">
|
||||||
|
<i class="bi bi-door-open"></i> Ins Wartezimmer
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Sperren / Entsperren
|
||||||
|
if (active) {
|
||||||
|
sbActiveWrapper.innerHTML = `
|
||||||
|
<form method="POST" action="/patients/deactivate/${id}" style="margin:0;">
|
||||||
|
<button type="submit" class="nav-item nav-btn">
|
||||||
|
<i class="bi bi-lock-fill"></i> Sperren
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
sbActiveWrapper.innerHTML = `
|
||||||
|
<form method="POST" action="/patients/activate/${id}" style="margin:0;">
|
||||||
|
<button type="submit" class="nav-item nav-btn">
|
||||||
|
<i class="bi bi-unlock-fill"></i> Entsperren
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Upload nur aktiv wenn Patient ausgewählt
|
||||||
|
sbUploadForm.action = "/patients/" + id + "/files";
|
||||||
|
sbUploadInput.disabled = false;
|
||||||
|
sbUploadBtn.disabled = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -2,14 +2,98 @@
|
|||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Rechnungsübersicht</title>
|
<title><%= t.adminInvoice.invoiceOverview %></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css" />
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Ubuntu;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background: #111827;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #1f2937;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main */
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-light">
|
<body>
|
||||||
|
<%
|
||||||
|
// ✅ active aus view setzen (view kommt vom Controller)
|
||||||
|
let active = "sales_year";
|
||||||
|
if (view === "quarter") active = "sales_quarter";
|
||||||
|
if (view === "month") active = "sales_month";
|
||||||
|
if (view === "patient") active = "sales_patient";
|
||||||
|
if (view === "year") active = "sales_year";
|
||||||
|
%>
|
||||||
|
|
||||||
|
<div class="layout">
|
||||||
|
<!-- ✅ neue Invoice Sidebar -->
|
||||||
|
<%- include("../partials/invoice_sidebar", { active, t }) %>
|
||||||
|
|
||||||
|
<!-- MAIN CONTENT -->
|
||||||
|
<div class="main">
|
||||||
<!-- =========================
|
<!-- =========================
|
||||||
NAVBAR
|
NAVBAR
|
||||||
========================== -->
|
========================== -->
|
||||||
@ -18,13 +102,12 @@
|
|||||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||||
>
|
>
|
||||||
<i class="bi bi-calculator fs-4"></i>
|
<i class="bi bi-calculator fs-4"></i>
|
||||||
<span class="fw-semibold fs-5">Rechnungsübersicht</span>
|
<span class="fw-semibold fs-5"><%= t.adminInvoice.invoiceOverview %></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
|
||||||
<div class="ms-auto">
|
<div class="ms-auto">
|
||||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||||
⬅️ Dashboard
|
⬅️ <%= t.global.dashboard %>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -34,6 +117,9 @@
|
|||||||
========================== -->
|
========================== -->
|
||||||
<div class="container-fluid mt-4">
|
<div class="container-fluid mt-4">
|
||||||
<form method="get" class="row g-2 mb-4">
|
<form method="get" class="row g-2 mb-4">
|
||||||
|
<!-- ✅ view beibehalten -->
|
||||||
|
<input type="hidden" name="view" value="<%= view %>" />
|
||||||
|
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@ -55,25 +141,27 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<button class="btn btn-outline-secondary">Filtern</button>
|
<button class="btn btn-outline-secondary">
|
||||||
|
Filter
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- =========================
|
<!-- ✅ NUR EINE TABELLE -->
|
||||||
GRID – 4 SPALTEN
|
|
||||||
========================== -->
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<!-- =========================
|
<% if (view === "year") { %>
|
||||||
JAHRESUMSATZ
|
|
||||||
========================== -->
|
<!-- Jahresumsatz -->
|
||||||
<div class="col-xl-3 col-lg-6">
|
<div class="col-12">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-header fw-semibold">Jahresumsatz</div>
|
<div class="card-header fw-semibold">
|
||||||
|
<%= t.adminInvoice.annualSales %>
|
||||||
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<table class="table table-sm table-striped mb-0">
|
<table class="table table-striped mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Jahr</th>
|
<th><%= t.global.year %></th>
|
||||||
<th class="text-end">€</th>
|
<th class="text-end">€</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -84,12 +172,12 @@
|
|||||||
Keine Daten
|
Keine Daten
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %> <% yearly.forEach(y => { %>
|
<% } %>
|
||||||
|
|
||||||
|
<% yearly.forEach(y => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= y.year %></td>
|
<td><%= y.year %></td>
|
||||||
<td class="text-end fw-semibold">
|
<td class="text-end fw-semibold"><%= Number(y.total).toFixed(2) %></td>
|
||||||
<%= Number(y.total).toFixed(2) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -98,17 +186,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- =========================
|
<% } else if (view === "quarter") { %>
|
||||||
QUARTALSUMSATZ
|
|
||||||
========================== -->
|
<!-- Quartalsumsatz -->
|
||||||
<div class="col-xl-3 col-lg-6">
|
<div class="col-12">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-header fw-semibold">Quartalsumsatz</div>
|
<div class="card-header fw-semibold">
|
||||||
|
<%= t.adminInvoice.quarterlySales %>
|
||||||
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<table class="table table-sm table-striped mb-0">
|
<table class="table table-striped mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Jahr</th>
|
<th><%= t.global.year %></th>
|
||||||
<th>Q</th>
|
<th>Q</th>
|
||||||
<th class="text-end">€</th>
|
<th class="text-end">€</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -120,13 +210,13 @@
|
|||||||
Keine Daten
|
Keine Daten
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %> <% quarterly.forEach(q => { %>
|
<% } %>
|
||||||
|
|
||||||
|
<% quarterly.forEach(q => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= q.year %></td>
|
<td><%= q.year %></td>
|
||||||
<td>Q<%= q.quarter %></td>
|
<td>Q<%= q.quarter %></td>
|
||||||
<td class="text-end fw-semibold">
|
<td class="text-end fw-semibold"><%= Number(q.total).toFixed(2) %></td>
|
||||||
<%= Number(q.total).toFixed(2) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -135,17 +225,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- =========================
|
<% } else if (view === "month") { %>
|
||||||
MONATSUMSATZ
|
|
||||||
========================== -->
|
<!-- Monatsumsatz -->
|
||||||
<div class="col-xl-3 col-lg-6">
|
<div class="col-12">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-header fw-semibold">Monatsumsatz</div>
|
<div class="card-header fw-semibold">
|
||||||
|
<%= t.adminInvoice.monthSales %>
|
||||||
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<table class="table table-sm table-striped mb-0">
|
<table class="table table-striped mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Monat</th>
|
<th><%= t.global.month %></th>
|
||||||
<th class="text-end">€</th>
|
<th class="text-end">€</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -156,12 +248,12 @@
|
|||||||
Keine Daten
|
Keine Daten
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %> <% monthly.forEach(m => { %>
|
<% } %>
|
||||||
|
|
||||||
|
<% monthly.forEach(m => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= m.month %></td>
|
<td><%= m.month %></td>
|
||||||
<td class="text-end fw-semibold">
|
<td class="text-end fw-semibold"><%= Number(m.total).toFixed(2) %></td>
|
||||||
<%= Number(m.total).toFixed(2) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -170,15 +262,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- =========================
|
<% } else if (view === "patient") { %>
|
||||||
UMSATZ PRO PATIENT
|
|
||||||
========================== -->
|
<!-- Umsatz pro Patient -->
|
||||||
<div class="col-xl-3 col-lg-6">
|
<div class="col-12">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-header fw-semibold">Umsatz pro Patient</div>
|
<div class="card-header fw-semibold">
|
||||||
|
<%= t.adminInvoice.patientsSales %>
|
||||||
|
</div>
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
<!-- 🔍 Suche -->
|
|
||||||
<form method="get" class="mb-2 d-flex gap-2">
|
<form method="get" class="mb-2 d-flex gap-2">
|
||||||
|
<!-- ✅ view beibehalten -->
|
||||||
|
<input type="hidden" name="view" value="<%= view %>" />
|
||||||
<input type="hidden" name="fromYear" value="<%= fromYear %>" />
|
<input type="hidden" name="fromYear" value="<%= fromYear %>" />
|
||||||
<input type="hidden" name="toYear" value="<%= toYear %>" />
|
<input type="hidden" name="toYear" value="<%= toYear %>" />
|
||||||
|
|
||||||
@ -187,23 +282,25 @@
|
|||||||
name="q"
|
name="q"
|
||||||
value="<%= search %>"
|
value="<%= search %>"
|
||||||
class="form-control form-control-sm"
|
class="form-control form-control-sm"
|
||||||
placeholder="Patient suchen..."
|
placeholder="<%= t.adminInvoice.patientsSales %>"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button class="btn btn-sm btn-outline-primary">Suchen</button>
|
<button class="btn btn-sm btn-outline-primary">
|
||||||
|
<%= t.adminInvoice.search %>
|
||||||
|
</button>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="/admin/invoices?fromYear=<%= fromYear %>&toYear=<%= toYear %>"
|
href="/admin/invoices?view=patient&fromYear=<%= fromYear %>&toYear=<%= toYear %>"
|
||||||
class="btn btn-sm btn-outline-secondary"
|
class="btn btn-sm btn-outline-secondary"
|
||||||
>
|
>
|
||||||
Reset
|
<%= t.global.reset %>
|
||||||
</a>
|
</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<table class="table table-sm table-striped mb-0">
|
<table class="table table-striped mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Patient</th>
|
<th><%= t.adminInvoice.patient %></th>
|
||||||
<th class="text-end">€</th>
|
<th class="text-end">€</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -214,12 +311,12 @@
|
|||||||
Keine Daten
|
Keine Daten
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %> <% patients.forEach(p => { %>
|
<% } %>
|
||||||
|
|
||||||
|
<% patients.forEach(p => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= p.patient %></td>
|
<td><%= p.patient %></td>
|
||||||
<td class="text-end fw-semibold">
|
<td class="text-end fw-semibold"><%= Number(p.total).toFixed(2) %></td>
|
||||||
<%= Number(p.total).toFixed(2) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -227,6 +324,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Praxis System</title>
|
<title>Dashboard</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
@ -21,193 +21,75 @@
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sidebar */
|
/* ✅ erzwingt Sidebar links */
|
||||||
.sidebar {
|
.sidebar-wrap {
|
||||||
width: 240px;
|
width: 260px;
|
||||||
background: #111827;
|
flex: 0 0 260px;
|
||||||
color: white;
|
}
|
||||||
padding: 20px;
|
|
||||||
|
/* ✅ Main rechts */
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
padding: 12px 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #cbd5e1;
|
|
||||||
text-decoration: none;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item:hover {
|
|
||||||
background: #1f2937;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item.active {
|
|
||||||
background: #2563eb;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .spacer {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Main */
|
|
||||||
.main {
|
|
||||||
flex: 1;
|
|
||||||
padding: 25px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar h3 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
flex: 1;
|
|
||||||
padding: 24px;
|
|
||||||
background: #f4f6f9;
|
background: #f4f6f9;
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.waiting-monitor {
|
.content {
|
||||||
flex: 1;
|
padding: 24px;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waiting-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(7, 1fr);
|
|
||||||
grid-auto-rows: 80px;
|
|
||||||
gap: 12px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waiting-slot {
|
|
||||||
border: 2px dashed #cbd5e1;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #f8fafc;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waiting-slot.occupied {
|
|
||||||
border-style: solid;
|
|
||||||
background: #eefdf5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.patient-text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waiting-slot.clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.15s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.waiting-slot.clickable:hover {
|
|
||||||
transform: scale(1.03);
|
|
||||||
box-shadow: 0 0 0 2px #2563eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item.locked {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
.nav-item.locked:hover {
|
|
||||||
background: transparent;
|
|
||||||
color: #cbd5e1;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<!-- ✅ SIDEBAR ausgelagert -->
|
<!-- ✅ Sidebar links fix -->
|
||||||
<%- include("partials/sidebar", { user, active: "patients" }) %>
|
<div class="sidebar-wrap">
|
||||||
|
<%- include("partials/sidebar", { user, active: "dashboard" }) %>
|
||||||
<!-- MAIN CONTENT -->
|
|
||||||
<div class="main">
|
|
||||||
<div class="topbar">
|
|
||||||
<h3>Willkommen, <%= user.username %></h3>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Flash Messages -->
|
<!-- ✅ Main rechts -->
|
||||||
|
<div class="main">
|
||||||
|
<!-- ✅ Schwarzer Balken wie patients -->
|
||||||
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
|
<div
|
||||||
|
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||||
|
>
|
||||||
|
<i class="bi bi-house-door fs-4"></i>
|
||||||
|
<span class="fw-semibold fs-5">
|
||||||
|
Willkommen, <%= (user.username || '').toUpperCase() %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-auto">
|
||||||
|
<a href="/logout" class="btn btn-outline-light btn-sm">
|
||||||
|
Logout
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
<%- include("partials/flash") %>
|
<%- include("partials/flash") %>
|
||||||
|
|
||||||
<!-- =========================
|
<div class="card shadow">
|
||||||
WARTEZIMMER MONITOR
|
<div class="card-body">
|
||||||
========================= -->
|
<h5 class="mb-0">🪑 Wartezimmer-Monitor</h5>
|
||||||
<div class="waiting-monitor">
|
|
||||||
<h5 class="mb-3">🪑 Wartezimmer-Monitor</h5>
|
|
||||||
|
|
||||||
<div class="waiting-grid">
|
<div class="text-muted mt-2">
|
||||||
<% if (waitingPatients && waitingPatients.length > 0) { %>
|
<% if (waitingPatients && waitingPatients.length > 0) { %>
|
||||||
|
Patienten im Wartezimmer: <%= waitingPatients.length %>
|
||||||
<% waitingPatients.forEach(p => { %>
|
|
||||||
|
|
||||||
<% if (user.role === 'arzt') { %>
|
|
||||||
<a href="/patients/<%= p.id %>/overview" class="waiting-slot occupied clickable">
|
|
||||||
<div class="patient-text">
|
|
||||||
<div class="name"><%= p.firstname %> <%= p.lastname %></div>
|
|
||||||
<div class="birthdate">
|
|
||||||
<%= new Date(p.birthdate).toLocaleDateString("de-DE") %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<div class="waiting-slot occupied">
|
Keine Patienten im Wartezimmer.
|
||||||
<div class="patient-text">
|
|
||||||
<div class="name"><%= p.firstname %> <%= p.lastname %></div>
|
|
||||||
<div class="birthdate">
|
|
||||||
<%= new Date(p.birthdate).toLocaleDateString("de-DE") %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% }) %>
|
|
||||||
|
|
||||||
<% } else { %>
|
|
||||||
<div class="text-muted">Keine Patienten im Wartezimmer.</div>
|
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="/js/flash_auto_hide.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -75,6 +75,6 @@
|
|||||||
|
|
||||||
<!-- ✅ Zurück zum Dashboard -->
|
<!-- ✅ Zurück zum Dashboard -->
|
||||||
<a href="/dashboard" class="nav-item">
|
<a href="/dashboard" class="nav-item">
|
||||||
<i class="bi bi-arrow-left"></i> Dashboard
|
<i class="bi bi-arrow-left"></i> <%= t.global.dashboard %>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
36
views/partials/invoice_sidebar.ejs
Normal file
36
views/partials/invoice_sidebar.ejs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<div class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="bi bi-cash-coin"></i>
|
||||||
|
Invoice Menü
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/admin/invoices?view=year"
|
||||||
|
class="nav-item <%= active === 'sales_year' ? 'active' : '' %>"
|
||||||
|
>
|
||||||
|
<i class="bi bi-calendar3"></i> <%= t.adminInvoice.annualSales %>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/admin/invoices?view=quarter"
|
||||||
|
class="nav-item <%= active === 'sales_quarter' ? 'active' : '' %>"
|
||||||
|
>
|
||||||
|
<i class="bi bi-calendar2-week"></i> <%= t.adminInvoice.quarterlySales %>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/admin/invoices?view=month"
|
||||||
|
class="nav-item <%= active === 'sales_month' ? 'active' : '' %>"
|
||||||
|
>
|
||||||
|
<i class="bi bi-calendar2"></i> <%= t.adminInvoice.monthSales %>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/admin/invoices?view=patient"
|
||||||
|
class="nav-item <%= active === 'sales_patient' ? 'active' : '' %>"
|
||||||
|
>
|
||||||
|
<i class="bi bi-people"></i> <%= t.adminInvoice.patientsSales %>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="spacer"></div>
|
||||||
|
</div>
|
||||||
101
views/partials/patient_overview_dashboard_sidebar.ejs
Normal file
101
views/partials/patient_overview_dashboard_sidebar.ejs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<div class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="bi bi-person-lines-fill"></i>
|
||||||
|
Patient
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Patient Badge -->
|
||||||
|
<% if (patient) { %>
|
||||||
|
<div class="patient-badge">
|
||||||
|
<div class="patient-name">
|
||||||
|
<strong><%= patient.firstname %> <%= patient.lastname %></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="patient-badge">
|
||||||
|
<div class="patient-name">
|
||||||
|
<strong>Kein Patient gewählt</strong>
|
||||||
|
</div>
|
||||||
|
<div class="patient-meta">
|
||||||
|
Bitte auswählen
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background: #111827;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-badge {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-name {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #1f2937;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
177
views/partials/patient_sidebar.ejs
Normal file
177
views/partials/patient_sidebar.ejs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<div class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="bi bi-person-lines-fill"></i>
|
||||||
|
Patient
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Patient Info wird per JS ersetzt -->
|
||||||
|
<div class="patient-badge" id="sidebarPatientInfo">
|
||||||
|
<div class="patient-name">
|
||||||
|
<strong>Kein Patient gewählt</strong>
|
||||||
|
</div>
|
||||||
|
<div class="patient-meta text-muted">Bitte Patient auswählen</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Übersicht -->
|
||||||
|
<a id="sbOverview" href="#" class="nav-item disabled">
|
||||||
|
<i class="bi bi-clipboard2-check"></i> Übersicht
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ✅ Verlauf -->
|
||||||
|
<a id="sbHistory" href="#" class="nav-item disabled">
|
||||||
|
<i class="bi bi-clock-history"></i> Verlauf
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ✅ Bearbeiten -->
|
||||||
|
<a id="sbEdit" href="#" class="nav-item disabled">
|
||||||
|
<i class="bi bi-pencil-square"></i> Bearbeiten
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ✅ Medikamente -->
|
||||||
|
<a id="sbMeds" href="#" class="nav-item disabled">
|
||||||
|
<i class="bi bi-capsule"></i> Medikamente
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ✅ Wartezimmer -->
|
||||||
|
<div id="sbWaitingRoomWrapper">
|
||||||
|
<div class="nav-item disabled">
|
||||||
|
<i class="bi bi-door-open"></i> Ins Wartezimmer
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Sperren / Entsperren -->
|
||||||
|
<div id="sbActiveWrapper">
|
||||||
|
<div class="nav-item disabled">
|
||||||
|
<i class="bi bi-lock-fill"></i> Sperren / Entsperren
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ Upload -->
|
||||||
|
<div class="sidebar-upload">
|
||||||
|
<div style="font-weight: 600; margin: 10px 0 6px 0; color: #e5e7eb">
|
||||||
|
<i class="bi bi-paperclip"></i> Datei Upload
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form
|
||||||
|
id="sbUploadForm"
|
||||||
|
method="POST"
|
||||||
|
action="#"
|
||||||
|
enctype="multipart/form-data"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="sbUploadInput"
|
||||||
|
type="file"
|
||||||
|
name="file"
|
||||||
|
class="form-control form-control-sm mb-2"
|
||||||
|
disabled
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
id="sbUploadBtn"
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-sm btn-outline-light w-100"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
📎 Hochladen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="sidebar-muted" style="margin-top: 6px">
|
||||||
|
Nur aktiv nach Patientenauswahl
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="spacer"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background: #111827;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-badge {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-name {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.patient-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #1f2937;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-upload {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-muted {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,42 +1,11 @@
|
|||||||
<div class="sidebar">
|
|
||||||
|
|
||||||
<!-- ✅ Logo + Sprachbuttons -->
|
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:30px;">
|
|
||||||
<div class="logo" style="margin:0;">
|
|
||||||
🩺 Praxis System
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ✅ Sprache oben rechts -->
|
|
||||||
<div style="display:flex; gap:6px;">
|
|
||||||
<a
|
|
||||||
href="/lang/de"
|
|
||||||
class="btn btn-sm btn-outline-light <%= lang === 'de' ? 'active' : '' %>"
|
|
||||||
style="padding:2px 8px; font-size:12px;"
|
|
||||||
title="Deutsch"
|
|
||||||
>
|
|
||||||
DE
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="/lang/es"
|
|
||||||
class="btn btn-sm btn-outline-light <%= lang === 'es' ? 'active' : '' %>"
|
|
||||||
style="padding:2px 8px; font-size:12px;"
|
|
||||||
title="Español"
|
|
||||||
>
|
|
||||||
ES
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%
|
<%
|
||||||
const role = user?.role || null;
|
const role = user?.role || null;
|
||||||
|
|
||||||
// ✅ Regeln:
|
// ✅ Regeln
|
||||||
// Arztbereich: NUR arzt
|
const canDoctorArea = role === "arzt"; // nur Arzt
|
||||||
const canDoctorArea = role === "arzt";
|
const canAdminArea = role === "admin"; // nur Admin
|
||||||
|
const canPatients = role === "arzt" || role === "mitarbeiter";
|
||||||
// Verwaltung: NUR admin
|
const canStaffArea = role === "arzt" || role === "mitarbeiter"; // Medikamente + offene Leistungen
|
||||||
const canAdminArea = role === "admin";
|
|
||||||
|
|
||||||
function hrefIfAllowed(allowed, href) {
|
function hrefIfAllowed(allowed, href) {
|
||||||
return allowed ? href : "#";
|
return allowed ? href : "#";
|
||||||
@ -51,41 +20,55 @@
|
|||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
<div class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<i class="bi bi-hospital"></i>
|
||||||
|
Praxis System
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dashboard -->
|
||||||
|
<a
|
||||||
|
href="/dashboard"
|
||||||
|
class="nav-item <%= active === 'dashboard' ? 'active' : '' %>"
|
||||||
|
>
|
||||||
|
<i class="bi bi-house-door"></i> Dashboard
|
||||||
|
</a>
|
||||||
|
|
||||||
<!-- Patienten -->
|
<!-- Patienten -->
|
||||||
<a
|
<a
|
||||||
href="<%= hrefIfAllowed(canDoctorArea, '/patients') %>"
|
href="<%= hrefIfAllowed(canPatients, '/patients') %>"
|
||||||
class="nav-item <%= active === 'patients' ? 'active' : '' %> <%= lockClass(canDoctorArea) %>"
|
class="nav-item <%= active === 'patients' ? 'active' : '' %> <%= lockClass(canPatients) %>"
|
||||||
<%- lockClick(canDoctorArea) %>
|
<%- lockClick(canPatients) %>
|
||||||
title="<%= canDoctorArea ? '' : 'Nur Arzt' %>"
|
title="<%= canPatients ? '' : 'Nur Arzt oder Mitarbeiter' %>"
|
||||||
>
|
>
|
||||||
<i class="bi bi-people"></i> <%= t.sidebar.patients %>
|
<i class="bi bi-people"></i> Patienten
|
||||||
<% if (!canDoctorArea) { %>
|
<% if (!canPatients) { %>
|
||||||
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Medikamente -->
|
<!-- Medikamente -->
|
||||||
<a
|
<a
|
||||||
href="<%= hrefIfAllowed(canDoctorArea, '/medications') %>"
|
href="<%= hrefIfAllowed(canStaffArea, '/medications') %>"
|
||||||
class="nav-item <%= active === 'medications' ? 'active' : '' %> <%= lockClass(canDoctorArea) %>"
|
class="nav-item <%= active === 'medications' ? 'active' : '' %> <%= lockClass(canStaffArea) %>"
|
||||||
<%- lockClick(canDoctorArea) %>
|
<%- lockClick(canStaffArea) %>
|
||||||
title="<%= canDoctorArea ? '' : 'Nur Arzt' %>"
|
title="<%= canStaffArea ? '' : 'Nur Arzt oder Mitarbeiter' %>"
|
||||||
>
|
>
|
||||||
<i class="bi bi-capsule"></i> <%= t.sidebar.medications %>
|
<i class="bi bi-capsule"></i> Medikamente
|
||||||
<% if (!canDoctorArea) { %>
|
<% if (!canStaffArea) { %>
|
||||||
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Offene Leistungen -->
|
<!-- Offene Leistungen -->
|
||||||
<a
|
<a
|
||||||
href="<%= hrefIfAllowed(canDoctorArea, '/services/open') %>"
|
href="<%= hrefIfAllowed(canStaffArea, '/services/open') %>"
|
||||||
class="nav-item <%= active === 'services' ? 'active' : '' %> <%= lockClass(canDoctorArea) %>"
|
class="nav-item <%= active === 'services' ? 'active' : '' %> <%= lockClass(canStaffArea) %>"
|
||||||
<%- lockClick(canDoctorArea) %>
|
<%- lockClick(canStaffArea) %>
|
||||||
title="<%= canDoctorArea ? '' : 'Nur Arzt' %>"
|
title="<%= canStaffArea ? '' : 'Nur Arzt oder Mitarbeiter' %>"
|
||||||
>
|
>
|
||||||
<i class="bi bi-receipt"></i> <%= t.sidebar.servicesOpen %>
|
<i class="bi bi-receipt"></i> Offene Leistungen
|
||||||
<% if (!canDoctorArea) { %>
|
<% if (!canStaffArea) { %>
|
||||||
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
@ -97,20 +80,20 @@
|
|||||||
<%- lockClick(canDoctorArea) %>
|
<%- lockClick(canDoctorArea) %>
|
||||||
title="<%= canDoctorArea ? '' : 'Nur Arzt' %>"
|
title="<%= canDoctorArea ? '' : 'Nur Arzt' %>"
|
||||||
>
|
>
|
||||||
<i class="bi bi-cash-coin"></i> <%= t.sidebar.billing %>
|
<i class="bi bi-cash-stack"></i> Abrechnung
|
||||||
<% if (!canDoctorArea) { %>
|
<% if (!canDoctorArea) { %>
|
||||||
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Verwaltung (nur Admin) -->
|
<!-- Verwaltung -->
|
||||||
<a
|
<a
|
||||||
href="<%= hrefIfAllowed(canAdminArea, '/admin/users') %>"
|
href="<%= hrefIfAllowed(canAdminArea, '/admin/users') %>"
|
||||||
class="nav-item <%= active === 'admin' ? 'active' : '' %> <%= lockClass(canAdminArea) %>"
|
class="nav-item <%= active === 'admin' ? 'active' : '' %> <%= lockClass(canAdminArea) %>"
|
||||||
<%- lockClick(canAdminArea) %>
|
<%- lockClick(canAdminArea) %>
|
||||||
title="<%= canAdminArea ? '' : 'Nur Admin' %>"
|
title="<%= canAdminArea ? '' : 'Nur Admin' %>"
|
||||||
>
|
>
|
||||||
<i class="bi bi-gear"></i> <%= t.sidebar.admin %>
|
<i class="bi bi-gear"></i> Verwaltung
|
||||||
<% if (!canAdminArea) { %>
|
<% if (!canAdminArea) { %>
|
||||||
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
<span style="margin-left:auto;"><i class="bi bi-lock-fill"></i></span>
|
||||||
<% } %>
|
<% } %>
|
||||||
@ -122,3 +105,58 @@
|
|||||||
<i class="bi bi-box-arrow-right"></i> Logout
|
<i class="bi bi-box-arrow-right"></i> Logout
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar {
|
||||||
|
width: 260px;
|
||||||
|
background: #111827;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #1f2937;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.locked {
|
||||||
|
opacity: 0.45;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -2,24 +2,63 @@
|
|||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Patientenübersicht</title>
|
<title>
|
||||||
|
Patient: <%= patient.firstname %> <%= patient.lastname %>
|
||||||
|
</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Ubuntu;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-light">
|
<body>
|
||||||
|
<div class="layout">
|
||||||
|
<!-- ✅ Sidebar -->
|
||||||
|
<%- include("partials/patient_overview_dashboard_sidebar", { patient, active: "overview" }) %>
|
||||||
|
|
||||||
|
<!-- ✅ MAIN -->
|
||||||
|
<div class="main">
|
||||||
<!-- NAVBAR -->
|
<!-- NAVBAR -->
|
||||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<div
|
<div
|
||||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||||
>
|
>
|
||||||
<span style="font-size: 1.4rem">👥</span>
|
<i class="bi bi-person-badge fs-4"></i>
|
||||||
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
<span class="fw-semibold fs-5">
|
||||||
|
<%= patient.firstname %> <%= patient.lastname %>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ms-auto">
|
<div class="ms-auto d-flex gap-2">
|
||||||
|
<a href="/patients" class="btn btn-outline-light btn-sm">
|
||||||
|
⬅️ Patientenübersicht
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||||
⬅️ Dashboard
|
Dashboard
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -31,8 +70,8 @@
|
|||||||
<h4>👤 <%= patient.firstname %> <%= patient.lastname %></h4>
|
<h4>👤 <%= patient.firstname %> <%= patient.lastname %></h4>
|
||||||
|
|
||||||
<p class="text-muted mb-3">
|
<p class="text-muted mb-3">
|
||||||
Geboren am <%= new
|
Geboren am
|
||||||
Date(patient.birthdate).toLocaleDateString("de-DE") %>
|
<%= new Date(patient.birthdate).toLocaleDateString("de-DE") %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
@ -44,8 +83,8 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<strong>Adresse:</strong>
|
<strong>Adresse:</strong>
|
||||||
<%= patient.street || "" %> <%= patient.house_number || "" %>, <%=
|
<%= patient.street || "" %> <%= patient.house_number || "" %>,
|
||||||
patient.postal_code || "" %> <%= patient.city || "" %>
|
<%= patient.postal_code || "" %> <%= patient.city || "" %>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -132,10 +171,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% invoices.forEach(i => { %>
|
<% invoices.forEach(i => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><%= new Date(i.invoice_date).toLocaleDateString("de-DE") %></td>
|
||||||
<%= new Date(i.invoice_date).toLocaleDateString("de-DE")
|
|
||||||
%>
|
|
||||||
</td>
|
|
||||||
<td><%= Number(i.total_amount).toFixed(2) %> €</td>
|
<td><%= Number(i.total_amount).toFixed(2) %> €</td>
|
||||||
<td>
|
<td>
|
||||||
<% if (i.file_path) { %>
|
<% if (i.file_path) { %>
|
||||||
@ -146,7 +182,9 @@
|
|||||||
>
|
>
|
||||||
📄 Öffnen
|
📄 Öffnen
|
||||||
</a>
|
</a>
|
||||||
<% } else { %> - <% } %>
|
<% } else { %>
|
||||||
|
-
|
||||||
|
<% } %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
@ -159,5 +197,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -4,19 +4,65 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Patientenübersicht</title>
|
<title>Patientenübersicht</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css" />
|
||||||
|
<script src="/js/flash_auto_hide.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Ubuntu;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0;
|
||||||
|
background: #f4f6f9;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-col {
|
||||||
|
width: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-hide-flash {
|
||||||
|
transition: opacity 0.6s ease, transform 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-hide-flash.flash-hide {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
|
||||||
|
<body>
|
||||||
|
<div class="layout">
|
||||||
|
<!-- ✅ Sidebar -->
|
||||||
|
<%- include("partials/patient_sidebar", { active: "patients_list", patient: null }) %>
|
||||||
|
|
||||||
|
<!-- ✅ MAIN -->
|
||||||
|
<div class="main">
|
||||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<!-- 🟢 ZENTRIERTER TITEL -->
|
|
||||||
<div
|
<div
|
||||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||||
>
|
>
|
||||||
<span style="font-size: 1.4rem">👥</span>
|
<i class="bi bi-people fs-4"></i>
|
||||||
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
|
||||||
<div class="ms-auto">
|
<div class="ms-auto">
|
||||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||||
⬅️ Dashboard
|
⬅️ Dashboard
|
||||||
@ -27,9 +73,10 @@
|
|||||||
<div class="container-fluid mt-4">
|
<div class="container-fluid mt-4">
|
||||||
<%- include("partials/flash") %>
|
<%- include("partials/flash") %>
|
||||||
|
|
||||||
<!-- Aktionen oben -->
|
|
||||||
<div class="d-flex gap-2 mb-3">
|
<div class="d-flex gap-2 mb-3">
|
||||||
<a href="/patients/create" class="btn btn-success"> + Neuer Patient </a>
|
<a href="/patients/create" class="btn btn-success">
|
||||||
|
+ Neuer Patient
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card shadow">
|
<div class="card shadow">
|
||||||
@ -66,7 +113,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 d-flex gap-2">
|
<div class="col-md-3 d-flex gap-2">
|
||||||
<button class="btn btn-primary w-100">Suchen</button>
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
Suchen
|
||||||
|
</button>
|
||||||
<a href="/patients" class="btn btn-secondary w-100">
|
<a href="/patients" class="btn btn-secondary w-100">
|
||||||
Zurücksetzen
|
Zurücksetzen
|
||||||
</a>
|
</a>
|
||||||
@ -75,12 +124,10 @@
|
|||||||
|
|
||||||
<!-- Tabelle -->
|
<!-- Tabelle -->
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table
|
<table class="table table-bordered table-hover align-middle table-sm">
|
||||||
class="table table-bordered table-hover align-middle table-sm"
|
|
||||||
>
|
|
||||||
<thead class="table-dark">
|
<thead class="table-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th class="radio-col">✔</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>N.I.E. / DNI</th>
|
<th>N.I.E. / DNI</th>
|
||||||
<th>Geschlecht</th>
|
<th>Geschlecht</th>
|
||||||
@ -93,9 +140,9 @@
|
|||||||
<th>Notizen</th>
|
<th>Notizen</th>
|
||||||
<th>Erstellt</th>
|
<th>Erstellt</th>
|
||||||
<th>Geändert</th>
|
<th>Geändert</th>
|
||||||
<th>Aktionen</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<% if (patients.length === 0) { %>
|
<% if (patients.length === 0) { %>
|
||||||
<tr>
|
<tr>
|
||||||
@ -103,17 +150,34 @@
|
|||||||
Keine Patienten gefunden
|
Keine Patienten gefunden
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% } %> <% patients.forEach(p => { %>
|
<% } %>
|
||||||
<tr>
|
|
||||||
<td><%= p.id %></td>
|
<% patients.forEach(p => { %>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="selectedPatient"
|
||||||
|
class="form-check-input patient-radio"
|
||||||
|
data-id="<%= p.id %>"
|
||||||
|
data-firstname="<%= p.firstname %>"
|
||||||
|
data-lastname="<%= p.lastname %>"
|
||||||
|
data-waiting="<%= p.waiting_room ? '1' : '0' %>"
|
||||||
|
data-active="<%= p.active ? '1' : '0' %>"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<strong><%= p.firstname %> <%= p.lastname %></strong>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td><strong><%= p.firstname %> <%= p.lastname %></strong></td>
|
|
||||||
<td><%= p.dni || "-" %></td>
|
<td><%= p.dni || "-" %></td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<% if (p.gender === 'm') { %>m <% } else if (p.gender ===
|
<% if (p.gender === 'm') { %>m
|
||||||
'w') { %>w <% } else if (p.gender === 'd') { %>d <% } else {
|
<% } else if (p.gender === 'w') { %>w
|
||||||
%>-<% } %>
|
<% } else if (p.gender === 'd') { %>d
|
||||||
|
<% } else { %>-<% } %>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -134,7 +198,7 @@
|
|||||||
<% if (p.active) { %>
|
<% if (p.active) { %>
|
||||||
<span class="badge bg-success">Aktiv</span>
|
<span class="badge bg-success">Aktiv</span>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<span class="badge bg-secondary">Inaktiv</span>
|
<span class="badge bg-danger">Inaktiv</span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -144,127 +208,23 @@
|
|||||||
|
|
||||||
<td><%= new Date(p.created_at).toLocaleString("de-DE") %></td>
|
<td><%= new Date(p.created_at).toLocaleString("de-DE") %></td>
|
||||||
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
||||||
|
|
||||||
<!-- AKTIONEN -->
|
|
||||||
<td class="text-nowrap">
|
|
||||||
<div class="dropdown">
|
|
||||||
<button
|
|
||||||
class="btn btn-sm btn-outline-secondary"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
>
|
|
||||||
Auswahl ▾
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul
|
|
||||||
class="dropdown-menu dropdown-menu-end position-fixed"
|
|
||||||
>
|
|
||||||
<!-- ✏️ BEARBEITEN -->
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
href="/patients/edit/<%= p.id %>"
|
|
||||||
>
|
|
||||||
✏️ Bearbeiten
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><hr class="dropdown-divider" /></li>
|
|
||||||
|
|
||||||
<!-- 🪑 WARTEZIMMER -->
|
|
||||||
<% if (p.waiting_room) { %>
|
|
||||||
<li>
|
|
||||||
<span class="dropdown-item text-muted">
|
|
||||||
🪑 Wartet bereits
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<% } else { %>
|
|
||||||
<li>
|
|
||||||
<form
|
|
||||||
method="POST"
|
|
||||||
action="/patients/waiting-room/<%= p.id %>"
|
|
||||||
>
|
|
||||||
<button class="dropdown-item">
|
|
||||||
🪑 Ins Wartezimmer
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<li><hr class="dropdown-divider" /></li>
|
|
||||||
|
|
||||||
<!-- 💊 MEDIKAMENTE -->
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
href="/patients/<%= p.id %>/medications"
|
|
||||||
>
|
|
||||||
💊 Medikamente
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><hr class="dropdown-divider" /></li>
|
|
||||||
|
|
||||||
<!-- 🔒 STATUS -->
|
|
||||||
<li>
|
|
||||||
<% if (p.active) { %>
|
|
||||||
<form
|
|
||||||
method="POST"
|
|
||||||
action="/patients/deactivate/<%= p.id %>"
|
|
||||||
>
|
|
||||||
<button class="dropdown-item text-warning">
|
|
||||||
🔒 Sperren
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<% } else { %>
|
|
||||||
<form
|
|
||||||
method="POST"
|
|
||||||
action="/patients/activate/<%= p.id %>"
|
|
||||||
>
|
|
||||||
<button class="dropdown-item text-success">
|
|
||||||
🔓 Entsperren
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<% } %>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<!-- 📋 ÜBERSICHT -->
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="/patients/<%= p.id %>">
|
|
||||||
📋 Übersicht
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><hr class="dropdown-divider" /></li>
|
|
||||||
|
|
||||||
<!-- 📎 DATEI-UPLOAD -->
|
|
||||||
<li class="px-3 py-2">
|
|
||||||
<form
|
|
||||||
method="POST"
|
|
||||||
action="/patients/<%= p.id %>/files"
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
name="file"
|
|
||||||
class="form-control form-control-sm mb-2"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<button class="btn btn-sm btn-secondary w-100">
|
|
||||||
📎 Hochladen
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="text-muted mt-2" style="font-size: 13px;">
|
||||||
|
Patient auswählen → Sidebar links zeigt Aktionen ✅
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<!-- ✅ Helmet-safe -->
|
||||||
|
<script src="/js/patients_sidebar.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user