ecom / server /routes.ts
shashwatIDR's picture
Upload 106 files
1684141 verified
import type { Express } from "express";
import { createServer, type Server } from "http";
import { storage } from "./storage";
import { authenticateToken, requireRole, optionalAuth, generateToken, type AuthRequest } from "./middleware/auth";
import { upload } from "./middleware/multer";
import bcrypt from "bcrypt";
import express from "express";
import path from "path";
import {
insertUserSchema, insertSellerSchema, insertCategorySchema,
insertStoreSchema, insertProductSchema, insertOrderSchema, insertCartItemSchema,
type Order
} from "@shared/schema";
import { z } from "zod";
import { addPlaceholderImages } from "./add-placeholder-images";
export async function registerRoutes(app: Express): Promise<Server> {
// Serve uploaded files
app.use('/uploads', express.static(path.join(process.cwd(), 'uploads')));
// Serve attached assets
app.use('/attached_assets', express.static(path.join(process.cwd(), 'attached_assets')));
// Auth Routes
app.post("/api/auth/register", async (req, res) => {
try {
const userData = insertUserSchema.parse(req.body);
// Check if user already exists
const existingUser = await storage.getUserByEmail(userData.email) ||
await storage.getUserByUsername(userData.username);
if (existingUser) {
return res.status(400).json({ message: "User already exists" });
}
// Hash password
const hashedPassword = await bcrypt.hash(userData.password, 10);
// Convert latitude/longitude numbers to strings for database insertion
const processedUserData = {
...userData,
password: hashedPassword,
// Convert numbers to strings for decimal database fields
latitude: userData.latitude ? userData.latitude.toString() : undefined,
longitude: userData.longitude ? userData.longitude.toString() : undefined,
};
const user = await storage.createUser(processedUserData);
const token = generateToken({
id: user.id,
type: 'user',
username: user.username
});
res.json({
token,
user: {
id: user.id,
username: user.username,
email: user.email,
firstName: user.firstName,
lastName: user.lastName
}
});
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
// Registration error occurred
res.status(500).json({ message: "Registration failed" });
}
});
app.post("/api/auth/login", async (req, res) => {
try {
const { email, password } = req.body;
const user = await storage.getUserByEmail(email);
if (!user || !await bcrypt.compare(password, user.password)) {
return res.status(401).json({ message: "Invalid credentials" });
}
const token = generateToken({
id: user.id,
type: 'user',
username: user.username
});
res.json({
token,
user: {
id: user.id,
username: user.username,
email: user.email,
firstName: user.firstName,
lastName: user.lastName
}
});
} catch (error) {
res.status(500).json({ message: "Login failed" });
}
});
app.post("/api/auth/seller-login", async (req, res) => {
try {
const { username, password } = req.body;
const seller = await storage.getSellerByUsername(username);
if (!seller || !await bcrypt.compare(password, seller.password)) {
return res.status(401).json({ message: "Invalid credentials" });
}
const token = generateToken({
id: seller.id,
type: 'seller',
username: seller.username
});
res.json({
token,
seller: {
id: seller.id,
username: seller.username
}
});
} catch (error) {
res.status(500).json({ message: "Login failed" });
}
});
// Token verification endpoint
app.get("/api/auth/verify", authenticateToken, async (req: AuthRequest, res) => {
try {
const user = req.user;
if (!user) {
return res.status(401).json({ message: "Invalid token" });
}
// Return user data based on type
if (user.type === 'user') {
const fullUser = await storage.getUser(user.id);
if (!fullUser) {
return res.status(404).json({ message: "User not found" });
}
res.json({
user: {
id: fullUser.id,
username: fullUser.username,
email: fullUser.email,
firstName: fullUser.firstName,
lastName: fullUser.lastName
},
userType: 'user'
});
} else if (user.type === 'seller') {
const seller = await storage.getSeller(user.id);
if (!seller) {
return res.status(404).json({ message: "Seller not found" });
}
res.json({
seller: {
id: seller.id,
username: seller.username
},
userType: 'seller'
});
} else {
res.json({ userType: 'admin' });
}
} catch (error) {
// Token verification failed
res.status(500).json({ message: "Token verification failed" });
}
});
// User Routes
app.get("/api/user/profile", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const user = await storage.getUser(req.user!.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
const { password, ...userWithoutPassword } = user;
res.json(userWithoutPassword);
} catch (error) {
res.status(500).json({ message: "Failed to fetch profile" });
}
});
app.put("/api/user/profile", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const updateData = req.body;
// Remove password from update data if present
if (updateData.password) {
delete updateData.password;
}
// Remove id from update data if present
if (updateData.id) {
delete updateData.id;
}
const updatedUser = await storage.updateUser(req.user!.id, updateData);
const { password, ...userWithoutPassword } = updatedUser;
res.json(userWithoutPassword);
} catch (error) {
res.status(500).json({ message: "Failed to update profile" });
}
});
// Categories Routes
app.get("/api/categories", async (req, res) => {
try {
const categories = await storage.getAllCategories();
res.json(categories);
} catch (error) {
res.status(500).json({ message: "Failed to fetch categories" });
}
});
app.post("/api/categories", async (req, res) => {
try {
const categoryData = insertCategorySchema.parse(req.body);
const category = await storage.createCategory(categoryData);
res.json(category);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to create category" });
}
});
app.put("/api/categories/:id", async (req, res) => {
try {
const categoryData = insertCategorySchema.partial().parse(req.body);
const category = await storage.updateCategory(req.params.id, categoryData);
res.json(category);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to update category" });
}
});
app.delete("/api/categories/:id", async (req, res) => {
try {
await storage.deleteCategory(req.params.id);
res.json({ message: "Category deleted successfully" });
} catch (error) {
res.status(500).json({ message: "Failed to delete category" });
}
});
// Products Routes
app.get("/api/products", optionalAuth, async (req: AuthRequest, res) => {
try {
const { category, search, seller } = req.query;
let products;
if (search) {
products = await storage.searchProducts(search as string);
} else if (category) {
products = await storage.getProductsByCategory(category as string);
} else if (seller) {
products = await storage.getProductsBySeller(seller as string);
} else {
products = await storage.getAllProducts();
}
// Add seller and category information
const enrichedProducts = await Promise.all(products.map(async (product) => {
const seller = await storage.getSeller(product.sellerId);
const store = seller ? await storage.getStoreBysellerId(seller.id) : null;
const category = await storage.getCategory(product.categoryId);
return {
...product,
seller: seller ? { id: seller.id, username: seller.username } : null,
store: store ? { name: store.name, faceImage: store.faceImage } : null,
category: category ? { id: category.id, name: category.name } : null,
};
}));
res.json(enrichedProducts);
} catch (error) {
res.status(500).json({ message: "Failed to fetch products" });
}
});
app.get("/api/products/featured", async (req, res) => {
try {
let products = await storage.getFeaturedProductsByCategories();
// Check if we need to create more products for categories with less than 5
const categories = await storage.getAllCategories();
const sellers = await storage.getAllSellers();
if (sellers.length === 0) {
return res.json([]);
}
for (const category of categories) {
const categoryProducts = products.filter(p => p.categoryId === category.id);
const needed = 5 - categoryProducts.length;
if (needed > 0) {
// Create missing products with random images
for (let i = 0; i < needed; i++) {
const randomSeller = sellers[Math.floor(Math.random() * sellers.length)];
const productNumber = categoryProducts.length + i + 1;
const newProduct = await storage.createProduct({
title: `${category.name} Product ${productNumber}`,
description: `High-quality ${category.name.toLowerCase()} product featuring premium materials and exceptional craftsmanship. Perfect for everyday use with modern design aesthetics.`,
price: (Math.floor(Math.random() * 500) + 100).toString(), // Random price between 100-600
stock: Math.floor(Math.random() * 50) + 10, // Random stock between 10-60
images: [
`https://picsum.photos/400/400?random=${Date.now()}&${i}`,
`https://picsum.photos/400/400?random=${Date.now()}&${i}&sig=2`,
`https://picsum.photos/400/400?random=${Date.now()}&${i}&sig=3`
],
categoryId: category.id,
sellerId: randomSeller.id,
isActive: true
});
products.push(newProduct);
}
}
}
// Add seller and category information
const enrichedProducts = await Promise.all(products.map(async (product) => {
const seller = await storage.getSeller(product.sellerId);
const store = seller ? await storage.getStoreBysellerId(seller.id) : null;
const category = await storage.getCategory(product.categoryId);
return {
...product,
seller: seller ? { id: seller.id, username: seller.username } : null,
store: store ? { name: store.name, faceImage: store.faceImage } : null,
category: category ? { id: category.id, name: category.name } : null,
};
}));
res.json(enrichedProducts);
} catch (error) {
// Featured products fetch failed
res.status(500).json({ message: "Failed to fetch featured products" });
}
});
app.get("/api/products/:id", async (req, res) => {
try {
const product = await storage.getProduct(req.params.id);
if (!product) {
return res.status(404).json({ message: "Product not found" });
}
const seller = await storage.getSeller(product.sellerId);
const store = seller ? await storage.getStoreBysellerId(seller.id) : null;
const category = await storage.getCategory(product.categoryId);
const enrichedProduct = {
...product,
seller: seller ? { id: seller.id, username: seller.username } : null,
store: store ? {
id: store.id,
name: store.name,
description: store.description,
faceImage: store.faceImage,
bannerImage: store.bannerImage
} : null,
category: category ? { id: category.id, name: category.name } : null,
};
res.json(enrichedProduct);
} catch (error) {
res.status(500).json({ message: "Failed to fetch product" });
}
});
app.post("/api/products", authenticateToken, requireRole(['seller']), upload.array('images', 5), async (req: AuthRequest, res) => {
try {
// Check if seller has a store first
const store = await storage.getStoreBysellerId(req.user!.id);
if (!store) {
return res.status(400).json({ message: "You must create a store before adding products" });
}
// Convert form data strings to appropriate types
const formData = { ...req.body };
// Keep price and originalPrice as strings (decimal fields)
// Only convert stock to integer
if (formData.stock) formData.stock = parseInt(formData.stock, 10);
const productData = insertProductSchema.parse({
...formData,
sellerId: req.user!.id,
images: req.files ? (req.files as Express.Multer.File[]).map(file => `/uploads/${file.filename}`) : [],
});
const product = await storage.createProduct(productData);
res.json(product);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to create product" });
}
});
app.put("/api/products/:id", authenticateToken, requireRole(['seller']), upload.array('images', 5), async (req: AuthRequest, res) => {
try {
const product = await storage.getProduct(req.params.id);
if (!product) {
return res.status(404).json({ message: "Product not found" });
}
if (product.sellerId !== req.user!.id) {
return res.status(403).json({ message: "You can only update your own products" });
}
const updateData = { ...req.body };
// Convert form data strings to appropriate types
// Keep price and originalPrice as strings (decimal fields)
// Only convert stock to integer
if (updateData.stock) updateData.stock = parseInt(updateData.stock, 10);
if (req.files && (req.files as Express.Multer.File[]).length > 0) {
updateData.images = (req.files as Express.Multer.File[]).map(file => `/uploads/${file.filename}`);
}
const updatedProduct = await storage.updateProduct(req.params.id, updateData);
res.json(updatedProduct);
} catch (error) {
res.status(500).json({ message: "Failed to update product" });
}
});
app.delete("/api/products/:id", authenticateToken, requireRole(['seller']), async (req: AuthRequest, res) => {
try {
const product = await storage.getProduct(req.params.id);
if (!product) {
return res.status(404).json({ message: "Product not found" });
}
if (product.sellerId !== req.user!.id) {
return res.status(403).json({ message: "You can only delete your own products" });
}
await storage.deleteProduct(req.params.id);
res.json({ message: "Product deleted successfully" });
} catch (error) {
res.status(500).json({ message: "Failed to delete product" });
}
});
// Seller Orders Route
app.get("/api/seller/orders", authenticateToken, requireRole(['seller']), async (req: AuthRequest, res) => {
try {
// Get all orders that contain products from this seller
const sellerProducts = await storage.getProductsBySeller(req.user!.id);
const sellerProductIds = sellerProducts.map(p => p.id);
if (sellerProductIds.length === 0) {
return res.json([]);
}
const orders = await storage.getOrdersForSeller(sellerProductIds);
// Enrich orders with items (only seller's items) and user info
const enrichedOrders = await Promise.all(orders.map(async (order: Order) => {
const allItems = await storage.getOrderItems(order.id);
const sellerItems = allItems.filter(item => sellerProductIds.includes(item.productId));
const enrichedItems = await Promise.all(sellerItems.map(async (item) => {
const product = await storage.getProduct(item.productId);
return { ...item, product };
}));
// Get user details for this order
const user = await storage.getUser(order.userId);
return { ...order, items: enrichedItems, user: user ? {
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
phone: user.phone
} : null };
}));
res.json(enrichedOrders);
} catch (error) {
res.status(500).json({ message: "Failed to fetch seller orders" });
}
});
// Update order status by seller
app.patch("/api/seller/orders/:id", authenticateToken, requireRole(['seller']), async (req: AuthRequest, res) => {
try {
const orderId = req.params.id;
const { status, paymentStatus } = req.body;
// Verify the order contains the seller's products
const sellerProducts = await storage.getProductsBySeller(req.user!.id);
const sellerProductIds = sellerProducts.map(p => p.id);
const orderItems = await storage.getOrderItems(orderId);
const hasSellerItems = orderItems.some(item => sellerProductIds.includes(item.productId));
if (!hasSellerItems) {
return res.status(403).json({ message: "You can only update orders containing your products" });
}
const updates: { status?: string; paymentStatus?: string } = {};
if (status) updates.status = status;
if (paymentStatus) updates.paymentStatus = paymentStatus;
const updatedOrder = await storage.updateOrderStatusAndPayment(orderId, updates);
res.json(updatedOrder);
} catch (error) {
res.status(500).json({ message: "Failed to update order status" });
}
});
// Stores Routes
app.get("/api/stores", async (req, res) => {
try {
const stores = await storage.getAllStores();
// Enrich stores with seller information
const enrichedStores = await Promise.all(stores.map(async (store) => {
const seller = await storage.getSeller(store.sellerId);
return {
...store,
seller: seller ? { id: seller.id, username: seller.username } : null,
};
}));
res.json(enrichedStores);
} catch (error) {
res.status(500).json({ message: "Failed to fetch stores" });
}
});
app.get("/api/stores/:id", async (req, res) => {
try {
const store = await storage.getStore(req.params.id);
if (!store) {
return res.status(404).json({ message: "Store not found" });
}
const seller = await storage.getSeller(store.sellerId);
const products = await storage.getProductsBySeller(store.sellerId);
const enrichedProducts = await Promise.all(products.map(async (product) => {
const category = await storage.getCategory(product.categoryId);
return {
...product,
category: category ? { id: category.id, name: category.name } : null,
};
}));
res.json({
...store,
seller: seller ? { id: seller.id, username: seller.username } : null,
products: enrichedProducts
});
} catch (error) {
res.status(500).json({ message: "Failed to fetch store" });
}
});
app.post("/api/stores", authenticateToken, requireRole(['seller']), upload.fields([
{ name: 'bannerImage', maxCount: 1 },
{ name: 'faceImage', maxCount: 1 }
]), async (req: AuthRequest, res) => {
try {
// Check if seller already has a store
const existingStore = await storage.getStoreBysellerId(req.user!.id);
if (existingStore) {
return res.status(400).json({ message: "You can only create one store per seller account" });
}
const files = req.files as { [fieldname: string]: Express.Multer.File[] } || {};
const storeData = insertStoreSchema.parse({
...req.body,
sellerId: req.user!.id,
bannerImage: files.bannerImage ? `/uploads/${files.bannerImage[0].filename}` : null,
faceImage: files.faceImage ? `/uploads/${files.faceImage[0].filename}` : null,
});
const store = await storage.createStore(storeData);
res.json(store);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to create store" });
}
});
app.put("/api/stores/:id", authenticateToken, requireRole(['seller']), upload.fields([
{ name: 'bannerImage', maxCount: 1 },
{ name: 'faceImage', maxCount: 1 }
]), async (req: AuthRequest, res) => {
try {
const store = await storage.getStore(req.params.id);
if (!store) {
return res.status(404).json({ message: "Store not found" });
}
if (store.sellerId !== req.user!.id) {
return res.status(403).json({ message: "You can only update your own store" });
}
const files = req.files as { [fieldname: string]: Express.Multer.File[] };
const updateData = { ...req.body };
if (files.bannerImage) {
updateData.bannerImage = `/uploads/${files.bannerImage[0].filename}`;
}
if (files.faceImage) {
updateData.faceImage = `/uploads/${files.faceImage[0].filename}`;
}
const updatedStore = await storage.updateStore(req.params.id, updateData);
res.json(updatedStore);
} catch (error) {
res.status(500).json({ message: "Failed to update store" });
}
});
// Cart Routes
app.get("/api/cart", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const cartItems = await storage.getCartItems(req.user!.id);
// Enrich cart items with product details
const enrichedItems = await Promise.all(cartItems.map(async (item) => {
const product = await storage.getProduct(item.productId);
const seller = product ? await storage.getSeller(product.sellerId) : null;
const store = seller ? await storage.getStoreBysellerId(seller.id) : null;
return {
...item,
product: product ? {
...product,
seller: seller ? { id: seller.id, username: seller.username } : null,
store: store ? { name: store.name } : null,
} : null,
};
}));
res.json(enrichedItems.filter(item => item.product !== null));
} catch (error) {
res.status(500).json({ message: "Failed to fetch cart" });
}
});
app.post("/api/cart", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const cartItemData = insertCartItemSchema.parse({
...req.body,
userId: req.user!.id,
});
const cartItem = await storage.addToCart(cartItemData);
res.json(cartItem);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to add to cart" });
}
});
app.put("/api/cart/:id", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const { quantity } = req.body;
const cartItem = await storage.updateCartItem(req.params.id, quantity);
res.json(cartItem);
} catch (error) {
res.status(500).json({ message: "Failed to update cart item" });
}
});
app.delete("/api/cart/:id", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
await storage.removeFromCart(req.params.id);
res.json({ message: "Item removed from cart" });
} catch (error) {
res.status(500).json({ message: "Failed to remove from cart" });
}
});
// Orders Routes
app.get("/api/orders", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const orders = await storage.getOrdersByUser(req.user!.id);
// Enrich orders with items
const enrichedOrders = await Promise.all(orders.map(async (order) => {
const items = await storage.getOrderItems(order.id);
const enrichedItems = await Promise.all(items.map(async (item) => {
const product = await storage.getProduct(item.productId);
return { ...item, product };
}));
return { ...order, items: enrichedItems };
}));
res.json(enrichedOrders);
} catch (error) {
res.status(500).json({ message: "Failed to fetch orders" });
}
});
app.post("/api/orders", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const orderData = insertOrderSchema.parse({
...req.body,
userId: req.user!.id,
});
const order = await storage.createOrder(orderData);
// Create order items from cart
const cartItems = await storage.getCartItems(req.user!.id);
await Promise.all(cartItems.map(async (cartItem) => {
await storage.createOrderItem({
orderId: order.id,
productId: cartItem.productId,
quantity: cartItem.quantity,
price: req.body.items.find((item: any) => item.productId === cartItem.productId)?.price || "0",
});
}));
// Clear cart after order
await storage.clearCart(req.user!.id);
res.json(order);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to create order" });
}
});
// Cancel order endpoint
app.patch("/api/orders/:id/cancel", authenticateToken, requireRole(['user']), async (req: AuthRequest, res) => {
try {
const orderId = req.params.id;
// Get the order to verify ownership and check if it can be cancelled
const order = await storage.getOrder(orderId);
if (!order) {
return res.status(404).json({ message: "Order not found" });
}
// Verify the order belongs to the authenticated user
if (order.userId !== req.user!.id) {
return res.status(403).json({ message: "You can only cancel your own orders" });
}
// Check if the order can be cancelled (only pending orders can be cancelled)
if (order.status !== 'pending') {
return res.status(400).json({ message: "Order cannot be cancelled. Only pending orders can be cancelled." });
}
// Update order status to cancelled
const updatedOrder = await storage.updateOrderStatus(orderId, 'cancelled');
res.json(updatedOrder);
} catch (error) {
res.status(500).json({ message: "Failed to cancel order" });
}
});
// Admin Dev Routes (no auth required as per requirements)
app.get("/api/admin/sellers", async (req, res) => {
try {
const sellers = await storage.getAllSellers();
res.json(sellers);
} catch (error) {
res.status(500).json({ message: "Failed to fetch sellers" });
}
});
app.post("/api/admin/sellers", async (req, res) => {
try {
const sellerData = insertSellerSchema.parse(req.body);
// Check if seller already exists
const existingSeller = await storage.getSellerByUsername(sellerData.username);
if (existingSeller) {
return res.status(400).json({ message: "Seller already exists" });
}
// Hash password
const hashedPassword = await bcrypt.hash(sellerData.password, 10);
const seller = await storage.createSeller({
...sellerData,
password: hashedPassword,
plainTextPassword: sellerData.password, // Store for admin access recovery
});
res.json(seller);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ message: "Invalid input data", errors: error.errors });
}
res.status(500).json({ message: "Failed to create seller" });
}
});
app.get("/api/admin/users", async (req, res) => {
try {
const users = await storage.getAllUsers();
res.json(users);
} catch (error) {
res.status(500).json({ message: "Failed to fetch users" });
}
});
app.delete("/api/admin/sellers/:id", async (req, res) => {
try {
// First delete all products by this seller
const products = await storage.getProductsBySeller(req.params.id);
for (const product of products) {
await storage.deleteProduct(product.id);
}
// Delete all stores by this seller
const stores = await storage.getStoresBySeller(req.params.id);
for (const store of stores) {
await storage.deleteStore(store.id);
}
// Finally delete the seller
await storage.deleteSeller(req.params.id);
res.json({ message: "Seller and all associated data deleted successfully" });
} catch (error) {
res.status(500).json({ message: "Failed to delete seller" });
}
});
// Admin product management
app.delete("/api/admin/products/:id", async (req, res) => {
try {
await storage.deleteProduct(req.params.id);
res.json({ message: "Product deleted successfully" });
} catch (error) {
res.status(500).json({ message: "Failed to delete product" });
}
});
app.put("/api/admin/products/:id", async (req, res) => {
try {
const updatedProduct = await storage.updateProduct(req.params.id, req.body);
res.json(updatedProduct);
} catch (error) {
res.status(500).json({ message: "Failed to update product" });
}
});
// Admin Orders Route
app.get("/api/admin/orders", async (req, res) => {
try {
// Get all orders for admin
const orders = await storage.getAllOrders();
// Enrich orders with items and user info
const enrichedOrders = await Promise.all(orders.map(async (order: Order) => {
const items = await storage.getOrderItems(order.id);
const enrichedItems = await Promise.all(items.map(async (item) => {
const product = await storage.getProduct(item.productId);
return { ...item, product };
}));
// Get user details for this order
const user = await storage.getUser(order.userId);
return { ...order, items: enrichedItems, user: user ? {
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
phone: user.phone
} : null };
}));
res.json(enrichedOrders);
} catch (error) {
res.status(500).json({ message: "Failed to fetch admin orders" });
}
});
// Update order status by admin
app.patch("/api/admin/orders/:id", async (req, res) => {
try {
const orderId = req.params.id;
const { status, paymentStatus } = req.body;
const updates: { status?: string; paymentStatus?: string } = {};
if (status) updates.status = status;
if (paymentStatus) updates.paymentStatus = paymentStatus;
const updatedOrder = await storage.updateOrderStatusAndPayment(orderId, updates);
res.json(updatedOrder);
} catch (error) {
res.status(500).json({ message: "Failed to update order status" });
}
});
// Seller Dashboard Routes
app.get("/api/seller/store", authenticateToken, requireRole(['seller']), async (req: AuthRequest, res) => {
try {
const store = await storage.getStoreBysellerId(req.user!.id);
res.json(store);
} catch (error) {
res.status(500).json({ message: "Failed to fetch store" });
}
});
app.get("/api/seller/products", authenticateToken, requireRole(['seller']), async (req: AuthRequest, res) => {
try {
const products = await storage.getProductsBySeller(req.user!.id);
// Add category information
const enrichedProducts = await Promise.all(products.map(async (product) => {
const category = await storage.getCategory(product.categoryId);
return {
...product,
category: category ? { id: category.id, name: category.name } : null,
};
}));
res.json(enrichedProducts);
} catch (error) {
res.status(500).json({ message: "Failed to fetch products" });
}
});
const httpServer = createServer(app);
return httpServer;
}