Gamified Productivity Tracker JavaScript, PHP, MySQL

👤 Sharing: AI
Okay, here's a basic gamified productivity tracker example using JavaScript (for the frontend/UI), PHP (for the backend/API), and MySQL (for the database).  This is a simplified version to illustrate the core concepts.

**Important Considerations:**

*   **Security:**  This example lacks proper security measures (e.g., input sanitization, authentication, authorization). In a real application, security is paramount.
*   **Error Handling:**  Error handling is kept minimal for brevity. In a production environment, you need robust error handling.
*   **Scalability:**  This is a basic example and may not scale well for a large number of users.
*   **Modularity:** The code can be made more modular for better maintainability.

**Conceptual Overview**

1.  **Database (MySQL):**  Stores user information, tasks, points, and other relevant data.
2.  **Backend (PHP):**  Provides API endpoints for the frontend to interact with the database.  Handles user registration, login (simplified), task creation, task completion, point updates, and data retrieval.
3.  **Frontend (JavaScript/HTML/CSS):** Provides a user interface to:
    *   Display tasks
    *   Allow users to mark tasks as complete.
    *   Show user points/achievements.
    *   Add new tasks.

**1. Database Setup (MySQL)**

Create a database named `productivity_tracker`.  Then, create the following tables:

```sql
-- Database: productivity_tracker
CREATE DATABASE IF NOT EXISTS productivity_tracker;
USE productivity_tracker;

-- Table: users
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,  -- In reality, hash passwords!
    points INT DEFAULT 0
);

-- Table: tasks
CREATE TABLE IF NOT EXISTS tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    description VARCHAR(255) NOT NULL,
    completed BOOLEAN DEFAULT FALSE,
    points_value INT DEFAULT 10,  -- Points awarded for completing the task
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Sample user (DO NOT use such simple password in reality)
INSERT INTO users (username, password, points) VALUES ('testuser', 'password', 0);

-- Sample Tasks
INSERT INTO tasks (user_id, description, points_value) VALUES (1, 'Learn JavaScript', 10);
INSERT INTO tasks (user_id, description, points_value) VALUES (1, 'Read a chapter of a book', 15);

```

**2. Backend (PHP)**

Create a directory for your PHP files (e.g., `api`).  Inside that directory, create the following files:

**`api/db_connect.php`:**

```php
<?php
$servername = "localhost";
$username = "root"; // Replace with your MySQL username
$password = "";     // Replace with your MySQL password
$dbname = "productivity_tracker";

$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// Set content type to JSON for API responses
header('Content-Type: application/json');
?>
```

**`api/get_tasks.php`:**

```php
<?php
require_once 'db_connect.php';

// Simple Authentication (replace with proper authentication!)
$userId = isset($_GET['user_id']) ? intval($_GET['user_id']) : 1; // Assume user ID 1 if not provided
// In a real app, you would verify a token or session

$sql = "SELECT * FROM tasks WHERE user_id = $userId";
$result = $conn->query($sql);

$tasks = array();
if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        $tasks[] = $row;
    }
}

echo json_encode($tasks);

$conn->close();
?>
```

**`api/complete_task.php`:**

```php
<?php
require_once 'db_connect.php';

// Simple Authentication (replace with proper authentication!)
// In a real app, you would verify a token or session
$userId = isset($_POST['user_id']) ? intval($_POST['user_id']) : 1;
$taskId = isset($_POST['task_id']) ? intval($_POST['task_id']) : 0;

if ($taskId <= 0) {
    echo json_encode(array("status" => "error", "message" => "Invalid task ID"));
    exit;
}

// Get the task's points value
$sql = "SELECT points_value FROM tasks WHERE id = $taskId AND user_id = $userId";
$result = $conn->query($sql);

if ($result->num_rows == 0) {
    echo json_encode(array("status" => "error", "message" => "Task not found or not owned by user"));
    exit;
}

$row = $result->fetch_assoc();
$pointsValue = $row['points_value'];


// Update the task status to completed
$sql = "UPDATE tasks SET completed = TRUE WHERE id = $taskId AND user_id = $userId";

if ($conn->query($sql) === TRUE) {
    // Update the user's points
    $sql = "UPDATE users SET points = points + $pointsValue WHERE id = $userId";

    if ($conn->query($sql) === TRUE) {
        echo json_encode(array("status" => "success", "message" => "Task completed and points updated"));
    } else {
        echo json_encode(array("status" => "error", "message" => "Error updating user points: " . $conn->error));
    }

} else {
    echo json_encode(array("status" => "error", "message" => "Error updating task: " . $conn->error));
}

$conn->close();
?>
```

