Rezept hinzugefügt auswahl der MEdikamente

This commit is contained in:
Cay 2026-01-08 18:57:44 +00:00
parent 798ba92b8a
commit d41b0d22d1
13 changed files with 1019 additions and 771 deletions

View File

@ -1,13 +1,23 @@
const db = require("../db"); const db = require("../db");
const { createUser, getAllUsers} = require("../services/admin.service"); const { createUser, getAllUsers } = require("../services/admin.service");
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
async function listUsers(req, res) { async function listUsers(req, res) {
const { q } = req.query;
try { try {
const users = await getAllUsers(db); let users;
if (q) {
users = await getAllUsers(db, q);
} else {
users = await getAllUsers(db);
}
res.render("admin_users", { res.render("admin_users", {
users, users,
currentUser: req.session.user currentUser: req.session.user,
query: { q },
}); });
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -18,7 +28,7 @@ async function listUsers(req, res) {
function showCreateUser(req, res) { function showCreateUser(req, res) {
res.render("admin_create_user", { res.render("admin_create_user", {
error: null, error: null,
user: req.session.user user: req.session.user,
}); });
} }
@ -30,20 +40,20 @@ async function postCreateUser(req, res) {
password, password,
role, role,
fachrichtung, fachrichtung,
arztnummer arztnummer,
} = req.body; } = req.body;
first_name = first_name?.trim(); first_name = first_name?.trim();
last_name = last_name?.trim(); last_name = last_name?.trim();
username = username?.trim(); username = username?.trim();
fachrichtung = fachrichtung?.trim(); fachrichtung = fachrichtung?.trim();
arztnummer = arztnummer?.trim(); arztnummer = arztnummer?.trim();
// 🔴 Grundvalidierung // 🔴 Grundvalidierung
if (!first_name || !last_name || !username || !password || !role) { if (!first_name || !last_name || !username || !password || !role) {
return res.render("admin_create_user", { return res.render("admin_create_user", {
error: "Alle Pflichtfelder müssen ausgefüllt sein", error: "Alle Pflichtfelder müssen ausgefüllt sein",
user: req.session.user user: req.session.user,
}); });
} }
@ -52,7 +62,7 @@ async function postCreateUser(req, res) {
if (!fachrichtung || !arztnummer) { if (!fachrichtung || !arztnummer) {
return res.render("admin_create_user", { return res.render("admin_create_user", {
error: "Für Ärzte sind Fachrichtung und Arztnummer Pflicht", error: "Für Ärzte sind Fachrichtung und Arztnummer Pflicht",
user: req.session.user user: req.session.user,
}); });
} }
} else { } else {
@ -75,20 +85,18 @@ async function postCreateUser(req, res) {
req.session.flash = { req.session.flash = {
type: "success", type: "success",
message: "Benutzer erfolgreich angelegt" message: "Benutzer erfolgreich angelegt",
}; };
res.redirect("/admin/users"); res.redirect("/admin/users");
} catch (error) { } catch (error) {
res.render("admin_create_user", { res.render("admin_create_user", {
error, error,
user: req.session.user user: req.session.user,
}); });
} }
} }
async function changeUserRole(req, res) { async function changeUserRole(req, res) {
const userId = req.params.id; const userId = req.params.id;
const { role } = req.body; const { role } = req.body;
@ -98,19 +106,21 @@ async function changeUserRole(req, res) {
return res.redirect("/admin/users"); return res.redirect("/admin/users");
} }
db.query( db.query("UPDATE users SET role = ? WHERE id = ?", [role, userId], (err) => {
"UPDATE users SET role = ? WHERE id = ?", if (err) {
[role, userId], console.error(err);
err => { req.session.flash = {
if (err) { type: "danger",
console.error(err); message: "Fehler beim Ändern der Rolle",
req.session.flash = { type: "danger", message: "Fehler beim Ändern der Rolle" }; };
} else { } else {
req.session.flash = { type: "success", message: "Rolle erfolgreich geändert" }; req.session.flash = {
} type: "success",
res.redirect("/admin/users"); message: "Rolle erfolgreich geändert",
};
} }
); res.redirect("/admin/users");
});
} }
async function resetUserPassword(req, res) { async function resetUserPassword(req, res) {
@ -123,27 +133,74 @@ async function resetUserPassword(req, res) {
} }
const hash = await bcrypt.hash(password, 10); const hash = await bcrypt.hash(password, 10);
db.query( db.query(
"UPDATE users SET password = ? WHERE id = ?", "UPDATE users SET password = ? WHERE id = ?",
[hash, userId], [hash, userId],
err => { (err) => {
if (err) { if (err) {
console.error(err); console.error(err);
req.session.flash = { type: "danger", message: "Fehler beim Zurücksetzen" }; req.session.flash = {
type: "danger",
message: "Fehler beim Zurücksetzen",
};
} else { } else {
req.session.flash = { type: "success", message: "Passwort zurückgesetzt" }; req.session.flash = {
type: "success",
message: "Passwort zurückgesetzt",
};
} }
res.redirect("/admin/users"); res.redirect("/admin/users");
} }
); );
} }
function activateUser(req, res) {
const userId = req.params.id;
db.query("UPDATE users SET active = 1 WHERE id = ?", [userId], (err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Benutzer konnte nicht aktiviert werden",
};
} else {
req.session.flash = {
type: "success",
message: "Benutzer wurde aktiviert",
};
}
res.redirect("/admin/users");
});
}
function deactivateUser(req, res) {
const userId = req.params.id;
db.query("UPDATE users SET active = 0 WHERE id = ?", [userId], (err) => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Benutzer konnte nicht deaktiviert werden",
};
} else {
req.session.flash = {
type: "success",
message: "Benutzer wurde deaktiviert",
};
}
res.redirect("/admin/users");
});
}
module.exports = { module.exports = {
listUsers, listUsers,
showCreateUser, showCreateUser,
postCreateUser, postCreateUser,
changeUserRole, changeUserRole,
resetUserPassword resetUserPassword,
activateUser,
deactivateUser,
}; };

View File

