feat: Notizen Feature hinzugefügt inkl. Split-View
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 34s
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 34s
This commit is contained in:
@@ -228,3 +228,9 @@ Das Projekt basiert auf bewährten Web-Standards:
|
||||
* **Strukturierte Anzeige in der Box-Ansicht:** Die öffentliche Ansicht eines Lagerorts per QR-Code (`public_location.php`) zeigt nun Artikelrelationen (z.B. Zubehör innerhalb eines Hauptartikels) hierarchisch eingerückt an.
|
||||
* **Fixes:**
|
||||
* Die störende JavaScript `confirm()`-Meldung beim Löschen von Artikeln in der Übersicht (`articles.php`) wurde durch ein einheitliches, modernes Bootstrap-Modal ersetzt.
|
||||
|
||||
### 19.06.2026
|
||||
* **Features:**
|
||||
* **Notizen:** Neue Funktion "Notizen" hinzugefügt inkl. Rich-Text-Editor.
|
||||
* **Haushaltsfreigabe:** Notizen können mit dem Haushalt geteilt werden.
|
||||
* **Design-Update:** Die Notizen-Übersichtsseite nutzt nun eine Split-View (Liste links, Inhalt rechts).
|
||||
|
||||
15
fix_files.php
Normal file
15
fix_files.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
$f1 = '/entwicklung/packliste/src/articles.php';
|
||||
$c1 = file_get_contents($f1);
|
||||
$pos1 = strpos($c1, "<?php require_once 'footer.php'; ?>");
|
||||
if ($pos1 !== false) {
|
||||
file_put_contents($f1, substr($c1, 0, $pos1 + strlen("<?php require_once 'footer.php'; ?>")) . "\n");
|
||||
}
|
||||
|
||||
$f2 = '/entwicklung/packliste/src/storage_locations.php';
|
||||
$c2 = file_get_contents($f2);
|
||||
$pos2 = strpos($c2, "<?php require_once 'footer.php'; ?>");
|
||||
if ($pos2 !== false) {
|
||||
file_put_contents($f2, substr($c2, 0, $pos2 + strlen("<?php require_once 'footer.php'; ?>")) . "\n");
|
||||
}
|
||||
echo "Cleaned up file endings.\n";
|
||||
@@ -528,3 +528,23 @@ CREATE TABLE `todo_lists` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(
|
||||
CREATE TABLE `todo_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `todo_list_id` int(11) NOT NULL, `title` varchar(255) NOT NULL, `is_completed` tinyint(1) DEFAULT 0, `order_index` int(11) DEFAULT 0, PRIMARY KEY (`id`), KEY `todo_list_id` (`todo_list_id`), CONSTRAINT `fk_todo_items_list` FOREIGN KEY (`todo_list_id`) REFERENCES `todo_lists` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
ALTER TABLE `packing_lists` ADD COLUMN `todo_list_id` int(11) DEFAULT NULL;
|
||||
ALTER TABLE `packing_lists` ADD CONSTRAINT `fk_packing_list_todo` FOREIGN KEY (`todo_list_id`) REFERENCES `todo_lists` (`id`) ON DELETE SET NULL;
|
||||
|
||||
--
|
||||
-- Table structure for table `notes`
|
||||
--
|
||||
DROP TABLE IF EXISTS `notes`;
|
||||
CREATE TABLE `notes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`household_id` int(11) DEFAULT NULL,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`content` text NOT NULL,
|
||||
`is_shared` tinyint(1) DEFAULT 0,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `household_id` (`household_id`),
|
||||
CONSTRAINT `notes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `notes_ibfk_2` FOREIGN KEY (`household_id`) REFERENCES `households` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
124
src/add_note.php
Normal file
124
src/add_note.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
require_once 'db_connect.php';
|
||||
|
||||
$current_user_id = $_SESSION['user_id'];
|
||||
$stmt_household = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
|
||||
$stmt_household->bind_param("i", $current_user_id);
|
||||
$stmt_household->execute();
|
||||
$current_user_household_id = $stmt_household->get_result()->fetch_assoc()['household_id'];
|
||||
$stmt_household->close();
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$title = trim($_POST['title'] ?? '');
|
||||
$content = $_POST['content'] ?? '';
|
||||
$is_shared = isset($_POST['is_shared']) ? 1 : 0;
|
||||
|
||||
if (empty($title)) {
|
||||
$error = "Bitte gib einen Titel ein.";
|
||||
} else {
|
||||
$stmt = $conn->prepare("INSERT INTO notes (user_id, household_id, title, content, is_shared) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("iissi", $current_user_id, $current_user_household_id, $title, $content, $is_shared);
|
||||
if ($stmt->execute()) {
|
||||
$new_id = $stmt->insert_id;
|
||||
header("Location: edit_note.php?id=$new_id&success=1");
|
||||
exit;
|
||||
} else {
|
||||
$error = "Fehler beim Speichern der Notiz.";
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
|
||||
$page_title = "Neue Notiz";
|
||||
require_once 'header.php';
|
||||
?>
|
||||
|
||||
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
||||
<style>
|
||||
.ql-editor {
|
||||
min-height: 300px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-0"><i class="fas fa-plus-circle text-primary me-2"></i>Neue Notiz erstellen</h2>
|
||||
<a href="notes.php" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Zurück zur Übersicht</a>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><i class="fas fa-exclamation-triangle me-2"></i><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-4">
|
||||
<form action="add_note.php" method="post" id="noteForm">
|
||||
<div class="mb-4">
|
||||
<label for="title" class="form-label fw-bold">Titel der Notiz</label>
|
||||
<input type="text" class="form-control form-control-lg" id="title" name="title" required value="<?php echo htmlspecialchars($_POST['title'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label fw-bold">Inhalt</label>
|
||||
<div id="editor-container" class="bg-white"></div>
|
||||
<input type="hidden" name="content" id="hiddenContent">
|
||||
</div>
|
||||
|
||||
<?php if ($current_user_household_id): ?>
|
||||
<div class="mb-4 form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="is_shared" name="is_shared" <?php echo isset($_POST['is_shared']) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="is_shared">
|
||||
<i class="fas fa-share-alt text-success me-1"></i> Mit dem Haushalt teilen
|
||||
</label>
|
||||
<div class="form-text">Andere Mitglieder deines Haushalts können diese Notiz sehen und bearbeiten.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end mt-4">
|
||||
<a href="notes.php" class="btn btn-light me-md-2">Abbrechen</a>
|
||||
<button type="submit" class="btn btn-primary px-5"><i class="fas fa-save me-2"></i>Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
|
||||
<script>
|
||||
var quill = new Quill('#editor-container', {
|
||||
theme: 'snow',
|
||||
placeholder: 'Schreibe hier deine Notiz...',
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
||||
[{ 'size': ['small', false, 'large', 'huge'] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||
[{ 'align': [] }],
|
||||
['link', 'clean']
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
var form = document.getElementById('noteForm');
|
||||
form.onsubmit = function() {
|
||||
var content = document.getElementById('hiddenContent');
|
||||
content.value = quill.root.innerHTML;
|
||||
return true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
@@ -68,4 +68,18 @@ $check_loc_token = $conn->query("SHOW COLUMNS FROM storage_locations LIKE 'publi
|
||||
if ($check_loc_token && $check_loc_token->num_rows == 0) {
|
||||
$conn->query("ALTER TABLE storage_locations ADD COLUMN public_token VARCHAR(64) UNIQUE DEFAULT NULL");
|
||||
}
|
||||
|
||||
// Ensure notes table exists
|
||||
$conn->query("CREATE TABLE IF NOT EXISTS notes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
household_id INT DEFAULT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
is_shared TINYINT(1) DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (household_id) REFERENCES households(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci");
|
||||
?>
|
||||
|
||||
21
src/delete_note.php
Normal file
21
src/delete_note.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
require_once 'db_connect.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id'])) {
|
||||
$note_id = intval($_POST['id']);
|
||||
$current_user_id = $_SESSION['user_id'];
|
||||
|
||||
// Only allow owner to delete
|
||||
$stmt = $conn->prepare("DELETE FROM notes WHERE id = ? AND user_id = ?");
|
||||
$stmt->bind_param("ii", $note_id, $current_user_id);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
header("Location: notes.php");
|
||||
exit;
|
||||
217
src/edit_note.php
Normal file
217
src/edit_note.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
require_once 'db_connect.php';
|
||||
|
||||
$current_user_id = $_SESSION['user_id'];
|
||||
$stmt_household = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
|
||||
$stmt_household->bind_param("i", $current_user_id);
|
||||
$stmt_household->execute();
|
||||
$current_user_household_id = $stmt_household->get_result()->fetch_assoc()['household_id'];
|
||||
$stmt_household->close();
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if (isset($_GET['success']) && $_GET['success'] == 1) {
|
||||
$success = "Notiz erfolgreich gespeichert.";
|
||||
}
|
||||
|
||||
$note_id = isset($_GET['id']) ? intval($_GET['id']) : (isset($_POST['id']) ? intval($_POST['id']) : 0);
|
||||
|
||||
if (!$note_id) {
|
||||
header("Location: notes.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch note to check permissions
|
||||
$stmt = $conn->prepare("SELECT * FROM notes WHERE id = ?");
|
||||
$stmt->bind_param("i", $note_id);
|
||||
$stmt->execute();
|
||||
$note = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
|
||||
if (!$note) {
|
||||
header("Location: notes.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$can_edit = false;
|
||||
if ($note['user_id'] == $current_user_id) {
|
||||
$can_edit = true;
|
||||
} else if ($note['household_id'] == $current_user_household_id && $note['is_shared']) {
|
||||
$can_edit = true;
|
||||
}
|
||||
|
||||
if (!$can_edit) {
|
||||
header("Location: notes.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$title = trim($_POST['title'] ?? '');
|
||||
$content = $_POST['content'] ?? '';
|
||||
$is_shared = isset($_POST['is_shared']) ? 1 : 0;
|
||||
|
||||
if (empty($title)) {
|
||||
$error = "Bitte gib einen Titel ein.";
|
||||
} else {
|
||||
if ($note['user_id'] == $current_user_id) {
|
||||
$stmt = $conn->prepare("UPDATE notes SET title = ?, content = ?, is_shared = ? WHERE id = ?");
|
||||
$stmt->bind_param("ssii", $title, $content, $is_shared, $note_id);
|
||||
} else {
|
||||
// Wenn nicht Owner, darf er Titel & Content ändern, aber nicht is_shared
|
||||
$stmt = $conn->prepare("UPDATE notes SET title = ?, content = ? WHERE id = ?");
|
||||
$stmt->bind_param("ssi", $title, $content, $note_id);
|
||||
}
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$success = "Notiz erfolgreich aktualisiert.";
|
||||
// Refresh note data
|
||||
$stmt_refresh = $conn->prepare("SELECT * FROM notes WHERE id = ?");
|
||||
$stmt_refresh->bind_param("i", $note_id);
|
||||
$stmt_refresh->execute();
|
||||
$note = $stmt_refresh->get_result()->fetch_assoc();
|
||||
$stmt_refresh->close();
|
||||
} else {
|
||||
$error = "Fehler beim Speichern der Notiz.";
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
|
||||
$page_title = "Notiz bearbeiten";
|
||||
require_once 'header.php';
|
||||
?>
|
||||
|
||||
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
||||
<style>
|
||||
.ql-editor {
|
||||
min-height: 300px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-0"><i class="fas fa-edit text-primary me-2"></i>Notiz bearbeiten</h2>
|
||||
<a href="notes.php" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Zurück zur Übersicht</a>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><i class="fas fa-exclamation-triangle me-2"></i><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
<i class="fas fa-check-circle me-2"></i><?php echo htmlspecialchars($success); ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-4">
|
||||
<form action="edit_note.php" method="post" id="noteForm">
|
||||
<input type="hidden" name="id" value="<?php echo $note['id']; ?>">
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="title" class="form-label fw-bold">Titel der Notiz</label>
|
||||
<input type="text" class="form-control form-control-lg" id="title" name="title" required value="<?php echo htmlspecialchars($_POST['title'] ?? $note['title']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label fw-bold">Inhalt</label>
|
||||
<!-- We inject the HTML content into the editor container -->
|
||||
<div id="editor-container" class="bg-white"><?php echo $_POST['content'] ?? $note['content']; ?></div>
|
||||
<input type="hidden" name="content" id="hiddenContent">
|
||||
</div>
|
||||
|
||||
<?php if ($note['user_id'] == $current_user_id && $current_user_household_id): ?>
|
||||
<div class="mb-4 form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="is_shared" name="is_shared" <?php echo ($note['is_shared']) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="is_shared">
|
||||
<i class="fas fa-share-alt text-success me-1"></i> Mit dem Haushalt teilen
|
||||
</label>
|
||||
</div>
|
||||
<?php elseif ($note['is_shared']): ?>
|
||||
<div class="mb-4 text-muted">
|
||||
<i class="fas fa-info-circle me-1"></i> Diese Notiz wird mit dem Haushalt geteilt.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end mt-4">
|
||||
<?php if ($note['user_id'] == $current_user_id): ?>
|
||||
<button type="button" class="btn btn-outline-danger me-auto" onclick="confirmDelete(<?php echo $note['id']; ?>)">
|
||||
<i class="fas fa-trash me-2"></i>Löschen
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<a href="notes.php" class="btn btn-light me-md-2">Abbrechen</a>
|
||||
<button type="submit" class="btn btn-primary px-5"><i class="fas fa-save me-2"></i>Änderungen speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal für Löschen -->
|
||||
<div class="modal fade" id="deleteNoteModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title"><i class="fas fa-exclamation-triangle me-2"></i>Notiz löschen</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
<p class="mb-0 fs-5">Möchtest du diese Notiz wirklich löschen?</p>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<form action="delete_note.php" method="post" id="deleteNoteForm">
|
||||
<input type="hidden" name="id" id="deleteNoteId" value="">
|
||||
<button type="submit" class="btn btn-danger">Unwiderruflich löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
|
||||
<script>
|
||||
var quill = new Quill('#editor-container', {
|
||||
theme: 'snow',
|
||||
placeholder: 'Schreibe hier deine Notiz...',
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
||||
[{ 'size': ['small', false, 'large', 'huge'] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||
[{ 'align': [] }],
|
||||
['link', 'clean']
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
var form = document.getElementById('noteForm');
|
||||
form.onsubmit = function() {
|
||||
var content = document.getElementById('hiddenContent');
|
||||
content.value = quill.root.innerHTML;
|
||||
return true;
|
||||
};
|
||||
|
||||
function confirmDelete(id) {
|
||||
document.getElementById('deleteNoteId').value = id;
|
||||
var myModal = new bootstrap.Modal(document.getElementById('deleteNoteModal'));
|
||||
myModal.show();
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
@@ -72,6 +72,7 @@ if (isset($_SESSION['user_id'])) {
|
||||
<li class="nav-item"><a class="nav-link" href="packing_lists.php"><i class="fas fa-clipboard-list fa-fw"></i>Packlisten</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="storage_locations.php"><i class="fas fa-archive fa-fw"></i>Lagerorte</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="todo_lists.php"><i class="fas fa-list-check fa-fw"></i>ToDo-Listen</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="notes.php"><i class="fas fa-sticky-note fa-fw"></i>Notizen</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="categories.php"><i class="fas fa-tags fa-fw"></i>Kategorien</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="manufacturers.php"><i class="fas fa-industry fa-fw"></i>Hersteller</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="household.php"><i class="fas fa-users-cog fa-fw"></i>Haushalt</a></li>
|
||||
|
||||
209
src/notes.php
Normal file
209
src/notes.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
require_once 'db_connect.php';
|
||||
|
||||
$page_title = "Notizen";
|
||||
require_once 'header.php';
|
||||
|
||||
$current_user_id = $_SESSION['user_id'];
|
||||
$stmt_household = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
|
||||
$stmt_household->bind_param("i", $current_user_id);
|
||||
$stmt_household->execute();
|
||||
$current_user_household_id = $stmt_household->get_result()->fetch_assoc()['household_id'];
|
||||
$stmt_household->close();
|
||||
|
||||
// Fetch notes list
|
||||
$sql = "SELECT n.*, u.username as owner_name
|
||||
FROM notes n
|
||||
JOIN users u ON n.user_id = u.id
|
||||
WHERE n.user_id = ? OR (n.household_id = ? AND n.is_shared = 1 AND n.household_id IS NOT NULL)
|
||||
ORDER BY n.updated_at DESC";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("ii", $current_user_id, $current_user_household_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$notes = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$notes[] = $row;
|
||||
}
|
||||
$stmt->close();
|
||||
|
||||
// Check if a specific note is selected
|
||||
$active_note = null;
|
||||
$active_note_id = isset($_GET['id']) ? intval($_GET['id']) : null;
|
||||
|
||||
if ($active_note_id) {
|
||||
foreach ($notes as $note) {
|
||||
if ($note['id'] == $active_note_id) {
|
||||
$active_note = $note;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Quill Theme for rendering content -->
|
||||
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
||||
<style>
|
||||
/* Anpassungen für die Anzeige ohne Editor-Rahmen */
|
||||
.ql-editor.render-only {
|
||||
border: none;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
min-height: auto;
|
||||
}
|
||||
.note-list-row {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.note-list-row:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.note-list-row.active {
|
||||
background-color: #e9ecef;
|
||||
border-left: 4px solid #0d6efd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-0"><i class="fas fa-sticky-note text-warning me-2"></i>Notizen</h2>
|
||||
<a href="add_note.php" class="btn btn-primary shadow-sm"><i class="fas fa-plus me-2"></i>Neue Notiz</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Linke Seite: Liste -->
|
||||
<div class="col-lg-5 mb-4">
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Titel & Status</th>
|
||||
<th class="text-end">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($notes)): ?>
|
||||
<tr>
|
||||
<td colspan="2" class="text-center py-4 text-muted">Keine Notizen vorhanden.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($notes as $note): ?>
|
||||
<?php $is_active = ($active_note && $active_note['id'] == $note['id']); ?>
|
||||
<tr class="note-list-row <?php echo $is_active ? 'active' : ''; ?>" onclick="window.location='notes.php?id=<?php echo $note['id']; ?>'">
|
||||
<td class="py-3">
|
||||
<div class="fw-bold text-dark mb-1">
|
||||
<?php echo htmlspecialchars($note['title']); ?>
|
||||
</div>
|
||||
<div class="small">
|
||||
<?php if ($note['user_id'] == $current_user_id): ?>
|
||||
<span class="badge bg-secondary me-1">Ich</span>
|
||||
<?php else: ?>
|
||||
<span class="text-muted me-1"><i class="fas fa-user fa-xs"></i> <?php echo htmlspecialchars($note['owner_name']); ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($note['is_shared']): ?>
|
||||
<span class="badge bg-success" title="Geteilt"><i class="fas fa-share-alt"></i></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-end" onclick="event.stopPropagation();">
|
||||
<a href="edit_note.php?id=<?php echo $note['id']; ?>" class="btn btn-sm btn-outline-primary" title="Bearbeiten">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<?php if ($note['user_id'] == $current_user_id): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="confirmDelete(<?php echo $note['id']; ?>)" title="Löschen">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rechte Seite: Inhalt -->
|
||||
<div class="col-lg-7 mb-4">
|
||||
<?php if ($active_note): ?>
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="d-flex justify-content-between align-items-start mb-3 border-bottom pb-3">
|
||||
<h3 class="mb-0 fw-bold"><?php echo htmlspecialchars($active_note['title']); ?></h3>
|
||||
<div class="text-end text-muted small">
|
||||
<div>Zuletzt geändert: <?php echo date('d.m.Y H:i', strtotime($active_note['updated_at'])); ?></div>
|
||||
<?php if ($active_note['is_shared']): ?>
|
||||
<div><i class="fas fa-share-alt text-success me-1"></i>Mit Haushalt geteilt</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ql-snow">
|
||||
<div class="ql-editor render-only">
|
||||
<?php echo $active_note['content']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 pt-3 border-top text-end">
|
||||
<a href="edit_note.php?id=<?php echo $active_note['id']; ?>" class="btn btn-primary">
|
||||
<i class="fas fa-edit me-2"></i>Diese Notiz bearbeiten
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="card shadow-sm border-0 h-100 bg-light d-flex align-items-center justify-content-center" style="min-height: 400px;">
|
||||
<div class="text-center text-muted p-5">
|
||||
<i class="fas fa-sticky-note fa-4x mb-3 text-secondary opacity-50"></i>
|
||||
<h4>Keine Notiz ausgewählt</h4>
|
||||
<p>Wähle links eine Notiz aus der Liste, um ihren Inhalt hier zu lesen.</p>
|
||||
<a href="add_note.php" class="btn btn-outline-primary mt-2">
|
||||
<i class="fas fa-plus me-2"></i>Jetzt eine Notiz erstellen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal für Löschen -->
|
||||
<div class="modal fade" id="deleteNoteModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title"><i class="fas fa-exclamation-triangle me-2"></i>Notiz löschen</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
<p class="mb-0 fs-5">Möchtest du diese Notiz wirklich löschen?</p>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<form action="delete_note.php" method="post" id="deleteNoteForm">
|
||||
<input type="hidden" name="id" id="deleteNoteId" value="">
|
||||
<button type="submit" class="btn btn-danger">Unwiderruflich löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function confirmDelete(id) {
|
||||
document.getElementById('deleteNoteId').value = id;
|
||||
var myModal = new bootstrap.Modal(document.getElementById('deleteNoteModal'));
|
||||
myModal.show();
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
Reference in New Issue
Block a user