**`api/add_task.php`:**

```php
<?php
require_once 'db_connect.php';

// Simple Authentication (replace with proper authentication!)
// In a real app, you would verify a token or session
$userId = isset($_POST['user_id']) ? intval($_POST['user_id']) : 1;
$description = isset($_POST['description']) ? $_POST['description'] : '';
$pointsValue = isset($_POST['points_value']) ? intval($_POST['points_value']) : 10; // Default points

if (empty($description)) {
    echo json_encode(array("status" => "error", "message" => "Description cannot be empty"));
    exit;
}

$sql = "INSERT INTO tasks (user_id, description, points_value) VALUES ($userId, '$description', $pointsValue)";

if ($conn->query($sql) === TRUE) {
    echo json_encode(array("status" => "success", "message" => "Task added successfully"));
} else {
    echo json_encode(array("status" => "error", "message" => "Error adding task: " . $conn->error));
}

$conn->close();
?>
```

**`api/get_user_points.php`:**

```php
<?php
require_once 'db_connect.php';

// Simple Authentication (replace with proper authentication!)
$userId = isset($_GET['user_id']) ? intval($_GET['user_id']) : 1; // Assume user ID 1 if not provided
// In a real app, you would verify a token or session

$sql = "SELECT points FROM users WHERE id = $userId";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();
    echo json_encode(array("points" => $row['points']));
} else {
    echo json_encode(array("points" => 0)); // Or an error message
}

$conn->close();
?>
```

**3. Frontend (HTML/JavaScript)**

Create an HTML file (e.g., `index.html`) and a JavaScript file (e.g., `script.js`) in the same directory or a `js` subdirectory.  Include CSS for styling as desired.

**`index.html`:**

```html
<!DOCTYPE html>
<html>
<head>
    <title>Gamified Productivity Tracker</title>
    <link rel="stylesheet" href="style.css"> <!-- Optional styling -->
</head>
<body>
    <h1>Productivity Tracker</h1>

    <div id="points-display">Points: <span id="current-points">0</span></div>

    <div id="task-list">
        <h2>Tasks</h2>
        <ul id="tasks"></ul>
    </div>

    <div id="add-task-form">
        <h2>Add New Task</h2>
        <input type="text" id="new-task-description" placeholder="Task description">
        <input type="number" id="new-task-points" placeholder="Points" value="10">
        <button id="add-task-button">Add Task</button>
    </div>

    <script src="script.js"></script>
</body>
</html>
```

**`script.js`:**

```javascript
const tasksList = document.getElementById('tasks');
const pointsDisplay = document.getElementById('current-points');
const addTaskDescriptionInput = document.getElementById('new-task-description');
const addTaskPointsInput = document.getElementById('new-task-points');
const addTaskButton = document.getElementById('add-task-button');

const userId = 1; // Replace with actual user ID (from login, session, etc.)
const apiUrl = 'api/'; // Adjust if your PHP files are in a different directory

// Function to fetch tasks from the API
async function getTasks() {
    try {
        const response = await fetch(`${apiUrl}get_tasks.php?user_id=${userId}`);
        const tasks = await response.json();

        tasksList.innerHTML = ''; // Clear existing tasks

        tasks.forEach(task => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `
                <input type="checkbox" id="task-${task.id}" data-task-id="${task.id}" ${task.completed ? 'checked' : ''}>
                <label for="task-${task.id}">${task.description} (Points: ${task.points_value})</label>
            `;
            tasksList.appendChild(listItem);

            const checkbox = listItem.querySelector('input[type="checkbox"]');
            checkbox.addEventListener('change', completeTask);
        });
    } catch (error) {
        console.error('Error fetching tasks:', error);
        tasksList.innerHTML = '<li>Error loading tasks.</li>';
    }
}

// Function to complete a task
async function completeTask(event) {
    const taskId = event.target.dataset.taskId;

    try {
        const response = await fetch(`${apiUrl}complete_task.php`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: `user_id=${userId}&task_id=${taskId}`,
        });

        const data = await response.json();

        if (data.status === 'success') {
            console.log('Task completed!');
            getTasks(); // Refresh task list
            getUserPoints(); // Refresh points
        } else {
            console.error('Error completing task:', data.message);
            alert('Error completing task: ' + data.message);
        }
    } catch (error) {
        console.error('Error completing task:', error);
        alert('Error completing task.  Check the console.');
    }
}

// Function to add a new task
async function addTask() {
    const description = addTaskDescriptionInput.value.trim();
    const pointsValue = parseInt(addTaskPointsInput.value);

    if (description === '') {
        alert('Please enter a task description.');
        return;
    }

    try {
        const response = await fetch(`${apiUrl}add_task.php`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: `user_id=${userId}&description=${description}&points_value=${pointsValue}`,
        });

        const data = await response.json();

        if (data.status === 'success') {
            console.log('Task added!');
            addTaskDescriptionInput.value = ''; // Clear the input
            addTaskPointsInput.value = '10'; // Reset points to default
            getTasks(); // Refresh task list
        } else {
            console.error('Error adding task:', data.message);
            alert('Error adding task: ' + data.message);
        }
    } catch (error) {
        console.error('Error adding task:', error);
        alert('Error adding task. Check the console.');
    }
}

// Function to get the user's points
async function getUserPoints() {
    try {
        const response = await fetch(`${apiUrl}get_user_points.php?user_id=${userId}`);
        const data = await response.json();
        pointsDisplay.textContent = data.points;
    } catch (error) {
        console.error('Error fetching user points:', error);
        pointsDisplay.textContent = 'Error';
    }
}

// Event listeners
addTaskButton.addEventListener('click', addTask);

// Initial load
getTasks();
getUserPoints();

```

