From 9f05f404f3174be3cac55b8fcb20cb19ce9fc4ce Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 22 Nov 2025 13:52:11 +0000 Subject: [PATCH] Auto commit: 2025-11-22T13:52:11.419Z --- apply.php | 47 +++ assets/css/main.css | 308 +++++++++++++++++ db/migrations/001_create_users_table.sql | 9 + db/migrations/002_create_tasks_table.sql | 11 + .../003_create_applications_table.sql | 9 + index.php | 322 ++++++++++-------- login.php | 57 ++++ logout.php | 6 + manage-task.php | 155 +++++++++ manage-tasks.php | 56 +++ my-applications.php | 58 ++++ post-task.php | 62 ++++ profile.php | 101 ++++++ shared/footer.php | 6 + shared/header.php | 55 +++ signup.php | 109 ++++++ 16 files changed, 1225 insertions(+), 146 deletions(-) create mode 100644 apply.php create mode 100644 assets/css/main.css create mode 100644 db/migrations/001_create_users_table.sql create mode 100644 db/migrations/002_create_tasks_table.sql create mode 100644 db/migrations/003_create_applications_table.sql create mode 100644 login.php create mode 100644 logout.php create mode 100644 manage-task.php create mode 100644 manage-tasks.php create mode 100644 my-applications.php create mode 100644 post-task.php create mode 100644 profile.php create mode 100644 shared/footer.php create mode 100644 shared/header.php create mode 100644 signup.php diff --git a/apply.php b/apply.php new file mode 100644 index 0000000..82c9c66 --- /dev/null +++ b/apply.php @@ -0,0 +1,47 @@ +prepare("SELECT id FROM applications WHERE task_id = ? AND user_id = ?"); + $stmt->execute([$task_id, $user_id]); + if ($stmt->fetch()) { + // User has already applied + header('Location: index.php?message=already_applied'); + exit(); + } + + // Check if user is the task owner + $stmt = db()->prepare("SELECT id FROM tasks WHERE id = ? AND user_id = ?"); + $stmt->execute([$task_id, $user_id]); + if ($stmt->fetch()) { + // User is the task owner + header('Location: index.php?message=owner_cannot_apply'); + exit(); + } + + try { + $stmt = db()->prepare("INSERT INTO applications (task_id, user_id) VALUES (?, ?)"); + $stmt->execute([$task_id, $user_id]); + header('Location: index.php?message=applied_successfully'); + exit(); + } catch (PDOException $e) { + error_log($e->getMessage()); + header('Location: index.php?message=application_failed'); + exit(); + } + } +} + +// Redirect to index if accessed directly without POST +header('Location: index.php'); diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..5369c30 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,308 @@ +@import url('https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;700&display=swap'); + +/* General Body & Typography */ +body { + font-family: 'Be Vietnam Pro', sans-serif; + background-color: #f8f9fa; + color: #212529; + margin: 0; + line-height: 1.6; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; +} + +/* Header & Navigation */ +.header { + background-color: #ffffff; + padding: 1rem 2rem; + border-bottom: 1px solid #dee2e6; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.04); + position: sticky; + top: 0; + z-index: 1000; +} + +.logo { + font-size: 1.75rem; + font-weight: 700; + color: #0d6efd; + text-decoration: none; +} + +.nav-buttons .btn { + margin-left: 1rem; +} + +.welcome-message { + margin-right: 1rem; + color: #495057; + font-weight: 500; +} + +/* Buttons */ +.btn { + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + text-decoration: none; + font-weight: 700; + font-size: 1rem; + transition: all 0.3s ease; + border: none; + cursor: pointer; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); +} + +.btn-primary { + background: linear-gradient(45deg, #0d6efd, #0a58ca); + color: #ffffff; +} + +.btn-primary:hover { + transform: translateY(-3px); + box-shadow: 0 6px 12px rgba(13, 110, 253, 0.25); +} + +.btn-secondary { + background-color: #6c757d; + color: #fff; +} + +.btn-secondary:hover { + background-color: #5a6268; +} + +.btn-success { + background-color: #198754; + color: white; +} + +.btn-danger { + background-color: #dc3545; +color: white; +} + +/* Forms */ +.form-container { + max-width: 500px; + margin: 2rem auto; + padding: 2.5rem; + background-color: #ffffff; + border-radius: 1rem; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); +} + +.form-container h1 { + text-align: center; + margin-bottom: 2rem; + font-size: 2.25rem; + color: #0d6efd; +} + +.form-group { + margin-bottom: 1.5rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; + font-weight: 700; + color: #495057; +} + +.form-group input, .form-group textarea { + width: 100%; + padding: 0.85rem; + border: 1px solid #ced4da; + border-radius: 0.5rem; + font-size: 1rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.form-group input:focus, .form-group textarea:focus { + outline: none; + border-color: #0d6efd; + box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15); +} + +/* Search Form */ +.search-form { + display: flex; + gap: 1rem; + margin: 2rem 0; + padding: 1.5rem; + background-color: #fff; + border-radius: 0.75rem; + box-shadow: 0 4px 12px rgba(0,0,0,0.05); +} + +.search-form input { + flex-grow: 1; + padding: 0.75rem; + border: 1px solid #ced4da; + border-radius: 0.5rem; +} + +/* Task Cards */ +.task-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1.75rem; +} + +.task-card { + background-color: #ffffff; + border-radius: 1rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); + padding: 1.75rem; + transition: all 0.3s ease; + display: flex; + flex-direction: column; + border: 1px solid transparent; +} + +.task-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); + border-color: #0d6efd; +} + +.task-card h3 { + margin-top: 0; + font-size: 1.35rem; + color: #0d6efd; +} + +.task-meta { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 1rem; + color: #6c757d; + font-size: 0.9rem; +} + +.task-meta a { + color: #0d6efd; + text-decoration: none; + font-weight: 600; +} + +.task-payout { + font-size: 1.75rem; + font-weight: 700; + color: #198754; + margin-top: auto; + padding-top: 1rem; +} + +/* Page Headers */ +.page-header { + margin-bottom: 2rem; + border-bottom: 1px solid #dee2e6; + padding-bottom: 1rem; +} + +.page-header h1 { + font-size: 2.75rem; + color: #0d6efd; +} + +/* Alerts & Status Badges */ +.alert { + padding: 1rem; + margin-bottom: 1rem; + border-radius: 0.5rem; + border: 1px solid transparent; +} + +.alert-success { + color: #0f5132; + background-color: #d1e7dd; + border-color: #badbcc; +} + +.alert-warning { + color: #664d03; + background-color: #fff3cd; + border-color: #ffecb5; +} + +.alert-danger { + color: #842029; + background-color: #f8d7da; + border-color: #f5c2c7; +} + +.status-badge { + padding: 0.3em 0.7em; + font-size: 0.85em; + font-weight: 700; + border-radius: 0.5rem; + text-transform: capitalize; +} + +.status-open { + background-color: #cfe2ff; + color: #052c65; +} +.status-pending { + background-color: #fff3cd; + color: #664d03; +} +.status-assigned, .status-accepted { + background-color: #d1e7dd; + color: #0f5132; +} +.status-rejected { + background-color: #f8d7da; + color: #842029; +} + +/* Management & Profile Pages */ +.task-manage-card, .application-card, .applicant-card, .task-card-profile { + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.75rem; + padding: 1.5rem; + margin-bottom: 1rem; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +.applicant-card { + display: flex; + justify-content: space-between; + align-items: center; +} + +.profile-page .page-header { + text-align: center; +} + +.profile-section { + margin-top: 3rem; +} + +.profile-section h2 { + font-size: 1.75rem; + margin-bottom: 1.5rem; + border-bottom: 2px solid #dee2e6; + padding-bottom: 0.5rem; + color: #0d6efd; +} + +/* Footer */ +.footer { + text-align: center; + padding: 2rem; + margin-top: 2rem; + background-color: #e9ecef; + border-top: 1px solid #dee2e6; + color: #6c757d; +} diff --git a/db/migrations/001_create_users_table.sql b/db/migrations/001_create_users_table.sql new file mode 100644 index 0000000..aabf488 --- /dev/null +++ b/db/migrations/001_create_users_table.sql @@ -0,0 +1,9 @@ +-- Create the users table +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + full_name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + phone VARCHAR(50) NOT NULL, + password VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); diff --git a/db/migrations/002_create_tasks_table.sql b/db/migrations/002_create_tasks_table.sql new file mode 100644 index 0000000..0ba58bb --- /dev/null +++ b/db/migrations/002_create_tasks_table.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS tasks ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + title VARCHAR(255) NOT NULL, + description TEXT NOT NULL, + category VARCHAR(100), + location VARCHAR(255), + payout DECIMAL(10, 2) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) +); diff --git a/db/migrations/003_create_applications_table.sql b/db/migrations/003_create_applications_table.sql new file mode 100644 index 0000000..ade0f6c --- /dev/null +++ b/db/migrations/003_create_applications_table.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS applications ( + id INT AUTO_INCREMENT PRIMARY KEY, + task_id INT NOT NULL, + user_id INT NOT NULL, + status VARCHAR(20) NOT NULL DEFAULT 'applied', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); diff --git a/index.php b/index.php index 7205f3d..bc88c2e 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,180 @@ [ + 'text' => 'You have already applied for this task.', + 'type' => 'warning' + ], + 'owner_cannot_apply' => [ + 'text' => 'You cannot apply for your own task.', + 'type' => 'warning' + ], + 'applied_successfully' => [ + 'text' => 'You have successfully applied for the task.', + 'type' => 'success' + ], + 'application_failed' => [ + 'text' => 'There was an error submitting your application.', + 'type' => 'danger' + ] +]; + +// Fetch tasks from the database +try { + $search = $_GET['search'] ?? ''; + $category = $_GET['category'] ?? ''; + $location = $_GET['location'] ?? ''; + + $sql = "SELECT t.*, u.id as user_id_poster, u.full_name as user_name FROM tasks t JOIN users u ON t.user_id = u.id WHERE t.status = 'open'"; + $params = []; + + if (!empty($search)) { + $sql .= " AND (t.title LIKE :search OR t.description LIKE :search)"; + $params[':search'] = '%' . $search . '%'; + } + + if (!empty($category)) { + $sql .= " AND t.category LIKE :category"; + $params[':category'] = '%' . $category . '%'; + } + + if (!empty($location)) { + $sql .= " AND t.location LIKE :location"; + $params[':location'] = '%' . $location . '%'; + } + + $sql .= " ORDER BY t.created_at DESC"; + + $stmt = db()->prepare($sql); + $stmt->execute($params); + $tasks = $stmt->fetchAll(); +} catch (PDOException $e) { + // Handle database error gracefully + error_log($e->getMessage()); + $tasks = []; +} -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); ?> - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ + + + +
+
-
- - - + + +
+

Get anything done, today.

+

The best place to find quick help for your daily tasks.

+ Post a Task +
+ +

Available Tasks

+ +
+ + + + +
+ +
+ +

No tasks found matching your criteria. Try broadening your search!

+ + +
+

+
+ + Posted by: +
+
$
+ +
+ + +
+ +
+ + +
+ + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..5085fd5 --- /dev/null +++ b/login.php @@ -0,0 +1,57 @@ +prepare("SELECT * FROM users WHERE email = ?"); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['user_name'] = $user['full_name']; + header("Location: index.php"); + exit; + } else { + $error = 'Invalid email or password.'; + } + } catch (PDOException $e) { + $error = "Database error: " . $e->getMessage(); + } + } +} +?> + +
+
+

