diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..19ebc49 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,127 @@ +body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + background-color: #f4f7f6; + color: #333; + line-height: 1.6; +} + +.navbar { + background-color: #ffffff; + border-bottom: 1px solid #e7e7e7; + padding: 1rem 2rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.navbar-brand { + font-weight: bold; + font-size: 1.5rem; + color: #007bff; +} + +.nav-links a { + color: #555; + text-decoration: none; + margin-left: 1.5rem; + font-size: 1rem; +} + +.nav-links a:hover { + color: #007bff; +} + +.container { + max-width: 960px; + margin: 2rem auto; + padding: 0 1rem; +} + +.card { + background-color: #ffffff; + border: 1px solid #e7e7e7; + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.card-title { + font-size: 1.25rem; + font-weight: bold; +} + +.card-meta { + font-size: 0.9rem; + color: #777; +} + +.card-body p { + margin-bottom: 1rem; +} + +.form-control { + width: 100%; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 4px; + margin-bottom: 1rem; +} + +.btn { + display: inline-block; + padding: 0.75rem 1.5rem; + border-radius: 4px; + text-decoration: none; + font-weight: bold; + text-align: center; + cursor: pointer; +} + +.btn-primary { + background-color: #007bff; + color: #ffffff; + border: 1px solid #007bff; +} + +.btn-primary:hover { + background-color: #0056b3; +} + +.btn-secondary { + background-color: #6c757d; + color: #ffffff; + border: 1px solid #6c757d; +} + +.footer { + text-align: center; + padding: 2rem 0; + margin-top: 2rem; + font-size: 0.9rem; + color: #777; +} + +/* Vote buttons */ +.vote-buttons { + display: flex; + gap: 1rem; + align-items: center; +} + +.like-button, .dislike-button { + background: none; + border: none; + cursor: pointer; + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 1rem; +} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..ef67a6a --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,27 @@ + +document.addEventListener('DOMContentLoaded', function() { + const voteButtons = document.querySelectorAll('.vote-buttons a'); + + voteButtons.forEach(button => { + button.addEventListener('click', function(e) { + e.preventDefault(); + const url = this.href; + const likeCountSpan = this.querySelector('span'); + const dislikeButton = this.parentElement.querySelector('.dislike-button'); + const dislikeCountSpan = dislikeButton.querySelector('span'); + + fetch(url) + .then(response => response.json()) + .then(data => { + if (data.success) { + likeCountSpan.textContent = data.likes; + dislikeCountSpan.textContent = data.dislikes; + } else { + // Handle errors if needed + console.error(data.error); + } + }) + .catch(error => console.error('Error:', error)); + }); + }); +}); diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..375229d --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,22 @@ +exec($sql); + echo "Success.\n"; + } catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); + } + } +} + +apply_migrations(); + diff --git a/db/migrations/001_create_users_and_skills_tables.sql b/db/migrations/001_create_users_and_skills_tables.sql new file mode 100644 index 0000000..68e6c93 --- /dev/null +++ b/db/migrations/001_create_users_and_skills_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + email VARCHAR(100) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + display_name VARCHAR(50), + description TEXT, + occupation VARCHAR(100), + location VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS skills ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + skill_name VARCHAR(100) NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/002_create_posts_table.sql b/db/migrations/002_create_posts_table.sql new file mode 100644 index 0000000..081ea68 --- /dev/null +++ b/db/migrations/002_create_posts_table.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS posts ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) +); diff --git a/db/migrations/003_add_likes_to_posts.sql b/db/migrations/003_add_likes_to_posts.sql new file mode 100644 index 0000000..22dc2f9 --- /dev/null +++ b/db/migrations/003_add_likes_to_posts.sql @@ -0,0 +1 @@ +ALTER TABLE posts ADD COLUMN likes INT DEFAULT 0, ADD COLUMN dislikes INT DEFAULT 0; \ No newline at end of file diff --git a/db/migrations/004_create_post_votes_table.sql b/db/migrations/004_create_post_votes_table.sql new file mode 100644 index 0000000..85751b5 --- /dev/null +++ b/db/migrations/004_create_post_votes_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS post_votes ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + post_id INT NOT NULL, + vote_type ENUM('like', 'dislike') NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY user_post_vote (user_id, post_id), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE +); diff --git a/db/migrations/005_add_city_country_to_users.sql b/db/migrations/005_add_city_country_to_users.sql new file mode 100644 index 0000000..f7fbc82 --- /dev/null +++ b/db/migrations/005_add_city_country_to_users.sql @@ -0,0 +1,4 @@ +ALTER TABLE users +ADD COLUMN city VARCHAR(100), +ADD COLUMN country VARCHAR(100), +DROP COLUMN location; diff --git a/db/migrations/006_remove_likes_from_posts.sql b/db/migrations/006_remove_likes_from_posts.sql new file mode 100644 index 0000000..b9b3650 --- /dev/null +++ b/db/migrations/006_remove_likes_from_posts.sql @@ -0,0 +1,3 @@ +ALTER TABLE posts +DROP COLUMN likes, +DROP COLUMN dislikes; diff --git a/db/migrations/007_change_vote_type_to_int.sql b/db/migrations/007_change_vote_type_to_int.sql new file mode 100644 index 0000000..5da8df3 --- /dev/null +++ b/db/migrations/007_change_vote_type_to_int.sql @@ -0,0 +1,2 @@ +ALTER TABLE post_votes +CHANGE COLUMN vote_type vote INT NOT NULL; diff --git a/handle_create_post.php b/handle_create_post.php new file mode 100644 index 0000000..c15dd09 --- /dev/null +++ b/handle_create_post.php @@ -0,0 +1,26 @@ +prepare('INSERT INTO posts (user_id, content) VALUES (?, ?)'); + $stmt->execute([$user_id, $content]); + set_flash_message('Post created successfully!', 'success'); + } catch (PDOException $e) { + error_log("Failed to create post: " . $e->getMessage()); + set_flash_message('Failed to create post. Please try again.', 'danger'); + } + } else { + set_flash_message('Post content cannot be empty.', 'danger'); + } +} + +header("Location: index.php"); +exit; diff --git a/handle_like.php b/handle_like.php new file mode 100644 index 0000000..6a79310 --- /dev/null +++ b/handle_like.php @@ -0,0 +1,63 @@ + false, 'error' => 'User not logged in.']); + exit(); +} + +if (!isset($_GET['post_id']) || !isset($_GET['action'])) { + echo json_encode(['success' => false, 'error' => 'Invalid request.']); + exit(); +} + +$postId = (int)$_GET['post_id']; +$action = $_GET['action']; +$userId = $_SESSION['user_id']; +$vote = ($action === 'like') ? 1 : -1; + +$pdo = db(); + +try { + $pdo->beginTransaction(); + + // Check for existing vote + $stmt = $pdo->prepare('SELECT vote FROM post_votes WHERE user_id = :user_id AND post_id = :post_id'); + $stmt->execute(['user_id' => $userId, 'post_id' => $postId]); + $existingVote = $stmt->fetchColumn(); + + if ($existingVote) { + if ($existingVote == $vote) { + // User is undoing their vote + $stmt = $pdo->prepare('DELETE FROM post_votes WHERE user_id = :user_id AND post_id = :post_id'); + $stmt->execute(['user_id' => $userId, 'post_id' => $postId]); + } else { + // User is changing their vote + $stmt = $pdo->prepare('UPDATE post_votes SET vote = :vote WHERE user_id = :user_id AND post_id = :post_id'); + $stmt->execute(['vote' => $vote, 'user_id' => $userId, 'post_id' => $postId]); + } + } else { + // New vote + $stmt = $pdo->prepare('INSERT INTO post_votes (user_id, post_id, vote) VALUES (:user_id, :post_id, :vote)'); + $stmt->execute(['user_id' => $userId, 'post_id' => $postId, 'vote' => $vote]); + } + + $pdo->commit(); + + // Fetch new like/dislike counts + $stmt = $pdo->prepare('SELECT + (SELECT COUNT(*) FROM post_votes WHERE post_id = :post_id AND vote = 1) as likes, + (SELECT COUNT(*) FROM post_votes WHERE post_id = :post_id AND vote = -1) as dislikes + '); + $stmt->execute(['post_id' => $postId]); + $counts = $stmt->fetch(PDO::FETCH_ASSOC); + + echo json_encode(['success' => true, 'likes' => $counts['likes'], 'dislikes' => $counts['dislikes']]); + +} catch (Exception $e) { + $pdo->rollBack(); + echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]); +} \ No newline at end of file diff --git a/handle_login.php b/handle_login.php new file mode 100644 index 0000000..a0d2e30 --- /dev/null +++ b/handle_login.php @@ -0,0 +1,32 @@ +prepare('SELECT id, password_hash FROM users WHERE email = ?'); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password_hash'])) { + $_SESSION['user_id'] = $user['id']; + set_flash_message('You have been successfully logged in.', 'success'); + header("Location: index.php"); + exit; + } else { + set_flash_message('Invalid email or password.', 'danger'); + header("Location: login.php"); + exit; + } + } catch (PDOException $e) { + set_flash_message('Database error. Please try again.', 'danger'); + error_log("Login DB Error: " . $e->getMessage()); + header("Location: login.php"); + exit; + } +} diff --git a/handle_profile_setup.php b/handle_profile_setup.php new file mode 100644 index 0000000..08dbb96 --- /dev/null +++ b/handle_profile_setup.php @@ -0,0 +1,70 @@ +prepare( + "UPDATE users SET display_name = ?, description = ?, occupation = ?, city = ?, country = ? WHERE id = ?" + ); + $stmt->execute([$displayName, $description, $occupation, $city, $country, $userId]); + + // Handle skills + $skills = json_decode($skillsJson, true); + + if (is_array($skills) && !empty($skills)) { + // First, remove existing skills for the user to prevent duplicates on re-editing + $deleteStmt = $pdo->prepare("DELETE FROM skills WHERE user_id = ?"); + $deleteStmt->execute([$userId]); + + // Insert new skills + $insertStmt = $pdo->prepare("INSERT INTO skills (user_id, skill_name) VALUES (?, ?)"); + foreach ($skills as $skill) { + if (!empty(trim($skill))) { + $insertStmt->execute([$userId, trim($skill)]); + } + } + } + + set_flash_message('Profile updated successfully!', 'success'); + // Redirect to a success page or the main feed + header('Location: profile.php?id=' . $userId); + exit(); + + } catch (PDOException $e) { + set_flash_message('Database error: ' . $e->getMessage(), 'danger'); + header('Location: profile_setup.php'); + exit(); + } + +} else { + // If not a POST request, redirect away + header('Location: profile_setup.php'); + exit(); +} +?> diff --git a/handle_signup.php b/handle_signup.php new file mode 100644 index 0000000..3d54630 --- /dev/null +++ b/handle_signup.php @@ -0,0 +1,68 @@ +prepare("SELECT id FROM users WHERE username = ? OR email = ?"); +$stmt->execute([$username, $email]); +if ($stmt->fetch()) { + set_flash_message('Username or email already exists.', 'danger'); + header('Location: signup.php'); + exit(); +} + +// --- Create User --- +$password_hash = password_hash($password, PASSWORD_DEFAULT); + +$stmt = $pdo->prepare("INSERT INTO users (username, email, password_hash, display_name) VALUES (?, ?, ?, ?)"); +try { + $stmt->execute([$username, $email, $password_hash, $username]); + $user_id = $pdo->lastInsertId(); + + // Log the user in + $_SESSION['user_id'] = $user_id; + $_SESSION['username'] = $username; + + set_flash_message('You have successfully registered. Please complete your profile.', 'success'); + // Redirect to profile setup + header('Location: profile_setup.php'); + exit(); + +} catch (PDOException $e) { + set_flash_message('Database error. Please try again.', 'danger'); + error_log("Signup DB Error: " . $e->getMessage()); + header('Location: signup.php'); + exit(); +} diff --git a/includes/flash_messages.php b/includes/flash_messages.php new file mode 100644 index 0000000..53763da --- /dev/null +++ b/includes/flash_messages.php @@ -0,0 +1,17 @@ + $message, + 'type' => $type + ]; +} + +function display_flash_message() { + if (isset($_SESSION['flash_message'])) { + $message = $_SESSION['flash_message']['message']; + $type = $_SESSION['flash_message']['type']; + unset($_SESSION['flash_message']); + echo "
{$message}
"; + } +} diff --git a/index.php b/index.php index 7205f3d..e3841d0 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,111 @@ query(' + SELECT + posts.id, + posts.content, + posts.created_at, + users.display_name, + users.id as user_id, + (SELECT COUNT(*) FROM post_votes WHERE post_id = posts.id AND vote = 1) as likes, + (SELECT COUNT(*) FROM post_votes WHERE post_id = posts.id AND vote = -1) as dislikes + FROM posts + JOIN users ON posts.user_id = users.id + ORDER BY posts.created_at DESC + '); + $posts = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + // Handle database errors gracefully + error_log("DB Error: " . $e->getMessage()); +} -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); ?> - + - - - New Style - - - - - - - - - - - - - - - - - - - + + + Welcome to Our Social Platform + + -
-
-

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

