import express from "express"; import bcrypt from "bcryptjs"; import jwt from "jsonwebtoken"; import Vendor from "../models/Vendor.model.js"; import Store from "../models/Store.model.js"; import Invitation from "../models/Invitation.model.js"; import { protectVendor } from "../middleware/vendorAuthMiddleware.js"; const router = express.Router(); /** * Register a New Vendor (and create a corresponding Store) * @route POST /api/auth/register */ router.post("/register", async (req, res) => { const { username, password, invitationCode } = req.body; try { if (!username || !password || !invitationCode) { return res.status(400).json({ error: "All fields are required." }); } // Verify invitation code const invitation = await Invitation.findOne({ code: invitationCode, isUsed: false, }); console.log(`Invitation: ${invitation}`); if (!invitation) { return res.status(400).json({ error: "Invalid or used invitation code." }); } // Check if vendor already exists const existingVendor = await Vendor.findOne({ username }); if (existingVendor) { return res.status(400).json({ error: "Vendor already exists." }); } // Hash the password const hashedPassword = await bcrypt.hash(password, 10); // Create the vendor const vendor = new Vendor({ username, passwordHash: hashedPassword, }); await vendor.save(); // Create a store for this vendor const store = new Store({ vendorId: vendor._id, storeName: `${username}'s Store`, welcomeMessage: "Welcome to my store!", categories: [], }); await store.save(); // Attach `storeId` to vendor vendor.storeId = store._id; await vendor.save(); // Mark invitation as used invitation.isUsed = true; invitation.usedBy = vendor._id; invitation.usedAt = new Date(); await invitation.save(); return res .status(201) .json({ message: "Vendor registered successfully", store }); } catch (error) { console.error("Error registering vendor:", error); return res.status(500).json({ error: error.message }); } }); /** * Vendor Login * @route POST /api/auth/login */ router.post("/login", async (req, res) => { const { username, password } = req.body; try { if (!username || !password) { return res.status(400).json({ error: "Username and password are required." }); } const vendor = await Vendor.findOne({ username }); if (!vendor) { return res.status(401).json({ error: "Invalid credentials." }); } const isMatch = await bcrypt.compare(password, vendor.passwordHash); if (!isMatch) { return res.status(401).json({ error: "Invalid credentials." }); } // Generate a JWT const token = jwt.sign( { id: vendor._id, role: "vendor" }, process.env.JWT_SECRET, { expiresIn: "7d" } ); // Store the token in the DB to identify the current session vendor.currentToken = token; await vendor.save(); return res.json({ token, role: "vendor" }); } catch (error) { console.error("Error logging in vendor:", error); return res.status(500).json({ error: error.message }); } }); /** * Vendor Logout * @route POST /api/auth/logout * @access Private (Vendors only) */ router.post("/logout", protectVendor, async (req, res) => { try { await Vendor.findByIdAndUpdate(req.user._id, { currentToken: null }); return res.json({ message: "Successfully logged out." }); } catch (error) { console.error("Error logging out vendor:", error); return res.status(500).json({ error: "Failed to log out." }); } }); /** * Get Vendor Info * @route GET /api/auth/me * @access Private (Vendors only) */ router.get("/me", protectVendor, async (req, res) => { try { const vendor = await Vendor.findById(req.user._id).select("-passwordHash -currentToken"); if (!vendor) { return res.status(404).json({ error: "Vendor not found." }); } vendor.lastOnline = new Date(); await vendor.save(); const store = await Store.findOne({ vendorId: vendor._id }); return res.json({ vendor, store }); } catch (error) { console.error("Error fetching vendor info:", error); return res.status(500).json({ error: "Failed to fetch vendor data." }); } }); export default router;