258 lines
8.3 KiB
JavaScript
258 lines
8.3 KiB
JavaScript
/**
|
|
* controllers/calendar.controller.js
|
|
*/
|
|
|
|
const db = require("../db");
|
|
const Holidays = require("date-holidays");
|
|
|
|
// ── Hilfsfunktionen ──────────────────────────────────────────────────────────
|
|
|
|
function pad(n) {
|
|
return String(n).padStart(2, "0");
|
|
}
|
|
|
|
function toISO(d) {
|
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
}
|
|
|
|
// ── Hauptseite (EJS rendern) ─────────────────────────────────────────────────
|
|
|
|
exports.index = async (req, res) => {
|
|
try {
|
|
// Alle aktiven Ärzte (users mit role = 'arzt')
|
|
const [doctors] = await db.promise().query(`
|
|
SELECT id, username AS name, doctor_color AS color
|
|
FROM users
|
|
WHERE role = 'arzt' AND active = 1
|
|
ORDER BY username
|
|
`);
|
|
|
|
const today = toISO(new Date());
|
|
|
|
return res.render("calendar/index", {
|
|
active: "calendar",
|
|
doctors,
|
|
today,
|
|
user: req.session.user,
|
|
});
|
|
} catch (err) {
|
|
console.error("❌ calendar.index:", err.message);
|
|
return res.status(500).send("Interner Serverfehler");
|
|
}
|
|
};
|
|
|
|
// ── API: Termine eines Tages ─────────────────────────────────────────────────
|
|
|
|
exports.getAppointments = async (req, res) => {
|
|
try {
|
|
const { date } = req.params; // YYYY-MM-DD
|
|
|
|
const [rows] = await db.promise().query(
|
|
`SELECT
|
|
a.id, a.doctor_id, a.date,
|
|
TIME_FORMAT(a.time, '%H:%i') AS time,
|
|
a.duration, a.patient_name, a.notes, a.status,
|
|
u.username AS doctor_name,
|
|
u.doctor_color AS doctor_color
|
|
FROM appointments a
|
|
JOIN users u ON u.id = a.doctor_id
|
|
WHERE a.date = ?
|
|
ORDER BY a.time, u.username`,
|
|
[date]
|
|
);
|
|
|
|
return res.json(rows);
|
|
} catch (err) {
|
|
console.error("❌ getAppointments:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Termin erstellen ────────────────────────────────────────────────────
|
|
|
|
exports.createAppointment = async (req, res) => {
|
|
try {
|
|
const { doctor_id, date, time, duration = 15, patient_name, notes = "" } =
|
|
req.body;
|
|
|
|
if (!doctor_id || !date || !time || !patient_name?.trim()) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "doctor_id, date, time und patient_name sind Pflicht" });
|
|
}
|
|
|
|
// Kollisionsprüfung
|
|
const [conflict] = await db.promise().query(
|
|
`SELECT id FROM appointments
|
|
WHERE doctor_id = ? AND date = ? AND time = ? AND status != 'cancelled'`,
|
|
[doctor_id, date, time]
|
|
);
|
|
|
|
if (conflict.length > 0) {
|
|
return res.status(409).json({ error: "Dieser Zeitslot ist bereits belegt" });
|
|
}
|
|
|
|
const [result] = await db.promise().query(
|
|
`INSERT INTO appointments (doctor_id, date, time, duration, patient_name, notes)
|
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
[doctor_id, date, time, duration, patient_name.trim(), notes]
|
|
);
|
|
|
|
return res.status(201).json({ id: result.insertId });
|
|
} catch (err) {
|
|
console.error("❌ createAppointment:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Termin aktualisieren ────────────────────────────────────────────────
|
|
|
|
exports.updateAppointment = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { doctor_id, date, time, duration, patient_name, notes, status } =
|
|
req.body;
|
|
|
|
await db.promise().query(
|
|
`UPDATE appointments
|
|
SET doctor_id = ?, date = ?, time = ?, duration = ?,
|
|
patient_name = ?, notes = ?, status = ?
|
|
WHERE id = ?`,
|
|
[doctor_id, date, time, duration, patient_name, notes, status, id]
|
|
);
|
|
|
|
return res.json({ success: true });
|
|
} catch (err) {
|
|
console.error("❌ updateAppointment:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Termin löschen ──────────────────────────────────────────────────────
|
|
|
|
exports.deleteAppointment = async (req, res) => {
|
|
try {
|
|
await db.promise().query("DELETE FROM appointments WHERE id = ?", [
|
|
req.params.id,
|
|
]);
|
|
return res.json({ success: true });
|
|
} catch (err) {
|
|
console.error("❌ deleteAppointment:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Status ändern ───────────────────────────────────────────────────────
|
|
|
|
exports.patchStatus = async (req, res) => {
|
|
try {
|
|
const allowed = ["scheduled", "completed", "cancelled"];
|
|
const { status } = req.body;
|
|
|
|
if (!allowed.includes(status)) {
|
|
return res.status(400).json({ error: "Ungültiger Status" });
|
|
}
|
|
|
|
await db
|
|
.promise()
|
|
.query("UPDATE appointments SET status = ? WHERE id = ?", [
|
|
status,
|
|
req.params.id,
|
|
]);
|
|
|
|
return res.json({ success: true });
|
|
} catch (err) {
|
|
console.error("❌ patchStatus:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Feiertage eines Jahres ──────────────────────────────────────────────
|
|
|
|
exports.getHolidays = (req, res) => {
|
|
try {
|
|
const year = parseInt(req.params.year);
|
|
const country = (req.query.country || process.env.HOLIDAY_COUNTRY || "DE").toUpperCase();
|
|
const state = (req.query.state || process.env.HOLIDAY_STATE || "").toUpperCase();
|
|
|
|
if (isNaN(year) || year < 1900 || year > 2100) {
|
|
return res.status(400).json({ error: "Ungültiges Jahr" });
|
|
}
|
|
|
|
const hd = new Holidays();
|
|
const inited = state ? hd.init(country, state) : hd.init(country);
|
|
|
|
if (!inited) {
|
|
return res.status(400).json({ error: `Unbekanntes Land/Bundesland: ${country}/${state}` });
|
|
}
|
|
|
|
const holidays = hd
|
|
.getHolidays(year)
|
|
.filter((h) => ["public", "bank"].includes(h.type))
|
|
.map((h) => ({
|
|
date: h.date.substring(0, 10),
|
|
name: h.name,
|
|
type: h.type,
|
|
}));
|
|
|
|
return res.json({ country, state, year, holidays });
|
|
} catch (err) {
|
|
console.error("❌ getHolidays:", err.message);
|
|
return res.status(500).json({ error: "Fehler beim Laden der Feiertage" });
|
|
}
|
|
};
|
|
|
|
// ── API: Patienten-Suche (Autocomplete) ─────────────────────────────────────
|
|
|
|
exports.searchPatients = async (req, res) => {
|
|
try {
|
|
const q = (req.query.q || "").trim();
|
|
|
|
if (q.length < 1) return res.json([]);
|
|
|
|
const like = `%${q}%`;
|
|
|
|
const [rows] = await db.promise().query(
|
|
`SELECT
|
|
id,
|
|
firstname,
|
|
lastname,
|
|
birthdate,
|
|
CONCAT(firstname, ' ', lastname) AS full_name
|
|
FROM patients
|
|
WHERE active = 1
|
|
AND (
|
|
firstname LIKE ? OR
|
|
lastname LIKE ? OR
|
|
CONCAT(firstname, ' ', lastname) LIKE ?
|
|
)
|
|
ORDER BY lastname, firstname
|
|
LIMIT 10`,
|
|
[like, like, like]
|
|
);
|
|
|
|
return res.json(rows);
|
|
} catch (err) {
|
|
console.error("❌ searchPatients:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|
|
|
|
// ── API: Arzt-Farbe speichern ────────────────────────────────────────────────
|
|
|
|
exports.updateDoctorColor = async (req, res) => {
|
|
try {
|
|
const { color } = req.body;
|
|
await db
|
|
.promise()
|
|
.query("UPDATE users SET doctor_color = ? WHERE id = ?", [
|
|
color,
|
|
req.params.id,
|
|
]);
|
|
return res.json({ success: true });
|
|
} catch (err) {
|
|
console.error("❌ updateDoctorColor:", err.message);
|
|
return res.status(500).json({ error: "Datenbankfehler" });
|
|
}
|
|
};
|