feat: implement user profiles and social walls (Tasks #171, #173, #174)

This commit is contained in:
2026-01-13 23:24:19 +01:00
parent 477f447b67
commit ed62ac0641
8 changed files with 372 additions and 20 deletions

View File

@@ -51,11 +51,13 @@ io.on('connection', (socket) => {
if (rows.length > 0) {
// User exists, update last seen
const existingUsername = rows[0].username;
con.prepare(`UPDATE users SET last_seen = ? WHERE wallet_address = ?`, (err, uStmt) => {
if (err) return console.error("Prepare error:", err);
uStmt.run(now, walletAddress, (err) => {
uStmt.finalize();
if (err) console.error("Update error:", err);
socket.emit('usernameUpdated', { username: existingUsername });
broadcastUserList();
});
});
@@ -77,6 +79,7 @@ io.on('connection', (socket) => {
iStmt.run(walletAddress, finalUsername, now, (err) => {
iStmt.finalize();
if (err) console.error("Insert error:", err);
socket.emit('usernameUpdated', { username: finalUsername });
broadcastUserList();
});
});
@@ -165,6 +168,61 @@ io.on('connection', (socket) => {
});
});
socket.on('getProfile', (walletAddress) => {
console.log(`Fetching profile for ${walletAddress}`);
con.prepare(`SELECT wallet_address, username, bio, banner_color, last_seen FROM users WHERE wallet_address = ?`, (err, stmt) => {
if (err) return socket.emit('error', { message: 'Database error' });
stmt.all(walletAddress, (err, rows) => {
stmt.finalize();
if (err || rows.length === 0) return socket.emit('error', { message: 'User not found' });
const user = rows[0];
// Fetch posts
con.prepare(`SELECT * FROM posts WHERE wallet_address = ? ORDER BY timestamp DESC LIMIT 50`, (err, pStmt) => {
if (err) return socket.emit('profileData', { ...user, posts: [] });
pStmt.all(walletAddress, (err, posts) => {
pStmt.finalize();
socket.emit('profileData', { ...user, posts: posts || [] });
});
});
});
});
});
socket.on('updateProfile', ({ walletAddress, bio, bannerColor }) => {
console.log(`Updating profile for ${walletAddress}`);
con.prepare(`UPDATE users SET bio = ?, banner_color = ? WHERE wallet_address = ?`, (err, stmt) => {
if (err) return socket.emit('error', { message: 'Database error' });
stmt.run(bio, bannerColor, walletAddress, (err) => {
stmt.finalize();
if (err) return socket.emit('error', { message: 'Failed to update profile' });
socket.emit('profileUpdated', { bio, bannerColor });
broadcastUserList();
});
});
});
socket.on('createPost', ({ walletAddress, content }) => {
if (!content || content.trim() === '') return;
console.log(`New post from ${walletAddress}: ${content}`);
const timestamp = new Date().toISOString();
con.prepare(`INSERT INTO posts (id, wallet_address, content, timestamp) VALUES (nextval('seq_post_id'), ?, ?, ?)`, (err, stmt) => {
if (err) return socket.emit('error', { message: 'Database error' });
stmt.run(walletAddress, content, timestamp, (err) => {
stmt.finalize();
if (err) return socket.emit('error', { message: 'Failed to create post' });
// Fetch all posts to broadcast update or just emit the new one
// For simplicity, we'll just tell the user it was created
socket.emit('postCreated', { content, timestamp });
// If we want a live feed, we could broadcast to a "profile room"
// For now, the user can just refresh or we emit to them
});
});
});
socket.on('toggleReaction', ({ messageId, walletAddress, emoji }) => {
console.log(`Toggling reaction: ${emoji} on message ${messageId} by ${walletAddress}`);
con.prepare(`SELECT * FROM reactions WHERE message_id = ? AND wallet_address = ? AND emoji = ?`, (err, stmt) => {