diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..45825c3
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,120 @@
+
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
+
+:root {
+ --primary-color: #4A90E2;
+ --secondary-color: #50E3C2;
+ --background-color: #F4F7F9;
+ --surface-color: #FFFFFF;
+ --text-color: #333333;
+ --border-color: #E0E6ED;
+ --border-radius: 0.5rem;
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+}
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ background-color: var(--background-color);
+ color: var(--text-color);
+ line-height: 1.5;
+}
+
+.navbar {
+ background-color: var(--surface-color);
+ box-shadow: var(--shadow-sm);
+}
+
+.navbar-brand {
+ font-weight: 700;
+ color: var(--primary-color) !important;
+}
+
+.container {
+ max-width: 1140px;
+}
+
+.card {
+ border: none;
+ border-radius: var(--border-radius);
+ box-shadow: var(--shadow-md);
+ background-color: var(--surface-color);
+}
+
+.card-header {
+ background-color: transparent;
+ border-bottom: 1px solid var(--border-color);
+ font-weight: 600;
+ padding: 1rem 1.5rem;
+}
+
+.card-body {
+ padding: 1.5rem;
+}
+
+.form-control, .form-select {
+ border-radius: var(--border-radius);
+ border: 1px solid var(--border-color);
+ padding: 0.75rem 1rem;
+}
+
+.form-control:focus {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 0.25rem rgba(74, 144, 226, 0.25);
+}
+
+.btn {
+ border-radius: var(--border-radius);
+ padding: 0.75rem 1.5rem;
+ font-weight: 600;
+ transition: all 0.2s ease-in-out;
+}
+
+.btn-primary {
+ background-color: var(--primary-color);
+ border-color: var(--primary-color);
+}
+
+.btn-primary:hover {
+ opacity: 0.9;
+}
+
+.table {
+ border-color: var(--border-color);
+}
+
+.table th {
+ font-weight: 600;
+ background-color: #F9FAFB;
+}
+
+.table td, .table th {
+ vertical-align: middle;
+}
+
+.toast-container {
+ position: fixed;
+ top: 1rem;
+ right: 1rem;
+ z-index: 1090;
+}
+
+.toast {
+ border-radius: var(--border-radius);
+ border: none;
+ box-shadow: var(--shadow-md);
+}
+
+.toast-header {
+ border-bottom: 1px solid rgba(0,0,0,0.05);
+}
+
+.table .btn-sm {
+ padding: 0.25rem 0.6rem;
+}
+
+.feather-sm {
+ width: 16px;
+ height: 16px;
+ vertical-align: text-bottom;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..836654d
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,90 @@
+
+document.addEventListener('DOMContentLoaded', function () {
+ // --- Client-side validation for the add contact form ---
+ const addContactForm = document.getElementById('addContactForm');
+ if (addContactForm) {
+ addContactForm.addEventListener('submit', function (event) {
+ if (!validateForm(this)) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ });
+ }
+
+ // --- Client-side validation for the edit contact form ---
+ const editContactForm = document.getElementById('editContactForm');
+ if (editContactForm) {
+ editContactForm.addEventListener('submit', function(event) {
+ if (!validateForm(this)) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ });
+ }
+
+ // --- Edit Modal Handler ---
+ const editContactModal = document.getElementById('editContactModal');
+ if (editContactModal) {
+ editContactModal.addEventListener('show.bs.modal', function (event) {
+ const button = event.relatedTarget;
+ // Extract info from data-bs-* attributes
+ const id = button.getAttribute('data-id');
+ const name = button.getAttribute('data-name');
+ const email = button.getAttribute('data-email');
+ const phone = button.getAttribute('data-phone');
+
+ // Update the modal's content.
+ const modalTitle = editContactModal.querySelector('.modal-title');
+ const contactIdInput = editContactModal.querySelector('#edit_contact_id');
+ const nameInput = editContactModal.querySelector('#edit_name');
+ const emailInput = editContactModal.querySelector('#edit_email');
+ const phoneInput = editContactModal.querySelector('#edit_phone');
+
+ modalTitle.textContent = 'Edit Contact: ' + name;
+ contactIdInput.value = id;
+ nameInput.value = name;
+ emailInput.value = email;
+ phoneInput.value = phone;
+ });
+ }
+
+ // --- Toast notification handling ---
+ const toastEl = document.getElementById('notificationToast');
+ if (toastEl) {
+ const toast = new bootstrap.Toast(toastEl, { delay: 5000 });
+ toast.show();
+ }
+
+ // --- Feather Icons ---
+ feather.replace();
+});
+
+/**
+ * Validates a contact form (add or edit).
+ * @param {HTMLFormElement} form The form element to validate.
+ * @returns {boolean} True if valid, false otherwise.
+ */
+function validateForm(form) {
+ const name = form.querySelector('input[name="name"]');
+ const email = form.querySelector('input[name="email"]');
+ let isValid = true;
+
+ // Reset invalid states
+ name.classList.remove('is-invalid');
+ email.classList.remove('is-invalid');
+
+ // Validate Name
+ if (name.value.trim() === '') {
+ name.classList.add('is-invalid');
+ isValid = false;
+ }
+
+ // Validate Email
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (email.value.trim() === '' || !emailPattern.test(email.value)) {
+ email.classList.add('is-invalid');
+ isValid = false;
+ }
+
+ return isValid;
+}
diff --git a/index.php b/index.php
index 6f7ffab..ab4aac9 100644
--- a/index.php
+++ b/index.php
@@ -1,131 +1,260 @@
exec("CREATE TABLE IF NOT EXISTS contacts (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL,
+ phone VARCHAR(50),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )");
+
+ // Handle POST requests
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Add a new contact
+ if (isset($_POST['add_contact'])) {
+ $name = trim($_POST['name']);
+ $email = trim($_POST['email']);
+ $phone = trim($_POST['phone']);
+
+ if (!empty($name) && !empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ $stmt = $pdo->prepare("INSERT INTO contacts (name, email, phone) VALUES (?, ?, ?)");
+ $stmt->execute([$name, $email, $phone]);
+ $_SESSION['notification'] = ['type' => 'success', 'message' => 'Contact added successfully!'];
+ } else {
+ $_SESSION['notification'] = ['type' => 'danger', 'message' => 'Invalid data. Please check your input.'];
+ }
+ }
+ // Update an existing contact
+ elseif (isset($_POST['update_contact'])) {
+ $id = $_POST['contact_id'];
+ $name = trim($_POST['name']);
+ $email = trim($_POST['email']);
+ $phone = trim($_POST['phone']);
+
+ if (!empty($id) && !empty($name) && !empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ $stmt = $pdo->prepare("UPDATE contacts SET name = ?, email = ?, phone = ? WHERE id = ?");
+ $stmt->execute([$name, $email, $phone, $id]);
+ $_SESSION['notification'] = ['type' => 'success', 'message' => 'Contact updated successfully!'];
+ } else {
+ $_SESSION['notification'] = ['type' => 'danger', 'message' => 'Invalid data. Please check your input.'];
+ }
+ }
+ // Delete a contact
+ elseif (isset($_POST['delete_contact'])) {
+ $id = $_POST['contact_id'];
+ if (!empty($id)) {
+ $stmt = $pdo->prepare("DELETE FROM contacts WHERE id = ?");
+ $stmt->execute([$id]);
+ $_SESSION['notification'] = ['type' => 'info', 'message' => 'Contact deleted.'];
+ }
+ }
+
+ header("Location: index.php");
+ exit;
+ }
+
+ // Check for notification from session
+ if (isset($_SESSION['notification'])) {
+ $notification = $_SESSION['notification'];
+ unset($_SESSION['notification']);
+ }
+
+ // Fetch all contacts
+ $stmt = $pdo->query("SELECT id, name, email, phone, created_at FROM contacts ORDER BY created_at DESC");
+ $contacts = $stmt->fetchAll();
+
+} catch (PDOException $e) {
+ // For a real app, you'd log this error and show a user-friendly message.
+ $notification = ['type' => 'danger', 'message' => 'Database error: ' . $e->getMessage()];
+ $contacts = [];
+}
?>
-
+
-
-
- New Style
-
-
-
-
+
+
+ CRM - Contact Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWiZZy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Name |
+ Email |
+ Phone |
+ Date Added |
+ Actions |
+
+
+
+
+
+ | No contacts yet. Add one to get started! |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+