From 1fa578e3124059cdec8339b3f009df1844dd2c23 Mon Sep 17 00:00:00 2001
From: Esenjin <esenjin@sangigi-fuchsia.fr>
Date: Sun, 23 Feb 2025 19:20:23 +0100
Subject: [PATCH] ajout d'un mode "brouillon" pour les chapitres

ils ne sont visibles que par les admins
---
 admin/api/save-chapter.php |  28 +-
 admin/story-edit.php       |   4 +
 assets/css/components.css  |  56 ++++
 assets/js/story-edit.js    | 512 ++++++++++++++++++-------------------
 chapitre.php               |  24 +-
 index.php                  |  25 +-
 roman.php                  |   9 +-
 version.txt                |   2 +-
 8 files changed, 381 insertions(+), 279 deletions(-)

diff --git a/admin/api/save-chapter.php b/admin/api/save-chapter.php
index 293b585..cb7a6e6 100644
--- a/admin/api/save-chapter.php
+++ b/admin/api/save-chapter.php
@@ -5,16 +5,20 @@ require_once '../../includes/stories.php';
 
 if (!Auth::check()) {
     http_response_code(401);
-    exit('Non autorisé');
+    exit(json_encode(['success' => false, 'error' => 'Non autorisé']));
 }
 
 $input = json_decode(file_get_contents('php://input'), true);
 $storyId = $input['storyId'] ?? null;
 $chapterId = $input['chapterId'] ?? null;
 $title = $input['title'] ?? '';
