-- SQL Database Schema
-- Create database
CREATE DATABASE IF NOT EXISTS planning_db CHARACTER SET utf8mb4 COLLATE
utf8mb4_unicode_ci;
USE planning_db;
-- Table for Admin (simple, hashed password)
CREATE TABLE admins (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert default admin (username: admin, password: admin123 hashed with password_hash)
INSERT INTO admins (username, password) VALUES ('admin',
'$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/[Link]/igi'); -- Hashed 'admin123'
-- Table for News
CREATE TABLE news (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table for Events
CREATE TABLE events (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
event_date DATE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table for Media (Gallery and Carousel)
CREATE TABLE media (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
path VARCHAR(500) NOT NULL, -- Relative path to uploaded file
description VARCHAR(255),
type ENUM('gallery', 'carousel') NOT NULL,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table for Downloads
CREATE TABLE downloads (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
path VARCHAR(500) NOT NULL,
description VARCHAR(255) NOT NULL,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table for Contact Messages
CREATE TABLE messages (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Indexes for performance
CREATE INDEX idx_news_date ON news(created_at);
CREATE INDEX idx_events_date ON events(event_date, created_at);
CREATE INDEX idx_media_type ON media(type);
CREATE INDEX idx_messages_date ON messages(created_at);
php
<?php
// [Link] - Database Configuration
$host = 'localhost';
$dbname = 'planning_db';
$username = 'your_db_user'; // Replace with your DB username
$password = 'your_db_password'; // Replace with your DB password
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username,
$password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
?>
php
<?php
// api/[Link] - Admin Login
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit;
$input = json_decode(file_get_contents('php://input'), true);
$username = $input['username'] ?? '';
$password = $input['password'] ?? '';
if (empty($username) || empty($password)) {
echo json_encode(['error' => 'Missing credentials']);
exit;
}
$stmt = $pdo->prepare("SELECT id, password FROM admins WHERE username = ?");
$stmt->execute([$username]);
$admin = $stmt->fetch(PDO::FETCH_ASSOC);
if ($admin && password_verify($password, $admin['password'])) {
$_SESSION['admin_id'] = $admin['id'];
echo json_encode(['success' => true]);
} else {
echo json_encode(['error' => 'Invalid credentials']);
?>
php
<?php
// api/[Link] - Admin Logout
session_start();
session_destroy();
header('Content-Type: application/json');
echo json_encode(['success' => true]);
?>
php
<?php
// api/[Link] - Get and Post News (Admin only for post)
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'GET') {
// Get all news
$stmt = $pdo->query("SELECT id, title, content, created_at FROM news ORDER BY created_at
DESC");
$news = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($news);
} elseif ($method === 'POST') {
// Check admin session
if (!isset($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
$input = json_decode(file_get_contents('php://input'), true);
$title = $input['title'] ?? '';
$content = $input['content'] ?? '';
if (empty($title) || empty($content)) {
echo json_encode(['error' => 'Missing fields']);
exit;
}
$stmt = $pdo->prepare("INSERT INTO news (title, content) VALUES (?, ?)");
$stmt->execute([$title, $content]);
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
?>
php
<?php
// api/[Link] - Get and Post Events (Admin only for post)
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'GET') {
// Get all events
$stmt = $pdo->query("SELECT id, title, content, event_date, created_at FROM events ORDER
BY event_date ASC");
$events = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($events);
} elseif ($method === 'POST') {
// Check admin session
if (!isset($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
$input = json_decode(file_get_contents('php://input'), true);
$title = $input['title'] ?? '';
$content = $input['content'] ?? '';
$event_date = $input['event_date'] ?? '';
if (empty($title) || empty($content) || empty($event_date)) {
echo json_encode(['error' => 'Missing fields']);
exit;
$stmt = $pdo->prepare("INSERT INTO events (title, content, event_date) VALUES (?, ?, ?)");
$stmt->execute([$title, $content, $event_date]);
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
?>
php
<?php
// api/[Link] - Get and Post Media (Admin only for post, handles file upload)
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
$upload_dir = '../uploads/media/'; // Create this directory with 755 permissions
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
if ($method === 'GET') {
$type = $_GET['type'] ?? null;
if ($type) {
$stmt = $pdo->prepare("SELECT id, name, path, description, type, uploaded_at FROM
media WHERE type = ? ORDER BY uploaded_at DESC");
$stmt->execute([$type]);
} else {
$stmt = $pdo->query("SELECT id, name, path, description, type, uploaded_at FROM media
ORDER BY uploaded_at DESC");
$media = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($media);
} elseif ($method === 'POST') {
// Check admin session
if (!isset($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
if (isset($_FILES['files']) && $_FILES['files']['error'] === UPLOAD_ERR_OK) {
$description = $_POST['description'] ?? '';
$type = $_POST['type'] ?? 'gallery';
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'video/mp4', 'video/avi',
'video/mov'];
$max_size = 50 * 1024 * 1024; // 50MB
foreach ($_FILES['files']['tmp_name'] as $key => $tmp_name) {
if ($_FILES['files']['error'][$key] === UPLOAD_ERR_OK) {
$file_name = basename($_FILES['files']['name'][$key]);
$file_size = $_FILES['files']['size'][$key];
$file_type = $_FILES['files']['type'][$key];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if (!in_array($file_type, $allowed_types) || $file_size > $max_size) {
continue; // Skip invalid files
$new_name = uniqid() . '_' . $file_name;
$target_path = $upload_dir . $new_name;
if (move_uploaded_file($tmp_name, $target_path)) {
$stmt = $pdo->prepare("INSERT INTO media (name, path, description, type) VALUES
(?, ?, ?, ?)");
$stmt->execute([$file_name, $target_path, $description, $type]);
echo json_encode(['success' => true]);
} else {
echo json_encode(['error' => 'No file uploaded']);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
?>
php
<?php
// api/[Link] - Get and Post Downloads (Admin only for post, handles file upload)
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
$upload_dir = '../uploads/downloads/'; // Create this directory with 755 permissions
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
if ($method === 'GET') {
// Get all downloads
$stmt = $pdo->query("SELECT id, name, path, description, uploaded_at FROM downloads
ORDER BY uploaded_at DESC");
$downloads = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($downloads);
} elseif ($method === 'POST') {
// Check admin session
if (!isset($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
$description = $_POST['description'] ?? '';
$allowed_exts = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'jpg', 'png', 'gif'];
$file_ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$max_size = 50 * 1024 * 1024; // 50MB
if (!in_array($file_ext, $allowed_exts) || $_FILES['file']['size'] > $max_size) {
echo json_encode(['error' => 'Invalid file type or size']);
exit;
$file_name = basename($_FILES['file']['name']);
$new_name = uniqid() . '_' . $file_name;
$target_path = $upload_dir . $new_name;
if (move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
$stmt = $pdo->prepare("INSERT INTO downloads (name, path, description) VALUES
(?, ?, ?)");
$stmt->execute([$file_name, $target_path, $description]);
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
} else {
echo json_encode(['error' => 'Upload failed']);
} else {
echo json_encode(['error' => 'No file uploaded']);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
?>
php
<?php
// api/[Link] - Get and Post Messages (Public post, Admin get)
session_start();
require_once '../[Link]';
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'GET') {
// Check admin session for get
if (!isset($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
// Get all messages
$stmt = $pdo->query("SELECT id, name, email, message, created_at FROM messages ORDER
BY created_at DESC");
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($messages);
} elseif ($method === 'POST') {
// Public post
$input = json_decode(file_get_contents('php://input'), true);
$name = $input['name'] ?? '';
$email = $input['email'] ?? '';
$message = $input['message'] ?? '';
if (empty($name) || empty($email) || empty($message)) {
echo json_encode(['error' => 'Missing fields']);
exit;
$stmt = $pdo->prepare("INSERT INTO messages (name, email, message) VALUES (?, ?, ?)");
$stmt->execute([$name, $email, $message]);
echo json_encode(['success' => true]);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
?>
php
<?php
// [Link] - Serve file downloads (protect with .htaccess if needed)
require_once '[Link]'; // Adjust path
$id = $_GET['id'] ?? 0;
if ($id) {
$stmt = $pdo->prepare("SELECT path, name FROM downloads WHERE id = ?");
$stmt->execute([$id]);
$download = $stmt->fetch(PDO::FETCH_ASSOC);
if ($download) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $download['name'] . '"');
header('Content-Length: ' . filesize($download['path']));
readfile($download['path']);
exit;
http_response_code(404);
?>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Planning and Development Bureau</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
header {
background-color: #333;
color: white;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
.logo {
font-size: 24px;
font-weight: bold;
nav ul {
list-style: none;
display: flex;
gap: 20px;
nav a {
color: white;
text-decoration: none;
padding: 10px;
nav a:hover {
background-color: #555;
#carousel {
position: relative;
max-width: 800px;
margin: 20px auto;
overflow: hidden;
border-radius: 10px;
height: 400px;
.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transform: translateX(100%);
transition: transform 0.5s ease-in-out;
.[Link] {
transform: translateX(0%);
.prev, .next {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: rgba(0,0,0,0.5);
color: white;
border: none;
padding: 10px;
cursor: pointer;
z-index: 10;
.prev {
left: 10px;
.next {
right: 10px;
main {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
section {
margin-bottom: 40px;
#news, #events, #gallery, #downloads, #contacts, #departments {
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
form {
display: flex;
flex-direction: column;
gap: 10px;
max-width: 400px;
input, textarea, button, select {
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
button {
background-color: #333;
color: white;
cursor: pointer;
button:hover {
background-color: #555;
.news-item, .event-item, .download-item, .message-item, .media-item {
border-bottom: 1px solid #ddd;
padding: 10px 0;
.media-item img, .media-item video {
max-width: 200px;
height: auto;
margin: 10px 0;
.admin-only {
display: none;
}
.admin-visible {
display: block;
#admin-login {
max-width: 300px;
margin: 0 auto;
.hidden {
display: none;
.division {
margin-bottom: 30px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
.division h3 {
color: #333;
border-bottom: 2px solid #333;
padding-bottom: 5px;
.directorate-list {
list-style-type: disc;
padding-left: 20px;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 10px;
position: fixed;
bottom: 0;
width: 100%;
</style>
</head>
<body>
<header>
<div class="logo">
<img src="[Link]" alt="Logo" width="50" height="50" style="margin-right: 10px;"> <!--
Replace with actual logo -->
Planning and Development Bureau
</div>
<nav>
<ul>
<li><a href="#" onclick="showPage('home')">Home</a></li>
<li><a href="#" onclick="showPage('departments')">Departments</a></li>
<li><a href="#" onclick="showPage('news')">News</a></li>
<li><a href="#" onclick="showPage('events')">Events</a></li>
<li><a href="#" onclick="showPage('gallery')">Gallery</a></li>
<li><a href="#" onclick="showPage('contacts')">Contacts</a></li>
<li><a href="#" onclick="showPage('downloads')">Downloads</a></li>
<li><a href="#" onclick="showPage('about')">About Us</a></li>
<li><a href="#" onclick="showPage('admin')">Admin</a></li>
</ul>
</nav>
</header>
<main>
<!-- Home Page -->
<div id="home" class="page">
<section id="carousel">
<!-- Slides loaded dynamically -->
<button class="prev" onclick="changeSlide(-1)">❮</button>
<button class="next" onclick="changeSlide(1)">❯</button>
</section>
</div>
<!-- Departments Page -->
<div id="departments" class="page hidden">
<h2>Departments</h2>
<div class="division">
<h3>Strategic Planning Division</h3>
<ul class="directorate-list">
<li>Directorate of Policy Analysis</li>
<li>Directorate of Research and Development</li>
<li>Directorate of Monitoring and Evaluation</li>
<li>Directorate of Data Management and Statistics</li>
</ul>
<p>This division focuses on long-term planning, policy formulation, and performance
tracking.</p>
</div>
<div class="division">
<h3>Infrastructure Development Division</h3>
<ul class="directorate-list">
<li>Directorate of Roads and Transportation</li>
<li>Directorate of Water Resources and Sanitation</li>
<li>Directorate of Energy and Power</li>
<li>Directorate of Urban and Rural Planning</li>
</ul>
<p>Responsible for developing and maintaining essential infrastructure across the
region.</p>
</div>
<div class="division">
<h3>Economic Development Division</h3>
<ul class="directorate-list">
<li>Directorate of Agriculture and Food Security</li>
<li>Directorate of Industry and Manufacturing</li>
<li>Directorate of Trade and Commerce</li>
<li>Directorate of Tourism and Cultural Affairs</li>
</ul>
<p>Aims to foster economic growth, job creation, and sustainable business
practices.</p>
</div>
<div class="division">
<h3>Human Resources and Administration Division</h3>
<ul class="directorate-list">
<li>Directorate of Personnel Management</li>
<li>Directorate of Finance and Budget</li>
<li>Directorate of Information Technology</li>
<li>Directorate of Legal and Compliance</li>
</ul>
<p>Manages internal operations, staff welfare, and administrative support.</p>
</div>
</div>
<!-- News Page -->
<div id="news" class="page hidden">
<h2>News</h2>
<div id="news-list">
<!-- News items loaded dynamically -->
</div>
</div>
<!-- Events Page -->
<div id="events" class="page hidden">
<h2>Events</h2>
<div id="events-list">
<!-- Event items loaded dynamically -->
</div>
</div>
<!-- Gallery Page -->
<div id="gallery" class="page hidden">
<h2>Gallery</h2>
<div id="gallery-list">
<!-- Media items loaded dynamically -->
</div>
</div>
<!-- Contacts Page -->
<div id="contacts" class="page hidden">
<h2>Contacts</h2>
<p>Contact us via the form below:</p>
<form id="contact-form">
<input type="text" id="contact-name" placeholder="Your Name" required>
<input type="email" id="contact-email" placeholder="Your Email" required>
<textarea id="contact-message" placeholder="Your Message" required></textarea>
<button type="button" onclick="sendMessage()">Send Message</button>
</form>
<p>Or email us at: info@[Link]</p>
</div>
<!-- Downloads Page -->
<div id="downloads" class="page hidden">
<h2>Downloads</h2>
<div id="download-list">
<!-- Download items loaded dynamically -->
</div>
</div>
<!-- About Us Page -->
<div id="about" class="page hidden">
<h2>About Us</h2>
<p>The Planning and Development Bureau is dedicated to fostering sustainable growth and
development through strategic planning, infrastructure enhancement, economic initiatives, and
efficient administration. Established to serve the community, we collaborate with stakeholders
to implement policies that drive progress and improve quality of life.</p>
<!-- Expanded static content to cover missing description points -->
</div>
<!-- Admin Page -->
<div id="admin" class="page hidden">
<h2>Admin Panel</h2>
<div id="admin-login">
<input type="text" id="admin-username" placeholder="Username">
<input type="password" id="admin-password" placeholder="Password">
<button onclick="loginAdmin()">Login</button>
</div>
<div id="admin-content" class="admin-only">
<button onclick="logoutAdmin()">Logout</button>
<h3>Manage Content</h3>
<!-- News Upload -->
<section>
<h4>Publish News</h4>
<form id="news-form">
<input type="text" id="news-title" placeholder="News Title" required>
<textarea id="news-content" placeholder="News Content" required></textarea>
<button type="button" onclick="publishNews()">Publish</button>
</form>
</section>
<!-- Events Upload -->
<section>
<h4>Publish Event</h4>
<form id="event-form">
<input type="text" id="event-title" placeholder="Event Title" required>
<textarea id="event-content" placeholder="Event Details" required></textarea>
<input type="date" id="event-date" required>
<button type="button" onclick="publishEvent()">Publish</button>
</form>
</section>
<!-- Media Upload -->
<section>
<h4>Upload Media</h4>
<form id="media-form" enctype="multipart/form-data">
<input type="file" id="media-upload" name="files" accept="image/*,video/*"
multiple required>
<input type="text" id="media-description" name="description" placeholder="Media
Description">
<select id="media-type" name="type">
<option value="gallery">Gallery</option>
<option value="carousel">Home Carousel</option>
</select>
<button type="button" onclick="uploadMedia()">Upload</button>
</form>
</section>
<!-- Documents Upload -->
<section>
<h4>Upload Document</h4>
<form id="upload-form" enctype="multipart/form-data">
<input type="file" id="file-upload" name="file"
accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.png,.gif" required>
<input type="text" id="file-description" name="description" placeholder="File
Description" required>
<button type="button" onclick="uploadFile()">Upload</button>
</form>
</section>
<!-- Manage Messages -->
<section>
<h4>Manage User Messages</h4>
<div id="messages-list">
<!-- Messages loaded dynamically -->
</div>
</section>
</div>
</div>
</main>
<footer>
<p>Developed by: Your Name | Links: <a href="#" style="color: #ccc;">Privacy Policy</a> | <a
href="#" style="color: #ccc;">Terms of Service</a> | © 2025 Planning and Development
Bureau</p>
</footer>
<script>
let currentSlide = 0;
let totalSlides = 0;
let slides = [];
let isAdmin = false;
const API_BASE = 'api/'; // Adjust if needed
// Utility function for API calls
async function apiCall(endpoint, options = {}) {
const response = await fetch(API_BASE + endpoint, options);
if (![Link]) {
throw new Error(`HTTP ${[Link]}`);
}
return await [Link]();
// Carousel functions
function initCarousel() {
slides = [Link]('.slide');
totalSlides = [Link];
if (totalSlides > 0) {
[Link]((slide, index) => {
[Link] = index === 0 ? 'translateX(0%)' : 'translateX(100%)';
if (index === 0) [Link]('active');
else [Link]('active');
});
currentSlide = 0;
function changeSlide(n) {
if (totalSlides <= 1) return;
let oldIndex = currentSlide;
currentSlide = (currentSlide + n + totalSlides) % totalSlides;
let newIndex = currentSlide;
let outTranslate = n > 0 ? '-100%' : '100%';
slides[oldIndex].[Link] = `translateX(${outTranslate})`;
slides[oldIndex].[Link]('active');
let inStart = n > 0 ? '100%' : '-100%';
slides[newIndex].[Link] = `translateX(${inStart})`;
slides[newIndex].offsetHeight;
slides[newIndex].[Link]('active');
slides[newIndex].[Link] = 'translateX(0%)';
setInterval(() => {
if (.[Link]('hidden') && totalSlides > 1) {
changeSlide(1);
}, 3000);
// Page navigation
function showPage(pageId) {
[Link]('.page').forEach(page => [Link]('hidden'));
[Link](pageId).[Link]('hidden');
if (pageId === 'home') loadCarouselMedia();
if (pageId === 'news') loadNews();
if (pageId === 'events') loadEvents();
if (pageId === 'gallery') loadGallery();
if (pageId === 'downloads') loadDownloads();
if (pageId === 'admin' && isAdmin) {
[Link]('admin-login').[Link]('hidden');
[Link]('admin-content').[Link]('admin-only');
loadMessages();
// Admin Login
async function loginAdmin() {
const username = [Link]('admin-username').value;
const password = [Link]('admin-password').value;
try {
const result = await apiCall('[Link]', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ username, password })
});
if ([Link]) {
isAdmin = true;
[Link]('admin-login').[Link]('hidden');
[Link]('admin-content').[Link]('admin-only');
loadMessages();
} else {
alert('Login failed');
} catch (err) {
alert('Error: ' + [Link]);
}
async function logoutAdmin() {
await apiCall('[Link]', { method: 'POST' });
isAdmin = false;
[Link]('admin-login').[Link]('hidden');
[Link]('admin-content').[Link]('admin-only');
// News
async function publishNews() {
const title = [Link]('news-title').value;
const content = [Link]('news-content').value;
try {
await apiCall('[Link]', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, content })
});
[Link]('news-form').reset();
loadNews();
} catch (err) {
alert('Error publishing news');
async function loadNews() {
try {
const news = await apiCall('[Link]');
const list = [Link]('news-list');
[Link] = '';
[Link](item => {
const div = [Link]('div');
[Link]('news-item');
[Link] = `<h3>${[Link]}</h3><p>${[Link]}</p><small>${new
Date(item.created_at).toLocaleDateString()}</small>`;
[Link](div);
});
} catch (err) {
[Link]('Error loading news');
// Events (similar)
async function publishEvent() {
const title = [Link]('event-title').value;
const content = [Link]('event-content').value;
const event_date = [Link]('event-date').value;
try {
await apiCall('[Link]', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, content, event_date })
});
[Link]('event-form').reset();
loadEvents();
} catch (err) {
alert('Error publishing event');
async function loadEvents() {
try {
const events = await apiCall('[Link]');
const list = [Link]('events-list');
[Link] = '';
[Link](item => {
const div = [Link]('div');
[Link]('event-item');
[Link] = `<h3>${[Link]}</h3><p>${[Link]}</p><small>Date: $
{item.event_date} | Posted: ${new Date(item.created_at).toLocaleDateString()}</small>`;
[Link](div);
});
} catch (err) {
[Link]('Error loading events');
// Media
async function uploadMedia() {
const formData = new FormData();
const files = [Link]('media-upload').files;
const description = [Link]('media-description').value;
const type = [Link]('media-type').value;
for (let file of files) {
[Link]('files[]', file);
[Link]('description', description);
[Link]('type', type);
try {
await apiCall('[Link]', { method: 'POST', body: formData });
[Link]('media-form').reset();
loadGallery();
if (type === 'carousel') loadCarouselMedia();
} catch (err) {
alert('Error uploading media');
async function loadGallery() {
try {
const media = await apiCall('[Link]?type=gallery');
const list = [Link]('gallery-list');
[Link] = '';
[Link](item => {
const div = [Link]('div');
[Link]('media-item');
if ([Link](/\.(mp4|avi|mov)$/i)) {
[Link] = `<video controls><source src="${[Link]}"
type="video/mp4"></video><p>${[Link]}</p>`;
} else {
[Link] = `<img src="${[Link]}" alt="${[Link]}"><p>$
{[Link]}</p>`;
[Link](div);
});
} catch (err) {
[Link]('Error loading gallery');
async function loadCarouselMedia() {
try {
const media = await apiCall('[Link]?type=carousel');
const carousel = [Link]('carousel');
const existingSlides = [Link]('.slide');
[Link](slide => [Link]());
[Link](0, 10).forEach(item => { // Limit to 10
if ([Link](/\.(jpg|jpeg|png|gif)$/i)) {
const img = [Link]('img');
[Link] = [Link];
[Link] = [Link];
[Link]('slide');
[Link](img);
});
initCarousel();
} catch (err) {
[Link]('Error loading carousel');
// Downloads
async function uploadFile() {
const formData = new FormData();
const file = [Link]('file-upload').files[0];
const description = [Link]('file-description').value;
[Link]('file', file);
[Link]('description', description);
try {
await apiCall('[Link]', { method: 'POST', body: formData });
[Link]('upload-form').reset();
loadDownloads();
} catch (err) {
alert('Error uploading file');
async function loadDownloads() {
try {
const downloads = await apiCall('[Link]');
const list = [Link]('download-list');
[Link] = '';
[Link](item => {
const div = [Link]('div');
[Link]('download-item');
[Link] = `<p><strong>${[Link]}</strong> - <a href="[Link]?
id=${[Link]}" download="${[Link]}">Download ${[Link]}</a></p><small>Uploaded: $
{new Date(item.uploaded_at).toLocaleDateString()}</small>`;
[Link](div);
});
} catch (err) {
[Link]('Error loading downloads');
// Messages
async function sendMessage() {
const name = [Link]('contact-name').value;
const email = [Link]('contact-email').value;
const message = [Link]('contact-message').value;
try {
await apiCall('[Link]', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ name, email, message })
});
alert('Message sent successfully!');
[Link]('contact-form').reset();
} catch (err) {
alert('Error sending message');
async function loadMessages() {
try {
const messages = await apiCall('[Link]');
const list = [Link]('messages-list');
[Link] = '';
[Link](item => {
const div = [Link]('div');
[Link]('message-item');
[Link] = `<h4>From: ${[Link]} (${[Link]})</h4><p>$
{[Link]}</p><small>${new Date(item.created_at).toLocaleDateString()}</small><hr>`;
[Link](div);
});
} catch (err) {
[Link]('Error loading messages');
// Initialize
[Link] = function() {
showPage('home');
loadNews();
loadEvents();
loadGallery();
loadDownloads();
loadCarouselMedia();
};
</script>
</body>
</html>
Additional Points Addressed from Original Description
File Formats: Upload handler in [Link] and [Link] explicitly checks for PDF,
DOC/DOCX, XLS/XLSX, PPT/PPTX, and images (JPG/PNG/GIF). Videos (MP4/AVI/MOV)
added for gallery as per updates.
Security: Admin login uses PHP sessions and password_verify. File uploads validate
types/sizes. Use HTTPS in production. Add CAPTCHA to contact form if needed.
Events Happening/Happened: Events table stores event_date; query sorts by it. Display
past/future based on current date (e.g., filter in JS if desired).
Interactive Website: Retained single-page app feel with AJAX/fetch for dynamic loads.
Carousel flips sides as updated.
Missing Static Content: Expanded About Us with a brief description. Footer links to
Privacy/Terms (static placeholders; add pages if needed).
Admin Management: Full CRUD simulation (post/get); extend with delete/edit via
additional endpoints if required.
Deployment Steps
1. Prepare Server Environment:
o Choose a hosting provider (e.g., shared hosting like Bluehost, or VPS like
DigitalOcean) with PHP 8.0+, MySQL 5.7+, and Apache/Nginx.
o Ensure mod_rewrite (for .htaccess) and file upload limits
(upload_max_filesize=50M in [Link]).
2. Set Up Database:
o Log into cPanel/phpMyAdmin (or MySQL Workbench for VPS).
o Create database planning_db.
o Run the SQL schema above to create tables and insert default admin (username:
admin, password: admin123).
3. Upload Files:
o Create directories: /uploads/media/ and /uploads/downloads/ with 755
permissions (chmod via FTP/cPanel).
o Upload all PHP files ([Link], api/*.php, [Link], [Link] renamed
to [Link]) to root directory via FTP (e.g., FileZilla).
o Update [Link] with your DB credentials.
o Add [Link] and initial photos to root (optional; carousel loads from DB).
4. Configure Server:
o In cPanel: Set document root to public_html.
o For security: Add .htaccess to deny access to api/ (or use folder permissions).
Example .htaccess in root:
text
<Files "[Link]">
Order allow,deny
Deny from all
</Files>
o Test locally with XAMPP/WAMP if possible.
5. Domain Configuration:
o Register domain (e.g., via GoDaddy) if not already.
o In hosting control panel: Add domain, point nameservers to host (e.g.,
[Link]).
o Update DNS: Add A record for domain to server IP (propagates in 1-48 hours).
o For subdomain (e.g., www): Add CNAME to @.
o SSL: Enable free Let's Encrypt via cPanel for HTTPS.
6. Test and Go Live:
o Access via IP first, then domain.
o Test: Login as admin, upload files, submit contact, view pages.
o Monitor errors in server logs (cPanel > Errors).
o Backup: Schedule DB backups in cPanel.
For production, consider adding error logging, input sanitization (already PDO-prepared), and
email integration (e.g., PHPMailer for real contact emails). If issues, check PHP error logs.