diff --git a/admin.php b/admin.php new file mode 100644 index 0000000..1ee4ee3 --- /dev/null +++ b/admin.php @@ -0,0 +1,157 @@ +prepare("INSERT INTO canned_replies (message) VALUES (?)"); + $stmt->execute([$_POST['message']]); + $_SESSION['feedback'] = ['type' => 'success', 'text' => 'Response added successfully!']; + } elseif ($action === 'delete' && !empty($_POST['id'])) { + $stmt = $pdo->prepare("DELETE FROM canned_replies WHERE id = ?"); + $stmt->execute([$_POST['id']]); + $_SESSION['feedback'] = ['type' => 'success', 'text' => 'Response deleted successfully!']; + } elseif ($action === 'update' && !empty($_POST['id']) && !empty($_POST['message'])) { + $stmt = $pdo->prepare("UPDATE canned_replies SET message = ? WHERE id = ?"); + $stmt->execute([$_POST['message'], $_POST['id']]); + $_SESSION['feedback'] = ['type' => 'success', 'text' => 'Response updated successfully!']; + } elseif ($action === 'edit' && !empty($_POST['id'])) { + // This is a GET-like action, but we use POST for simplicity + $stmt = $pdo->prepare("SELECT * FROM canned_replies WHERE id = ?"); + $stmt->execute([$_POST['id']]); + $message_to_edit = $stmt->fetch(); + $edit_mode = true; + } + } catch (PDOException $e) { + $_SESSION['feedback'] = ['type' => 'danger', 'text' => 'Database error: ' . $e->getMessage()]; + } + + if (!$edit_mode) { + header("Location: admin.php"); + exit(); + } +} + +// Fetch all canned replies to display +$replies = $pdo->query("SELECT * FROM canned_replies ORDER BY id DESC")->fetchAll(); + +// Get feedback message from session +$feedback = $_SESSION['feedback'] ?? null; +unset($_SESSION['feedback']); + +?> + + + + + + Admin - Manage Canned Responses + + + + + + + +
+
+
+

Manage Canned Responses

+ + + + + +
+
+ +
+
+
+ + + + + + + +
+ + +
+ + + + Cancel Edit + +
+
+
+ +

Existing Responses

+
+
+ +

No canned responses found. Add one above!

+ +
    + +
  • +

    +
    +
    + + + +
    +
    + + + +
    +
    +
  • + +
+ +
+
+
+
+
+ + + + diff --git a/api/get_reply.php b/api/get_reply.php new file mode 100644 index 0000000..7e7df0b --- /dev/null +++ b/api/get_reply.php @@ -0,0 +1,25 @@ +query("SELECT message FROM canned_replies ORDER BY RAND() LIMIT 1"); + $result = $stmt->fetch(); + + $reply_message = "Thanks for your message! We'll be in touch shortly."; // Default message + + if ($result) { + $reply_message = $result['message']; + } + + echo json_encode(['reply' => $reply_message]); + +} catch (Exception $e) { + // In case of error, return a default message + // For debugging, you might want to log the error: error_log($e->getMessage()); + http_response_code(500); + echo json_encode(['reply' => 'Sorry, something went wrong. Please try again later.']); +} diff --git a/assets/css/custom.css b/assets/css/custom.css index 443efd1..9b8bc1e 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -95,3 +95,36 @@ padding: 1rem; border-top: 1px solid #dee2e6; } + +/* Typing Indicator */ +.typing-indicator { + display: flex; + align-items: center; + padding: 0.5rem 1rem; +} + +.typing-indicator .dot { + width: 8px; + height: 8px; + margin: 0 2px; + background-color: #adb5bd; + border-radius: 50%; + animation: typing 1.4s infinite; +} + +.typing-indicator .dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-indicator .dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes typing { + 0%, 80%, 100% { + transform: scale(0); + } + 40% { + transform: scale(1.0); + } +} diff --git a/assets/js/main.js b/assets/js/main.js index a862e32..85d8b96 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -28,12 +28,28 @@ document.addEventListener("DOMContentLoaded", function () { chatInput.value = ""; chatBody.scrollTop = chatBody.scrollHeight; - // 2. Simulate bot reply - setTimeout(() => { - const botReply = "Thanks for your message! We'll be in touch shortly."; - addMessage(botReply, "bot"); - chatBody.scrollTop = chatBody.scrollHeight; - }, 500); + // 2. Get bot reply from API + showTypingIndicator(); + + fetch('api/get_reply.php') + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then(data => { + hideTypingIndicator(); + const botReply = data.reply || "Sorry, I couldn't get a response."; + addMessage(botReply, "bot"); + chatBody.scrollTop = chatBody.scrollHeight; + }) + .catch(error => { + hideTypingIndicator(); + console.error('Error fetching reply:', error); + addMessage("Sorry, something went wrong. Please try again.", "bot"); + chatBody.scrollTop = chatBody.scrollHeight; + }); } }); @@ -44,6 +60,21 @@ document.addEventListener("DOMContentLoaded", function () { chatBody.appendChild(messageElement); } + function showTypingIndicator() { + const typingIndicator = document.createElement("div"); + typingIndicator.classList.add("chat-message", "bot", "typing-indicator"); + typingIndicator.innerHTML = ''; + chatBody.appendChild(typingIndicator); + chatBody.scrollTop = chatBody.scrollHeight; + } + + function hideTypingIndicator() { + const typingIndicator = document.querySelector(".typing-indicator"); + if (typingIndicator) { + typingIndicator.remove(); + } + } + // Add initial bot message setTimeout(() => { addMessage("Hi there! How can I help you today?", "bot"); diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..fc7ff5c --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,55 @@ +exec("CREATE TABLE IF NOT EXISTS `migrations` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `migration` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); + echo "Checked/created `migrations` table.\n"; + + // 2. Get all executed migrations + $executedMigrations = $pdo->query("SELECT migration FROM `migrations`")->fetchAll(PDO::FETCH_COLUMN); + echo "Found " . count($executedMigrations) . " executed migrations.\n"; + + // 3. Find all migration files + $migrationFiles = glob(__DIR__ . '/migrations/*.sql'); + echo "Found " . count($migrationFiles) . " migration files.\n"; + + // 4. Run pending migrations + $migrationsRun = 0; + foreach ($migrationFiles as $file) { + $migrationName = basename($file); + if (!in_array($migrationName, $executedMigrations)) { + echo "Running migration: {$migrationName}...\n"; + + // Execute the SQL file + $sql = file_get_contents($file); + $pdo->exec($sql); + + // Record the migration + $stmt = $pdo->prepare("INSERT INTO `migrations` (migration) VALUES (?)"); + $stmt->execute([$migrationName]); + + echo "Successfully ran and recorded migration: {$migrationName}\n"; + $migrationsRun++; + } + } + + if ($migrationsRun === 0) { + echo "No new migrations to run.\n"; + } else { + echo "Finished running {$migrationsRun} new migrations.\n"; + } + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} catch (Exception $e) { + die("An error occurred: " . $e->getMessage()); +} diff --git a/db/migrations/001_create_canned_replies.sql b/db/migrations/001_create_canned_replies.sql new file mode 100644 index 0000000..3488303 --- /dev/null +++ b/db/migrations/001_create_canned_replies.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `canned_replies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;