-$content = $input['content'];
+$content = $input['content'] ?? '';
+$draft = $input['draft'] ?? false;
 
 try {
+    // Ajout de logs pour déboguer
+    error_log('Données reçues: ' . print_r($input, true));
+
     $story = Stories::get($storyId);
     if (!$story) {
         throw new Exception('Roman non trouvé');
@@ -22,28 +26,42 @@ try {
 
     if ($chapterId) {
         // Mise à jour d'un chapitre existant
+        $chapterUpdated = false;
         foreach ($story['chapters'] as &$chapter) {
-            if ($chapter['id'] == $chapterId) {
+            if ($chapter['id'] === $chapterId) {
                 $chapter['title'] = $title;
                 $chapter['content'] = $content;
+                $chapter['draft'] = $draft;
                 $chapter['updated'] = date('Y-m-d');
+                $chapterUpdated = true;
                 break;
             }
         }
+        if (!$chapterUpdated) {
+            throw new Exception('Chapitre non trouvé');
+        }
     } else {
         // Nouveau chapitre
         $story['chapters'][] = [
             'id' => uniqid(),
             'title' => $title,
             'content' => $content,
+            'draft' => $draft,
             'created' => date('Y-m-d'),
             'updated' => date('Y-m-d')
         ];
     }
 
-    Stories::save($story);
+    if (!Stories::save($story)) {
+        throw new Exception('Erreur lors de la sauvegarde du roman');
+    }
+
     echo json_encode(['success' => true]);
 } catch (Exception $e) {
+    error_log('Erreur dans save-chapter.php: ' . $e->getMessage());
     http_response_code(500);
-    echo json_encode(['error' => $e->getMessage()]);
+    echo json_encode([
+        'success' => false,
+        'error' => $e->getMessage()
+    ]);
 }
\ No newline at end of file
diff --git a/admin/story-edit.php b/admin/story-edit.php
index 625b292..c0ae206 100644
--- a/admin/story-edit.php
+++ b/admin/story-edit.php
@@ -149,6 +149,10 @@ function generateSlug($title) {
                     <div class="modal-header">
                         <h2>Éditer un chapitre</h2>
                         <input type="text" id="chapterTitle" placeholder="Titre du chapitre">
+                        <label class="draft-toggle">
+                            <input type="checkbox" id="chapterDraft">
+                            <span class="toggle-label">Mode brouillon</span>
+                        </label>
                     </div>
                     
                     <div class="editor-container">
diff --git a/assets/css/components.css b/assets/css/components.css
index 68b6b92..3e7a24e 100644
--- a/assets/css/components.css
+++ b/assets/css/components.css
@@ -328,6 +328,62 @@
     margin-top: var(--spacing-sm);
 }
 
+/* Styles pour le mode brouillon */
+.draft-toggle {
+    display: flex;
+    align-items: center;
+    gap: var(--spacing-sm);
+    margin-top: var(--spacing-sm);
+}
+
+.draft-toggle input[type="checkbox"] {
+    appearance: none;
+    width: 40px;
+    height: 20px;
+    background: var(--bg-secondary);
+    border-radius: 10px;
+    position: relative;
+    cursor: pointer;
+    transition: var(--transition-fast);
+}
+
+.draft-toggle input[type="checkbox"]::before {
+    content: '';
+    position: absolute;
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    background: var(--text-primary);
+    left: 2px;
+    top: 2px;
+    transition: var(--transition-fast);
+}
+
+.draft-toggle input[type="checkbox"]:checked {
+    background: var(--accent-primary);
+}
+
+.draft-toggle input[type="checkbox"]:checked::before {
+    transform: translateX(20px);
+}
+
+.chapter-item.draft {
+    opacity: 0.7;
+    border-style: dashed;
+}
+
+.chapter-item.draft::after {
+    content: 'Brouillon';
+    position: absolute;
+    top: 0.5rem;
+    right: 0.5rem;
+    background: var(--accent-primary);
+    color: var(--text-tertiary);
+    padding: 0.2rem 0.5rem;
+    border-radius: var(--radius-sm);
+    font-size: 0.8rem;
+}
+
 /* Media queries */
 @media (max-width: 768px) {
     .story-cover {
diff --git a/assets/js/story-edit.js b/assets/js/story-edit.js
index 7318416..4565be6 100644
--- a/assets/js/story-edit.js
+++ b/assets/js/story-edit.js
@@ -1,9 +1,29 @@
 document.addEventListener('DOMContentLoaded', function() {
+    // Récupération des paramètres et variables globales
     const urlParams = new URLSearchParams(window.location.search);
     const storyId = document.querySelector('input[name="id"]')?.value || urlParams.get('id');
     let currentChapterId = null;
+    let hasUnsavedChanges = false;
 
-    // Fonction de notification
+    // Références DOM pour l'éditeur
+    const modal = document.getElementById('chapterEditor');
+    const coverModal = document.getElementById('chapterCoverEditor');
+    const addChapterBtn = document.getElementById('addChapter');
+    const saveChapterBtn = document.getElementById('saveChapter');
+    const cancelEditBtn = document.getElementById('cancelEdit');
+    const chapterTitleInput = document.getElementById('chapterTitle');
+    const chaptersList = document.getElementById('chaptersList');
+    const chapterDraftToggle = document.getElementById('chapterDraft');
+    
+    // Éléments pour la modale de couverture
+    const coverPreview = document.querySelector('.current-cover-preview');
+    const chapterCoverInput = document.getElementById('chapterCover');
+    const saveCoverBtn = document.getElementById('saveCover');
+    const cancelCoverBtn = document.getElementById('cancelCoverEdit');
+    const deleteCoverBtn = document.getElementById('deleteCover');
+    let currentChapterCover = null;
+
+    // Notification système
     function showNotification(message, type = 'success') {
         const notification = document.createElement('div');
         notification.className = `notification ${type}`;
@@ -11,13 +31,11 @@ document.addEventListener('DOMContentLoaded', function() {
         
         document.body.appendChild(notification);
         
-        // Animation d'entrée
         setTimeout(() => {
             notification.style.opacity = '1';
             notification.style.transform = 'translateY(0)';
         }, 10);
         
-        // Auto-suppression après 3 secondes
         setTimeout(() => {
             notification.style.opacity = '0';
             notification.style.transform = 'translateY(-100%)';
@@ -25,33 +43,7 @@ document.addEventListener('DOMContentLoaded', function() {
         }, 3000);
     }
 
-    // Création de l'icône SVG pour le séparateur
-    const icons = {
-        divider: `
-            <svg viewBox="0 0 18 18">
-                <line class="ql-stroke" x1="3" x2="15" y1="9" y2="9"></line>
-            </svg>
-        `
-    };
-
-    // Ajout de l'icône à Quill
-    const Block = Quill.import('blots/block');
-    const icons_list = Quill.import('ui/icons');
-    icons_list['divider'] = icons.divider;
-
-    // Définition du format pour le séparateur
-    class DividerBlot extends Block {
-        static create() {
-            const node = super.create();
-            node.className = 'chapter-divider';
-            return node;
-        }
-    }
-    DividerBlot.blotName = 'divider';
-    DividerBlot.tagName = 'hr';
-    Quill.register(DividerBlot);
-
-    // Configuration et initialisation de Quill
+    // Configuration de l'éditeur Quill
     const quill = new Quill('#editor', {
         theme: 'snow',
         modules: {
@@ -115,39 +107,241 @@ document.addEventListener('DOMContentLoaded', function() {
                         };
                     }
                 }
-            },
-            keyboard: {
-                bindings: {
-                    tab: false,
-                    'indent backwards': false
-                }
             }
         },
         placeholder: 'Commencez à écrire votre chapitre ici...'
     });
 
-    // Gestion des chapitres
-    const modal = document.getElementById('chapterEditor');
-    const addChapterBtn = document.getElementById('addChapter');
-    const saveChapterBtn = document.getElementById('saveChapter');
-    const cancelEditBtn = document.getElementById('cancelEdit');
-    const chapterTitleInput = document.getElementById('chapterTitle');
-    const chaptersList = document.getElementById('chaptersList');
+    // Détection des changements non sauvegardés
+    function detectUnsavedChanges() {
+        quill.on('text-change', () => {
+            hasUnsavedChanges = true;
+        });
+        
+        if (chapterTitleInput) {
+            chapterTitleInput.addEventListener('input', () => {
+                hasUnsavedChanges = true;
+            });
+        }
+    }
 
-    // Éléments de la modale de couverture
-    const coverModal = document.getElementById('chapterCoverEditor');
-    const coverPreview = document.querySelector('.current-cover-preview');
-    const chapterCoverInput = document.getElementById('chapterCover');
-    const saveCoverBtn = document.getElementById('saveCover');
-    const cancelCoverBtn = document.getElementById('cancelCoverEdit');
-    const deleteCoverBtn = document.getElementById('deleteCover');
-    let currentChapterCover = null;
+    // Configuration de Sortable pour la réorganisation des chapitres
+    if (chaptersList) {
+        new Sortable(chaptersList, {
+            animation: 150,
+            handle: '.chapter-number',
+            ghostClass: 'sortable-ghost',
+            onEnd: async function(evt) {
+                const chapters = Array.from(chaptersList.children).map((item, index) => ({
+                    id: item.dataset.id,
+                    position: index
+                }));
 
-    // Gestionnaire pour le bouton de couverture
+                try {
+                    const response = await fetch('api/reorder-chapters.php', {
+                        method: 'POST',
+                        headers: {
+                            'Content-Type': 'application/json',
+                        },
+                        body: JSON.stringify({
+                            storyId: storyId,
+                            chapters: chapters
+                        })
+                    });
+
+                    if (!response.ok) {
+                        throw new Error('Erreur lors de la réorganisation');
+                    }
+
+                    chapters.forEach((chapter, index) => {
+                        const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`);
+                        if (element) {
+                            element.textContent = index + 1;
+                        }
+                    });
+
+                } catch (error) {
+                    console.error('Erreur:', error);
+                    showNotification('Erreur lors de la réorganisation des chapitres', 'error');
+                }
+            }
+        });
+    }
+
+    // Gestion de la sauvegarde du chapitre
+    if (saveChapterBtn) {
+        saveChapterBtn.addEventListener('click', async () => {
+            const title = chapterTitleInput.value.trim();
+            if (!title) {
+                showNotification('Le titre est requis', 'error');
+                return;
+            }
+
+            try {
+                const response = await fetch('api/save-chapter.php', {
+                    method: 'POST',
+                    headers: {
+                        'Content-Type': 'application/json',
+                    },
+                    body: JSON.stringify({
+                        storyId: storyId,
+                        chapterId: currentChapterId,
+                        title: title,
+                        content: quill.root.innerHTML,
+                        draft: chapterDraftToggle?.checked || false
+                    })
+                });
+
+                if (response.ok) {
+                    const result = await response.json();
+                    if (result.success) {
+                        hasUnsavedChanges = false;
+                        showNotification('Chapitre sauvegardé avec succès');
+                        setTimeout(() => location.reload(), 500);
+                    } else {
+                        throw new Error(result.error || 'Erreur lors de la sauvegarde');
+                    }
+                } else {
+                    throw new Error('Erreur réseau');
+                }
+            } catch (error) {
+                console.error('Erreur:', error);
+                showNotification('Erreur lors de la sauvegarde du chapitre', 'error');
+            }
+        });
+    }
+
+    // Gestionnaires d'événements pour l'édition des chapitres
+    if (addChapterBtn) {
+        addChapterBtn.addEventListener('click', () => {
+            currentChapterId = null;
+            chapterTitleInput.value = '';
+            quill.setContents([]);
+            if (chapterDraftToggle) {
+                chapterDraftToggle.checked = false;
+            }
+            hasUnsavedChanges = false;
+            modal.style.display = 'block';
+        });
+    }
+
+    if (cancelEditBtn) {
+        cancelEditBtn.addEventListener('click', () => {
+            if (hasUnsavedChanges) {
+                confirmDialog.show({
+                    title: 'Modifications non sauvegardées',
+                    message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?',
+                    confirmText: 'Fermer sans sauvegarder',
+                    onConfirm: () => {
+                        modal.style.display = 'none';
+                        hasUnsavedChanges = false;
+                    }
+                });
+            } else {
+                modal.style.display = 'none';
+            }
+        });
+    }
+
+    // Gestion des clics sur la liste des chapitres
     if (chaptersList) {
         chaptersList.addEventListener('click', async (e) => {
-            if (e.target.matches('.edit-cover')) {
-                const chapterItem = e.target.closest('.chapter-item');
+            const target = e.target;
+            
+            if (target.matches('.edit-chapter')) {
+                const chapterItem = target.closest('.chapter-item');
+                currentChapterId = chapterItem.dataset.id;
+                
+                try {
+                    const response = await fetch(`api/get-chapter.php?storyId=${storyId}&chapterId=${currentChapterId}`);
+                    
+                    if (!response.ok) {
+                        throw new Error('Erreur réseau');
+                    }
+                    
+                    const chapter = await response.json();
+                    
+                    // Mise à jour du titre
+                    chapterTitleInput.value = chapter.title || '';
+                    
+                    // Gestion du contenu
+                    if (chapter.html) {
+                        quill.root.innerHTML = chapter.html;
+                    } else if (chapter.content) {
+                        try {
+                            const content = typeof chapter.content === 'string' 
+                                ? JSON.parse(chapter.content)
+                                : chapter.content;
+                            quill.setContents(content);
+                        } catch (contentError) {
+                            console.error('Erreur de parsing du contenu:', contentError);
+                            quill.setText(chapter.content || '');
+                        }
+                    } else {
+                        quill.setContents([]);
+                    }
+
+                    // Mise à jour du mode brouillon
+                    if (chapterDraftToggle) {
+                        chapterDraftToggle.checked = chapter.draft || false;
+                    }
+                    
+                    modal.style.display = 'block';
+                    hasUnsavedChanges = false;
+                } catch (error) {
+                    console.error('Erreur détaillée:', error);
+                    showNotification('Erreur lors du chargement du chapitre', 'error');
+                }
+            }
+            
+            // Gestion de la suppression
+            if (target.matches('.delete-chapter')) {
+                const chapterItem = target.closest('.chapter-item');
+                const chapterId = chapterItem.dataset.id;
+                const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
+            
+                confirmDialog.show({
+                    title: 'Suppression du chapitre',
+                    message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
+                    confirmText: 'Supprimer',
+                    confirmClass: 'danger',
+                    onConfirm: async () => {
+                        try {
+                            const response = await fetch('api/delete-chapter.php', {
+                                method: 'POST',
+                                headers: {
+                                    'Content-Type': 'application/json',
+                                },
+                                body: JSON.stringify({
+                                    storyId: storyId,
+                                    chapterId: chapterId
+                                })
+                            });
+            
+                            if (!response.ok) throw new Error('Erreur réseau');
+            
+                            const result = await response.json();
+                            if (result.success) {
+                                chapterItem.style.opacity = '0';
+                                chapterItem.style.transform = 'translateX(-100%)';
+                                setTimeout(() => {
+                                    chapterItem.remove();
+                                    showNotification('Chapitre supprimé avec succès');
+                                }, 300);
+                            } else {
+                                throw new Error(result.error || 'Erreur lors de la suppression');
+                            }
+                        } catch (error) {
+                            console.error('Erreur:', error);
+                            showNotification(error.message, 'error');
+                        }
+                    }
+                });
+            }
+
+            // Gestion de la couverture
+            if (target.matches('.edit-cover')) {
+                const chapterItem = target.closest('.chapter-item');
                 const chapterId = chapterItem.dataset.id;
                 const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
                 
@@ -179,7 +373,7 @@ document.addEventListener('DOMContentLoaded', function() {
         });
     }
 
-    // Prévisualisation de l'image
+    // Prévisualisation de l'image de couverture
     if (chapterCoverInput) {
         chapterCoverInput.addEventListener('change', (e) => {
             const file = e.target.files[0];
@@ -231,6 +425,7 @@ document.addEventListener('DOMContentLoaded', function() {
                     showNotification('Couverture mise à jour avec succès');
                     coverModal.style.display = 'none';
                     chapterCoverInput.value = '';
+                    setTimeout(() => location.reload(), 500);
                 } else {
                     throw new Error(result.error || 'Erreur lors de la mise à jour');
                 }
@@ -270,6 +465,7 @@ document.addEventListener('DOMContentLoaded', function() {
                             showNotification('Couverture supprimée avec succès');
                             coverPreview.innerHTML = '';
                             coverModal.style.display = 'none';
+                            setTimeout(() => location.reload(), 500);
                         } else {
                             throw new Error(result.error || 'Erreur lors de la suppression');
                         }
@@ -282,208 +478,6 @@ document.addEventListener('DOMContentLoaded', function() {
         });
     }
 
-    // Configuration de Sortable pour la réorganisation des chapitres
-    if (chaptersList) {
-        new Sortable(chaptersList, {
-            animation: 150,
-            handle: '.chapter-number',
-            ghostClass: 'sortable-ghost',
-            onEnd: async function(evt) {
-                const chapters = Array.from(chaptersList.children).map((item, index) => ({
-                    id: item.dataset.id,
-                    position: index
-                }));
-
-                try {
-                    const response = await fetch('api/reorder-chapters.php', {
-                        method: 'POST',
-                        headers: {
-                            'Content-Type': 'application/json',
-                        },
-                        body: JSON.stringify({
-                            storyId: storyId,
-                            chapters: chapters
-                        })
-                    });
-
-                    if (!response.ok) {
-                        throw new Error('Erreur lors de la réorganisation');
-                    }
-
-                    chapters.forEach((chapter, index) => {
-                        const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`);
-                        if (element) {
-                            element.textContent = index + 1;
-                        }
-                    });
-
-                } catch (error) {
-                    console.error('Erreur:', error);
-                    showNotification('Erreur lors de la réorganisation des chapitres', 'error');
-                }
-            }
-        });
-    }
-
-    // Gestionnaires d'événements pour l'édition des chapitres
-    if (addChapterBtn) {
-        addChapterBtn.addEventListener('click', () => {
-            currentChapterId = null;
-            chapterTitleInput.value = '';
-            quill.setContents([]);
-            modal.style.display = 'block';
-        });
-    }
-
-    if (cancelEditBtn) {
-        cancelEditBtn.addEventListener('click', () => {
-            if (hasUnsavedChanges()) {
-                confirmDialog.show({
-                    title: 'Modifications non sauvegardées',
-                    message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?',
-                    confirmText: 'Fermer sans sauvegarder',
-                    onConfirm: () => {
-                        modal.style.display = 'none';
-                    }
-                });
-            } else {
-                modal.style.display = 'none';
-            }
-        });
-    }
-
-    // Gestion des clics sur la liste des chapitres
-    if (chaptersList) {
-        chaptersList.addEventListener('click', async (e) => {
-            const target = e.target;
-            
-            if (target.matches('.edit-chapter')) {
-                const chapterItem = target.closest('.chapter-item');
-                currentChapterId = chapterItem.dataset.id;
-                
-                try {
-                    const response = await fetch(`api/get-chapter.php?storyId=${storyId}&chapterId=${currentChapterId}`);
-                    
-                    if (!response.ok) {
-                        throw new Error('Erreur réseau');
-                    }
-                    
-                    const chapter = await response.json();
-                    
-                    // Mise à jour du titre
-                    chapterTitleInput.value = chapter.title || '';
-                    
-                    // Gestion du contenu
-                    if (chapter.html) {
-                        quill.root.innerHTML = chapter.html;
-                    } else if (chapter.content) {
-                        try {
-                            const content = typeof chapter.content === 'string' 
-                                ? JSON.parse(chapter.content)
-                                : chapter.content;
-                            quill.setContents(content);
-                        } catch (contentError) {
-                            console.error('Erreur de parsing du contenu:', contentError);
-                            quill.setText(chapter.content || '');
-                        }
-                    } else {
-                        quill.setContents([]);
-                    }
-                    
-                    modal.style.display = 'block';
-                } catch (error) {
-                    console.error('Erreur détaillée:', error);
-                    showNotification('Erreur lors du chargement du chapitre', 'error');
-                }
-            }
-            
-            // Gestion de la suppression
-            if (target.matches('.delete-chapter')) {
-                const chapterItem = target.closest('.chapter-item');
-                const chapterId = chapterItem.dataset.id;
-                const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
-            
-                confirmDialog.show({
-                    title: 'Suppression du chapitre',
-                    message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
-                    confirmText: 'Supprimer',
-                    confirmClass: 'danger',
-                    onConfirm: async () => {
-                        try {
-                            const response = await fetch('api/delete-chapter.php', {
-                                method: 'POST',
-                                headers: {
-                                    'Content-Type': 'application/json',
-                                },
-                                body: JSON.stringify({
-                                    storyId: storyId,
-                                    chapterId: chapterId
-                                })
-                            });
-            
-                            if (!response.ok) throw new Error('Erreur réseau');
-            
-                            const result = await response.json();
-                            if (result.success) {
-                                chapterItem.style.opacity = '0';
-                                chapterItem.style.transform = 'translateX(-100%)';
-                                setTimeout(() => {
-                                    chapterItem.remove();
-                                    showNotification('Chapitre supprimé avec succès');
-                                }, 300);
-                            } else {
-                                throw new Error(result.error || 'Erreur lors de la suppression');
-                            }
-                        } catch (error) {
-                            console.error('Erreur:', error);
-                            showNotification(error.message, 'error');
-                        }
-                    }
-                });
-            }
-        });
-    }
-
-    // Sauvegarde d'un chapitre
-    if (saveChapterBtn) {
-        saveChapterBtn.addEventListener('click', async () => {
-            const title = chapterTitleInput.value.trim();
-            if (!title) {
-                showNotification('Le titre est requis', 'error');
-                return;
-            }
-    
-            try {
-                const response = await fetch('api/save-chapter.php', {
-                    method: 'POST',
-                    headers: {
-                        'Content-Type': 'application/json',
-                    },
-                    body: JSON.stringify({
-                        storyId: storyId,
-                        chapterId: currentChapterId,
-                        title: title,
-                        content: quill.root.innerHTML
-                    })
-                });
-    
-                if (response.ok) {
-                    showNotification('Chapitre sauvegardé avec succès');
-                    setTimeout(() => location.reload(), 500);
-                } else {
-                    throw new Error('Erreur lors de la sauvegarde');
-                }
-            } catch (error) {
-                console.error('Erreur:', error);
-                showNotification('Erreur lors de la sauvegarde du chapitre', 'error');
-            }
-        });
-    }
-
-    function hasUnsavedChanges() {
-        if (!currentChapterId) {
-            return chapterTitleInput.value !== '' || quill.getLength() > 1;
-        }
-        return true;
-    }
+    // Initialisation
+    detectUnsavedChanges();
 });
\ No newline at end of file
diff --git a/chapitre.php b/chapitre.php
index bc22cb9..c646b2c 100644
--- a/chapitre.php
+++ b/chapitre.php
@@ -1,5 +1,6 @@
 <?php
 require_once 'includes/config.php';
+require_once 'includes/auth.php';
 require_once 'includes/stories.php';
 
 // Récupération des paramètres
@@ -22,6 +23,9 @@ if (!$story) {
 $currentChapter = null;
 $currentIndex = -1;
 foreach ($story['chapters'] as $index => $chapter) {
+    if (($chapter['draft'] ?? false) && !Auth::check()) {
+        continue;
+    }
     if ($chapter['id'] === $chapterId) {
         $currentChapter = $chapter;
         $currentIndex = $index;
@@ -35,8 +39,14 @@ if (!$currentChapter) {
 }
 
 // Récupération des chapitres précédent et suivant
-$prevChapter = $currentIndex > 0 ? $story['chapters'][$currentIndex - 1] : null;
-$nextChapter = $currentIndex < count($story['chapters']) - 1 ? $story['chapters'][$currentIndex + 1] : null;
+$visibleChapters = array_filter($story['chapters'], function($ch) {
+    return !($ch['draft'] ?? false) || Auth::check();
+});
+$visibleChapters = array_values($visibleChapters);
+
+$currentVisibleIndex = array_search($currentChapter, $visibleChapters);
+$prevChapter = $currentVisibleIndex > 0 ? $visibleChapters[$currentVisibleIndex - 1] : null;
+$nextChapter = $currentVisibleIndex < count($visibleChapters) - 1 ? $visibleChapters[$currentVisibleIndex + 1] : null;
 
 $config = Config::load();
 ?>
@@ -91,10 +101,16 @@ $config = Config::load();
         <aside class="chapters-menu">
             <h2>Chapitres</h2>
             <ul class="chapters-list">
-                <?php foreach ($story['chapters'] as $chapter): ?>
+                <?php 
+                $visibleChapters = array_filter($story['chapters'], function($chapter) {
+                    return !($chapter['draft'] ?? false) || Auth::check();
+                });
+                
+                foreach ($visibleChapters as $chapter): 
+                ?>
                     <li>
                         <a href="?story=<?= urlencode($storyId) ?>&chapter=<?= urlencode($chapter['id']) ?>"
-                           class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?>">
+                        class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?>">
                             <?= htmlspecialchars($chapter['title']) ?>
                         </a>
                     </li>
diff --git a/index.php b/index.php
index 6fc832b..40c51f7 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,6 @@
 <?php
 require_once 'includes/config.php';
+require_once 'includes/auth.php';
 require_once 'includes/stories.php';
 
 $config = Config::load();
@@ -77,16 +78,22 @@ function formatDate($date) {
                         class="novel-cover"
                         loading="lazy">
                         
-                    <div class="novel-info">
-                        <h2><?= htmlspecialchars($story['title']) ?></h2>
-                        <p>
-                            <?= count($story['chapters'] ?? []) ?> 
-                            chapitre<?= count($story['chapters'] ?? []) > 1 ? 's' : '' ?>
-                        </p>
-                        <div class="novel-date">
-                            Mis à jour le <?= formatDate($story['updated']) ?>
+                        <div class="novel-info">
+                            <h2><?= htmlspecialchars($story['title']) ?></h2>
+                            <?php
+                            $visibleChapters = array_filter($story['chapters'] ?? [], function($chapter) {
+                                return !($chapter['draft'] ?? false) || Auth::check();
+                            });
+                            $chapterCount = count($visibleChapters);
+                            ?>
+                            <p>
+                                <?= $chapterCount ?> 
+                                chapitre<?= $chapterCount > 1 ? 's' : '' ?>
+                            </p>
+                            <div class="novel-date">
+                                Mis à jour le <?= formatDate($story['updated']) ?>
+                            </div>
                         </div>
-                    </div>
                 </a>
             <?php endforeach; ?>
         </div>
diff --git a/roman.php b/roman.php
index 0ae1171..05969d3 100644
--- a/roman.php
+++ b/roman.php
@@ -1,5 +1,6 @@
 <?php
 require_once 'includes/config.php';
+require_once 'includes/auth.php';
 require_once 'includes/stories.php';
 
 // Récupération de l'ID du roman depuis l'URL
@@ -53,7 +54,13 @@ $config = Config::load();
             <h2>Chapitres</h2>
             <?php if (!empty($story['chapters'])): ?>
                 <ul class="chapters-list">
-                    <?php foreach ($story['chapters'] as $index => $chapter): ?>
+                    <?php
+                    $visibleChapters = array_filter($story['chapters'], function($chapter) {
+                        return !($chapter['draft'] ?? false) || Auth::check();
+                    });
+                    
+                    foreach ($visibleChapters as $chapter): 
+                    ?>
                         <li>
                             <a href="chapitre.php?story=<?= urlencode($story['id']) ?>&chapter=<?= urlencode($chapter['id']) ?>">
                                 <?= htmlspecialchars($chapter['title']) ?>
diff --git a/version.txt b/version.txt
index a5ba932..867e524 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.1.7
\ No newline at end of file
+1.2.0
\ No newline at end of file