Compare commits

...

2 Commits

Author SHA1 Message Date
Flatlogic Bot
db34ad1091 002 2025-10-22 19:18:04 +00:00
Flatlogic Bot
2e32207c38 001 2025-10-22 18:57:21 +00:00
14 changed files with 480 additions and 160 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'; ?>

5
assets/css/custom.css Normal file
View File

@ -0,0 +1,5 @@
/*
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.
*/

19
assets/js/main.js Normal file
View File

@ -0,0 +1,19 @@
// Main JavaScript file
(function() {
'use strict';
window.addEventListener('load', function() {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByClassName('needs-validation');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();

View File

@ -1,17 +1,57 @@
<?php <?php
// Generated by setup_mariadb_project.sh — edit as needed. // Database configuration
define('DB_HOST', '127.0.0.1'); define('DB_HOST', getenv('DB_HOST') ?: '127.0.0.1');
define('DB_NAME', 'app_30972'); define('DB_PORT', getenv('DB_PORT') ?: '3306');
define('DB_USER', 'app_30972'); define('DB_NAME', getenv('DB_NAME') ?: 'flatlogic');
define('DB_PASS', '9eb17a13-4a89-4e11-8517-0c201096e935'); define('DB_USER', getenv('DB_USER') ?: 'flatlogic');
define('DB_PASS', getenv('DB_PASS') ?: 'flatlogic');
function db() { function db() {
static $pdo; static $pdo;
if (!$pdo) { if ($pdo) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
}
return $pdo; return $pdo;
} }
try {
// Connect without specifying a database to create it if it doesn't exist
$dsn_init = 'mysql:host=' . DB_HOST . ';port=' . DB_PORT . ';charset=utf8mb4';
$pdo_init = new PDO($dsn_init, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$pdo_init->exec('CREATE DATABASE IF NOT EXISTS `' . DB_NAME . '`');
// Now connect to the specific database
$dsn = 'mysql:host=' . DB_HOST . ';port=' . DB_PORT . ';dbname=' . DB_NAME . ';charset=utf8mb4';
$pdo = new PDO($dsn, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
run_migrations($pdo);
return $pdo;
} catch (PDOException $e) {
// In a real app, you'd log this error and show a generic message
throw new PDOException($e->getMessage(), (int)$e->getCode());
}
}
function run_migrations($pdo) {
$pdo->exec('CREATE TABLE IF NOT EXISTS `migrations` (`migration` VARCHAR(255) NOT NULL, PRIMARY KEY (`migration`))');
$applied_migrations = $pdo->query('SELECT `migration` FROM `migrations`')->fetchAll(PDO::FETCH_COLUMN);
$migration_files = glob(__DIR__ . '/migrations/*.sql');
sort($migration_files);
foreach ($migration_files as $file) {
$migration_name = basename($file);
if (!in_array($migration_name, $applied_migrations)) {
$sql = file_get_contents($file);
$pdo->exec($sql);
$stmt = $pdo->prepare('INSERT INTO `migrations` (`migration`) VALUES (?)');
$stmt->execute([$migration_name]);
}
}
}

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS `service_requests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`message` text NOT NULL,
`status` varchar(50) NOT NULL DEFAULT 'pending',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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`;

13
footer.php Normal file
View File

@ -0,0 +1,13 @@
</main>
</div>
</div>
<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="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

46
header.php Normal file
View File

@ -0,0 +1,46 @@
<?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><?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=2.0">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'sans-serif'],
},
}
}
}
</script>
</head>
<body class="bg-gray-100 font-sans">
<div x-data="{ sidebarOpen: false }" class="flex h-screen bg-gray-200">
<?php include 'sidebar.php'; ?>
<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">

159
index.php
View File

@ -1,150 +1,17 @@
<?php <?php
declare(strict_types=1); $page_title = 'Welcome';
@ini_set('display_errors', '1'); require_once __DIR__ . '/header.php';
@error_reporting(E_ALL); ?>
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION; <div class="bg-white rounded-lg shadow-md p-8 text-center">
$now = date('Y-m-d H:i:s'); <div class="max-w-2xl mx-auto">
?> <h1 class="text-4xl font-bold text-gray-800 mb-4">Client Case Management, Simplified</h1>
<!doctype html> <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>
<html lang="en"> <div class="flex justify-center gap-4">
<head> <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>
<meta charset="utf-8" /> <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>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<?php
// Read project preview data from environment
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<!-- Meta description -->
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags -->
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<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;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head>
<body>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
</div> </div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div> </div>
</main> </div>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC) <?php require_once __DIR__ . '/footer.php'; ?>
</footer>
</body>
</html>

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;

94
request-service.php Normal file
View File

@ -0,0 +1,94 @@
<?php
require_once __DIR__ . '/mail/MailService.php';
$page_title = 'Request a Service';
$message = '';
$message_type = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$service_message = trim($_POST['message'] ?? '');
if (empty($name) || empty($email) || empty($service_message) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$message = 'Please fill in all fields correctly.';
$message_type = 'red';
} else {
try {
$pdo = db();
$stmt = $pdo->prepare(
'INSERT INTO service_requests (name, email, message) VALUES (?, ?, ?)'
);
$stmt->execute([$name, $email, $service_message]);
// Notify Admin
$admin_email = getenv('MAIL_TO') ?: 'admin@example.com';
$subject = 'New Service Request from ' . $name;
$html_content = "
<h1>New Service Request</h1>
<p><strong>Name:</strong> {$name}</p>
<p><strong>Email:</strong> {$email}</p>
<p><strong>Message:</strong></p>
<p>{$service_message}</p>
<p>This request is now pending approval in the admin dashboard.</p>
";
$text_content = strip_tags($html_content);
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 = '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 = 'red';
} catch (Exception $e) {
$message = 'Sorry, there was an error sending the notification. Please try again later.';
$message_type = 'red';
}
}
}
require_once __DIR__ . '/header.php';
?>
<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="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 !== '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>
<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>
<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>
<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>
<?php require_once __DIR__ . '/footer.php'; ?>

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>