This commit is contained in:
Flatlogic Bot 2025-10-22 19:18:04 +00:00
parent 2e32207c38
commit db34ad1091
11 changed files with 320 additions and 123 deletions

73
admin.php Normal file
View File

@ -0,0 +1,73 @@
<?php
session_start();
// If the user is not logged in, redirect to the login page.
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
require_once 'db/config.php';
$page_title = 'Admin Dashboard';
require_once __DIR__ . '/header.php';
$pdo = db();
$stmt = $pdo->query('SELECT id, name, email, message, status, created_at FROM service_requests ORDER BY created_at DESC');
$requests = $stmt->fetchAll();
?>
<div class="flex justify-between items-center mb-6">
<h1 class="text-3xl font-bold text-gray-800">Admin Dashboard</h1>
<a href="logout.php" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Logout</a>
</div>
<div class="bg-white rounded-lg shadow-md">
<div class="px-6 py-4 border-b">
<h2 class="text-xl font-semibold text-gray-800">Incoming Service Requests</h2>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Message</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Received At</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<?php if (empty($requests)): ?>
<tr>
<td colspan="7" class="px-6 py-4 text-center text-gray-500">No service requests yet.</td>
</tr>
<?php else: ?>
<?php foreach ($requests as $request): ?>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900"><?php echo htmlspecialchars($request['id']); ?></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><?php echo htmlspecialchars($request['name']); ?></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><a href="mailto:<?php echo htmlspecialchars($request['email']); ?>" class="text-indigo-600 hover:text-indigo-900"><?php echo htmlspecialchars($request['email']); ?></a></td>
<td class="px-6 py-4 text-sm text-gray-500"><div class="w-48 truncate"><?php echo nl2br(htmlspecialchars($request['message'])); ?></div></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><?php echo htmlspecialchars(date('M d, Y H:i', strtotime($request['created_at']))); ?></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">
<?php echo htmlspecialchars(ucfirst($request['status'])); ?>
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2">
<button class="px-3 py-1 text-xs text-white bg-green-600 rounded-md hover:bg-green-700 focus:outline-none">Approve</button>
<button class="px-3 py-1 text-xs text-white bg-red-600 rounded-md hover:bg-red-700 focus:outline-none">Deny</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php require_once __DIR__ . '/footer.php'; ?>

View File

@ -1,32 +1,5 @@
/* Orange and Dark Gray Theme */
:root {
--bs-primary: #fd7e14; /* Vivid Orange */
--bs-secondary: #6c757d;
--bs-dark: #343a40;
--bs-primary-rgb: 253, 126, 20;
}
body {
font-family: 'Inter', sans-serif;
background-color: #f8f9fa;
}
.btn-primary {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
.btn-primary:hover {
background-color: #e46a0a;
border-color: #d16209;
}
.navbar-dark {
background-color: var(--bs-dark) !important;
}
.footer {
background-color: #343a40;
color: white;
}
/*
This file is intentionally left minimal.
Most styles are handled by Tailwind CSS utility classes directly in the PHP files.
Use this file for custom components or styles that are difficult to achieve with utilities alone.
*/

View File

@ -0,0 +1,15 @@
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`role` varchar(50) NOT NULL DEFAULT 'admin',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Insert a default admin user with a temporary password 'password'
-- The password hash is for 'password'
INSERT INTO `users` (`username`, `password`, `role`)
SELECT 'admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin'
WHERE NOT EXISTS (SELECT 1 FROM `users` WHERE `username` = 'admin');

View File

@ -0,0 +1,6 @@
-- Add new columns to the service_requests table for detailed case information
ALTER TABLE `service_requests`
ADD COLUMN `case_title` VARCHAR(255) NULL AFTER `email`,
ADD COLUMN `case_type` VARCHAR(100) NULL AFTER `case_title`,
ADD COLUMN `urgency` VARCHAR(50) NULL AFTER `case_type`,
ADD COLUMN `services_required` VARCHAR(255) NULL AFTER `urgency`;

View File

@ -1,13 +1,13 @@
</main>
</div>
</div>
</main><!-- /.container -->
<footer class="footer mt-auto py-3">
<div class="container text-center">
<span>&copy; <?php echo date('Y'); ?> IA Cases. All Rights Reserved.</span>
<footer class="bg-white p-4 mt-auto border-t">
<div class="text-center">
<p class="text-gray-500">&copy; <?php echo date('Y'); ?> Client Portal. All Rights Reserved.</p>
</div>
</footer>
<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>

View File

@ -1,45 +1,46 @@
<?php require_once __DIR__ . '/db/config.php'; ?>
<!DOCTYPE html>
<?php
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$page_title = isset($page_title) ? $page_title : 'Client Portal';
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IA Cases</title>
<meta name="description" content="Client case management portal built with Flatlogic Generator.">
<meta name="keywords" content="client portal, case management, legal tech, client communication, document management, task management, flatlogic">
<meta property="og:title" content="IA Cases">
<meta property="og:description" content="Client case management portal built with Flatlogic Generator.">
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<title><?php echo htmlspecialchars($page_title); ?> - Client Portal</title>
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.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;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<link rel="stylesheet" href="assets/css/custom.css?v=2.0">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'sans-serif'],
},
}
}
}
</script>
</head>
<body>
<body class="bg-gray-100 font-sans">
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container">
<a class="navbar-brand" href="index.php">IA Cases</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<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" href="index.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="request-service.php">Request Service</a>
</li>
</ul>
</div>
</div>
</nav>
<div x-data="{ sidebarOpen: false }" class="flex h-screen bg-gray-200">
<?php include 'sidebar.php'; ?>
<main class="container my-5">
<div class="flex-1 flex flex-col overflow-hidden">
<header class="flex justify-between items-center p-4 bg-white border-b lg:hidden">
<a class="text-2xl font-bold text-gray-800" href="index.php">Client Portal</a>
<button @click="sidebarOpen = !sidebarOpen" class="text-gray-500 focus:outline-none">
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 6H20M4 12H20M4 18H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</button>
</header>
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-100 p-6">