Login

+
+ +
+ +
+ + +
+
+ + +
+ +
+

Don't have an account? Sign up

+
+
+ + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..766a593 --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ +prepare('SELECT * FROM tasks WHERE id = :task_id AND user_id = :user_id'); + $stmt->execute([':task_id' => $taskId, ':user_id' => $userId]); + $task = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$task) { + // If the user does not own this task, redirect them + header("Location: manage-tasks.php?message=access_denied"); + exit(); + } +} catch (PDOException $e) { + die("Database error: Could not verify task ownership."); +} + +// Handle POST request to update application status +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['application_id']) && isset($_POST['action'])) { + $applicationId = $_POST['application_id']; + $action = $_POST['action']; + + try { + $pdo->beginTransaction(); + + if ($action === 'accept') { + // 1. Set this application to 'accepted' + $stmt = $pdo->prepare('UPDATE applications SET status = 'accepted' WHERE id = :application_id AND task_id = :task_id'); + $stmt->execute([':application_id' => $applicationId, ':task_id' => $taskId]); + + // 2. Set the task status to 'assigned' + $stmt = $pdo->prepare('UPDATE tasks SET status = 'assigned' WHERE id = :task_id'); + $stmt->execute([':task_id' => $taskId]); + + // 3. Set all other pending applications for this task to 'rejected' + $stmt = $pdo->prepare('UPDATE applications SET status = 'rejected' WHERE task_id = :task_id AND id != :application_id AND status = 'pending''); + $stmt->execute([':task_id' => $taskId, ':application_id' => $applicationId]); + + $message = 'Application accepted! The task is now assigned.'; + $message_type = 'success'; + + } elseif ($action === 'reject') { + // Just reject this single application + $stmt = $pdo->prepare('UPDATE applications SET status = 'rejected' WHERE id = :application_id AND task_id = :task_id'); + $stmt->execute([':application_id' => $applicationId, ':task_id' => $taskId]); + $message = 'Application rejected.'; + $message_type = 'info'; + } + + $pdo->commit(); + header("Location: manage-task.php?id=$taskId&message=" . urlencode($message) . "&type=" . $message_type); + exit(); + + } catch (PDOException $e) { + $pdo->rollBack(); + // Log error instead of dying in production + die("Database error: Could not update application status. " . $e->getMessage()); + } +} + + +// Fetch all applications for this task +try { + $stmt = $pdo->prepare( + 'SELECT a.id, a.status, u.username, u.email + FROM applications a + JOIN users u ON a.user_id = u.id + WHERE a.task_id = :task_id + ORDER BY a.created_at DESC' + ); + $stmt->execute([':task_id' => $taskId]); + $applications = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Database error: Could not retrieve applications."); +} + + +$pageTitle = "Manage Task: " . htmlspecialchars($task['title']); +include 'shared/header.php'; +?> + +
+ + + +
+ + +
+

Applicants

+ +
There are no applicants for this task yet.
+ +
+ +
+
+ + () +
+
+ Status: +
+ +
+

This applicant was awarded the task.

+
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ +
+ + diff --git a/manage-tasks.php b/manage-tasks.php new file mode 100644 index 0000000..02dac87 --- /dev/null +++ b/manage-tasks.php @@ -0,0 +1,56 @@ +prepare( + 'SELECT id, title, description, status, created_at + FROM tasks + WHERE user_id = :user_id + ORDER BY created_at DESC' + ); + $stmt->bindParam(':user_id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $tasks = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Database error: Could not retrieve your tasks."); +} + +$pageTitle = "Manage Your Tasks"; +include 'shared/header.php'; +?> + +
+ + + +
You have not posted any tasks yet. Post one now!
+ + + +
+ + diff --git a/my-applications.php b/my-applications.php new file mode 100644 index 0000000..0dd3620 --- /dev/null +++ b/my-applications.php @@ -0,0 +1,58 @@ +prepare( + 'SELECT t.title, t.description, a.status, u.username AS poster_username + FROM applications a + JOIN tasks t ON a.task_id = t.id + JOIN users u ON t.user_id = u.id + WHERE a.user_id = :user_id + ORDER BY a.created_at DESC' + ); + $stmt->bindParam(':user_id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $applications = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + // In a real application, you would log this error + die("Database error: Could not retrieve your applications."); +} + +$pageTitle = "My Applications"; +include 'shared/header.php'; +?> + +
+ + + +
You have not applied for any tasks yet.
+ +
+ +
+

+

Posted by:

+

+
+ Status: +
+
+ +
+ +
+ + diff --git a/post-task.php b/post-task.php new file mode 100644 index 0000000..9b3416b --- /dev/null +++ b/post-task.php @@ -0,0 +1,62 @@ +prepare("INSERT INTO tasks (user_id, title, description, category, location, payout) VALUES (?, ?, ?, ?, ?, ?)"); + $stmt->execute([$user_id, $title, $description, $category, $location, $payout]); + header('Location: index.php'); + exit(); + } catch (PDOException $e) { + $error = "Database error: " . $e->getMessage(); + } + } +} +?> + +
+

