diff --git a/backend/middleware/authMiddleware.js b/backend/middleware/authMiddleware.js new file mode 100644 index 0000000..b16c7f2 --- /dev/null +++ b/backend/middleware/authMiddleware.js @@ -0,0 +1,16 @@ +import jwt from "jsonwebtoken"; + +const JWT_SECRET = process.env.JWT_SECRET || "supersecretkey"; + +export const authMiddleware = (req, res, next) => { + const token = req.headers.authorization?.split(" ")[1]; // Bearer token + if (!token) return res.status(401).json({ msg: "No token provided" }); + + try { + const decoded = jwt.verify(token, JWT_SECRET); + req.user = decoded; + next(); + } catch (err) { + res.status(401).json({ msg: "Invalid token" }); + } +}; diff --git a/backend/models/user.js b/backend/models/user.js new file mode 100644 index 0000000..83eca67 --- /dev/null +++ b/backend/models/user.js @@ -0,0 +1,8 @@ +import mongoose from "mongoose"; + +const userSchema = new mongoose.Schema({ + username: { type: String, required: true, unique: true }, + password: { type: String, required: true }, // hashed +}); + +export default mongoose.model("User", userSchema); diff --git a/backend/routes/authRoutes.js b/backend/routes/authRoutes.js new file mode 100644 index 0000000..0fe7600 --- /dev/null +++ b/backend/routes/authRoutes.js @@ -0,0 +1,11 @@ +import express from "express"; +import { register, login, protectedRoute } from "../controllers/authController.js"; +import { authMiddleware } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +router.post("/register", register); +router.post("/login", login); +router.get("/protected", authMiddleware, protectedRoute); + +export default router; diff --git a/src/index.css b/src/index.css index 30da0d3..5d09cb4 100644 --- a/src/index.css +++ b/src/index.css @@ -17,12 +17,6 @@ html, body { font-family: 'Lexend', system-ui, Avenir, Helvetica, Arial, sans-serif; /* apply Lexend globally */ } -body { - display: flex; - flex-direction: column; - width: 100%; -} - /* Optional: style scrollbar for future if needed */ ::-webkit-scrollbar { width: 6px; @@ -78,3 +72,70 @@ body { .scrollbar-thin::-webkit-scrollbar-thumb:hover { background-color: rgba(100, 100, 100, 0.7); } +/* Small devices: phones (up to 640px) */ +@media (max-width: 640px) { + header { + padding: 0.5rem 1rem; + font-size: 0.9rem; + } + + main { + padding: 1rem; + } + + footer { + padding: 1rem 0.5rem; + font-size: 0.8rem; + } +} + +/* Medium devices: tablets (641px to 768px) */ +@media (min-width: 641px) and (max-width: 768px) { + header { + padding: 1rem 2rem; + font-size: 1rem; + } + + main { + padding: 1.5rem; + } + + footer { + padding: 1.5rem; + font-size: 0.9rem; + } +} + +/* Large devices: laptops (769px to 1024px) */ +@media (min-width: 769px) and (max-width: 1024px) { + header { + padding: 1.5rem 3rem; + font-size: 1.1rem; + } + + main { + padding: 2rem; + } + + footer { + padding: 2rem; + font-size: 1rem; + } +} + +/* Extra large devices: desktops (1025px and up) */ +@media (min-width: 1025px) { + header { + padding: 2rem 4rem; + font-size: 1.2rem; + } + + main { + padding: 2.5rem; + } + + footer { + padding: 2.5rem; + font-size: 1rem; + } +} diff --git a/src/layout/MainLayout.jsx b/src/layout/MainLayout.jsx index d651db5..a14120d 100644 --- a/src/layout/MainLayout.jsx +++ b/src/layout/MainLayout.jsx @@ -4,20 +4,20 @@ import Footer from "../components/Footer"; const MainLayout = ({ children }) => { const location = useLocation(); - const hideFooterPaths = ["/about", "/chat"]; // Add any other routes where footer should be hidden + const hideFooterPaths = ["/about"]; const hideFooter = hideFooterPaths.includes(location.pathname); return ( -
+
{/* Fixed Header */}
{/* Page Content */} -
+
{children}
- {/* Footer that scrolls with page */} + {/* Footer */} {!hideFooter &&
}
); diff --git a/src/pages/AddNew.jsx b/src/pages/AddNew.jsx new file mode 100644 index 0000000..5cafdd6 --- /dev/null +++ b/src/pages/AddNew.jsx @@ -0,0 +1,106 @@ +import { useState } from "react"; +import { Navigate } from "react-router-dom"; +import fetcher from "../hooks/useFetcher"; + +export default function AddNew() { + // Check auth → (you can replace this with JWT/Context-based check later) + const token = localStorage.getItem("authToken"); + if (!token) { + return ; + } + + const [type, setType] = useState("projects"); + const [formData, setFormData] = useState({}); + const [message, setMessage] = useState(""); + + const handleChange = (e) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + const res = await fetcher.post(`${type}`, formData, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (res) { + setMessage("✅ Item added successfully!"); + setFormData({}); + } + } catch (err) { + setMessage("❌ Error adding item."); + } + }; + + return ( +
+
+

+ Add New Item +

+ + {/* Select type */} +
+ + +
+ + {/* Dynamic form fields */} +
+ + +