Compare commits

..

2 Commits

Author SHA1 Message Date
Flatlogic Bot
170f400581 data visualization for responses page 2025-10-15 18:23:13 +00:00
Flatlogic Bot
cdbc910be9 first stable working version 2025-10-15 18:14:20 +00:00
18 changed files with 1213 additions and 145 deletions

89
admin.php Normal file
View File

@ -0,0 +1,89 @@
<?php
require_once 'session.php';
require_once 'db/config.php';
$surveys = [];
try {
$pdo = db();
$stmt = $pdo->query("SELECT id, title, created_at FROM surveys ORDER BY created_at DESC");
$surveys = $stmt->fetchAll();
} catch (PDOException $e) {
// Handle error properly in a real app
error_log("Database error: " . $e->getMessage());
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="admin.php">Admin Panel</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="create_survey.php">Create Survey</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Survey Dashboard</h1>
<a href="create_survey.php" class="btn btn-primary">Create New Survey</a>
</div>
<div class="card">
<div class="card-header">
Existing Surveys
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Created At</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($surveys)): ?>
<tr>
<td colspan="4" class="text-center">No surveys found.</td>
</tr>
<?php else: ?>
<?php foreach ($surveys as $survey): ?>
<tr>
<td><?php echo htmlspecialchars($survey['id']); ?></td>
<td><?php echo htmlspecialchars($survey['title']); ?></td>
<td><?php echo htmlspecialchars($survey['created_at']); ?></td>
<td>
<a href="view_survey.php?id=<?php echo $survey['id']; ?>" class="btn btn-sm btn-info">View</a>
<a href="view_responses.php?survey_id=<?php echo $survey['id']; ?>" class="btn btn-sm btn-secondary">View Responses</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

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