@ -10,7 +10,7 @@ function createPatient(req, res) {
db.query( db.query(
"INSERT INTO patients (firstname, lastname, birthdate, active) VALUES (?, ?, ?, 1)", "INSERT INTO patients (firstname, lastname, birthdate, active) VALUES (?, ?, ?, 1)",
[firstname, lastname, birthdate], [firstname, lastname, birthdate],
err => { (err) => {
if (err) { if (err) {
console.error(err); console.error(err);
return res.send("Datenbankfehler"); return res.send("Datenbankfehler");
@ -26,15 +26,28 @@ function listPatients(req, res) {
let sql = "SELECT * FROM patients WHERE 1=1"; let sql = "SELECT * FROM patients WHERE 1=1";
const params = []; const params = [];
if (firstname) { sql += " AND firstname LIKE ?"; params.push(`%${firstname}%`); } if (firstname) {
if (lastname) { sql += " AND lastname LIKE ?"; params.push(`%${lastname}%`); } sql += " AND firstname LIKE ?";
if (birthdate) { sql += " AND birthdate = ?"; params.push(birthdate); } params.push(`%${firstname}%`);
}
if (lastname) {
sql += " AND lastname LIKE ?";
params.push(`%${lastname}%`);
}
if (birthdate) {
sql += " AND birthdate = ?";
params.push(birthdate);
}
sql += " ORDER BY lastname, firstname"; sql += " ORDER BY lastname, firstname";
db.query(sql, params, (err, patients) => { db.query(sql, params, (err, patients) => {
if (err) return res.send("Datenbankfehler"); if (err) return res.send("Datenbankfehler");
res.render("patients", { patients, query: req.query, user: req.session.user}); res.render("patients", {
patients,
query: req.query,
user: req.session.user,
});
}); });
} }
@ -43,12 +56,13 @@ function showEditPatient(req, res) {
"SELECT * FROM patients WHERE id = ?", "SELECT * FROM patients WHERE id = ?",
[req.params.id], [req.params.id],
(err, results) => { (err, results) => {
if (err || results.length === 0) return res.send("Patient nicht gefunden"); if (err || results.length === 0)
return res.send("Patient nicht gefunden");
res.render("patient_edit", { res.render("patient_edit", {
patient: results[0], patient: results[0],
error: null, error: null,
user: req.session.user, user: req.session.user,
returnTo: req.query.returnTo || null returnTo: req.query.returnTo || null,
}); });
} }
); );
@ -71,13 +85,13 @@ function updatePatient(req, res) {
postal_code, postal_code,
city, city,
country, country,
notes notes,
} = req.body; } = req.body;
if (!firstname || !lastname || !birthdate) { if (!firstname || !lastname || !birthdate) {
req.session.flash = { req.session.flash = {
type: "warning", type: "warning",
message: "Vorname, Nachname und Geburtsdatum sind Pflichtfelder" message: "Vorname, Nachname und Geburtsdatum sind Pflichtfelder",
}; };
return res.redirect("back"); return res.redirect("back");
} }
@ -112,9 +126,9 @@ function updatePatient(req, res) {
city || null, city || null,
country || null, country || null,
notes || null, notes || null,
id id,
], ],
err => { (err) => {
if (err) { if (err) {
console.error(err); console.error(err);
return res.send("Fehler beim Speichern"); return res.send("Fehler beim Speichern");
@ -174,14 +188,15 @@ function showPatientMedications(req, res) {
if (err) return res.send("Medikamente konnten nicht geladen werden"); if (err) return res.send("Medikamente konnten nicht geladen werden");
db.query(currentSql, [patientId], (err, currentMeds) => { db.query(currentSql, [patientId], (err, currentMeds) => {
if (err) return res.send("Aktuelle Medikation konnte nicht geladen werden"); if (err)
return res.send("Aktuelle Medikation konnte nicht geladen werden");
res.render("patient_medications", { res.render("patient_medications", {
patient: patients[0], patient: patients[0],
meds, meds,
currentMeds, currentMeds,
user: req.session.user, user: req.session.user,
returnTo returnTo,
}); });
}); });
}); });
@ -199,7 +214,7 @@ function moveToWaitingRoom(req, res) {
WHERE id = ? WHERE id = ?
`, `,
[id], [id],
err => { (err) => {
if (err) return res.send("Fehler beim Verschieben ins Wartezimmer"); if (err) return res.send("Fehler beim Verschieben ins Wartezimmer");
res.redirect("/patients"); res.redirect("/patients");
} }
@ -214,7 +229,7 @@ function showWaitingRoom(req, res) {
res.render("waiting_room", { res.render("waiting_room", {
patients, patients,
user: req.session.user user: req.session.user,
}); });
} }
); );
@ -236,15 +251,17 @@ function showPatientOverview(req, res) {
ORDER BY created_at DESC ORDER BY created_at DESC
`; `;
// 🔤 Services dynamisch nach Sprache laden const medicationVariantsSql = `
const servicesSql = (nameField) => `
SELECT SELECT
id, mv.id AS variant_id,
${nameField} AS name, m.name AS medication_name,
price mf.name AS form_name,
FROM services mv.dosage,
WHERE active = 1 mv.package
ORDER BY ${nameField} FROM medication_variants mv
JOIN medications m ON mv.medication_id = m.id
JOIN medication_forms mf ON mv.form_id = mf.id
ORDER BY m.name, mf.name, mv.dosage
`; `;
db.query(patientSql, [patientId], (err, patients) => { db.query(patientSql, [patientId], (err, patients) => {
@ -254,12 +271,22 @@ function showPatientOverview(req, res) {
const patient = patients[0]; const patient = patients[0];
// 🇪🇸 / 🇩🇪 Sprache bestimmen // 🇪🇸 / 🇩🇪 Sprache für Leistungen
const serviceNameField = const serviceNameField =
patient.country === "ES" patient.country === "ES"
? "COALESCE(NULLIF(name_es, ''), name_de)" ? "COALESCE(NULLIF(name_es, ''), name_de)"
: "name_de"; : "name_de";
const servicesSql = `
SELECT
id,
${serviceNameField} AS name,
price
FROM services
WHERE active = 1
ORDER BY ${serviceNameField}
`;
const todayServicesSql = ` const todayServicesSql = `
SELECT SELECT
ps.id, ps.id,
@ -279,18 +306,23 @@ function showPatientOverview(req, res) {
db.query(notesSql, [patientId], (err, notes) => { db.query(notesSql, [patientId], (err, notes) => {
if (err) return res.send("Fehler Notizen"); if (err) return res.send("Fehler Notizen");
db.query(servicesSql(serviceNameField), (err, services) => { db.query(servicesSql, (err, services) => {
if (err) return res.send("Fehler Leistungen"); if (err) return res.send("Fehler Leistungen");
db.query(todayServicesSql, [patientId], (err, todayServices) => { db.query(todayServicesSql, [patientId], (err, todayServices) => {
if (err) return res.send("Fehler heutige Leistungen"); if (err) return res.send("Fehler heutige Leistungen");
res.render("patient_overview", { db.query(medicationVariantsSql, (err, medicationVariants) => {
patient, if (err) return res.send("Fehler Medikamente");
notes,
services, res.render("patient_overview", {
todayServices, patient,
user: req.session.user notes,
services,
todayServices,
medicationVariants,
user: req.session.user,
});
}); });
}); });
}); });
@ -298,6 +330,47 @@ function showPatientOverview(req, res) {
}); });
} }
function assignMedicationToPatient(req, res) {
const patientId = req.params.id;
const { medication_variant_id, dosage_instruction, start_date, end_date } =
req.body;
if (!medication_variant_id) {
req.session.flash = {
type: "warning",
message: "Bitte ein Medikament auswählen",
};
return res.redirect(`/patients/${patientId}/overview`);
}
db.query(
`
INSERT INTO patient_medications
(patient_id, medication_variant_id, dosage_instruction, start_date, end_date)
VALUES (?, ?, ?, ?, ?)
`,
[
patientId,
medication_variant_id,
dosage_instruction || null,
start_date || new Date(),
end_date || null,
],
(err) => {
if (err) {
console.error(err);
return res.send("Fehler beim Verordnen");
}
req.session.flash = {
type: "success",
message: "Medikament erfolgreich verordnet",
};
res.redirect(`/patients/${patientId}/overview`);
}
);
}
function addPatientNote(req, res) { function addPatientNote(req, res) {
const patientId = req.params.id; const patientId = req.params.id;
@ -310,7 +383,7 @@ function addPatientNote(req, res) {
db.query( db.query(
"INSERT INTO patient_notes (patient_id, note) VALUES (?, ?)", "INSERT INTO patient_notes (patient_id, note) VALUES (?, ?)",
[patientId, note], [patientId, note],
err => { (err) => {
if (err) return res.send("Fehler beim Speichern der Notiz"); if (err) return res.send("Fehler beim Speichern der Notiz");
res.redirect(`/patients/${patientId}/overview`); res.redirect(`/patients/${patientId}/overview`);
} }
@ -323,7 +396,7 @@ function callFromWaitingRoom(req, res) {
db.query( db.query(
"UPDATE patients SET waiting_room = 0 WHERE id = ?", "UPDATE patients SET waiting_room = 0 WHERE id = ?",
[patientId], [patientId],
err => { (err) => {
if (err) return res.send("Fehler beim Entfernen aus dem Wartezimmer"); if (err) return res.send("Fehler beim Entfernen aus dem Wartezimmer");
res.redirect(`/patients/${patientId}/overview`); res.redirect(`/patients/${patientId}/overview`);
} }
@ -336,7 +409,7 @@ function dischargePatient(req, res) {
db.query( db.query(
"UPDATE patients SET discharged = 1 WHERE id = ?", "UPDATE patients SET discharged = 1 WHERE id = ?",
[patientId], [patientId],
err => { (err) => {
if (err) return res.send("Fehler beim Entlassen des Patienten"); if (err) return res.send("Fehler beim Entlassen des Patienten");
res.redirect("/waiting-room"); res.redirect("/waiting-room");
} }
@ -375,7 +448,7 @@ function showMedicationPlan(req, res) {
res.render("patient_plan", { res.render("patient_plan", {
patient: patients[0], patient: patients[0],
meds meds,
}); });
}); });
}); });
@ -392,19 +465,19 @@ function movePatientToWaitingRoom(req, res) {
WHERE id = ? WHERE id = ?
`, `,
[patientId], [patientId],
err => { (err) => {
if (err) { if (err) {
console.error(err); console.error(err);
req.session.flash = { req.session.flash = {
type: "danger", type: "danger",
message: "Fehler beim Zurücksetzen ins Wartezimmer" message: "Fehler beim Zurücksetzen ins Wartezimmer",
}; };
return res.redirect(`/patients/${patientId}/overview`); return res.redirect(`/patients/${patientId}/overview`);
} }
req.session.flash = { req.session.flash = {
type: "success", type: "success",
message: "Patient wurde ins Wartezimmer gesetzt" message: "Patient wurde ins Wartezimmer gesetzt",
}; };
res.redirect("/waiting-room"); res.redirect("/waiting-room");
@ -415,55 +488,107 @@ function movePatientToWaitingRoom(req, res) {
function deactivatePatient(req, res) { function deactivatePatient(req, res) {
const id = req.params.id; const id = req.params.id;
db.query( db.query("UPDATE patients SET active = 0 WHERE id = ?", [id], (err) => {
"UPDATE patients SET active = 0 WHERE id = ?", if (err) {
[id], console.error(err);
err => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Patient konnte nicht gesperrt werden"
};
return res.redirect("/patients");
}
req.session.flash = { req.session.flash = {
type: "success", type: "danger",
message: "Patient wurde gesperrt" message: "Patient konnte nicht gesperrt werden",
}; };
return res.redirect("/patients");
res.redirect("/patients");
} }
);
req.session.flash = {
type: "success",
message: "Patient wurde gesperrt",
};
res.redirect("/patients");
});
} }
function activatePatient(req, res) { function activatePatient(req, res) {
const id = req.params.id; const id = req.params.id;
db.query( db.query("UPDATE patients SET active = 1 WHERE id = ?", [id], (err) => {
"UPDATE patients SET active = 1 WHERE id = ?", if (err) {
[id], console.error(err);
err => {
if (err) {
console.error(err);
req.session.flash = {
type: "danger",
message: "Patient konnte nicht entsperrt werden"
};
return res.redirect("/patients");
}
req.session.flash = { req.session.flash = {
type: "success", type: "danger",
message: "Patient wurde entsperrt" message: "Patient konnte nicht entsperrt werden",
}; };
return res.redirect("/patients");
res.redirect("/patients");
} }
);
req.session.flash = {
type: "success",
message: "Patient wurde entsperrt",
};
res.redirect("/patients");
});
} }
async function showPatientOverviewDashborad(req, res) {
const patientId = req.params.id;
try {
// 👤 Patient
const [[patient]] = await db
.promise()
.query("SELECT * FROM patients WHERE id = ?", [patientId]);
if (!patient) {
return res.redirect("/patients");
}
// 💊 AKTUELLE MEDIKAMENTE (end_date IS NULL)
const [medications] = await db.promise().query(
`
SELECT
m.name AS medication_name,
mv.dosage AS variant_dosage,
pm.dosage_instruction,
pm.start_date
FROM patient_medications pm
JOIN medication_variants mv
ON pm.medication_variant_id = mv.id
JOIN medications m
ON mv.medication_id = m.id
WHERE pm.patient_id = ?
AND pm.end_date IS NULL
ORDER BY pm.start_date DESC
`,
[patientId]
);
// 🧾 RECHNUNGEN
const [invoices] = await db.promise().query(
`
SELECT
id,
invoice_date,
total_amount,
file_path,
status
FROM invoices
WHERE patient_id = ?
ORDER BY invoice_date DESC
`,
[patientId]
);
res.render("patient_overview_dashboard", {
patient,
medications,
invoices,
user: req.session.user,
});
} catch (err) {
console.error(err);
res.send("Datenbankfehler");
}
}
module.exports = { module.exports = {
listPatients, listPatients,
@ -481,5 +606,7 @@ module.exports = {
showMedicationPlan, showMedicationPlan,
movePatientToWaitingRoom, movePatientToWaitingRoom,
deactivatePatient, deactivatePatient,
activatePatient activatePatient,
showPatientOverviewDashborad,
assignMedicationToPatient,
}; };

Binary file not shown.

Binary file not shown.

View File

@ -6,7 +6,9 @@ const {
showCreateUser, showCreateUser,
postCreateUser, postCreateUser,
changeUserRole, changeUserRole,
resetUserPassword resetUserPassword,
activateUser,
deactivateUser,
} = require("../controllers/admin.controller"); } = require("../controllers/admin.controller");
const { requireAdmin } = require("../middleware/auth.middleware"); const { requireAdmin } = require("../middleware/auth.middleware");
@ -17,6 +19,7 @@ router.post("/create-user", requireAdmin, postCreateUser);
router.post("/users/change-role/:id", requireAdmin, changeUserRole); router.post("/users/change-role/:id", requireAdmin, changeUserRole);
router.post("/users/reset-password/:id", requireAdmin, resetUserPassword); router.post("/users/reset-password/:id", requireAdmin, resetUserPassword);
router.post("/users/activate/:id", requireAdmin, activateUser);
router.post("/users/deactivate/:id", requireAdmin, deactivateUser);
module.exports = router; module.exports = router;

View File

@ -1,10 +1,7 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
const { const { requireLogin, requireAdmin } = require("../middleware/auth.middleware");
requireLogin,
requireAdmin
} = require("../middleware/auth.middleware");
const { const {
listPatients, listPatients,
@ -20,7 +17,9 @@ const {
dischargePatient, dischargePatient,
showMedicationPlan, showMedicationPlan,
deactivatePatient, deactivatePatient,
activatePatient activatePatient,
showPatientOverviewDashborad,
assignMedicationToPatient,
} = require("../controllers/patient.controller"); } = require("../controllers/patient.controller");
router.get("/", requireLogin, listPatients); router.get("/", requireLogin, listPatients);
@ -35,8 +34,9 @@ router.post("/:id/notes", requireLogin, addPatientNote);
router.post("/waiting-room/call/:id", requireAdmin, callFromWaitingRoom); router.post("/waiting-room/call/:id", requireAdmin, callFromWaitingRoom);
router.post("/:id/discharge", requireLogin, dischargePatient); router.post("/:id/discharge", requireLogin, dischargePatient);
router.get("/:id/plan", requireLogin, showMedicationPlan); router.get("/:id/plan", requireLogin, showMedicationPlan);
router.post("/deactivate/:id", requireLogin, deactivatePatient); router.post("/deactivate/:id", requireLogin, deactivatePatient);
router.post("/activate/:id", requireLogin, activatePatient); router.post("/activate/:id", requireLogin, activatePatient);
router.get("/:id", requireLogin, showPatientOverviewDashborad);
router.post("/:id/medications/assign", requireLogin, assignMedicationToPatient);
module.exports = router; module.exports = router;

View File

@ -17,16 +17,8 @@ async function createUser(
`INSERT INTO users `INSERT INTO users
(first_name, last_name, username, password, role, fachrichtung, arztnummer, active) (first_name, last_name, username, password, role, fachrichtung, arztnummer, active)
VALUES (?, ?, ?, ?, ?, ?, ?, 1)`, VALUES (?, ?, ?, ?, ?, ?, ?, 1)`,
[ [first_name, last_name, username, hash, role, fachrichtung, arztnummer],
first_name, (err) => {
last_name,
username,
hash,
role,
fachrichtung,
arztnummer
],
err => {
if (err) { if (err) {
if (err.code === "ER_DUP_ENTRY") { if (err.code === "ER_DUP_ENTRY") {
return reject("Benutzername existiert bereits"); return reject("Benutzername existiert bereits");
@ -39,28 +31,33 @@ async function createUser(
}); });
} }
function getAllUsers(db) { async function getAllUsers(db, search = null) {
return new Promise((resolve, reject) => { let sql = `
db.query( SELECT *
`SELECT FROM users
id, WHERE 1=1
first_name, `;
last_name, const params = [];
username,
role, if (search) {
active, sql += `
lock_until AND (
FROM users first_name LIKE ?
ORDER BY last_name, first_name`, OR last_name LIKE ?
(err, users) => { OR username LIKE ?
if (err) return reject(err); )
resolve(users); `;
} const q = `%${search}%`;
); params.push(q, q, q);
}); }
sql += " ORDER BY last_name, first_name";
const [rows] = await db.promise().query(sql, params);
return rows;
} }
module.exports = { module.exports = {
createUser, createUser,
getAllUsers getAllUsers,
}; };

View File

@ -44,6 +44,30 @@
+ Neuen Benutzer anlegen + Neuen Benutzer anlegen
</a> </a>
</div> </div>
<div class="row mb-3 align-items-end">
<div class="col-md-6">
<form method="GET" action="/admin/users" class="d-flex gap-2">
<input
type="text"
name="q"
class="form-control"
placeholder="🔍 Benutzer suchen (Name oder Username)"
value="<%= query?.q || '' %>">
<button class="btn btn-outline-primary">
Suchen
</button>
<% if (query?.q) { %>
<a href="/admin/users" class="btn btn-outline-secondary">
Reset
</a>
<% } %>
</form>
</div>
</div>
<table class="table table-bordered table-hover align-middle"> <table class="table table-bordered table-hover align-middle">
<thead class="table-dark"> <thead class="table-dark">
<tr> <tr>

View File

@ -38,60 +38,6 @@ function formatDate(d) {
<% if (user && user.role === 'arzt') { %> <% if (user && user.role === 'arzt') { %>
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-body">
<h5 class="mb-3"> Medikament hinzufügen</h5>
<form method="POST"
action="/patients/<%= patient.id %>/medications?returnTo=<%= returnTo || '' %>">
<div class="mb-3">
<label class="form-label">Medikament</label>
<select name="medication_variant_id"
class="form-select"
required>
<option value="">Bitte wählen</option>
<% meds.forEach(m => { %>
<option value="<%= m.id %>">
<%= m.medication %>
<%= m.form %>
<%= m.dosage %>
<%= m.package %>
</option>
<% }) %>
</select>
</div>
<div class="mb-3">
<label class="form-label">Dosieranweisung</label>
<input type="text"
name="dosage_instruction"
class="form-control"
placeholder="z. B. 101 nach dem Essen">
</div>
<div class="row mb-3">
<div class="col">
<label class="form-label">Startdatum</label>
<input type="date"
name="start_date"
class="form-control">
</div>
<div class="col">
<label class="form-label">Enddatum</label>
<input type="date"
name="end_date"
class="form-control">
</div>
</div>
<button class="btn btn-primary">
💾 Medikament hinzufügen
</button>
</form>
</div>
</div>
<% } else { %> <% } else { %>

View File

@ -1,282 +1,274 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>Patientenübersicht <%= patient.firstname %> <%= patient.lastname %></title> <title>
<meta name="viewport" content="width=device-width, initial-scale=1"> Patientenübersicht <%= patient.firstname %> <%= patient.lastname %>
<link rel="stylesheet" href="/css/bootstrap.min.css"> </title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css" />
<script src="/js/service-search.js"></script> <script src="/js/service-search.js"></script>
</head>
</head> <body class="bg-light">
<body class="bg-light"> <!-- NAVBAR -->
<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"
>
<span style="font-size: 1.4rem">👨‍⚕️</span>
<span class="fw-semibold fs-5">
Patient <%= patient.firstname %> <%= patient.lastname %>
</span>
</div>
<nav class="navbar navbar-dark bg-dark px-3"> <div class="ms-auto">
<span class="navbar-brand"> <form
👨‍⚕️ Patient <%= patient.firstname %> <%= patient.lastname %> method="POST"
</span> action="/patients/<%= patient.id %>/waiting-room"
<a href="/waiting-room" class="btn btn-outline-light btn-sm"> onsubmit="return confirm('Patient ins Wartezimmer zurücksetzen?')"
🪑 Zurück >
</a> <button class="btn btn-warning btn-sm">🪑 Ins Wartezimmer</button>
<form method="POST"
action="/patients/<%= patient.id %>/waiting-room"
class="d-inline"
onsubmit="return confirm('Patient ins Wartezimmer zurücksetzen?')">
<button class="btn btn-warning">
🪑 Ins Wartezimmer
</button>
</form>
</nav>
<div class="container mt-4">
<%- include("partials/flash") %>
<!-- =========================
PATIENTENDATEN
========================== -->
<div class="card shadow mb-4">
<div class="card-body">
<h4>Patientendaten</h4>
<table class="table table-sm">
<tr>
<th>Vorname</th>
<td><%= patient.firstname %></td>
</tr>
<tr>
<th>Nachname</th>
<td><%= patient.lastname %></td>
</tr>
<tr>
<th>Geburtsdatum</th>
<td>
<%= patient.birthdate
? new Date(patient.birthdate).toLocaleDateString("de-DE")
: "-" %>
</td>
</tr>
<tr>
<th>Geschlecht</th>
<td>
<% if (patient.gender === 'm') { %>Männlich
<% } else if (patient.gender === 'w') { %>Weiblich
<% } else if (patient.gender === 'd') { %>Divers
<% } else { %><% } %>
</td>
</tr>
<tr>
<th>E-Mail</th>
<td><%= patient.email || "-" %></td>
</tr>
<tr>
<th>Telefon</th>
<td><%= patient.phone || "-" %></td>
</tr>
<tr>
<th>Adresse</th>
<td>
<%= patient.street || "" %> <%= patient.house_number || "" %><br>
<%= patient.postal_code || "" %> <%= patient.city || "" %><br>
<%= patient.country || "" %>
</td>
</tr>
</table>
</div>
</div>
<!-- =========================
AKTIONEN
========================== -->
<div class="d-flex flex-wrap gap-2 align-items-center mb-4">
<a href="/patients/<%= patient.id %>/medications?returnTo=overview"
class="btn btn-primary">
💊 Medikation
</a>
<a href="/patients/<%= patient.id %>/plan"
class="btn btn-outline-secondary">
📄 Medikationsplan
</a>
<a href="/patients/edit/<%= patient.id %>?returnTo=overview"
class="btn btn-outline-info">
✏️ Patient bearbeiten
</a>
<form method="POST"
action="/patients/<%= patient.id %>/discharge"
class="d-inline"
onsubmit="return confirm('Patient wirklich entlassen?')">
<button class="btn btn-danger">
🟥 Entlassen
</button>
</form> </form>
</div>
</nav>
</div> <div class="container mt-4">
<%- include("partials/flash") %>
<!-- ========================= <!-- PATIENTENDATEN -->
UNTERER BEREICH <div class="card shadow mb-4">
========================== --> <div class="card-body">
<div class="row"> <h4>Patientendaten</h4>
<table class="table table-sm">
<tr>
<th>Vorname</th>
<td><%= patient.firstname %></td>
</tr>
<tr>
<th>Nachname</th>
<td><%= patient.lastname %></td>
</tr>
<tr>
<th>Geburtsdatum</th>
<td>
<%= patient.birthdate ? new
Date(patient.birthdate).toLocaleDateString("de-DE") : "-" %>
</td>
</tr>
<tr>
<th>E-Mail</th>
<td><%= patient.email || "-" %></td>
</tr>
<tr>
<th>Telefon</th>
<td><%= patient.phone || "-" %></td>
</tr>
</table>
</div>
</div>
<!-- ========================= <!-- AKTIONEN -->
LINKS: NOTIZEN <div class="d-flex gap-2 mb-4">
========================== --> <a
<div class="col-md-7"> href="/patients/<%= patient.id %>/medications?returnTo=overview"
class="btn btn-primary"
>
💊 Medikation verwalten
</a>
<div class="card shadow"> <a
<div class="card-body"> href="/patients/edit/<%= patient.id %>?returnTo=overview"
class="btn btn-outline-info"
>
✏️ Patient bearbeiten
</a>
<h5>Notizen</h5> <form
method="POST"
action="/patients/<%= patient.id %>/discharge"
class="d-inline"
onsubmit="return confirm('Patient wirklich entlassen?')"
>
<button class="btn btn-danger">🟥 Entlassen</button>
</form>
</div>
<form method="POST" <!-- UNTERER BEREICH -->
action="/patients/<%= patient.id %>/notes" <div
class="mb-3"> class="row g-3"
style="
height: calc(100vh - 520px);
min-height: 320px;
padding-bottom: 3rem;
overflow: hidden;
"
>
<!-- 📝 NOTIZEN -->
<div class="col-lg-5 col-md-12 h-100">
<div class="card shadow h-100">
<div class="card-body d-flex flex-column h-100">
<h5>📝 Notizen</h5>
<textarea class="form-control mb-2" <form
name="note" method="POST"
rows="3" action="/patients/<%= patient.id %>/notes"
placeholder="Neue Notiz hinzufügen..."></textarea> style="flex-shrink: 0"
>
<textarea
class="form-control mb-2"
name="note"
rows="3"
style="resize: none"
placeholder="Neue Notiz hinzufügen…"
></textarea>
<button class="btn btn-sm btn-primary">
Notiz speichern
</button>
</form>
<button class="btn btn-sm btn-primary"> <hr class="my-2" style="flex-shrink: 0" />
Notiz speichern
</button>
</form>
<hr>
<% if (!notes || notes.length === 0) { %>
<p class="text-muted">Keine Notizen vorhanden</p>
<% } else { %>
<% notes.forEach(n => { %>
<div class="mb-3 p-2 border rounded bg-light">
<div class="small text-muted mb-1">
<%= new Date(n.created_at).toLocaleString("de-DE") %>
</div>
<div><%= n.note %></div>
</div>
<% }) %>
<% } %>
<div
style="
flex: 1 1 auto;
overflow-y: auto;
min-height: 0;
padding-bottom: 2rem;
"
>
<% if (!notes || notes.length === 0) { %>
<p class="text-muted">Keine Notizen vorhanden</p>
<% } else { %> <% notes.forEach(n => { %>
<div class="mb-3 p-2 border rounded bg-light">
<div class="small text-muted">
<%= new Date(n.created_at).toLocaleString("de-DE") %>
</div>
<div><%= n.note %></div>
</div> </div>
<% }) %> <% } %>
</div>
</div> </div>
</div>
</div> </div>
<!-- ========================= <!-- 💊 MEDIKAMENT -->
RECHTS: HEUTIGE LEISTUNGEN <div class="col-lg-3 col-md-6 h-100">
========================== --> <div class="card shadow h-100">
<div class="col-md-5"> <div class="card-body">
<h5>💊 Rezept erstellen</h5>
<div class="card shadow"> <form
<div class="card-body"> method="POST"
action="/patients/<%= patient.id %>/medications/assign"
>
<select
name="medication_variant_id"
class="form-select mb-2"
required
>
<option value="">Bitte auswählen…</option>
<% medicationVariants.forEach(mv => { %>
<option value="<%= mv.variant_id %>">
<%= mv.medication_name %> <%= mv.form_name %> <%=
mv.dosage %>
</option>
<% }) %>
</select>
<h5>Heutige Leistungen</h5> <input
type="text"
name="dosage_instruction"
class="form-control mb-2"
placeholder="z. B. 101"
/>
<!-- Leistung hinzufügen --> <input
<form method="POST" type="date"
action="/patients/<%= patient.id %>/services" name="start_date"
class="mb-3"> class="form-control mb-2"
value="<%= new Date().toISOString().split('T')[0] %>"
/>
<div class="mb-2"> <input type="date" name="end_date" class="form-control mb-3" />
<label class="form-label">Leistung suchen</label>
<input type="text"
id="serviceSearch"
class="form-control mb-2"
placeholder="Leistung suchen…">
</div>
<div class="mb-2"> <button class="btn btn-sm btn-success w-100">
<label class="form-label">Leistung</label> Verordnen
<select name="service_id" </button>
id="serviceSelect" </form>
class="form-select"
size="8"
required>
<% services.forEach(s => { %>
<option value="<%= s.id %>">
<%= s.name %>
<%= Number(s.price || 0).toFixed(2) %> €
</option>
<% }) %>
</select>
</div>
<div class="mb-2">
<label class="form-label">Menge</label>
<input type="number"
name="quantity"
class="form-control"
value="1"
min="1"
required>
</div>
<button class="btn btn-sm btn-success">
Leistung hinzufügen
</button>
</form>
<hr>
<!-- Heutige Leistungen anzeigen-->
<% if (!todayServices || todayServices.length === 0) { %>
<p class="text-muted">
Noch keine Leistungen für heute erfasst.
</p>
<% } else { %>
<% todayServices.forEach(ls => { %>
<div class="border rounded p-2 mb-2 bg-light">
<strong><%= ls.name %></strong><br>
Menge: <%= ls.quantity %><br>
Preis: <%= Number(ls.price).toFixed(2) %> €<br>
<small class="text-muted">
Arzt: <%= ls.doctor || "—" %>
</small>
<div class="mt-2 d-flex gap-2">
<!-- Preis ändern -->
<form method="POST"
action="/patient-services/update/<%= ls.id %>">
<input type="number"
step="0.01"
name="price"
value="<%= ls.price %>"
class="form-control form-control-sm mb-1"
required>
<button class="btn btn-sm btn-outline-warning">
💰 Preis ändern
</button>
</form>
<!-- Löschen -->
<form method="POST"
action="/patient-services/delete/<%= ls.id %>"
onsubmit="return confirm('Leistung wirklich löschen?')">
<button class="btn btn-sm btn-danger">
🗑️ Löschen
</button>
</form>
</div>
</div>
<% }) %>
<% } %>
</div>
</div> </div>
</div>
</div> </div>
<!-- 🧾 HEUTIGE LEISTUNGEN -->
<div class="col-lg-4 col-md-6 h-100">
<div class="card shadow h-100">
<div class="card-body d-flex flex-column h-100">
<h5>🧾 Heutige Leistungen</h5>
<form
method="POST"
action="/patients/<%= patient.id %>/services"
style="flex-shrink: 0"
>
<input
type="text"
id="serviceSearch"
class="form-control mb-2"
placeholder="Leistung suchen…"
/>
<select
name="service_id"
id="serviceSelect"
class="form-select mb-2"
size="5"
required
>
<% services.forEach(s => { %>
<option value="<%= s.id %>">
<%= s.name %> <%= Number(s.price || 0).toFixed(2) %> €
</option>
<% }) %>
</select>
<input
type="number"
name="quantity"
class="form-control mb-2"
value="1"
min="1"
/>
<button class="btn btn-sm btn-success w-100">
Leistung hinzufügen
</button>
</form>
<hr class="my-2" style="flex-shrink: 0" />
<div
style="
flex: 1 1 auto;
overflow-y: auto;
min-height: 0;
padding-bottom: 2rem;
"
>
<% if (!todayServices || todayServices.length === 0) { %>
<p class="text-muted">Noch keine Leistungen für heute.</p>
<% } else { %> <% todayServices.forEach(ls => { %>
<div class="border rounded p-2 mb-2 bg-light">
<strong><%= ls.name %></strong><br />
Menge: <%= ls.quantity %><br />
Preis: <%= Number(ls.price).toFixed(2) %> €
</div>
<% }) %> <% } %>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</body>
</div>
</body>
</html> </html>

View File

@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<title>Patientenübersicht</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css" />
</head>
<body class="bg-light">
<!-- NAVBAR -->
<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"
>
<span style="font-size: 1.4rem">👥</span>
<span class="fw-semibold fs-5">Patientenübersicht</span>
</div>
<div class="ms-auto">
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
⬅️ Dashboard
</a>
</div>
</nav>
<div class="container mt-4">
<!-- PATIENT INFO -->
<div class="card shadow mb-4">
<div class="card-body">
<h4>👤 <%= patient.firstname %> <%= patient.lastname %></h4>
<p class="text-muted mb-3">
Geboren am <%= new
Date(patient.birthdate).toLocaleDateString("de-DE") %>
</p>
<ul class="list-group">
<li class="list-group-item">
<strong>E-Mail:</strong> <%= patient.email || "-" %>
</li>
<li class="list-group-item">
<strong>Telefon:</strong> <%= patient.phone || "-" %>
</li>
<li class="list-group-item">
<strong>Adresse:</strong>
<%= patient.street || "" %> <%= patient.house_number || "" %>, <%=
patient.postal_code || "" %> <%= patient.city || "" %>
</li>
</ul>
</div>
</div>
<!-- =========================
MEDIKAMENTE & RECHNUNGEN
========================== -->
<div
class="row g-3"
style="
height: calc(100vh - 420px);
min-height: 300px;
padding-bottom: 3rem;
overflow: hidden;
"
>
<!-- 💊 MEDIKAMENTE -->
<div class="col-lg-6 h-100">
<div class="card shadow h-100">
<div class="card-body d-flex flex-column h-100">
<h5>💊 Aktuelle Medikamente</h5>
<div
style="
flex: 1 1 auto;
overflow-y: auto;
min-height: 0;
padding-bottom: 1.5rem;
"
>
<% if (medications.length === 0) { %>
<p class="text-muted">Keine aktiven Medikamente</p>
<% } else { %>
<table class="table table-sm table-bordered mt-2">
<thead class="table-light">
<tr>
<th>Medikament</th>
<th>Variante</th>
<th>Anweisung</th>
</tr>
</thead>
<tbody>
<% medications.forEach(m => { %>
<tr>
<td><%= m.medication_name %></td>
<td><%= m.variant_dosage %></td>
<td><%= m.dosage_instruction || "-" %></td>
</tr>
<% }) %>
</tbody>
</table>
<% } %>
</div>
</div>
</div>
</div>
<!-- 🧾 RECHNUNGEN -->
<div class="col-lg-6 h-100">
<div class="card shadow h-100">
<div class="card-body d-flex flex-column h-100">
<h5>🧾 Rechnungen</h5>
<div
style="
flex: 1 1 auto;
overflow-y: auto;
min-height: 0;
padding-bottom: 1.5rem;
"
>
<% if (invoices.length === 0) { %>
<p class="text-muted">Keine Rechnungen vorhanden</p>
<% } else { %>
<table class="table table-sm table-bordered mt-2">
<thead class="table-light">
<tr>
<th>Datum</th>
<th>Betrag</th>
<th>PDF</th>
</tr>
</thead>
<tbody>
<% invoices.forEach(i => { %>
<tr>
<td>
<%= new Date(i.invoice_date).toLocaleDateString("de-DE")
%>
</td>
<td><%= Number(i.total_amount).toFixed(2) %> €</td>
<td>
<% if (i.file_path) { %>
<a
href="<%= i.file_path %>"
target="_blank"
class="btn btn-sm btn-outline-primary"
>
📄 Öffnen
</a>
<% } else { %> - <% } %>
</td>
</tr>
<% }) %>
</tbody>
</table>
<% } %>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,74 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Medikationsplan <%= patient.firstname %> <%= patient.lastname %></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body class="bg-light">
<nav class="navbar navbar-dark bg-dark px-3">
<span class="navbar-brand">
📄 Medikationsplan <%= patient.firstname %> <%= patient.lastname %>
</span>
<a href="/patients/<%= patient.id %>/overview"
class="btn btn-outline-light btn-sm">
Zurück
</a>
</nav>
<div class="container mt-4">
<%- include("partials/flash") %>
<div class="card shadow">
<div class="card-body">
<table class="table table-bordered table-sm">
<thead class="table-light">
<tr>
<th>Medikament</th>
<th>Form</th>
<th>Dosierung</th>
<th>Packung</th>
<th>Anweisung</th>
<th>Zeitraum</th>
</tr>
</thead>
<tbody>
<% if (meds.length === 0) { %>
<tr>
<td colspan="6" class="text-center text-muted">
Keine aktuelle Medikation
</td>
</tr>
<% } %>
<% meds.forEach(m => { %>
<tr>
<td><%= m.medication %></td>
<td><%= m.form %></td>
<td><%= m.dosage %></td>
<td><%= m.package %></td>
<td><%= m.dosage_instruction || "-" %></td>
<td>
<%= m.start_date
? new Date(m.start_date).toLocaleDateString("de-DE")
: "-" %>
<%= m.end_date
? new Date(m.end_date).toLocaleDateString("de-DE")
: "laufend" %>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,257 +1,270 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<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" />
</head> </head>
<body class="bg-light"> <body class="bg-light">
<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
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>
<span class="fw-semibold fs-5">Patientenübersicht</span>
</div>
<!-- 🟢 ZENTRIERTER TITEL --> <!-- 🔵 RECHTS: DASHBOARD -->
<div class="position-absolute top-50 start-50 translate-middle <div class="ms-auto">
d-flex align-items-center gap-2 text-white"> <a href="/dashboard" class="btn btn-outline-primary btn-sm">
<span style="font-size: 1.4rem;">👥</span> ⬅️ Dashboard
<span class="fw-semibold fs-5">Patientenübersicht</span> </a>
</div> </div>
<!-- 🔵 RECHTS: DASHBOARD -->
<div class="ms-auto">
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
⬅️ Dashboard
</a>
</div>
</nav> </nav>
<div class="container-fluid mt-4"> <div class="container-fluid mt-4">
<%- include("partials/flash") %> <%- include("partials/flash") %>
<!-- Aktionen oben --> <!-- 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"> <a href="/patients/create" class="btn btn-success"> + Neuer Patient </a>
+ Neuer Patient </div>
</a>
</div>
<div class="card shadow"> <div class="card shadow">
<div class="card-body"> <div class="card-body">
<!-- Suchformular -->
<!-- Suchformular --> <form method="GET" action="/patients" class="row g-2 mb-4">
<form method="GET" action="/patients" class="row g-2 mb-4"> <div class="col-md-3">
<input
<div class="col-md-3"> type="text"
<input type="text" name="firstname"
name="firstname" class="form-control"
class="form-control" placeholder="Vorname"
placeholder="Vorname" value="<%= query?.firstname || '' %>"
value="<%= query?.firstname || '' %>"> />
</div>
<div class="col-md-3">
<input type="text"
name="lastname"
class="form-control"
placeholder="Nachname"
value="<%= query?.lastname || '' %>">
</div>
<div class="col-md-3">
<input type="date"
name="birthdate"
class="form-control"
value="<%= query?.birthdate || '' %>">
</div>
<div class="col-md-3 d-flex gap-2">
<button class="btn btn-primary w-100">
Suchen
</button>
<a href="/patients" class="btn btn-secondary w-100">
Zurücksetzen
</a>
</div>
</form>
<!-- Tabelle -->
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle table-sm">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>N.I.E. / DNI</th>
<th>Geschlecht</th>
<th>Geburtstag</th>
<th>E-Mail</th>
<th>Telefon</th>
<th>Adresse</th>
<th>Land</th>
<th>Status</th>
<th>Notizen</th>
<th>Erstellt</th>
<th>Geändert</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<% if (patients.length === 0) { %>
<tr>
<td colspan="13" class="text-center text-muted">
Keine Patienten gefunden
</td>
</tr>
<% } %>
<% patients.forEach(p => { %>
<tr>
<td><%= p.id %></td>
<td><strong><%= p.firstname %> <%= p.lastname %></strong></td>
<td><%= p.dni || "-" %></td>
<td>
<% if (p.gender === 'm') { %>m
<% } else if (p.gender === 'w') { %>w
<% } else if (p.gender === 'd') { %>d
<% } else { %>-<% } %>
</td>
<td><%= new Date(p.birthdate).toLocaleDateString("de-DE") %></td>
<td><%= p.email || "-" %></td>
<td><%= p.phone || "-" %></td>
<td>
<%= p.street || "" %> <%= p.house_number || "" %><br>
<%= p.postal_code || "" %> <%= p.city || "" %>
</td>
<td><%= p.country || "-" %></td>
<td>
<% if (p.active) { %>
<span class="badge bg-success">Aktiv</span>
<% } else { %>
<span class="badge bg-secondary">Inaktiv</span>
<% } %>
</td>
<td style="max-width: 200px;">
<%= p.notes ? p.notes.substring(0, 80) : "-" %>
</td>
<td><%= new Date(p.created_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>
<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>
<% }) %>
</tbody>
</table>
</div> </div>
</div> <div class="col-md-3">
</div> <input
type="text"
name="lastname"
class="form-control"
placeholder="Nachname"
value="<%= query?.lastname || '' %>"
/>
</div>
</div> <div class="col-md-3">
<script src="/js/bootstrap.bundle.min.js"></script> <input
</body> type="date"
name="birthdate"
class="form-control"
value="<%= query?.birthdate || '' %>"
/>
</div>
<div class="col-md-3 d-flex gap-2">
<button class="btn btn-primary w-100">Suchen</button>
<a href="/patients" class="btn btn-secondary w-100">
Zurücksetzen
</a>
</div>
</form>
<!-- Tabelle -->
<div class="table-responsive">
<table
class="table table-bordered table-hover align-middle table-sm"
>
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>N.I.E. / DNI</th>
<th>Geschlecht</th>
<th>Geburtstag</th>
<th>E-Mail</th>
<th>Telefon</th>
<th>Adresse</th>
<th>Land</th>
<th>Status</th>
<th>Notizen</th>
<th>Erstellt</th>
<th>Geändert</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<% if (patients.length === 0) { %>
<tr>
<td colspan="13" class="text-center text-muted">
Keine Patienten gefunden
</td>
</tr>
<% } %> <% patients.forEach(p => { %>
<tr>
<td><%= p.id %></td>
<td><strong><%= p.firstname %> <%= p.lastname %></strong></td>
<td><%= p.dni || "-" %></td>
<td>
<% if (p.gender === 'm') { %>m <% } else if (p.gender ===
'w') { %>w <% } else if (p.gender === 'd') { %>d <% } else {
%>-<% } %>
</td>
<td>
<%= new Date(p.birthdate).toLocaleDateString("de-DE") %>
</td>
<td><%= p.email || "-" %></td>
<td><%= p.phone || "-" %></td>
<td>
<%= p.street || "" %> <%= p.house_number || "" %><br />
<%= p.postal_code || "" %> <%= p.city || "" %>
</td>
<td><%= p.country || "-" %></td>
<td>
<% if (p.active) { %>
<span class="badge bg-success">Aktiv</span>
<% } else { %>
<span class="badge bg-secondary">Inaktiv</span>
<% } %>
</td>
<td style="max-width: 200px">
<%= p.notes ? p.notes.substring(0, 80) : "-" %>
</td>
<td><%= new Date(p.created_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>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script src="/js/bootstrap.bundle.min.js"></script>
</body>
</html> </html>