Post a New Task

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ + diff --git a/profile.php b/profile.php new file mode 100644 index 0000000..dc35e54 --- /dev/null +++ b/profile.php @@ -0,0 +1,101 @@ +prepare('SELECT id, full_name, email, created_at FROM users WHERE id = :id'); + $stmt->execute([':id' => $profileId]); + $profileUser = $stmt->fetch(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Database error: Could not retrieve user profile."); +} + +if (!$profileUser) { + // Handle user not found + header("Location: index.php?message=user_not_found"); + exit(); +} + +// Fetch tasks posted by the user +try { + $stmt = $pdo->prepare('SELECT * FROM tasks WHERE user_id = :user_id ORDER BY created_at DESC'); + $stmt->execute([':user_id' => $profileId]); + $postedTasks = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Database error: Could not retrieve posted tasks."); +} + +// Fetch tasks the user has completed (i.e., their application was accepted) +try { + $stmt = $pdo->prepare( + 'SELECT t.* FROM tasks t JOIN applications a ON t.id = a.task_id WHERE a.user_id = :user_id AND a.status = \'accepted\' ORDER BY t.created_at DESC' + ); + $stmt->execute([':user_id' => $profileId]); + $completedTasks = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Database error: Could not retrieve completed tasks."); +} + +$pageTitle = htmlspecialchars($profileUser['full_name']) . "'s Profile"; +include 'shared/header.php'; +?> + +
+ + + +
+