@ -0,0 +1,66 @@
body {
font-family: 'Inter', sans-serif;
background-color: #f8f9fa;
}
.navbar-brand {
font-weight: 700;
}
.hero {
background: linear-gradient(45deg, #0d6efd, #0dcaf0);
color: white;
padding: 6rem 0;
text-align: center;
}
.hero h1 {
font-size: 3.5rem;
font-weight: 700;
}
.hero p {
font-size: 1.25rem;
margin-bottom: 2rem;
}
.btn-hero {
font-size: 1.25rem;
padding: 0.75rem 2rem;
font-weight: 600;
}
.section {
padding: 4rem 0;
}
.question-card {
border: 1px solid #dee2e6;
border-radius: 0.5rem;
margin-bottom: 1.5rem;
background-color: #fff;
}
.question-card .card-header {
background-color: #f8f9fa;
border-bottom: 1px solid #dee2e6;
font-weight: 600;
display: flex;
justify-content: space-between;
align-items: center;
}
.question-card .card-body {
padding: 1.5rem;
}
.footer {
background-color: #343a40;
color: white;
padding: 2rem 0;
}
.footer a {
color: #0dcaf0;
}

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

@ -0,0 +1,65 @@
document.addEventListener('DOMContentLoaded', function () {
const addQuestionButtons = document.querySelectorAll('.add-question-btn');
const questionsContainer = document.getElementById('questions-container');
let questionCounter = 0;
addQuestionButtons.forEach(button => {
button.addEventListener('click', function () {
const type = this.dataset.type;
addQuestion(type);
});
});
function addQuestion(type) {
questionCounter++;
const questionId = `question-${questionCounter}`;
let questionHtml = `
<div class="card question-card" id="${questionId}">
<div class="card-header">
<span>Question ${questionCounter}</span>
<button type="button" class="btn-close" aria-label="Close" onclick="document.getElementById('${questionId}').remove()"></button>
</div>
<div class="card-body">
<div class="mb-3">
<label for="${questionId}-text" class="form-label">Question Text</label>
<input type="text" class="form-control" id="${questionId}-text" name="questions[${questionCounter}][text]" required>
</div>
<input type="hidden" name="questions[${questionCounter}][type]" value="${type}">
`;
switch (type) {
case 'text':
questionHtml += `<p class="text-muted">A short text answer will be collected.</p>`;
break;
case 'multiple-choice':
case 'checkboxes':
questionHtml += `
<div class="mb-3">
<label class="form-label">Options</label>
<div id="${questionId}-options-container">
<div class="input-group mb-2">
<input type="text" class="form-control" name="questions[${questionCounter}][options][]">
<button class="btn btn-outline-danger" type="button" onclick="this.parentElement.remove()">Remove</button>
</div>
</div>
<button class="btn btn-sm btn-outline-primary" type="button" onclick="addOption('${questionId}', ${questionCounter})">Add Option</button>
</div>
`;
break;
}
questionHtml += `</div></div>`;
questionsContainer.insertAdjacentHTML('beforeend', questionHtml);
}
window.addOption = function(questionId, questionIndex) {
const optionsContainer = document.getElementById(`${questionId}-options-container`);
const optionHtml = `
<div class="input-group mb-2">
<input type="text" class="form-control" name="questions[${questionIndex}][options][]">
<button class="btn btn-outline-danger" type="button" onclick="this.parentElement.remove()">Remove</button>
</div>
`;
optionsContainer.insertAdjacentHTML('beforeend', optionHtml);
}
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

90
create_survey.php Normal file
View File

@ -0,0 +1,90 @@
<?php
require_once 'session.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create a New Survey - survey-demo-app</title>
<meta name="description" content="Built with Flatlogic Generator">
<meta name="keywords" content="survey app, form builder, online forms, data collection, feedback tool, custom surveys, Flatlogic Generator">
<meta property="og:title" content="survey-demo-app">
<meta property="og:description" content="Built with Flatlogic Generator">
<meta property="og:image" content="">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="">
<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">
<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(); ?>">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="/">SurveyBuilder</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 active" href="create_survey.php">Create Survey</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="section">
<div class="container">
<div class="text-center mb-5">
<h2>Create a New Survey</h2>
<p class="lead">Start by giving your survey a title, then add your questions.</p>
</div>
<form id="survey-form" action="save_survey.php" method="POST">
<div class="card mb-4">
<div class="card-body">
<div class="mb-3">
<label for="survey-title" class="form-label">Survey Title</label>
<input type="text" class="form-control form-control-lg" id="survey-title" name="title" required>
</div>
<div class="mb-3">
<label for="survey-description" class="form-label">Description</label>
<textarea class="form-control" id="survey-description" name="description" rows="3"></textarea>
</div>
</div>
</div>
<div id="questions-container"></div>
<div class="d-flex justify-content-center my-4">
<div class="btn-group" role="group" aria-label="Add Question Buttons">
<button type="button" class="btn btn-outline-primary add-question-btn" data-type="text"><i class="bi bi-input-cursor-text"></i> Add Short Text</button>
<button type="button" class="btn btn-outline-primary add-question-btn" data-type="multiple-choice"><i class="bi bi-ui-radios"></i> Add Multiple Choice</button>
<button type="button" class="btn btn-outline-primary add-question-btn" data-type="checkboxes"><i class="bi bi-ui-checks"></i> Add Checkboxes</button>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-lg">Save Survey</button>
</div>
</form>
</div>
</main>
<footer class="footer mt-auto">
<div class="container text-center">
<p>&copy; <?php echo date("Y"); ?> SurveyBuilder. All Rights Reserved.</p>
<p><a href="privacy.php">Privacy Policy</a></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>

11
db/create_database.php Normal file
View File

@ -0,0 +1,11 @@
<?php
require_once __DIR__ . '/config.php';
try {
$pdo = new PDO('mysql:host='.DB_HOST, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("CREATE DATABASE IF NOT EXISTS `" . DB_NAME . "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
echo "Database '" . DB_NAME . "' created or already exists." . PHP_EOL;
} catch (PDOException $e) {
die("Database creation failed: " . $e->getMessage());
}

62
db/migrate.php Normal file
View File

@ -0,0 +1,62 @@
<?php
require_once 'config.php';
try {
$pdo = db();
// Create surveys table
$pdo->exec("CREATE TABLE IF NOT EXISTS surveys (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// Create questions table
$pdo->exec("CREATE TABLE IF NOT EXISTS questions (
id INT AUTO_INCREMENT PRIMARY KEY,
survey_id INT NOT NULL,
question_text VARCHAR(255) NOT NULL,
question_type VARCHAR(50) NOT NULL,
options TEXT, -- JSON encoded options for multiple_choice/checkboxes
FOREIGN KEY (survey_id) REFERENCES surveys(id) ON DELETE CASCADE
)");
$pdo->exec("CREATE TABLE IF NOT EXISTS survey_responses (
id INT AUTO_INCREMENT PRIMARY KEY,
survey_id INT NOT NULL,
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (survey_id) REFERENCES surveys(id) ON DELETE CASCADE
)");
$pdo->exec("CREATE TABLE IF NOT EXISTS survey_answers (
id INT AUTO_INCREMENT PRIMARY KEY,
response_id INT NOT NULL,
question_id INT NOT NULL,
answer_text TEXT,
FOREIGN KEY (response_id) REFERENCES survey_responses(id) ON DELETE CASCADE,
FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE
)");
// Create users table
$pdo->exec("CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// Insert a default admin user if one doesn't exist
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute(['admin']);
if ($stmt->rowCount() == 0) {
$username = 'admin';
$password = password_hash('password', PASSWORD_DEFAULT);
$pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)")->execute([$username, $password]);
}
echo "Database tables created successfully!";
} catch (PDOException $e) {
die("Database migration failed: " . $e->getMessage());
}

252
index.php
View File

@ -1,150 +1,114 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<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>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>survey-demo-app</title>
<meta name="description" content="Built with Flatlogic Generator">
<meta name="keywords" content="survey app, form builder, online forms, data collection, feedback tool, custom surveys, Flatlogic Generator">
<meta property="og:title" content="survey-demo-app">
<meta property="og:description" content="Built with Flatlogic Generator">
<meta property="og:image" content="">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="">
<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">
<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(); ?>">
</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>
<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>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="/">SurveyBuilder</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="create_survey.php">Create Survey</a>
</li>
<li class="nav-item">
<a class="nav-link" href="admin.php">Admin</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#about">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#features">Features</a>
</li>
</ul>
</div>
</div>
</nav>
<header class="hero">
<div class="container">
<h1>Create Beautiful Surveys, Effortlessly</h1>
<p>Build engaging forms and surveys to capture the data you need. Simple, fast, and free.</p>
<a href="create_survey.php" class="btn btn-light btn-hero">Get Started Now <i class="bi bi-arrow-right-short"></i></a>
</div>
</header>
<main>
<section id="about" class="section">
<div class="container">
<div class="row align-items-center">
<div class="col-md-6">
<h2>About SurveyBuilder</h2>
<p class="lead">SurveyBuilder is a modern tool designed to make survey creation intuitive and fast. Whether you're gathering customer feedback, conducting market research, or planning an event, we provide the tools you need to get answers.</p>
<p>Our mission is to simplify data collection without compromising on power or design.</p>
</div>
<div class="col-md-6 text-center">
<i class="bi bi-card-checklist" style="font-size: 10rem; color: #0dcaf0;"></i>
</div>
</div>
</div>
</section>
<section id="features" class="section bg-light">
<div class="container">
<div class="text-center mb-5">
<h2>Powerful Features, Simple Interface</h2>
<p class="lead">Everything you need to build and analyze surveys.</p>
</div>
<div class="row">
<div class="col-md-4 mb-4">
<div class="card h-100 text-center p-4">
<i class="bi bi-input-cursor-text" style="font-size: 3rem; color: #0d6efd;"></i>
<h4 class="mt-3">Multiple Question Types</h4>
<p>From short text to multiple choice and checkboxes, create the perfect question for any scenario.</p>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 text-center p-4">
<i class="bi bi-bar-chart-line" style="font-size: 3rem; color: #0d6efd;"></i>
<h4 class="mt-3">Real-time Results</h4>
<p>Watch responses roll in and analyze your data with a clean, simple dashboard.</p>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 text-center p-4">
<i class="bi bi-share" style="font-size: 3rem; color: #0d6efd;"></i>
<h4 class="mt-3">Easy Sharing</h4>
<p>Get a unique, shareable link for your survey the moment you publish it.</p>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="container text-center">
<p>&copy; <?php echo date("Y"); ?> SurveyBuilder. All Rights Reserved.</p>
<p><a href="privacy.php">Privacy Policy</a></p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

81
login.php Normal file
View File

@ -0,0 +1,81 @@
<?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'];
header("Location: admin.php");
exit;
} else {
$error = 'Invalid username or password.';
}
} catch (PDOException $e) {
$error = "Database error: " . $e->getMessage();
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Survey App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="index.php">SurveyApp</a>
</div>
</nav>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
Admin Login
</div>
<div class="card-body">
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form action="login.php" method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

6
logout.php Normal file
View File

@ -0,0 +1,6 @@
<?php
session_start();
session_unset();
session_destroy();
header("Location: login.php");
exit;

56
privacy.php Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Privacy Policy - survey-demo-app</title>
<meta name="description" content="Built with Flatlogic Generator">
<meta name="keywords" content="survey app, form builder, online forms, data collection, feedback tool, custom surveys, Flatlogic Generator">
<meta property="og:title" content="survey-demo-app">
<meta property="og:description" content="Built with Flatlogic Generator">
<meta property="og:image" content="">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="">
<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">
<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(); ?>">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="/">SurveyBuilder</a>
</div>
</nav>
<main class="section">
<div class="container">
<h1 class="mb-4">Privacy Policy</h1>
<p>This is a placeholder for your privacy policy. You should replace this content with your own policy, detailing how you collect, use, and protect your users' data.</p>
<h2>Information We Collect</h2>
<p>Detail the types of information you collect from users, such as personal identification information (name, email address, etc.) and non-personal information (browser type, etc.).</p>
<h2>How We Use Information</h2>
<p>Explain how you use the collected information, for example, to provide and improve your services, to communicate with users, and for marketing purposes.</p>
<h2>Data Protection</h2>
<p>Describe the measures you take to protect user data from unauthorized access or disclosure.</p>
<p>Last updated: <?php echo date("F j, Y"); ?></p>
</div>
</main>
<footer class="footer mt-auto">
<div class="container text-center">
<p>&copy; <?php echo date("Y"); ?> SurveyBuilder. All Rights Reserved.</p>
<p><a href="/">Home</a></p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

49
save_response.php Normal file
View File

@ -0,0 +1,49 @@
<?php
require_once 'db/config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$survey_id = filter_input(INPUT_POST, 'survey_id', FILTER_VALIDATE_INT);
$answers = $_POST['answers'] ?? [];
if (!$survey_id) {
http_response_code(400);
die('Bad request: survey_id is required.');
}
try {
$pdo = db();
$pdo->beginTransaction();
// 1. Create a new survey response
$stmt = $pdo->prepare("INSERT INTO survey_responses (survey_id) VALUES (?)");
$stmt->execute([$survey_id]);
$response_id = $pdo->lastInsertId();
// 2. Save each answer
$stmt = $pdo->prepare("INSERT INTO survey_answers (response_id, question_id, answer_text) VALUES (?, ?, ?)");
foreach ($answers as $question_id => $answer_text) {
if (is_array($answer_text)) {
// For checkboxes, implode the array into a string
$answer_text = implode(', ', $answer_text);
}
$stmt->execute([$response_id, $question_id, $answer_text]);
}
$pdo->commit();
// Redirect to a success page
header('Location: survey_success.php?response=true');
exit;
} catch (PDOException $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
// In a real app, you'd log this error
http_response_code(500);
die('Database error: ' . $e->getMessage());
}
} else {
http_response_code(405);
die('Method not allowed.');
}

75
save_survey.php Normal file
View File

@ -0,0 +1,75 @@
<?php
require_once 'db/config.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: create_survey.php');
exit;
}
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$questions = $_POST['questions'] ?? [];
if (empty($title) || empty($questions)) {
// Basic validation: Title and at least one question are required.
// In a real app, you'd want more robust validation and user feedback.
die('Error: Survey title and at least one question are required.');
}
try {
$pdo = db();
$pdo->beginTransaction();
// 1. Insert the survey
$stmt = $pdo->prepare("INSERT INTO surveys (title, description) VALUES (?, ?)");
$stmt->execute([$title, $description]);
$surveyId = $pdo->lastInsertId();
// 2. Insert the questions
$questionStmt = $pdo->prepare(
"INSERT INTO questions (survey_id, question_text, question_type, options) VALUES (?, ?, ?, ?)"
);
foreach ($questions as $question) {
$text = trim($question['text'] ?? '');
$type = trim($question['type'] ?? '');
$options = $question['options'] ?? [];
if (empty($text) || empty($type)) {
// Skip invalid/empty questions
continue;
}
// For choice-based questions, ensure options are provided and encode them as JSON
$optionsJson = null;
if (($type === 'multiple-choice' || $type === 'checkboxes')) {
// Filter out empty option strings
$validOptions = array_filter($options, function($val) {
return trim($val) !== '';
});
if (empty($validOptions)) {
// If no valid options, skip this question
continue;
}
$optionsJson = json_encode($validOptions);
}
$questionStmt->execute([$surveyId, $text, $type, $optionsJson]);
}
$pdo->commit();
// Redirect to a success page
header("Location: survey_success.php?id=" . $surveyId);
exit;
} catch (PDOException $e) {
// If anything goes wrong, roll back the transaction
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
// In a real app, log this error instead of showing it to the user
die("Database error: " . $e->getMessage());
} catch (Exception $e) {
die("An unexpected error occurred: " . $e->getMessage());
}

7
session.php Normal file
View File

@ -0,0 +1,7 @@
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}

21
sitemap.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://your-domain.com/</loc>
<lastmod>2025-10-15</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>http://your-domain.com/create_survey.php</loc>
<lastmod>2025-10-15</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>http://your-domain.com/privacy.php</loc>
<lastmod>2025-10-15</lastmod>
<changefreq>yearly</changefreq>
<priority>0.5</priority>
</url>
</urlset>

54
survey_success.php Normal file
View File

@ -0,0 +1,54 @@
<?php
$survey_id = isset($_GET['id']) ? htmlspecialchars($_GET['id']) : '#';
$survey_url = 'view_survey.php?id=' . $survey_id; // This page doesn't exist yet
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Survey Created! - survey-demo-app</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="/">SurveyBuilder</a>
</div>
</nav>
<main class="section">
<div class="container">
<div class="text-center py-5">
<?php if (isset($_GET['response'])): ?>
<h1 class="display-4">Thank You!</h1>
<p class="lead">Your response has been submitted successfully.</p>
<div class="mt-4">
<a href="/" class="btn btn-primary">Back to Home</a>
</div>
<?php else: ?>
<h1 class="display-4">🎉 Success!</h1>
<p class="lead">Your survey has been created successfully.</p>
<div class="mt-4">
<p>You can share this link with your respondents:</p>
<div class="input-group mb-3 mx-auto" style="max-width: 500px;">
<input type="text" class="form-control" id="surveyUrl" value="<?php echo htmlspecialchars($survey_url); ?>" readonly>
<button class="btn btn-outline-secondary" type="button" onclick="navigator.clipboard.writeText(document.getElementById('surveyUrl').value)">Copy</button>
</div>
<a href="<?php echo htmlspecialchars($survey_url); ?>" class="btn btn-primary">View Survey</a>
<a href="create_survey.php" class="btn btn-secondary">Create Another Survey</a>
</div>
<?php endif; ?>
</div>
</div>
</main>
<footer class="footer mt-auto">
<div class="container text-center">
<p>&copy; <?php echo date("Y"); ?> SurveyBuilder. All Rights Reserved.</p>
</div>
</footer>
</body>
</html>

243
view_responses.php Normal file
View File

@ -0,0 +1,243 @@
<?php
require_once 'session.php';
require_once 'db/config.php';
$survey_id = isset($_GET['survey_id']) ? (int)$_GET['survey_id'] : 0;
if (!$survey_id) {
http_response_code(400);
echo "Error: Survey ID is missing.";
exit;
}
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT title FROM surveys WHERE id = ?");
$stmt->execute([$survey_id]);
$survey = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$survey) {
http_response_code(404);
echo "Error: Survey not found.";
exit;
}
$stmt = $pdo->prepare("
SELECT q.id AS question_id, q.question_text, q.question_type, sa.answer_text
FROM survey_answers sa
JOIN questions q ON sa.question_id = q.id
WHERE q.survey_id = ?
");
$stmt->execute([$survey_id]);
$answers = $stmt->fetchAll(PDO::FETCH_ASSOC);
$chart_data = [];
$text_answers = [];
foreach ($answers as $answer) {
$question_id = $answer['question_id'];
$question_text = $answer['question_text'];
$question_type = $answer['question_type'];
$answer_text = $answer['answer_text'];
if ($question_type === 'multiple-choice' || $question_type === 'checkboxes') {
if (!isset($chart_data[$question_id])) {
$chart_data[$question_id] = [
'question_text' => $question_text,
'answers' => [],
];
}
if ($question_type === 'checkboxes') {
$selected_options = explode(',', $answer_text);
foreach ($selected_options as $option) {
$option = trim($option);
if (!empty($option)) {
if (!isset($chart_data[$question_id]['answers'][$option])) {
$chart_data[$question_id]['answers'][$option] = 0;
}
$chart_data[$question_id]['answers'][$option]++;
}
}
} else { // multiple-choice
if (!isset($chart_data[$question_id]['answers'][$answer_text])) {
$chart_data[$question_id]['answers'][$answer_text] = 0;
}
$chart_data[$question_id]['answers'][$answer_text]++;
}
} else {
if (!isset($text_answers[$question_id])) {
$text_answers[$question_id] = [
'question_text' => $question_text,
'answers' => [],
];
}
$text_answers[$question_id]['answers'][] = $answer_text;
}
}
} catch (PDOException $e) {
http_response_code(500);
echo "Database error: " . htmlspecialchars($e->getMessage());
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responses for <?php echo htmlspecialchars($survey['title']); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/holtzy/D3-graph-gallery@master/LIB/d3.layout.cloud.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="admin.php">Admin Panel</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="create_survey.php">Create Survey</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
<h1 class="mb-4">Responses for "<?php echo htmlspecialchars($survey['title']); ?>"</h1>
<a href="admin.php" class="btn btn-secondary mb-4">&larr; Back to Dashboard</a>
<?php if (empty($chart_data) && empty($text_answers)): ?>
<div class="alert alert-info">
No responses have been submitted for this survey yet.
</div>
<?php else: ?>
<div class="row">
<?php foreach ($chart_data as $question_id => $data): ?>
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-header">
<?php echo htmlspecialchars($data['question_text']); ?>
</div>
<div class="card-body">
<canvas id="chart-<?php echo $question_id; ?>"></canvas>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if (!empty($text_answers)): ?>
<hr class="my-5">
<h2>Text Answers</h2>
<?php foreach ($text_answers as $question_id => $data): ?>
<div class="card mb-4">
<div class="card-header">
<?php echo htmlspecialchars($data['question_text']); ?>
</div>
<div class="card-body">
<div id="word-cloud-<?php echo $question_id; ?>"></div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php endif; ?>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
<?php foreach ($chart_data as $question_id => $data): ?>
new Chart(document.getElementById('chart-<?php echo $question_id; ?>'), {
type: 'bar',
data: {
labels: <?php echo json_encode(array_keys($data['answers'])); ?>,
datasets: [{
label: 'Number of Responses',
data: <?php echo json_encode(array_values($data['answers'])); ?>,
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
<?php endforeach; ?>
<?php foreach ($text_answers as $question_id => $data): ?>
var text = <?php echo json_encode(implode(" ", $data['answers'])); ?>;
var words = text.split(/\s+/).map(function(word) {
return word.replace(/[^\w\s]/gi, '').toLowerCase();
}).filter(function(word) {
return word.length > 3;
});
var wordCounts = {};
words.forEach(function(word) {
wordCounts[word] = (wordCounts[word] || 0) + 1;
});
var word_data = Object.keys(wordCounts).map(function(key) {
return {text: key, size: wordCounts[key]};
});
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 450 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var svg = d3.select("#word-cloud-<?php echo $question_id; ?>").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layout = d3.layout.cloud()
.size([width, height])
.words(word_data.map(function(d) { return {text: d.text, size:d.size*10}; }))
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw);
layout.start();
function draw(words) {
svg
.append("g")
.attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
<?php endforeach; ?>
});
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

129
view_survey.php Normal file
View File

@ -0,0 +1,129 @@
<?php
require_once 'db/config.php';
$survey_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$survey_id) {
http_response_code(400);
echo "Error: Survey ID is missing or invalid.";
exit;
}
try {
$pdo = db();
// Fetch survey details
$stmt = $pdo->prepare("SELECT title, description FROM surveys WHERE id = ?");
$stmt->execute([$survey_id]);
$survey = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$survey) {
http_response_code(404);
echo "Error: Survey not found.";
exit;
}
// Fetch questions
$stmt = $pdo->prepare("SELECT id, question_text, question_type, options FROM questions WHERE survey_id = ? ORDER BY id ASC");
$stmt->execute([$survey_id]);
$questions = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
http_response_code(500);
echo "Database error: " . htmlspecialchars($e->getMessage());
exit;
}
?>
<!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($survey['title']); ?> - Survey</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="index.php">SurveyApp</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="create_survey.php">Create Survey</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="container mt-5">
<div class="card">
<div class="card-header">
<h1><?php echo htmlspecialchars($survey['title']); ?></h1>
</div>
<div class="card-body">
<p class="lead"><?php echo nl2br(htmlspecialchars($survey['description'])); ?></p>
<hr>
<form action="save_response.php" method="POST" id="surveyForm">
<input type="hidden" name="survey_id" value="<?php echo $survey_id; ?>">
<?php foreach ($questions as $index => $question): ?>
<?php var_dump($question['question_type']); ?>
<div class="mb-4">
<label for="question_<?php echo $question['id']; ?>" class="form-label fw-bold"><?php echo ($index + 1) . ". " . htmlspecialchars($question['question_text']); ?></label>
<?php if ($question['question_type'] === 'text'): ?>
<input type="text" name="answers[<?php echo $question['id']; ?>]" id="question_<?php echo $question['id']; ?>_text" class="form-control" required>
<?php elseif ($question['question_type'] === 'multiple-choice'): ?>
<?php $options = json_decode($question['options'], true); ?>
<?php if ($options): ?>
<?php foreach ($options as $option): ?>
<div class="form-check">
<input class="form-check-input" type="radio" name="answers[<?php echo $question['id']; ?>]" id="option_<?php echo $question['id'] . '_' . htmlspecialchars($option); ?>" value="<?php echo htmlspecialchars($option); ?>" required>
<label class="form-check-label" for="option_<?php echo $question['id'] . '_' . htmlspecialchars($option); ?>">
<?php echo htmlspecialchars($option); ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php elseif ($question['question_type'] === 'checkboxes'): ?>
<?php $options = json_decode($question['options'], true); ?>
<?php if ($options): ?>
<?php foreach ($options as $option): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="answers[<?php echo $question['id']; ?>][]" id="option_<?php echo $question['id'] . '_' . htmlspecialchars($option); ?>" value="<?php echo htmlspecialchars($option); ?>">
<label class="form-check-label" for="option_<?php echo $question['id'] . '_' . htmlspecialchars($option); ?>">
<?php echo htmlspecialchars($option); ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endforeach; ?>
<button type="submit" class="btn btn-primary">Submit Answers</button>
</form>
</div>
</div>
</main>
<footer class="footer mt-auto py-3 bg-light">
<div class="container text-center">
<span class="text-muted">© 2025 SurveyApp. All rights reserved. | <a href="privacy.php">Privacy Policy</a></span>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>