+ + + +
+ + +
+
+
Create a Post
+
+ + +
+
+
+ +

Feed

+ +
No posts yet. Be the first to share!
+ + +
+
+ + Posted on +
+
+

+
+ +
+ + + + +
+

Connect and Share

+

Join our community to connect with friends, share your thoughts, and discover new things.

+ Get Started + Have an account? Login +
+
-
- + + + + + - + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..a7dc630 --- /dev/null +++ b/login.php @@ -0,0 +1,48 @@ + + + + + + + Login + + + + +
+
+
+
+
+

Login

+ +
+
+ + +
+
+ + +
+ +
+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..a3c70ca --- /dev/null +++ b/logout.php @@ -0,0 +1,11 @@ +prepare('SELECT display_name, description, occupation FROM users WHERE id = ?'); +$stmt->execute([$user_id]); +$user = $stmt->fetch(); + +if (!$user) { + header('Location: index.php'); + exit(); +} + + $stmt = $p->prepare('SELECT p.id, p.content, p.created_at, u.display_name, (SELECT COUNT(*) FROM post_votes WHERE post_id = p.id AND vote = 1) as likes, (SELECT COUNT(*) FROM post_votes WHERE post_id = p.id AND vote = -1) as dislikes FROM posts p JOIN users u ON p.user_id = u.id WHERE p.user_id = ? ORDER BY p.created_at DESC'); + $stmt->execute([$user_id]); + $posts = $stmt->fetchAll(); + +?> + + + + + + <?= htmlspecialchars($user['display_name']) ?>'s Profile + + + + + +
+ +
+
+

+

+

+
+
+ +

Posts by

+ + +

This user has no posts yet.

+ + +
+
+

+ +

Posted on

+
+
+ + + Back to Feed +
+ + + + + diff --git a/profile_setup.php b/profile_setup.php new file mode 100644 index 0000000..1dc98d6 --- /dev/null +++ b/profile_setup.php @@ -0,0 +1,196 @@ + + + + + + + Complete Your Profile + + + + + + + + +
+
+
+
+
+

Setup Your Profile

+ +

Welcome! Let's get your profile ready.

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+
+ +
+ +
+ +
+ + +
+ + +
+ + +
+ +
+
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/signup.php b/signup.php new file mode 100644 index 0000000..d9b2c59 --- /dev/null +++ b/signup.php @@ -0,0 +1,66 @@ + + + + + + + Sign Up - Social Platform + + + + + + +
+
+
+
+
+

Create Your Account

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

+ Already have an account? Login +

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