diff --git a/agent.md b/agent.md new file mode 100644 index 0000000..6c40b66 --- /dev/null +++ b/agent.md @@ -0,0 +1,20 @@ +# Project Tasks + +This file tracks the progress of the project. + +## Completed + +- [x] **Leaderboard UI**: Create a static, visually-styled leaderboard page with a podium for top players and a table for others. +- [x] **Member Profile Modal**: Display player profiles in a modal dialog instead of a separate page. +- [x] **Refine Profile Modal**: Update the profile modal to remove the bio and include `joined_date`, `matches_played`, `wins`, and `losses`. +- [x] **Implement Register/Login**: Build user registration and login functionality. This will be a prerequisite for features that require user authentication. + +## In Progress + +- [ ] **Training Game Interest Form**: Create a form for players to register their interest in training games. The form will allow users to look up their account with their phone number. If an account doesn't exist, submitting the form will create one. + +## Backlog + +- [ ] **Backend for Player Data**: Create a backend endpoint to serve the list of players, replacing the mock data in `index.php`. +- [ ] **Player Dashboard**: Build a personalized dashboard for logged-in players to see their own detailed stats, track progress over time, and manage their information. +- [ ] **Branded Landing Page**: Develop a more formal, public-facing homepage for the application that explains its purpose and value. \ No newline at end of file diff --git a/db/migrations/001_create_users_table.php b/db/migrations/001_create_users_table.php new file mode 100644 index 0000000..4cc3bd0 --- /dev/null +++ b/db/migrations/001_create_users_table.php @@ -0,0 +1,29 @@ +exec($sql); + echo "Table 'users' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migrations/002_seed_users_table.php b/db/migrations/002_seed_users_table.php new file mode 100644 index 0000000..b33c511 --- /dev/null +++ b/db/migrations/002_seed_users_table.php @@ -0,0 +1,49 @@ + 1, 'name' => 'Alex Mercer', 'points' => 1500, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player1/100/100', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => '2020-12-01', 'matches_played' => 98, 'wins' => 70, 'losses' => 28], + ['rank' => 2, 'name' => 'Samira Khan', 'points' => 1450, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player2/100/100', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => '2020-11-15', 'matches_played' => 102, 'wins' => 65, 'losses' => 37], + ['rank' => 3, 'name' => 'Leo Martinez', 'points' => 1420, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player3/100/100', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => '2021-01-05', 'matches_played' => 95, 'wins' => 60, 'losses' => 35], + ['rank' => 4, 'name' => 'Chloe Davis', 'points' => 1390, 'trend' => 'same', 'img' => 'https://picsum.photos/seed/player4/80/80', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => '2021-02-20', 'matches_played' => 90, 'wins' => 58, 'losses' => 32], + ['rank' => 5, 'name' => 'Ben Carter', 'points' => 1350, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player5/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => '2021-03-10', 'matches_played' => 88, 'wins' => 55, 'losses' => 33], + ['rank' => 6, 'name' => 'Eva Rostova', 'points' => 1310, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player6/80/80', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => '2021-04-01', 'matches_played' => 85, 'wins' => 52, 'losses' => 33], + ['rank' => 7, 'name' => 'Daniel Park', 'points' => 1280, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player7/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => '2021-05-25', 'matches_played' => 82, 'wins' => 50, 'losses' => 32], + ['rank' => 8, 'name' => 'Olivia Chen', 'points' => 1250, 'trend' => 'same', 'img' => 'https://picsum.photos/seed/player8/80/80', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => '2021-06-15', 'matches_played' => 80, 'wins' => 48, 'losses' => 32], + ['rank' => 9, 'name' => 'Niko Bellic', 'points' => 1220, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player9/80/80', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => '2021-07-01', 'matches_played' => 78, 'wins' => 45, 'losses' => 33], + ['rank' => 10, 'name' => 'Jasmine Kaur', 'points' => 1190, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player10/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => '2021-08-10', 'matches_played' => 75, 'wins' => 42, 'losses' => 33], +]; + +try { + $pdo = db(); + $stmt = $pdo->prepare( + "INSERT INTO users (name, phone_number, role, rank, points, trend, img, position, joined_date, matches_played, wins, losses, `group`) + VALUES (:name, :phone_number, 'player', :rank, :points, :trend, :img, :position, :joined_date, :matches_played, :wins, :losses, :group) + ON DUPLICATE KEY UPDATE name=VALUES(name), points=VALUES(points), trend=VALUES(trend), img=VALUES(img), position=VALUES(position), joined_date=VALUES(joined_date), matches_played=VALUES(matches_played), wins=VALUES(wins), losses=VALUES(losses), `group`=VALUES(`group`);" + ); + + foreach ($players as $i => $player) { + // Assign a unique placeholder phone number + $phoneNumber = '+155501' . str_pad($i, 2, '0', STR_PAD_LEFT); + + $stmt->execute([ + ':name' => $player['name'], + ':phone_number' => $phoneNumber, + ':rank' => $player['rank'], + ':points' => $player['points'], + ':trend' => $player['trend'], + ':img' => $player['img'], + ':position' => $player['position'], + ':joined_date' => $player['joined_date'], + ':matches_played' => $player['matches_played'], + ':wins' => $player['wins'], + ':losses' => $player['losses'], + ':group' => $player['group'] + ]); + } + + echo "Table 'users' seeded successfully." . PHP_EOL; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migrations/003_add_nickname_to_users.php b/db/migrations/003_add_nickname_to_users.php new file mode 100644 index 0000000..41e1a8d --- /dev/null +++ b/db/migrations/003_add_nickname_to_users.php @@ -0,0 +1,11 @@ +exec($sql); + echo "Migration successful: 'nickname' column added to 'users' table." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migrations/004_add_photo_to_users.php b/db/migrations/004_add_photo_to_users.php new file mode 100644 index 0000000..730368d --- /dev/null +++ b/db/migrations/004_add_photo_to_users.php @@ -0,0 +1,11 @@ +exec($sql); + echo "Migration successful: 'photo' column added to 'users' table." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage() . PHP_EOL); +} diff --git a/index.php b/index.php index 6531aa3..f8335b7 100644 --- a/index.php +++ b/index.php @@ -1,17 +1,25 @@ query("SELECT *, DATE_FORMAT(joined_date, '%M %e, %Y') as formatted_joined_date FROM users WHERE role = 'player' ORDER BY points DESC, name ASC"); + $players = $stmt->fetchAll(); + + foreach ($players as $key => &$player) { + $player['rank'] = $key + 1; + } + unset($player); + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} + // --- Data Simulation --- -$players = [ - ['rank' => 1, 'name' => 'Alex Mercer', 'points' => 1500, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player1/100/100', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => 'December 1, 2020', 'matches_played' => 98, 'wins' => 70, 'losses' => 28], - ['rank' => 2, 'name' => 'Samira Khan', 'points' => 1450, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player2/100/100', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => 'November 15, 2020', 'matches_played' => 102, 'wins' => 65, 'losses' => 37], - ['rank' => 3, 'name' => 'Leo Martinez', 'points' => 1420, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player3/100/100', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => 'January 5, 2021', 'matches_played' => 95, 'wins' => 60, 'losses' => 35], - ['rank' => 4, 'name' => 'Chloe Davis', 'points' => 1390, 'trend' => 'same', 'img' => 'https://picsum.photos/seed/player4/80/80', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => 'February 20, 2021', 'matches_played' => 90, 'wins' => 58, 'losses' => 32], - ['rank' => 5, 'name' => 'Ben Carter', 'points' => 1350, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player5/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => 'March 10, 2021', 'matches_played' => 88, 'wins' => 55, 'losses' => 33], - ['rank' => 6, 'name' => 'Eva Rostova', 'points' => 1310, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player6/80/80', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => 'April 1, 2021', 'matches_played' => 85, 'wins' => 52, 'losses' => 33], - ['rank' => 7, 'name' => 'Daniel Park', 'points' => 1280, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player7/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => 'May 25, 2021', 'matches_played' => 82, 'wins' => 50, 'losses' => 32], - ['rank' => 8, 'name' => 'Olivia Chen', 'points' => 1250, 'trend' => 'same', 'img' => 'https://picsum.photos/seed/player8/80/80', 'group' => 'B3SC Strikers', 'position' => 'Forward', 'joined_date' => 'June 15, 2021', 'matches_played' => 80, 'wins' => 48, 'losses' => 32], - ['rank' => 9, 'name' => 'Niko Bellic', 'points' => 1220, 'trend' => 'down', 'img' => 'https://picsum.photos/seed/player9/80/80', 'group' => 'B3SC Defenders', 'position' => 'Defender', 'joined_date' => 'July 1, 2021', 'matches_played' => 78, 'wins' => 45, 'losses' => 33], - ['rank' => 10, 'name' => 'Jasmine Kaur', 'points' => 1190, 'trend' => 'up', 'img' => 'https://picsum.photos/seed/player10/80/80', 'group' => 'B3SC Midfield', 'position' => 'Midfielder', 'joined_date' => 'August 10, 2021', 'matches_played' => 75, 'wins' => 42, 'losses' => 33], -]; $podium = array_slice($players, 0, 3); $rest_of_players = array_slice($players, 3); @@ -55,6 +63,14 @@ function get_trend_icon_modal($trend) {
+
+ + Welcome, ! + Logout + + Login / Register + +

