This commit is contained in:
Flatlogic Bot 2025-10-27 21:34:11 +00:00
parent 50088c45be
commit 6e132e0b38
19 changed files with 1333 additions and 198 deletions

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# SecureLife Insurance Application
This is a comprehensive insurance application system built with PHP. It features a public-facing landing page, a multi-step insurance application form, and a secure, feature-rich admin dashboard.
## Features
* **Modern Homepage:** A visually appealing and responsive homepage.
* **Multi-Step Subscription Form:** A user-friendly, multi-step form for insurance applications.
* **Dynamic Form Fields:** The form dynamically shows fields based on the selected insurance type.
* **Admin Dashboard:** A secure admin dashboard to manage and view applications.
* **Application Management:** Admins can view, search, filter, and update the status of applications.
* **Email Notifications:** Automatic email notifications to users and admins upon application submission and status changes.
* **Analytics Chart:** A chart on the admin dashboard to visualize application trends.
* **Details View:** A detailed view for each application.
## Setup and Installation
1. **Database:**
* The database configuration is in `db/config.php`. Update the credentials if needed.
* To create the necessary tables, run the migration script: `php db/migrate.php`.
2. **Email:**
* The email configuration is in `mail/config.php`. You can configure your SMTP settings there.
## Configuration
* **Database:** `db/config.php`
* **Email:** `mail/config.php`
* **Admin Credentials:** The admin username and password are currently hardcoded in `admin.php`. It is recommended to move these to a more secure configuration file.
## Customization
* **Car Data:** The list of car manufacturers and models can be found and modified in `subscribe-step2.php`.
* **Styling:** The application's styling can be customized in `assets/css/custom.css`.

140
admin-details.php Normal file
View File

@ -0,0 +1,140 @@
<?php
session_start();
// --- Authentication Check ---
$is_logged_in = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true;
if (!$is_logged_in) {
header('Location: admin.php');
exit;
}
require_once __DIR__ . '/db/config.php';
// --- Data Fetching ---
$subscription = null;
$error_message = null;
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
$error_message = "Invalid application ID.";
} else {
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM subscriptions WHERE id = :id");
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();
$subscription = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$subscription) {
$error_message = "Application not found.";
}
} catch (PDOException $e) {
$error_message = "Database error: " . $e->getMessage();
}
}
function get_specific_coverage_details_html($sub) {
$type = $sub['insuranceType'] ?? 'N/A';
$output = '';
switch ($type) {
case 'Car':
$output .= "<p><strong>Car Make:</strong> " . htmlspecialchars($sub['carMake']) . "</p>";
$output .= "<p><strong>Car Model:</strong> " . htmlspecialchars($sub['carModel']) . "</p>";
$output .= "<p><strong>Year of Manufacture:</strong> " . htmlspecialchars($sub['carYear']) . "</p>";
break;
case 'Health':
$output .= "<p><strong>Number of Dependents:</strong> " . htmlspecialchars($sub['healthDependents']) . "</p>";
break;
case 'Life':
$output .= "<p><strong>Coverage Amount:</strong> $" . number_format($sub['lifeCoverage'], 2) . "</p>";
break;
case 'Home':
$output .= "<p><strong>Property Type:</strong> " . htmlspecialchars($sub['homeType']) . "</p>";
break;
}
return $output;
}
// --- Page Setup ---
$page_title = "Application Details";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?> - SecureLife</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">SecureLife</a>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="admin.php?action=logout">Logout</a>
</li>
</ul>
</div>
</header>
<main class="container my-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 fw-bold">Application #<?php echo htmlspecialchars($subscription['id'] ?? ''); ?></h1>
<a href="admin.php" class="btn btn-outline-secondary"> &larr; Back to Dashboard</a>
</div>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
<?php elseif ($subscription): ?>
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-header bg-white p-4 border-0">
<div class="d-flex justify-content-between">
<h2 class="h5 fw-bold mb-0">Details</h2>
<?php
$status = $subscription['status'];
$badge_class = 'bg-secondary'; // Default
if ($status === 'Pending') {
$badge_class = 'bg-warning text-dark';
} elseif ($status === 'Approved') {
$badge_class = 'bg-success';
} elseif ($status === 'Rejected') {
$badge_class = 'bg-danger';
}
?>
<p class="mb-0"><strong>Status:</strong> <span class="badge <?php echo $badge_class; ?>"><?php echo htmlspecialchars($status); ?></span></p>
</div>
</div>
<div class="card-body p-4">
<div class="row">
<div class="col-md-6">
<h5 class="fw-bold">Personal Information</h5>
<p><strong>Full Name:</strong> <?php echo htmlspecialchars($subscription['fullName']); ?></p>
<p><strong>Email:</strong> <?php echo htmlspecialchars($subscription['email']); ?></p>
<p><strong>Phone:</strong> <?php echo htmlspecialchars($subscription['phone']); ?></p>
<p><strong>Submitted At:</strong> <?php echo date("F j, Y, g:i a", strtotime($subscription['created_at'])); ?></p>
</div>
<div class="col-md-6">
<h5 class="fw-bold">Insurance Details</h5>
<p><strong>Insurance Type:</strong> <?php echo htmlspecialchars($subscription['insuranceType']); ?></p>
<?php echo get_specific_coverage_details_html($subscription); ?>
</div>
</div>
</div>
</div>
<?php endif; ?>
</main>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

84
admin.php Normal file
View File

