Add community features to media outlets and improve UI

Implement community section for each media outlet, including post creation, viewing, and replies, along with navigation and backend API routes.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 9a264234-c5d7-4dcc-adf3-a954b149b30d
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/9a264234-c5d7-4dcc-adf3-a954b149b30d/AX0T336
This commit is contained in:
kimjaehyeon0101
2025-10-14 09:37:47 +00:00
parent 2ea8ecb0ff
commit 4f0b4c7e1d
6 changed files with 986 additions and 1 deletions

View File

@ -2,7 +2,7 @@ import type { Express } from "express";
import { createServer, type Server } from "http";
import { storage } from "./storage";
import { setupAuth, isAuthenticated } from "./simpleAuth";
import { insertArticleSchema, insertMediaOutletRequestSchema, insertBidSchema, insertCommentSchema, insertPredictionBetSchema } from "@shared/schema";
import { insertArticleSchema, insertMediaOutletRequestSchema, insertBidSchema, insertCommentSchema, insertPredictionBetSchema, insertCommunityPostSchema, insertCommunityReplySchema } from "@shared/schema";
export async function registerRoutes(app: Express): Promise<Server> {
// Auth middleware
@ -392,6 +392,153 @@ export async function registerRoutes(app: Express): Promise<Server> {
}
});
// Community routes
app.get('/api/media-outlets/:slug/community', async (req, res) => {
try {
const outlet = await storage.getMediaOutletBySlug(req.params.slug);
if (!outlet) {
return res.status(404).json({ message: "Media outlet not found" });
}
const sort = req.query.sort as string || 'latest';
const posts = await storage.getCommunityPostsByOutlet(outlet.id, sort);
res.json(posts);
} catch (error) {
console.error("Error fetching community posts:", error);
res.status(500).json({ message: "Failed to fetch community posts" });
}
});
app.get('/api/community/posts/:id', async (req, res) => {
try {
const post = await storage.getCommunityPostById(req.params.id);
if (!post) {
return res.status(404).json({ message: "Post not found" });
}
// Increment view count
await storage.incrementPostViews(req.params.id);
res.json(post);
} catch (error) {
console.error("Error fetching community post:", error);
res.status(500).json({ message: "Failed to fetch community post" });
}
});
app.post('/api/media-outlets/:slug/community', isAuthenticated, async (req: any, res) => {
try {
const outlet = await storage.getMediaOutletBySlug(req.params.slug);
if (!outlet) {
return res.status(404).json({ message: "Media outlet not found" });
}
const userId = req.user.claims?.sub || req.user.id;
const postData = insertCommunityPostSchema.parse({
...req.body,
mediaOutletId: outlet.id,
authorId: userId
});
const post = await storage.createCommunityPost(postData);
res.status(201).json(post);
} catch (error) {
console.error("Error creating community post:", error);
res.status(500).json({ message: "Failed to create community post" });
}
});
app.patch('/api/community/posts/:id', isAuthenticated, async (req: any, res) => {
try {
const userId = req.user.claims?.sub || req.user.id;
const post = await storage.getCommunityPostById(req.params.id);
if (!post) {
return res.status(404).json({ message: "Post not found" });
}
if (post.authorId !== userId) {
return res.status(403).json({ message: "Not authorized to edit this post" });
}
const updated = await storage.updateCommunityPost(req.params.id, req.body);
res.json(updated);
} catch (error) {
console.error("Error updating community post:", error);
res.status(500).json({ message: "Failed to update community post" });
}
});
app.delete('/api/community/posts/:id', isAuthenticated, async (req: any, res) => {
try {
const userId = req.user.claims?.sub || req.user.id;
const user = await storage.getUser(userId);
const post = await storage.getCommunityPostById(req.params.id);
if (!post) {
return res.status(404).json({ message: "Post not found" });
}
if (post.authorId !== userId && user?.role !== 'admin' && user?.role !== 'superadmin') {
return res.status(403).json({ message: "Not authorized to delete this post" });
}
await storage.deleteCommunityPost(req.params.id);
res.status(204).send();
} catch (error) {
console.error("Error deleting community post:", error);
res.status(500).json({ message: "Failed to delete community post" });
}
});
app.post('/api/community/posts/:id/like', isAuthenticated, async (req: any, res) => {
try {
const post = await storage.getCommunityPostById(req.params.id);
if (!post) {
return res.status(404).json({ message: "Post not found" });
}
await storage.incrementPostLikes(req.params.id);
const updated = await storage.getCommunityPostById(req.params.id);
res.json(updated);
} catch (error) {
console.error("Error liking post:", error);
res.status(500).json({ message: "Failed to like post" });
}
});
app.get('/api/community/posts/:id/replies', async (req, res) => {
try {
const replies = await storage.getRepliesByPost(req.params.id);
res.json(replies);
} catch (error) {
console.error("Error fetching replies:", error);
res.status(500).json({ message: "Failed to fetch replies" });
}
});
app.post('/api/community/posts/:id/replies', isAuthenticated, async (req: any, res) => {
try {
const post = await storage.getCommunityPostById(req.params.id);
if (!post) {
return res.status(404).json({ message: "Post not found" });
}
const userId = req.user.claims?.sub || req.user.id;
const replyData = insertCommunityReplySchema.parse({
...req.body,
postId: req.params.id,
authorId: userId
});
const reply = await storage.createCommunityReply(replyData);
res.status(201).json(reply);
} catch (error) {
console.error("Error creating reply:", error);
res.status(500).json({ message: "Failed to create reply" });
}
});
const httpServer = createServer(app);
return httpServer;
}