Posted Tasks

+ +

has not posted any tasks yet.

+ +
+ +
+

+

Status:

+

Payout: $

+
+ +
+ +
+ +
+

Completed Tasks

+ +

has not completed any tasks yet.

+ +
+ +
+

+

Status:

+

Payout: $

+
+ +
+ +
+
+ + diff --git a/shared/footer.php b/shared/footer.php new file mode 100644 index 0000000..3f65f6c --- /dev/null +++ b/shared/footer.php @@ -0,0 +1,6 @@ + + + + diff --git a/shared/header.php b/shared/header.php new file mode 100644 index 0000000..5fa0011 --- /dev/null +++ b/shared/header.php @@ -0,0 +1,55 @@ + + + + + + + <?= htmlspecialchars($pageTitle ?? 'CashTask') ?> + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
diff --git a/signup.php b/signup.php new file mode 100644 index 0000000..234247c --- /dev/null +++ b/signup.php @@ -0,0 +1,109 @@ +prepare("SELECT * FROM users WHERE email = ?"); + $stmt->execute([$email]); + $existing_user = $stmt->fetch(); + + if ($existing_user) { + $errors[] = 'A user with this email already exists.'; + } else { + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + + $stmt = $pdo->prepare("INSERT INTO users (full_name, email, phone, password) VALUES (?, ?, ?, ?)"); + $stmt->execute([$full_name, $email, $phone, $hashed_password]); + + header("Location: login.php?registration=success"); + exit; + } + } catch (PDOException $e) { + // In a real app, you would log this error, not show it to the user. + $errors[] = "Database error. Please try again later."; + } + } +} + +$pageTitle = 'Sign Up'; +require_once __DIR__ . '/shared/header.php'; +?> + +
+

Create an Account

+ + +
+ +

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ + \ No newline at end of file