@ -0,0 +1,84 @@
<?php
session_start();
// --- Configuration ---
// IMPORTANT: These are hardcoded for demonstration purposes.
// In a real-world application, use a secure way to store and manage credentials.
$admin_credentials = require __DIR__ . '/config/admin_credentials.php';
define('ADMIN_USERNAME', $admin_credentials['username']);
define('ADMIN_PASSWORD', $admin_credentials['password']);
$error_message = null;
$is_logged_in = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true;
// --- Logout Logic ---
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
session_unset();
session_destroy();
header('Location: admin.php');
exit;
}
// --- Login Logic ---
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username']) && isset($_POST['password'])) {
if ($_POST['username'] === ADMIN_USERNAME && $_POST['password'] === ADMIN_PASSWORD) {
$_SESSION['isAdmin'] = true;
header('Location: admin.php');
exit;
} else {
$error_message = "Invalid username or password.";
}
}
// --- Page Setup ---
$page_title = $is_logged_in ? "Admin Dashboard" : "Admin Login";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?> - SecureLife</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">SecureLife</a>
<?php if ($is_logged_in): ?>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="admin.php?action=logout">Logout</a>
</li>
</ul>
<?php endif; ?>
</div>
</header>
<main class="container my-5">
<?php
if ($is_logged_in) {
include 'partials/admin_dashboard.php';
} else {
// Pass the error message to the login form
include 'partials/admin_login.php';
}
?>
</main>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

68
api/chart-data.php Normal file
View File

@ -0,0 +1,68 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
try {
$pdo = db();
// 1. Data for the line chart (applications over time)
$line_chart_stmt = $pdo->prepare(
"SELECT DATE(created_at) as date, COUNT(*) as count
FROM subscriptions
WHERE created_at >= CURDATE() - INTERVAL 30 DAY
GROUP BY DATE(created_at)
ORDER BY date ASC"
);
$line_chart_stmt->execute();
$line_chart_results = $line_chart_stmt->fetchAll(PDO::FETCH_ASSOC);
$line_chart_labels = [];
$line_chart_data = [];
foreach ($line_chart_results as $row) {
$line_chart_labels[] = $row['date'];
$line_chart_data[] = (int)$row['count'];
}
// 2. Data for status counts (key metrics)
$status_stmt = $pdo->prepare("SELECT status, COUNT(*) as count FROM subscriptions GROUP BY status");
$status_stmt->execute();
$status_results = $status_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
$total_applications = array_sum($status_results);
$status_counts = [
'Total' => $total_applications,
'Approved' => $status_results['Approved'] ?? 0,
'Pending' => $status_results['Pending'] ?? 0,
'Rejected' => $status_results['Rejected'] ?? 0,
];
// 3. Data for insurance type distribution (pie chart)
$type_stmt = $pdo->prepare("SELECT insuranceType, COUNT(*) as count FROM subscriptions GROUP BY insuranceType");
$type_stmt->execute();
$type_results = $type_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
$pie_chart_labels = array_keys($type_results);
$pie_chart_data = array_values($type_results);
// --- Combine all data into a single response ---
echo json_encode([
'success' => true,
'line_chart' => [
'labels' => $line_chart_labels,
'data' => $line_chart_data,
],
'key_metrics' => $status_counts,
'pie_chart' => [
'labels' => $pie_chart_labels,
'data' => $pie_chart_data,
],
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Failed to fetch chart data.',
'error' => $e->getMessage() // For debugging
]);
}

60
api/update-status.php Normal file
View File

@ -0,0 +1,60 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../mail/MailService.php';
$response = ['success' => false, 'message' => 'Invalid request'];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$id = $data['id'] ?? null;
$status = $data['status'] ?? null;
$allowed_statuses = ['Pending', 'Approved', 'Rejected'];
if ($id && $status && in_array($status, $allowed_statuses)) {
try {
$pdo = db();
$stmt = $pdo->prepare("UPDATE subscriptions SET status = :status WHERE id = :id");
$stmt->execute([':status' => $status, ':id' => $id]);
if ($stmt->rowCount() > 0) {
$response = ['success' => true, 'message' => 'Status updated successfully.'];
// Fetch user details for email notification
$stmt = $pdo->prepare("SELECT fullName, email, insuranceType FROM subscriptions WHERE id = :id");
$stmt->execute([':id' => $id]);
$subscription = $stmt->fetch(PDO::FETCH_ASSOC);
if ($subscription) {
$user_email = $subscription['email'];
$user_name = $subscription['fullName'];
$insurance_type = $subscription['insuranceType'];
$subject = '';
$body = '';
if ($status === 'Approved') {
$subject = "Congratulations! Your SecureLife Application is Approved";
$body = "<h1>Application Approved!</h1><p>Dear {$user_name},</p><p>We are pleased to inform you that your application for <strong>{$insurance_type}</strong> insurance has been approved. Welcome to SecureLife!</p><p>We will follow up with your policy documents shortly.</p>";
} elseif ($status === 'Rejected') {
$subject = "Update on Your SecureLife Application";
$body = "<h1>Application Update</h1><p>Dear {$user_name},</p><p>We have carefully reviewed your application for <strong>{$insurance_type}</strong> insurance. We regret to inform you that we are unable to approve your application at this time.</p><p>Thank you for your interest in SecureLife.</p>";
}
if (!empty($subject) && !empty($body)) {
MailService::sendMail($user_email, $subject, $body);
}
}
} else {
$response['message'] = 'Could not find a subscription with that ID or status is unchanged.';
}
} catch (Exception $e) {
$response['message'] = 'An error occurred: ' . $e->getMessage();
}
} else {
$response['message'] = 'Invalid ID or status provided.';
}
}
echo json_encode($response);

View File