B3SC Leaderboard

Season 1 - Premier Division

@@ -63,24 +79,28 @@ function get_trend_icon_modal($trend) {
$player): ?> +
-
-
- B3SC #<?php echo $player['rank']; ?> ranked player +
+ B3SC #<?php echo $player['rank']; ?> ranked player
-
PTS
+
PTS
@@ -101,22 +121,26 @@ function get_trend_icon_modal($trend) { + - + - - + + @@ -143,6 +167,7 @@ function get_trend_icon_modal($trend) { const triggerElement = event.relatedTarget; const name = triggerElement.getAttribute('data-player-name'); + const nickname = triggerElement.getAttribute('data-player-nickname'); const img = triggerElement.getAttribute('data-player-img').replace('/100/100', '/150/150').replace('/80/80', '/150/150'); const rank = triggerElement.getAttribute('data-player-rank'); const points = triggerElement.getAttribute('data-player-points'); @@ -153,6 +178,8 @@ function get_trend_icon_modal($trend) { const wins = triggerElement.getAttribute('data-player-wins'); const losses = triggerElement.getAttribute('data-player-losses'); + const displayName = (nickname && nickname !== '--') ? `${name} (${nickname})` : name; + function getTrendIconModal(trend) { if (trend === 'up') { return ''; @@ -169,7 +196,7 @@ function get_trend_icon_modal($trend) {
${name} -

${name}

+

${displayName}

${position}

Joined on ${joined}

diff --git a/login.php b/login.php new file mode 100644 index 0000000..a76437e --- /dev/null +++ b/login.php @@ -0,0 +1,185 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $position_str = implode(', ', $positions); + + $sql = "INSERT INTO users (phone_number, name, nickname, position, photo, joined_date, role) VALUES (:phone_number, :name, :nickname, :position, :photo, CURDATE(), 'player')"; + $stmt = $pdoconn->prepare($sql); + + $stmt->bindParam(':phone_number', $phone_number); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':nickname', $nickname); + $stmt->bindParam(':position', $position_str); + $stmt->bindParam(':photo', $photo_path); + + $stmt->execute(); + + $user_id = $pdoconn->lastInsertId(); + $sql = "SELECT * FROM users WHERE id = :id"; + $stmt = $pdoconn->prepare($sql); + $stmt->bindParam(':id', $user_id); + $stmt->execute(); + $_SESSION['user'] = $stmt->fetch(PDO::FETCH_ASSOC); + + header("Location: index.php"); + exit(); + + } catch (PDOException $e) { + $error = "Database error during registration: " . $e->getMessage(); + } + } else { + $error = "Please fill out all required fields."; + $phone_number_for_registration = $phone_number; // Keep phone number for the form + } +} +// Handle Phone Number Lookup +else if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['phone'])) { + $phone_number = $_POST['phone']; + try { + $pdoconn = db(); + $pdoconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $sql = "SELECT * FROM users WHERE phone_number = :phone_number"; + $stmt = $pdoconn->prepare($sql); + $stmt->bindParam(':phone_number', $phone_number); + $stmt->execute(); + + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($user) { + $_SESSION['user'] = $user; + header("Location: index.php"); + exit(); + } else { + // User not found, set phone number to show registration form + $phone_number_for_registration = $phone_number; + } + + } catch (PDOException $e) { + $error = "Database error: " . $e->getMessage(); + } +} +?> + + + + + + Login / Register + + + + +
+
+
+
+
+

Login or Register

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

Welcome! Let's get you set up.

+
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ + +
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..2f45770 --- /dev/null +++ b/logout.php @@ -0,0 +1,7 @@ + \ No newline at end of file