- {user &&
- user.blogs &&
- user.blogs.map((blog, index) => (
-
-
-

-
+
+
+ {/* Header */}
+
+
+ My Blogs
+
+
Manage your amazing stories
+ {user && user.blogs && user.blogs.length > 0 && (
+
+
+ ✍️ {user.blogs.length} {user.blogs.length === 1 ? 'Blog' : 'Blogs'}
+
+
+ 👤 {user.name}
+
+
+ )}
+
+
+ {/* Blogs Grid */}
+ {user && user.blogs && user.blogs.length > 0 ? (
+
+ {user.blogs.map((blog, index) => (
+
+ ))}
+
+ ) : (
+
- ))}
+ )}
+
);
};
+
+
export default UserBlogs;
diff --git a/client/src/index.css b/client/src/index.css
index 4d994261..0d57ae5f 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -1,4 +1,16 @@
-*{
+/* Using Tailwind via CDN (script in public/index.html). Keep a minimal local stylesheet for global rules. */
+
+* {
margin: 0;
padding: 0;
-}
\ No newline at end of file
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ background-color: #f8fafc; /* light slate */
+ color: #0f172a; /* slate-900 */
+}
diff --git a/client/src/index.js b/client/src/index.js
index a77935ac..f10fdfec 100644
--- a/client/src/index.js
+++ b/client/src/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
-import './index.css';
+// Global styles moved to public/custom.css and Tailwind is loaded via CDN in public/index.html
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
diff --git a/client/tailwind.config.js b/client/tailwind.config.js
new file mode 100644
index 00000000..ba73e062
--- /dev/null
+++ b/client/tailwind.config.js
@@ -0,0 +1,16 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: [
+ "./index.html",
+ "./src/**/*.{js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {
+ colors: {
+ primary: '#3b82f6',
+ secondary: '#8b5cf6',
+ }
+ },
+ },
+ plugins: [],
+}
diff --git a/server/.env b/server/.env
new file mode 100644
index 00000000..1b50b397
--- /dev/null
+++ b/server/.env
@@ -0,0 +1 @@
+MONGO_URI=mongodb://localhost:27017/Blog
diff --git a/server/config/db.js b/server/config/db.js
index 28343a4a..f52c706d 100644
--- a/server/config/db.js
+++ b/server/config/db.js
@@ -1,10 +1,10 @@
-const mongoose = require("mongoose");
-require('dotenv').config();
+import mongoose from "mongoose";
+import dotenv from 'dotenv';
+dotenv.config();
mongoose.set('strictQuery', false);
-
mongoose.connect(process.env.MONGO_URI || "mongodb://mongo:27017/Blog").then(()=>{
console.log("connected!");
}).catch((err)=>{
diff --git a/server/controller/blog-controller.js b/server/controller/blog-controller.js
index 1cf77188..3e142273 100644
--- a/server/controller/blog-controller.js
+++ b/server/controller/blog-controller.js
@@ -1,17 +1,16 @@
-const mongoose = require("mongoose");
-const Blog = require("../model/Blog");
-const User = require("../model/User");
-const { ApiResponse } = require("../utils/ApiResponse");
-const { ApiError } = require("../utils/ApiError");
+import mongoose from "mongoose";
+import Blog from "../model/Blog.js";
+import User from "../model/User.js";
+import { ApiResponse } from "../utils/ApiResponse.js";
+import { ApiError } from "../utils/ApiError.js";
const getAllBlogs = async (req, res, next) => {
try {
- const blogs = await Blog.find();
- if (!blogs || blogs.length === 0) {
- return res.status(404).json(new ApiError(404, "No blogs found"));
- }
+ const blogs = await Blog.find().populate("user");
+ console.log("getAllBlogs - Found blogs:", blogs.length);
return res.status(200).json(new ApiResponse(200, { blogs }, "Blogs found"));
} catch (e) {
+ console.error("Error in getAllBlogs:", e);
return res.status(500).json(new ApiError(500, e.message));
}
};
@@ -21,22 +20,27 @@ const addBlog = async (req, res, next) => {
const currentDate = new Date();
try {
+ console.log("Adding blog with data:", { title, desc, img, user });
+
const existingUser = await User.findById(user);
if (!existingUser) {
+ console.log("User not found:", user);
return res.status(400).json(new ApiError(400, "Unauthorized"));
}
const blog = new Blog({ title, desc, img, user, date: currentDate });
+
+ // Save blog first
+ await blog.save();
+
+ // Then update user with blog reference
+ existingUser.blogs.push(blog._id);
+ await existingUser.save();
- const session = await mongoose.startSession();
- session.startTransaction();
- await blog.save({ session });
- existingUser.blogs.push(blog);
- await existingUser.save({ session });
- await session.commitTransaction();
-
+ console.log("Blog created successfully:", blog);
return res.status(201).json(new ApiResponse(201, { blog }, "Blog created successfully"));
} catch (e) {
+ console.error("Error in addBlog:", e);
return res.status(500).json(new ApiError(500, e.message));
}
};
@@ -59,7 +63,7 @@ const updateBlog = async (req, res, next) => {
const getById = async (req, res, next) => {
const id = req.params.id;
try {
- const blog = await Blog.findById(id);
+ const blog = await Blog.findById(id).populate("user");
if (!blog) {
return res.status(404).json(new ApiError(404, "Blog not found"));
}
@@ -90,14 +94,18 @@ const deleteBlog = async (req, res, next) => {
const getByUserId = async (req, res, next) => {
const userId = req.params.id;
try {
+ console.log("getByUserId - Getting blogs for user:", userId);
const userBlogs = await User.findById(userId).populate("blogs");
if (!userBlogs) {
- return res.status(404).json(new ApiError(404, "No blog found for this user"));
+ console.log("User not found:", userId);
+ return res.status(404).json(new ApiError(404, "User not found"));
}
+ console.log("getByUserId - Found user with", userBlogs.blogs?.length || 0, "blogs");
return res.status(200).json(new ApiResponse(200, { user: userBlogs }, "Blogs retrieved successfully"));
} catch (e) {
+ console.error("Error in getByUserId:", e);
return res.status(500).json(new ApiError(500, e.message));
}
};
-module.exports = { getAllBlogs, addBlog, updateBlog, getById, deleteBlog, getByUserId };
\ No newline at end of file
+export { getAllBlogs, addBlog, updateBlog, getById, deleteBlog, getByUserId };
\ No newline at end of file
diff --git a/server/controller/user-contoller.js b/server/controller/user-contoller.js
index c6387a7d..78e438dc 100644
--- a/server/controller/user-contoller.js
+++ b/server/controller/user-contoller.js
@@ -1,7 +1,7 @@
-const User = require("../model/User");
-const bcrypt = require("bcryptjs");
-const { ApiResponse } = require("../utils/ApiResponse");
-const { ApiError } = require("../utils/ApiError");
+import User from "../model/User.js";
+import bcrypt from "bcryptjs";
+import { ApiResponse } from "../utils/ApiResponse.js";
+import { ApiError } from "../utils/ApiError.js";
const getAllUser = async (req, res, next) => {
try {
@@ -62,4 +62,4 @@ const logIn = async (req, res, next) => {
}
};
-module.exports = { getAllUser, signUp, logIn };
+export { getAllUser, signUp, logIn };
diff --git a/server/model/Blog.js b/server/model/Blog.js
index 5661287f..588bcb4c 100644
--- a/server/model/Blog.js
+++ b/server/model/Blog.js
@@ -1,4 +1,4 @@
-const mongoose = require("mongoose");
+import mongoose from "mongoose";
const Schema = mongoose.Schema;
@@ -26,4 +26,4 @@ const blogSchema = new Schema({
},
})
-module.exports = mongoose.model("Blog", blogSchema);
\ No newline at end of file
+export default mongoose.model("Blog", blogSchema);
\ No newline at end of file
diff --git a/server/model/User.js b/server/model/User.js
index 1ee5cdff..b620f310 100644
--- a/server/model/User.js
+++ b/server/model/User.js
@@ -1,4 +1,4 @@
-const mongoose = require("mongoose");
+import mongoose from "mongoose";
const Schema = mongoose.Schema;
@@ -23,4 +23,4 @@ const userSchema = new Schema({
blogs: [{ type: mongoose.Types.ObjectId, ref: "Blog", required: true }],
})
-module.exports = mongoose.model("User", userSchema);
\ No newline at end of file
+export default mongoose.model("User", userSchema);
\ No newline at end of file
diff --git a/server/package.json b/server/package.json
index 0bc1d46f..61520551 100644
--- a/server/package.json
+++ b/server/package.json
@@ -1,83 +1,24 @@
-{
-
-
- "name": "blogapp",
-
-
- "version": "1.0.0",
-
-
- "description": "",
-
-
- "main": "server.js",
-
-
- "scripts": {
-
-
-
-
- "start": "nodemon server.js",
-
-
-
-
- "test": "echo \"Error: no test specified\" && exit 1"
-
-
- },
-
-
- "author": "khushi patel",
-
-
- "license": "ISC",
-
-
- "devDependencies": {
-
-
-
-
- "nodemon": "^2.0.16"
-
-
- },
-
-
- "dependencies": {
-
-
-
-
- "bcryptjs": "^2.4.3",
-
-
-
-
- "cors": "^2.8.5",
-
-
-
-
- "dotenv": "^16.5.0",
-
-
-
-
- "express": "^4.18.1",
-
-
-
-
- "helmet": "^8.1.0",
-
-
-
-
- "mongoose": "^6.3.4"
-
-
- }
-}
+{
+ "name": "blogapp",
+ "version": "1.0.0",
+ "description": "",
+ "main": "server.js",
+ "type": "module",
+ "scripts": {
+ "start": "nodemon server.js",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "khushi patel",
+ "license": "ISC",
+ "devDependencies": {
+ "nodemon": "^2.0.16"
+ },
+ "dependencies": {
+ "bcryptjs": "^2.4.3",
+ "cors": "^2.8.5",
+ "dotenv": "^16.5.0",
+ "express": "^4.18.1",
+ "helmet": "^8.1.0",
+ "mongoose": "^6.3.4"
+ }
+}
diff --git a/server/routes/blog-routes.js b/server/routes/blog-routes.js
index 549697a6..16c61527 100644
--- a/server/routes/blog-routes.js
+++ b/server/routes/blog-routes.js
@@ -1,13 +1,13 @@
-const express = require("express")
+import express from "express";
+import { getAllBlogs, addBlog, updateBlog, getById, deleteBlog, getByUserId } from "../controller/blog-controller.js";
+
const blogRouter = express.Router();
-const { getAllBlogs , addBlog ,
- updateBlog ,getById ,
- deleteBlog , getByUserId} = require("../controller/blog-controller");
-blogRouter.get("/",getAllBlogs);
+blogRouter.get("/", getAllBlogs);
blogRouter.post('/add', addBlog);
-blogRouter.put("/update/:id", updateBlog);
+blogRouter.get("/user/:id", getByUserId);
blogRouter.get("/:id", getById);
-blogRouter.delete("/:id",deleteBlog);
-blogRouter.get("/user/:id",getByUserId)
-module.exports = blogRouter;
\ No newline at end of file
+blogRouter.put("/update/:id", updateBlog);
+blogRouter.delete("/:id", deleteBlog);
+
+export default blogRouter;
\ No newline at end of file
diff --git a/server/routes/user-routes.js b/server/routes/user-routes.js
index b36dcee7..74dbcc0f 100644
--- a/server/routes/user-routes.js
+++ b/server/routes/user-routes.js
@@ -1,10 +1,10 @@
-const express = require("express");
-const { getAllUser , signUp ,logIn } = require("../controller/user-contoller");
-const userRouter = express.Router();
+import express from "express";
+import { getAllUser, signUp, logIn } from "../controller/user-contoller.js";
+const userRouter = express.Router();
-userRouter.get("/",getAllUser);
+userRouter.get("/", getAllUser);
userRouter.post("/signup", signUp);
-userRouter.post("/login" , logIn);
+userRouter.post("/login", logIn);
-module.exports = userRouter;
\ No newline at end of file
+export default userRouter;
\ No newline at end of file
diff --git a/server/server.js b/server/server.js
index d9e8b048..172eea7e 100644
--- a/server/server.js
+++ b/server/server.js
@@ -1,9 +1,11 @@
-const express = require("express");
-const userRouter = require("./routes/user-routes");
-const blogRouter = require("./routes/blog-routes");
-const helmet = require("helmet");
-require("./config/db");
-const cors = require("cors");
+import express from "express";
+import userRouter from "./routes/user-routes.js";
+import blogRouter from "./routes/blog-routes.js";
+import helmet from "helmet";
+import "./config/db.js";
+import cors from "cors";
+import http from "http";
+import https from "https";
const app = express();
@@ -27,6 +29,34 @@ app.use("/api", (req, res, next) => {
res.send("hello");
});
+// Image proxy to avoid hotlinking/CORS issues for external image URLs
+app.get('/images/proxy', (req, res) => {
+ const imageUrl = req.query.url;
+ if (!imageUrl) return res.status(400).send('Missing url param');
+ let parsed;
+ try {
+ parsed = new URL(imageUrl);
+ } catch (e) {
+ return res.status(400).send('Invalid URL');
+ }
+
+ const client = parsed.protocol === 'https:' ? https : http;
+ const request = client.get(imageUrl, (imageRes) => {
+ if (imageRes.statusCode && imageRes.statusCode >= 400) {
+ res.status(imageRes.statusCode).send('Failed to fetch image');
+ return;
+ }
+ const contentType = imageRes.headers['content-type'] || 'image/jpeg';
+ res.setHeader('Content-Type', contentType);
+ imageRes.pipe(res);
+ });
+
+ request.on('error', (err) => {
+ console.error('Image proxy error:', err.message);
+ res.status(500).send('Error fetching image');
+ });
+});
+
//define port
app.listen(5001, () => console.log("app started at 5001..."));
diff --git a/server/utils/ApiError.js b/server/utils/ApiError.js
index 7fa485ff..ba9a2ff9 100644
--- a/server/utils/ApiError.js
+++ b/server/utils/ApiError.js
@@ -21,4 +21,4 @@ class ApiError extends Error {
}
}
-export {ApiError}
\ No newline at end of file
+export { ApiError };
\ No newline at end of file
diff --git a/server/utils/ApiResponse.js b/server/utils/ApiResponse.js
index cb2a284a..13c7dd55 100644
--- a/server/utils/ApiResponse.js
+++ b/server/utils/ApiResponse.js
@@ -7,4 +7,4 @@ class ApiResponse {
}
}
-export { ApiResponse }
\ No newline at end of file
+export { ApiResponse };
\ No newline at end of file
diff --git a/server/yarn.lock b/server/yarn.lock
index 6a549298..399fef22 100644
--- a/server/yarn.lock
+++ b/server/yarn.lock
@@ -1272,6 +1272,11 @@ hasown@^2.0.0:
dependencies:
function-bind "^1.1.2"
+helmet@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz"
+ integrity sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==
+
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"