**`style.css` (Optional):**

```css
body {
    font-family: sans-serif;
    margin: 20px;
}

h1 {
    text-align: center;
}

#points-display {
    text-align: right;
    margin-bottom: 10px;
}

#task-list ul {
    list-style: none;
    padding: 0;
}

#task-list li {
    border: 1px solid #ccc;
    padding: 5px;
    margin-bottom: 5px;
}

#add-task-form {
    margin-top: 20px;
}

#add-task-form input[type="text"],
#add-task-form input[type="number"] {
    padding: 5px;
    margin-right: 5px;
}
```

**How to Run:**

1.  **Set up your environment:**  Make sure you have PHP, MySQL, and a web server (e.g., Apache or Nginx) installed and configured.
2.  **Create the database and tables:** Execute the SQL script in your MySQL server.
3.  **Configure the PHP connection:**  Edit `api/db_connect.php` with your MySQL credentials.
4.  **Place files:** Put the PHP files in a directory accessible by your web server (e.g., `htdocs` or `www`).  Place `index.html`, `script.js`, and `style.css` in the same directory or a subdirectory accessible from the webserver.
5.  **Access in your browser:** Open `index.html` in your web browser (e.g., `http://localhost/your_directory/index.html`).  Replace `your_directory` with the name of the directory where you placed the files.

**Explanation**

*   **PHP:** The PHP scripts handle communication with the database. They receive requests from the JavaScript frontend, execute SQL queries, and return the results as JSON.

*   **JavaScript:** The JavaScript code dynamically updates the HTML page with data fetched from the PHP API. It also handles user interactions like completing tasks and adding new tasks.  `fetch` is used for making API requests.

*   **MySQL:** The MySQL database stores the data for users, tasks, and points.

**Improvements and Next Steps**

*   **Proper Authentication:** Implement a secure authentication system (e.g., using sessions, tokens, and password hashing).  Never store plain-text passwords.
*   **More sophisticated gamification:** Add levels, badges, achievements, leaderboards, and other gamification elements to make the app more engaging.
*   **Task prioritization and categories:** Allow users to prioritize tasks and categorize them.
*   **Due dates and reminders:** Add functionality for setting due dates and sending reminders.
*   **Mobile-first design:**  Make the app responsive and mobile-friendly.
*   **Frameworks:** Consider using a JavaScript framework like React, Angular, or Vue.js for a more structured frontend and a PHP framework like Laravel or Symfony for a more robust backend.
*   **Input validation and sanitization:**  Always validate and sanitize user input to prevent security vulnerabilities (e.g., SQL injection, XSS).
*   **Error Handling:** Implement thorough error handling and logging.
*   **AJAX error messages:** Give better messages to the user when an error occurs.
*   **Code organization:** Break the JavaScript and PHP code into smaller, more manageable functions and classes.
*   **Automated testing:** Implement automated tests to ensure the quality of your code.

This example provides a starting point for building a more feature-rich and secure gamified productivity tracker. Remember to prioritize security and best practices as you develop your application.
👁️ Viewed: 8

Comments