View File

@ -1,12 +1,15 @@
<?php require_once __DIR__ . '/header.php'; ?>
<?php
$page_title = 'Welcome';
require_once __DIR__ . '/header.php';
?>
<div class="px-4 py-5 my-5 text-center">
<h1 class="display-5 fw-bold text-body-emphasis">Client Case Management, Simplified</h1>
<div class="col-lg-6 mx-auto">
<p class="lead mb-4">Welcome to your dedicated client portal. Request services, track case progress, and communicate with your account manager seamlessly. Get started by requesting a service below.</p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
<a href="request-service.php" class="btn btn-primary btn-lg px-4 gap-3">Request a Service</a>
<button type="button" class="btn btn-outline-secondary btn-lg px-4">Log In</button>
<div class="bg-white rounded-lg shadow-md p-8 text-center">
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold text-gray-800 mb-4">Client Case Management, Simplified</h1>
<p class="text-lg text-gray-600 mb-8">Welcome to your dedicated client portal. Request services, track case progress, and communicate with your account manager seamlessly. Get started by requesting a service below.</p>
<div class="flex justify-center gap-4">
<a href="request-service.php" class="inline-block px-8 py-3 text-lg font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Request a Service</a>
<a href="login.php" class="inline-block px-8 py-3 text-lg font-medium text-indigo-600 bg-indigo-100 rounded-md hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Log In</a>
</div>
</div>
</div>

73
login.php Normal file
View File

@ -0,0 +1,73 @@
<?php
session_start();
require_once 'db/config.php';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($username) || empty($password)) {
$error = 'Please enter both username and password.';
} else {
try {
$pdo = db();
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?');
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = $user['role'];
header('Location: admin.php');
exit;
} else {
$error = 'Invalid username or password.';
}
} catch (PDOException $e) {
// In a real app, you'd log this error.
$error = 'An error occurred. Please try again later.';
}
}
}
$page_title = 'Admin Login';
require_once __DIR__ . '/header.php';
?>
<div class="flex items-center justify-center min-h-full">
<div class="w-full max-w-md p-8 space-y-6 bg-white rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-center text-gray-900">Admin Login</h1>
<?php if ($error): ?>
<div class="p-4 text-sm text-red-700 bg-red-100 rounded-lg" role="alert">
<?php echo htmlspecialchars($error); ?>
</div>
<?php endif; ?>
<form action="login.php" method="post" class="space-y-6">
<div>
<label for="username" class="text-sm font-medium text-gray-700">Username</label>
<div class="mt-1">
<input type="text" id="username" name="username" required
class="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
</div>
<div>
<label for="password" class="text-sm font-medium text-gray-700">Password</label>
<div class="mt-1">
<input type="password" id="password" name="password" required
class="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
</div>
<div>
<button type="submit"
class="w-full px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Sign in
</button>
</div>
</form>
</div>
</div>
<?php require_once __DIR__ . '/footer.php'; ?>

6
logout.php Normal file
View File

@ -0,0 +1,6 @@
<?php
session_start();
$_SESSION = [];
session_destroy();
header('Location: login.php');
exit;

View File