@ -1,109 +1,155 @@
/* SecureLife Custom Styles */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
/* assets/css/custom.css */
:root {
--primary-color: #0052CC;
--secondary-color: #00A3BF;
--bg-light: #F8F9FA;
--surface-white: #FFFFFF;
--text-dark: #212529;
--text-light: #6c757d;
--border-radius: 0.5rem;
--shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--primary-color: #0A2540;
--accent-color: #00c4ff;
--light-bg: #f8f9fa;
--white: #ffffff;
--font-family: 'Inter', sans-serif;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--bg-light);
color: var(--text-dark);
font-family: var(--font-family);
background-color: var(--white);
color: #333;
}
/* Header */
.navbar-brand {
font-family: var(--font-family);
font-weight: 700;
color: var(--primary-color);
}
.hero {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: var(--surface-white);
padding: 6rem 0;
text-align: center;
}
.hero h1 {
font-weight: 700;
font-size: 3.5rem;
}
.hero p {
font-size: 1.25rem;
font-weight: 300;
margin-bottom: 2rem;
}
.btn-primary {
.btn-primary-modern {
background-color: var(--primary-color);
border-color: var(--primary-color);
font-weight: 600;
padding: 0.75rem 2rem;
border-radius: var(--border-radius);
color: var(--white);
font-weight: 500;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
.btn-primary-modern:hover {
background-color: #001f36;
border-color: #001f36;
}
.section-title {
.btn-accent-modern {
background-color: var(--accent-color);
border-color: var(--accent-color);
color: var(--primary-color);
font-weight: 700;
margin-bottom: 3rem;
text-align: center;
}
.accordion-item {
border: 1px solid #dee2e6;
border-radius: var(--border-radius) !important;
margin-bottom: 1rem;
box-shadow: var(--shadow-sm);
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
transition: all 0.3s ease;
}
.accordion-item:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-md);
.btn-accent-modern:hover {
background-color: #00a2d1;
border-color: #00a2d1;
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
.accordion-header {
border-radius: var(--border-radius);
/* Hero Section */
.hero-section {
background: url('https://picsum.photos/1600/900?random=1') no-repeat center center;
background-size: cover;
position: relative;
padding: 8rem 0;
}
.accordion-button {
font-weight: 600;
color: var(--text-dark);
border-radius: var(--border-radius) !important;
.hero-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(10, 37, 64, 0.7);
}
.accordion-button:not(.collapsed) {
background-color: var(--primary-color);
color: var(--surface-white);
box-shadow: inset 0 -1px 0 rgba(0,0,0,.125);
.hero-section .container {
position: relative;
z-index: 2;
}
.accordion-button:focus {
box-shadow: 0 0 0 0.25rem rgba(0, 82, 204, 0.25);
/* Services Section */
.service-card {
border: none;
border-radius: 0.75rem;
background-color: var(--white);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
text-align: center;
padding: 2rem;
}
.accordion-body img {
max-width: 150px;
border-radius: var(--border-radius);
box-shadow: var(--shadow-sm);
.service-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.1);
}
footer {
background-color: var(--surface-white);
padding: 2rem 0;
margin-top: 4rem;
border-top: 1px solid #e9ecef;
.service-card .icon-box {
width: 80px;
height: 80px;
margin: 0 auto 1.5rem;
border-radius: 50%;
background-color: var(--accent-color);
color: var(--primary-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
transition: all 0.3s ease;
}
.service-card:hover .icon-box {
transform: rotate(360deg);
}
/* Why Choose Us Section */
.bg-light-blue {
background-color: #f0f8ff;
border-radius: 1rem;
padding: 4rem 0;
}
.feature-box {
transition: all 0.3s ease;
}
.feature-box:hover {
transform: scale(1.05);
}
.text-primary-modern {
color: var(--primary-color) !important;
}
/* Footer */
footer.bg-dark {
background-color: var(--primary-color) !important;
}
/* Animation */
.service-card, .feature-box {
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.5s forwards;
}
@keyframes fadeInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
.row.g-4 > * {
animation-delay: calc(var(--animation-order) * 100ms);
}

View File

@ -1 +1,66 @@
// SecureLife Main JS
function updateStatus(id, status) {
if (!confirm(`Are you sure you want to change the status to "${status}"?`)) {
return;
}
fetch('api/update-status.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: id, status: status }),
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.location.reload();
} else {
alert('Error updating status: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An unexpected error occurred.');
});
}
document.addEventListener('DOMContentLoaded', function() {
const chartCanvas = document.getElementById('applicationsChart');
if (chartCanvas) {
fetch('/api/chart-data.php')
.then(response => response.json())
.then(data => {
if (data.success) {
const ctx = chartCanvas.getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [{
label: 'New Applications',
data: data.data,
fill: false,
borderColor: '#0052CC',
tension: 0.1
}]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
},
responsive: true,
maintainAspectRatio: false
}
});
} else {
console.error('Failed to load chart data:', data.message);
}
})
.catch(error => console.error('Error fetching chart data:', error));
}
});

View File

@ -0,0 +1,7 @@
<?php
// It is recommended to use environment variables for credentials.
return [
'username' => 'admin',
'password' => 'password',
];

14
config/car_data.php Normal file
View File

@ -0,0 +1,14 @@
<?php
return [
'Toyota' => ['Camry', 'Corolla', 'RAV4', 'Highlander'],
'Honda' => ['Civic', 'Accord', 'CR-V', 'Pilot'],
'Ford' => ['F-150', 'Mustang', 'Explorer', 'Escape'],
'Chevrolet' => ['Silverado', 'Equinox', 'Malibu', 'Tahoe'],
'Nissan' => ['Rogue', 'Altima', 'Sentra'],
'Jeep' => ['Wrangler', 'Grand Cherokee'],
'Hyundai' => ['Elantra', 'Sonata', 'Tucson'],
'BMW' => ['3 Series', '5 Series', 'X3', 'X5'],
'Mercedes-Benz' => ['C-Class', 'E-Class', 'GLC'],
'Audi' => ['A4', 'A6', 'Q5'],
];

35
db/migrate.php Normal file
View File

@ -0,0 +1,35 @@
<?php
require_once __DIR__ . '/../db/config.php';
try {
// First, connect without a database name to create it
$pdo_admin = new PDO('mysql:host=' . DB_HOST, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$pdo_admin->exec("CREATE DATABASE IF NOT EXISTS `" . DB_NAME . "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
echo "Database '" . DB_NAME . "' created or already exists.\n";
// Now, connect to the specific database to run migrations
$pdo = db();
$migrationsDir = __DIR__ . '/migrations';
$files = glob($migrationsDir . '/*.sql');
if (empty($files)) {
echo "No migration files found.\n";
exit;
}
sort($files);
foreach ($files as $file) {
echo "Running migration: " . basename($file) . "...\n";
$sql = file_get_contents($file);
$pdo->exec($sql);
echo "Migration successful.\n";
}
echo "All migrations completed.\n";
} catch (PDOException $e) {
die("Database migration failed: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,14 @@
CREATE TABLE IF NOT EXISTS subscriptions (
id INT AUTO_INCREMENT PRIMARY KEY,
fullName VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(50) NOT NULL,
insuranceType VARCHAR(50) NOT NULL,
carMake VARCHAR(100),
carModel VARCHAR(100),
carYear INT,
healthDependents INT,
lifeCoverage DECIMAL(15, 2),
homeType VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,2 @@
ALTER TABLE subscriptions
ADD COLUMN status VARCHAR(50) NOT NULL DEFAULT 'submitted' AFTER homeType;

222
index.php
View File

@ -3,156 +3,116 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Meta Tags -->
<title>SecureLife - Your Future, Secured</title>
<meta name="description" content="SecureLife offers comprehensive and affordable insurance plans for car, health, life, and home. Get your free quote today. Built with Flatlogic Generator.">
<meta name="keywords" content="insurance, car insurance, health insurance, life insurance, home insurance, insurance platform, get quote, secure life, Flatlogic Generator">
<meta property="og:title" content="SecureLife - Your Future, Secured">
<meta property="og:description" content="SecureLife offers comprehensive and affordable insurance plans for car, health, life, and home. Get your free quote today.">
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<!-- Bootstrap 5 CSS -->
<title>SecureLife - Your Future, Secured.</title>
<meta name="description" content="SecureLife offers comprehensive and affordable insurance plans for car, health, life, and home. Get your free quote today.">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/custom.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<!-- Header -->
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm sticky-top">
<div class="container">
<a class="navbar-brand" href="#">SecureLife</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">About</a></li>
<li class="nav-item"><a class="nav-link" href="#">Contact</a></li>
</ul>
</div>
<a class="navbar-brand" href="index.php" style="font-family: 'Inter', sans-serif; font-weight: 700; color: #0A2540;">SecureLife</a>
<a href="subscribe.php" class="btn btn-primary-modern d-none d-lg-inline-block">Get a Quote</a>
</div>
</header>
<!-- Hero Section -->
<section class="hero">
<section class="hero-section text-white text-center">
<div class="container">
<h1>Your Future, Secured.</h1>
<p class="lead">Affordable, reliable insurance plans tailored for you.</p>
<a href="subscribe.php" class="btn btn-primary btn-lg">Get Your Free Quote</a>
<h1 class="display-3 fw-bold">Your Future, Secured.</h1>
<p class="lead my-4">Comprehensive and affordable insurance plans tailored for you.</p>
<a href="subscribe.php" class="btn btn-accent-modern btn-lg">Get Your Free Quote</a>
</div>
</section>
<!-- Main Content -->
<main class="container mt-5 pt-4">
<h2 class="section-title">Comprehensive Coverage for Every Need</h2>
<main class="container my-5">
<!-- Services Section -->
<section id="services" class="py-5 text-center">
<h2 class="fw-bold">Comprehensive Coverage for Every Need</h2>
<p class="lead text-muted mb-5">Explore our insurance options designed to protect what matters most.</p>
<div class="row g-4">
<div class="col-md-6 col-lg-3 d-flex align-items-stretch">
<div class="card service-card">
<div class="card-body">
<div class="icon-box"><i class="bi bi-car-front-fill"></i></div>
<h5 class="card-title">Car Insurance</h5>
<p class="card-text">Hit the road with confidence. Comprehensive coverage against accidents, theft, and damages.</p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3 d-flex align-items-stretch">
<div class="card service-card">
<div class="card-body">
<div class="icon-box"><i class="bi bi-heart-pulse-fill"></i></div>
<h5 class="card-title">Health Insurance</h5>
<p class="card-text">Your health is your wealth. Access a wide network of hospitals and specialists.</p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3 d-flex align-items-stretch">
<div class="card service-card">
<div class="card-body">
<div class="icon-box"><i class="bi bi-person-heart"></i></div>
<h5 class="card-title">Life Insurance</h5>
<p class="card-text">Secure your family's future. A financial safety net for your loved ones.</p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3 d-flex align-items-stretch">
<div class="card service-card">
<div class="card-body">
<div class="icon-box"><i class="bi bi-house-heart-fill"></i></div>
<h5 class="card-title">Home Insurance</h5>
<p class="card-text">Protect your biggest investment. Coverage from natural disasters to theft.</p>
</div>
</div>
</div>
</div>
</section>
<!-- Accordion for Insurance Types -->
<div class="accordion" id="insuranceAccordion">
<!-- Why Choose Us Section -->
<section id="why-choose-us" class="py-5 mt-5 bg-light-blue">
<div class="container text-center">
<h2 class="fw-bold">Why Choose SecureLife?</h2>
<p class="lead text-muted mb-5">We provide more than just insurance. We provide peace of mind.</p>
<div class="row g-4">
<div class="col-md-4">
<div class="feature-box">
<i class="bi bi-shield-check fs-1 text-primary-modern"></i>
<h4 class="mt-3">Trusted & Reliable</h4>
<p>With years of experience, we are a name you can trust.</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-box">
<i class="bi bi-headset fs-1 text-primary-modern"></i>
<h4 class="mt-3">24/7 Support</h4>
<p>Our team is always here to help, any time of the day.</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-box">
<i class="bi bi-file-earmark-text fs-1 text-primary-modern"></i>
<h4 class="mt-3">Easy Claims</h4>
<p>A hassle-free claims process to get you back on your feet.</p>
</div>
</div>
</div>
</div>
</section>
<!-- Car Insurance -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne">
<i class="bi bi-car-front-fill me-3"></i> Car Insurance
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#insuranceAccordion">
<div class="accordion-body">
<div class="row align-items-center">
<div class="col-md-3 text-center">
<img src="https://images.pexels.com/photos/116675/pexels-photo-116675.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Car on a scenic road" class="img-fluid">
</div>
<div class="col-md-9">
<strong>Hit the road with confidence.</strong> Our car insurance provides comprehensive coverage against accidents, theft, and damages. We offer flexible plans with options for roadside assistance and rental car reimbursement, ensuring you're never left stranded.
</div>
</div>
</div>
</div>
</div>
<!-- Health Insurance -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo">
<i class="bi bi-heart-pulse-fill me-3"></i> Health Insurance
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#insuranceAccordion">
<div class="accordion-body">
<div class="row align-items-center">
<div class="col-md-3 text-center">
<img src="https://images.pexels.com/photos/4021775/pexels-photo-4021775.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Doctor with a stethoscope" class="img-fluid">
</div>
<div class="col-md-9">
<strong>Your health is your wealth.</strong> Protect it with our wide range of health insurance plans. Gain access to a vast network of hospitals and specialists, with coverage for everything from routine check-ups to major surgeries.
</div>
</div>
</div>
</div>
</div>
<!-- Life Insurance -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingThree">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree">
<i class="bi bi-person-hearts me-3"></i> Life Insurance
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#insuranceAccordion">
<div class="accordion-body">
<div class="row align-items-center">
<div class="col-md-3 text-center">
<img src="https://images.pexels.com/photos/3184423/pexels-photo-3184423.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Happy family" class="img-fluid">
</div>
<div class="col-md-9">
<strong>Secure your family's future.</strong> Our life insurance policies provide a financial safety net for your loved ones in your absence. Choose from term life, whole life, and investment-linked plans to find the perfect fit for your long-term goals.
</div>
</div>
</div>
</div>
</div>
<!-- Home Insurance -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingFour">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFour">
<i class="bi bi-house-heart-fill me-3"></i> Home Insurance
</button>
</h2>
<div id="collapseFour" class="accordion-collapse collapse" data-bs-parent="#insuranceAccordion">
<div class="accordion-body">
<div class="row align-items-center">
<div class="col-md-3 text-center">
<img src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Modern beautiful house" class="img-fluid">
</div>
<div class="col-md-9">
<strong>Protect your biggest investment.</strong> Our home insurance covers your property and belongings against fire, theft, natural disasters, and more. Enjoy peace of mind knowing that your sanctuary is safe and sound.
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="text-center text-muted">
<div class="container">
<p>&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</div>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<!-- Bootstrap 5 JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- Custom JS -->
<script src="assets/js/main.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

View File

@ -105,7 +105,7 @@ class MailService
if (!file_exists($configPath)) {
throw new \RuntimeException('Mail config not found. Copy mail/config.sample.php to mail/config.php and fill in credentials.');
}
$cfg = require $configPath;
$cfg = require_once $configPath;
if (!is_array($cfg)) {
throw new \RuntimeException('Invalid mail config format: expected array');
}

View File

@ -0,0 +1,168 @@
<?php
require_once __DIR__ . '/../db/config.php';
try {
$pdo = db();
// --- Pagination Settings ---
$limit = 10; // Subscriptions per page
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$offset = ($page - 1) * $limit;
// --- Filtering and Searching ---
$base_sql = "FROM subscriptions";
$params = [];
$where_clauses = [];
if (!empty($_GET['status'])) {
$where_clauses[] = "status = :status";
$params[':status'] = $_GET['status'];
}
if (!empty($_GET['search'])) {
$where_clauses[] = "(fullName LIKE :search OR email LIKE :search)";
$params[':search'] = '%' . $_GET['search'] . '%';
}
if (!empty($where_clauses)) {
$base_sql .= " WHERE " . implode(' AND ', $where_clauses);
}
// --- Get Total Count for Pagination ---
$count_stmt = $pdo->prepare("SELECT COUNT(id) " . $base_sql);
$count_stmt->execute($params);
$total_subscriptions = $count_stmt->fetchColumn();
$total_pages = ceil($total_subscriptions / $limit);
// --- Get Subscriptions for Current Page ---
$subscriptions_sql = "SELECT id, fullName, email, insuranceType, status, created_at " . $base_sql . " ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($subscriptions_sql);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
foreach ($params as $key => &$val) {
$stmt->bindParam($key, $val);
}
$stmt->execute();
$subscriptions = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
die("Database error: " . $e->getMessage());
}
?>
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-4">
<h2 class="card-title h5 fw-bold">Application Trends</h2>
<p class="text-muted small">New applications over the last 30 days.</p>
<canvas id="applicationsChart"></canvas>
</div>
</div>
</div>
</div>
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-4">
<h2 class="card-title h5 fw-bold">All Applications</h2>
<p class="text-muted small">Manage all insurance applications.</p>
<!-- Filter and Search Form -->
<form action="admin.php" method="GET" class="row g-3 align-items-center mb-4">
<div class="col-md-5">
<input type="text" name="search" class="form-control" placeholder="Search by name or email..." value="<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>">
</div>
<div class="col-md-4">
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="Pending" <?php echo (($_GET['status'] ?? '') === 'Pending') ? 'selected' : ''; ?>>Pending</option>
<option value="Approved" <?php echo (($_GET['status'] ?? '') === 'Approved') ? 'selected' : ''; ?>>Approved</option>
<option value="Rejected" <?php echo (($_GET['status'] ?? '') === 'Rejected') ? 'selected' : ''; ?>>Rejected</option>
</select>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary-modern w-100">Filter</button>
<a href="admin.php" class="btn btn-secondary w-100 mt-2">Clear</a>
</div>
</form>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th scope="col">ID</th>
<th scope="col">Full Name</th>
<th scope="col">Email</th>
<th scope="col">Insurance Type</th>
<th scope="col">Status</th>
<th scope="col">Date</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($subscriptions)): ?>
<tr>
<td colspan="7" class="text-center text-muted py-4">No applications found.</td>
</tr>
<?php else: ?>
<?php foreach ($subscriptions as $sub): ?>
<tr>
<td><?php echo htmlspecialchars($sub['id']); ?></td>
<td><?php echo htmlspecialchars($sub['fullName']); ?></td>
<td><?php echo htmlspecialchars($sub['email']); ?></td>
<td><?php echo htmlspecialchars($sub['insuranceType']); ?></td>
<td>
<?php
$status = $sub['status'];
$badge_class = 'bg-secondary'; // Default
if ($status === 'Pending') {
$badge_class = 'bg-warning text-dark';
} elseif ($status === 'Approved') {
$badge_class = 'bg-success';
} elseif ($status === 'Rejected') {
$badge_class = 'bg-danger';
}
?>
<span class="badge <?php echo $badge_class; ?>"><?php echo htmlspecialchars($status); ?></span>
</td>
<td><?php echo date("Y-m-d", strtotime($sub['created_at'])); ?></td>
<td>
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" id="dropdownMenuButton-<?php echo $sub['id']; ?>" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-gear"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton-<?php echo $sub['id']; ?>">
<li><a class="dropdown-item" href="admin-details.php?id=<?php echo $sub['id']; ?>">Details</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" onclick="updateStatus(<?php echo $sub['id']; ?>, 'Pending')">Set Pending</a></li>
<li><a class="dropdown-item" href="#" onclick="updateStatus(<?php echo $sub['id']; ?>, 'Approved')">Set Approved</a></li>
<li><a class="dropdown-item" href="#" onclick="updateStatus(<?php echo $sub['id']; ?>, 'Rejected')">Set Rejected</a></li>
</ul>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<?php if ($page > 1): ?>
<li class="page-item"><a class="page-link" href="?page=<?php echo $page - 1; ?>&search=<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>&status=<?php echo htmlspecialchars($_GET['status'] ?? ''); ?>">Previous</a></li>
<?php endif; ?>
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<li class="page-item <?php echo ($i == $page) ? 'active' : ''; ?>"><a class="page-link" href="?page=<?php echo $i; ?>&search=<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>&status=<?php echo htmlspecialchars($_GET['status'] ?? ''); ?>"><?php echo $i; ?></a></li>
<?php endfor; ?>
<?php if ($page < $total_pages): ?>
<li class="page-item"><a class="page-link" href="?page=<?php echo $page + 1; ?>&search=<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>&status=<?php echo htmlspecialchars($_GET['status'] ?? ''); ?>">Next</a></li>
<?php endif; ?>
</ul>
</nav>
</div>
</div>

25
partials/admin_login.php Normal file
View File

@ -0,0 +1,25 @@
<div class="row justify-content-center">
<div class="col-lg-5">
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<h1 class="card-title text-center mb-4 fw-bold">Admin Login</h1>
<?php if (isset($error_message)): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
<?php endif; ?>
<form action="admin.php" method="post">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control form-control-lg" id="username" name="username" required value="admin">
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control form-control-lg" id="password" name="password" required value="password">
</div>
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary-modern btn-lg">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>

168
subscribe-step2.php Normal file
View File

@ -0,0 +1,168 @@
<?php
session_start();
if (!isset($_SESSION['personal_details'])) {
header('Location: subscribe.php');
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$_SESSION['insurance_details'] = [
'insuranceType' => filter_input(INPUT_POST, 'insuranceType', FILTER_SANITIZE_STRING),
'carMake' => filter_input(INPUT_POST, 'carMake', FILTER_SANITIZE_STRING),
'carModel' => filter_input(INPUT_POST, 'carModel', FILTER_SANITIZE_STRING),
'carYear' => filter_input(INPUT_POST, 'carYear', FILTER_SANITIZE_STRING),
'healthDependents' => filter_input(INPUT_POST, 'healthDependents', FILTER_SANITIZE_NUMBER_INT),
'lifeCoverage' => filter_input(INPUT_POST, 'lifeCoverage', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION),
'homeType' => filter_input(INPUT_POST, 'homeType', FILTER_SANITIZE_STRING),
];
header('Location: subscribe-step3.php');
exit;
}
$car_data = require __DIR__ . '/config/car_data.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subscribe - SecureLife</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">SecureLife</a>
</div>
</header>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<h1 class="card-title text-center mb-2 fw-bold">Choose Your Coverage</h1>
<p class="text-center text-muted mb-5">Step 2: Select your insurance plan and details</p>
<form action="subscribe-step2.php" method="POST">
<div class="mb-4">
<label for="insuranceType" class="form-label fs-5">Insurance Type</label>
<select class="form-select form-select-lg" id="insuranceType" name="insuranceType" required>
<option value="" selected disabled>-- Select an insurance type --</option>
<option value="Car">Car Insurance</option>
<option value="Health">Health Insurance</option>
<option value="Life">Life Insurance</option>
<option value="Home">Home Insurance</option>
</select>
</div>
<div id="carFields" class="dynamic-fields d-none border-top pt-4 mt-4">
<div class="mb-3">
<label for="carMake" class="form-label">Car Make</label>
<select class="form-select" id="carMake" name="carMake">
<option value="" selected disabled>-- Select Make --</option>
<?php foreach (array_keys($car_data) as $make): ?>
<option value="<?php echo $make; ?>"><?php echo $make; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="carModel" class="form-label">Car Model</label>
<select class="form-select" id="carModel" name="carModel" disabled>
<option value="" selected disabled>-- Select Model --</option>
</select>
</div>
<div class="mb-3">
<label for="carYear" class="form-label">Year of Manufacture</label>
<input type="date" class="form-control" id="carYear" name="carYear">
</div>
</div>
<div id="healthFields" class="dynamic-fields d-none border-top pt-4 mt-4">
<div class="mb-3">
<label for="healthDependents" class="form-label">Number of Dependents</label>
<input type="number" class="form-control" id="healthDependents" name="healthDependents" placeholder="e.g., 2">
</div>
</div>
<div id="lifeFields" class="dynamic-fields d-none border-top pt-4 mt-4">
<div class="mb-3">
<label for="lifeCoverage" class="form-label">Desired Coverage Amount ($)</label>
<input type="number" class="form-control" id="lifeCoverage" name="lifeCoverage" step="1000" placeholder="e.g., 500000">
</div>
</div>
<div id="homeFields" class="dynamic-fields d-none border-top pt-4 mt-4">
<div class="mb-3">
<label for="homeType" class="form-label">Property Type</label>
<select class="form-select" id="homeType" name="homeType">
<option value="House">House</option>
<option value="Apartment">Apartment</option>
<option value="Condo">Condo</option>
</select>
</div>
</div>
<div class="d-flex justify-content-between mt-5">
<a href="subscribe.php" class="btn btn-secondary btn-lg">&larr; Go Back</a>
<button type="submit" class="btn btn-primary-modern btn-lg">Next Step &rarr;</button>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
const carData = <?php echo json_encode($car_data); ?>;
document.getElementById('insuranceType').addEventListener('change', function () {
document.querySelectorAll('.dynamic-fields').forEach(function (el) {
el.classList.add('d-none');
});
var selectedType = this.value;
if (selectedType) {
var fieldsetId = selectedType.toLowerCase() + 'Fields';
var fieldset = document.getElementById(fieldsetId);
if (fieldset) {
fieldset.classList.remove('d-none');
}
}
});
document.getElementById('carMake').addEventListener('change', function() {
const carModelSelect = document.getElementById('carModel');
const selectedMake = this.value;
// Clear existing options
carModelSelect.innerHTML = '<option value="" selected disabled>-- Select Model --</option>';
if (selectedMake && carData[selectedMake]) {
carModelSelect.disabled = false;
carData[selectedMake].forEach(function(model) {
const option = document.createElement('option');
option.value = model;
option.textContent = model;
carModelSelect.appendChild(option);
});
} else {
carModelSelect.disabled = true;
}
});
</script>
</body>
</html>

173
subscribe-step3.php Normal file
View File

@ -0,0 +1,173 @@
<?php
session_start();
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/mail/MailService.php';
// Redirect to step 1 if session is not fully populated
if (!isset($_SESSION['personal_details']) || !isset($_SESSION['insurance_details'])) {
header('Location: subscribe.php');
exit;
}
$personal_details = $_SESSION['personal_details'];
$insurance_details = $_SESSION['insurance_details'];
function get_coverage_details_html($details) {
$type = $details['insuranceType'] ?? 'N/A';
$output = '';
switch ($type) {
case 'Car':
$output .= "<li><strong>Car Make:</strong> " . htmlspecialchars($details['carMake']) . "</li>";
$output .= "<li><strong>Car Model:</strong> " . htmlspecialchars($details['carModel']) . "</li>";
$output .= "<li><strong>Year of Manufacture:</strong> " . htmlspecialchars($details['carYear']) . "</li>";
break;
case 'Health':
$output .= "<li><strong>Number of Dependents:</strong> " . htmlspecialchars($details['healthDependents']) . "</li>";
break;
case 'Life':
$output .= "<li><strong>Coverage Amount:</strong> $" . number_format($details['lifeCoverage'], 2) . "</li>";
break;
case 'Home':
$output .= "<li><strong>Property Type:</strong> " . htmlspecialchars($details['homeType']) . "</li>";
break;
}
return $output;
}
$show_success_message = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$pdo = db();
$stmt = $pdo->prepare(
"INSERT INTO subscriptions (fullName, email, phone, insuranceType, carMake, carModel, carYear, healthDependents, lifeCoverage, homeType) " .
"VALUES (:fullName, :email, :phone, :insuranceType, :carMake, :carModel, :carYear, :healthDependents, :lifeCoverage, :homeType)"
);
$stmt->execute([
':fullName' => $personal_details['fullName'],
':email' => $personal_details['email'],
':phone' => $personal_details['phone'],
':insuranceType' => $insurance_details['insuranceType'],
':carMake' => $insurance_details['carMake'] ?? null,
':carModel' => $insurance_details['carModel'] ?? null,
':carYear' => $insurance_details['carYear'] ?: null,
':healthDependents' => $insurance_details['healthDependents'] ?: null,
':lifeCoverage' => $insurance_details['lifeCoverage'] ?: null,
':homeType' => $insurance_details['homeType'] ?? null,
]);
$submission_id = $pdo->lastInsertId();
// --- Send Confirmation Email to User ---
$user_subject = "Your Subscription to SecureLife is Confirmed!";
$user_body_html = "<h1>Welcome to SecureLife, " . htmlspecialchars($personal_details['fullName']) . "!</h1>";
$user_body_html .= "<p>We have received your application for " . htmlspecialchars($insurance_details['insuranceType']) . " insurance. Here is a summary of your submission:</p>";
$user_body_html .= "<ul>" . get_coverage_details_html($insurance_details) . "</ul>";
$user_body_html .= "<p>We will review your application and get back to you shortly. Your submission ID is: <strong>{$submission_id}</strong></p>";
MailService::sendMail($personal_details['email'], $user_subject, $user_body_html);
// --- Send Notification Email to Admin ---
$admin_subject = "New Insurance Application Received (#{$submission_id})";
$admin_body_html = "<h1>New Submission</h1>";
$admin_body_html .= "<p>A new insurance application has been submitted by <strong>" . htmlspecialchars($personal_details['fullName']) . "</strong>.</p>";
$admin_body_html .= "<h5>Personal Details</h5><ul>";
$admin_body_html .= "<li>Name: " . htmlspecialchars($personal_details['fullName']) . "</li>";
$admin_body_html .= "<li>Email: " . htmlspecialchars($personal_details['email']) . "</li>";
$admin_body_html .= "<li>Phone: " . htmlspecialchars($personal_details['phone']) . "</li></ul>";
$admin_body_html .= "<h5>Insurance Details</h5><ul>";
$admin_body_html .= "<li>Type: " . htmlspecialchars($insurance_details['insuranceType']) . "</li>";
$admin_body_html .= get_coverage_details_html($insurance_details) . "</ul>";
$admin_body_html .= "<p>You can view this submission in the <a href=\"http://{\$\_SERVER['HTTP_HOST']}/admin.php\">Admin Dashboard</a>.</p>";
MailService::sendMail(null, $admin_subject, $admin_body_html); // $to = null uses MAIL_TO from env
// Clear the session and show a success message
session_unset();
session_destroy();
$show_success_message = true;
} catch (PDOException $e) {
error_log("Database error: " . $e->getMessage());
die("An error occurred. Please try again later.");
} catch (Exception $e) {
error_log("Mail sending error: " . $e->getMessage());
die("An error occurred. Please try again later.");
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Confirm Subscription - SecureLife</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">SecureLife</a>
</div>
</header>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<?php if ($show_success_message): ?>
<div class="text-center">
<i class="bi bi-check-circle-fill text-success" style="font-size: 4rem;"></i>
<h1 class="card-title mt-4 fw-bold">Subscription Complete!</h1>
<p class="text-muted fs-5">Thank you for choosing SecureLife. A confirmation email has been sent to you. We will be in touch shortly.</p>
<a href="index.php" class="btn btn-primary-modern btn-lg mt-4">Back to Home</a>
</div>
<?php else: ?>
<h1 class="card-title text-center mb-2 fw-bold">Confirm Your Details</h1>
<p class="text-center text-muted mb-5">Step 3: Please review your information before confirming.</p>
<div class="bg-light-blue p-4 rounded-3">
<div class="row">
<div class="col-md-6">
<h5 class="fw-bold">Personal Details</h5>
<ul class="list-unstyled">
<li><strong>Full Name:</strong> <?php echo htmlspecialchars($personal_details['fullName']); ?></li>
<li><strong>Email:</strong> <?php echo htmlspecialchars($personal_details['email']); ?></li>
<li><strong>Phone:</strong> <?php echo htmlspecialchars($personal_details['phone']); ?></li>
</ul>
</div>
<div class="col-md-6">
<h5 class="fw-bold">Insurance Details</h5>
<ul class="list-unstyled">
<li><strong>Insurance Type:</strong> <?php echo htmlspecialchars($insurance_details['insuranceType']); ?></li>
<?php echo get_coverage_details_html($insurance_details); ?>
</ul>
</div>
</div>
</div>
<form action="subscribe-step3.php" method="POST">
<div class="d-flex justify-content-between mt-5">
<a href="subscribe-step2.php" class="btn btn-secondary btn-lg">&larr; Go Back</a>
<button type="submit" class="btn btn-success btn-lg">Confirm Subscription &check;</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
</div>
</main>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

72
subscribe.php Normal file
View File

@ -0,0 +1,72 @@
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$_SESSION['personal_details'] = [
'fullName' => filter_input(INPUT_POST, 'fullName', FILTER_SANITIZE_STRING),
'email' => filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL),
'phone' => filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING),
];
header('Location: subscribe-step2.php');
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subscribe - SecureLife</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">SecureLife</a>
</div>
</header>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm border-0" style="border-radius: 0.75rem;">
<div class="card-body p-5">
<h1 class="card-title text-center mb-2 fw-bold">Get Your Free Quote</h1>
<p class="text-center text-muted mb-5">Step 1: Tell us about yourself</p>
<form action="subscribe.php" method="POST">
<div class="mb-4">
<label for="fullName" class="form-label fs-5">Full Name</label>
<input type="text" class="form-control form-control-lg" id="fullName" name="fullName" placeholder="e.g., John Doe" required>
</div>
<div class="mb-4">
<label for="email" class="form-label fs-5">Email Address</label>
<input type="email" class="form-control form-control-lg" id="email" name="email" placeholder="e.g., john.doe@example.com" required>
</div>
<div class="mb-4">
<label for="phone" class="form-label fs-5">Phone Number</label>
<input type="tel" class="form-control form-control-lg" id="phone" name="phone" placeholder="e.g., (555) 123-4567" required>
</div>
<div class="d-grid mt-5">
<button type="submit" class="btn btn-primary-modern btn-lg">Next Step &rarr;</button>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
<footer class="text-center py-4 mt-auto bg-dark text-white">
<p class="mb-0">&copy; <?php echo date("Y"); ?> SecureLife. All Rights Reserved.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>