@ -11,7 +11,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (empty($name) || empty($email) || empty($service_message) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$message = 'Please fill in all fields correctly.';
$message_type = 'danger';
$message_type = 'red';
} else {
try {
$pdo = db();
@ -36,14 +36,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
MailService::sendMail($admin_email, $subject, $html_content, $text_content);
$message = 'Thank you! Your service request has been submitted successfully. An account manager will review it shortly.';
$message_type = 'success';
$message_type = 'green';
} catch (PDOException $e) {
// In a real app, log this error.
$message = 'Sorry, there was an error submitting your request. Please try again later.';
$message_type = 'danger';
$message_type = 'red';
} catch (Exception $e) {
$message = 'Sorry, there was an error sending the notification. Please try again later.';
$message_type = 'danger';
$message_type = 'red';
}
}
}
@ -51,48 +51,42 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_once __DIR__ . '/header.php';
?>
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm">
<div class="card-body p-5">
<h1 class="card-title text-center mb-4"><?php echo $page_title; ?></h1>
<div class="max-w-4xl mx-auto">
<div class="bg-white rounded-lg shadow-md">
<div class="p-8">
<h1 class="text-3xl font-bold text-center text-gray-800 mb-6"><?php echo $page_title; ?></h1>
<?php if ($message): ?>
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
<?php echo htmlspecialchars($message); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if ($message): ?>
<div class="p-4 mb-6 text-sm text-<?php echo $message_type; ?>-700 bg-<?php echo $message_type; ?>-100 rounded-lg" role="alert">
<?php echo htmlspecialchars($message); ?>
</div>
<?php endif; ?>
<?php if ($message_type !== 'success'): ?>
<form action="request-service.php" method="POST" class="needs-validation" novalidate>
<div class="mb-3">
<label for="name" class="form-label">Full Name</label>
<input type="text" class="form-control" id="name" name="name" required>
<div class="invalid-feedback">
Please enter your full name.
</div>
<?php if ($message_type !== 'green'): ?>
<form action="request-service.php" method="POST" class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium text-gray-700">Full Name</label>
<div class="mt-1">
<input type="text" name="name" id="name" required class="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control" id="email" name="email" required>
<div class="invalid-feedback">
Please enter a valid email address.
</div>
</div>
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email Address</label>
<div class="mt-1">
<input type="email" name="email" id="email" required class="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="mb-3">
<label for="message" class="form-label">Describe the service you need</label>
<textarea class="form-control" id="message" name="message" rows="5" required></textarea>
<div class="invalid-feedback">
Please describe the service you require.
</div>
</div>
<div>
<label for="message" class="block text-sm font-medium text-gray-700">Describe the service you need</label>
<div class="mt-1">
<textarea id="message" name="message" rows="5" required class="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-lg px-5">Submit Request</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
<div class="text-center">
<button type="submit" class="inline-block px-8 py-3 text-lg font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Submit Request</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>

53
sidebar.php Normal file
View File

@ -0,0 +1,53 @@
<!-- Sidebar -->
<div
x-show="sidebarOpen"
@click.away="sidebarOpen = false"
class="fixed inset-0 z-40 flex transition-transform duration-300 ease-in-out bg-gray-900 bg-opacity-50 lg:hidden"
x-transition:enter="transition-opacity ease-linear duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<div
class="fixed inset-y-0 left-0 z-50 w-64 px-4 py-8 overflow-y-auto transition-transform duration-300 ease-in-out transform bg-white shadow-lg lg:static lg:inset-auto lg:translate-x-0"
:class="{ '-translate-x-full': !sidebarOpen, 'translate-x-0': sidebarOpen }"
>
<div class="flex items-center justify-between px-2">
<a class="text-2xl font-bold text-gray-800" href="index.php">Client Portal</a>
<button @click="sidebarOpen = false" class="text-gray-600 lg:hidden">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
<nav class="mt-10">
<a href="index.php" class="flex items-center px-4 py-2 text-gray-700 rounded-md hover:bg-gray-200">
<i class="bi bi-house-door me-3"></i>
<span class="mx-4 font-medium">Home</span>
</a>
<a href="request-service.php" class="flex items-center px-4 py-2 mt-5 text-gray-700 rounded-md hover:bg-gray-200">
<i class="bi bi-card-list me-3"></i>
<span class="mx-4 font-medium">Request Service</span>
</a>
<?php if (isset($_SESSION['user_id'])) : ?>
<a href="admin.php" class="flex items-center px-4 py-2 mt-5 text-gray-700 rounded-md hover:bg-gray-200">
<i class="bi bi-person-badge me-3"></i>
<span class="mx-4 font-medium">Admin</span>
</a>
<a href="logout.php" class="flex items-center px-4 py-2 mt-5 text-gray-700 rounded-md hover:bg-gray-200">
<i class="bi bi-box-arrow-right me-3"></i>
<span class="mx-4 font-medium">Logout</span>
</a>
<?php else : ?>
<a href="login.php" class="flex items-center px-4 py-2 mt-5 text-gray-700 rounded-md hover:bg-gray-200">
<i class="bi bi-box-arrow-in-right me-3"></i>
<span class="mx-4 font-medium">Login</span>
</a>
<?php endif; ?>
</nav>
</div>