diff --git a/client/src/App.tsx b/client/src/App.tsx
index 51aff2d..fbc1846 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -3,6 +3,7 @@ import { Provider } from 'react-redux';
import { Toaster } from 'react-hot-toast';
import { store } from './store';
import Layout from './components/Layout';
+import PrivateRoute from './components/PrivateRoute';
import Products from './pages/Products';
import Orders from './pages/Orders';
import Analytics from './pages/Analytics';
@@ -11,6 +12,7 @@ import Expenses from './pages/Expenses';
import Settings from './pages/Settings';
import DataImport from './pages/DataImport';
import Login from './pages/Login';
+import Register from './pages/Register';
import './App.css';
function App() {
@@ -21,15 +23,18 @@ function App() {
} />
- }>
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
+ } />
+ }>
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
@@ -38,4 +43,4 @@ function App() {
);
}
-export default App;
\ No newline at end of file
+export default App;
diff --git a/client/src/components/PrivateRoute.tsx b/client/src/components/PrivateRoute.tsx
new file mode 100644
index 0000000..b1afdad
--- /dev/null
+++ b/client/src/components/PrivateRoute.tsx
@@ -0,0 +1,10 @@
+import { useSelector } from 'react-redux';
+import { Navigate, Outlet } from 'react-router-dom';
+import { RootState } from '../store';
+
+const PrivateRoute = () => {
+ const isAuthenticated = useSelector((state: RootState) => state.auth.isAuthenticated);
+ return isAuthenticated ? : ;
+};
+
+export default PrivateRoute;
diff --git a/client/src/pages/Login.tsx b/client/src/pages/Login.tsx
index 1918fd5..76e7b90 100644
--- a/client/src/pages/Login.tsx
+++ b/client/src/pages/Login.tsx
@@ -1,4 +1,29 @@
+import { useState, FormEvent } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useDispatch, useSelector } from 'react-redux';
+import { loginStart, loginSuccess, loginFailure } from '../store/slices/authSlice';
+import { RootState } from '../store';
+import api from '../utils/api';
+
const Login = () => {
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+ const { loading, error } = useSelector((state: RootState) => state.auth);
+
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ dispatch(loginStart());
+ try {
+ const { data } = await api.post('/auth/login', { email, password });
+ dispatch(loginSuccess(data));
+ navigate('/');
+ } catch (err: any) {
+ dispatch(loginFailure(err.response?.data?.message || 'Login failed'));
+ }
+ };
+
return (
@@ -6,34 +31,46 @@ const Login = () => {
Sign in to your account
+
+ Or{' '}
+
+ create a new account
+
+
-
);
};
-export default Login;
\ No newline at end of file
+export default Login;
diff --git a/client/src/pages/Register.tsx b/client/src/pages/Register.tsx
new file mode 100644
index 0000000..0e7a799
--- /dev/null
+++ b/client/src/pages/Register.tsx
@@ -0,0 +1,86 @@
+import { useState, FormEvent } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { useDispatch, useSelector } from 'react-redux';
+import { loginStart, loginSuccess, loginFailure } from '../store/slices/authSlice';
+import { RootState } from '../store';
+import api from '../utils/api';
+
+const Register = () => {
+ const [name, setName] = useState('');
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+ const { loading, error } = useSelector((state: RootState) => state.auth);
+
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ dispatch(loginStart());
+ try {
+ const { data } = await api.post('/auth/register', { name, email, password });
+ dispatch(loginSuccess(data));
+ navigate('/');
+ } catch (err: any) {
+ dispatch(loginFailure(err.response?.data?.message || 'Registration failed'));
+ }
+ };
+
+ return (
+
+
+
+
+ Create your account
+
+
+ Already have an account?{' '}
+
+ Sign in
+
+
+
+
+
+
+ );
+};
+
+export default Register;
diff --git a/client/src/store/slices/authSlice.ts b/client/src/store/slices/authSlice.ts
index a1dfafc..7f704b5 100644
--- a/client/src/store/slices/authSlice.ts
+++ b/client/src/store/slices/authSlice.ts
@@ -1,17 +1,26 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+interface User {
+ id: string;
+ name: string;
+ email: string;
+}
+
interface AuthState {
isAuthenticated: boolean;
- user: any | null;
+ user: User | null;
token: string | null;
loading: boolean;
error: string | null;
}
+const storedToken = localStorage.getItem('token');
+const storedUser = localStorage.getItem('user');
+
const initialState: AuthState = {
- isAuthenticated: false,
- user: null,
- token: null,
+ isAuthenticated: !!storedToken,
+ user: storedUser ? JSON.parse(storedUser) : null,
+ token: storedToken,
loading: false,
error: null,
};
@@ -24,12 +33,14 @@ const authSlice = createSlice({
state.loading = true;
state.error = null;
},
- loginSuccess: (state, action: PayloadAction<{ user: any; token: string }>) => {
+ loginSuccess: (state, action: PayloadAction<{ user: User; token: string }>) => {
state.isAuthenticated = true;
state.user = action.payload.user;
state.token = action.payload.token;
state.loading = false;
state.error = null;
+ localStorage.setItem('token', action.payload.token);
+ localStorage.setItem('user', JSON.stringify(action.payload.user));
},
loginFailure: (state, action: PayloadAction) => {
state.loading = false;
@@ -40,9 +51,11 @@ const authSlice = createSlice({
state.user = null;
state.token = null;
state.error = null;
+ localStorage.removeItem('token');
+ localStorage.removeItem('user');
},
},
});
export const { loginStart, loginSuccess, loginFailure, logout } = authSlice.actions;
-export default authSlice.reducer;
\ No newline at end of file
+export default authSlice.reducer;
diff --git a/client/src/utils/api.ts b/client/src/utils/api.ts
new file mode 100644
index 0000000..ea435db
--- /dev/null
+++ b/client/src/utils/api.ts
@@ -0,0 +1,27 @@
+import axios from 'axios';
+
+const api = axios.create({
+ baseURL: '/api',
+});
+
+api.interceptors.request.use((config) => {
+ const token = localStorage.getItem('token');
+ if (token) {
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+ return config;
+});
+
+api.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (error.response?.status === 401) {
+ localStorage.removeItem('token');
+ localStorage.removeItem('user');
+ window.location.href = '/login';
+ }
+ return Promise.reject(error);
+ }
+);
+
+export default api;
diff --git a/server/src/models/Customer.ts b/server/src/models/Customer.ts
index 0ed8eff..27e25d2 100644
--- a/server/src/models/Customer.ts
+++ b/server/src/models/Customer.ts
@@ -14,6 +14,7 @@ export interface ICustomer extends Document {
};
totalOrders: number;
totalSpent: number;
+ userId: mongoose.Types.ObjectId;
dateCreated: Date;
dateUpdated: Date;
}
@@ -32,6 +33,7 @@ const CustomerSchema: Schema = new Schema({
},
totalOrders: { type: Number, default: 0 },
totalSpent: { type: Number, default: 0 },
+ userId: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true },
dateCreated: { type: Date, default: Date.now },
dateUpdated: { type: Date, default: Date.now },
});
diff --git a/server/src/models/Expense.ts b/server/src/models/Expense.ts
index 8990fcf..4a95142 100644
--- a/server/src/models/Expense.ts
+++ b/server/src/models/Expense.ts
@@ -7,6 +7,7 @@ export interface IExpense extends Document {
date: Date;
receiptUrl?: string;
notes?: string;
+ userId: mongoose.Types.ObjectId;
dateCreated: Date;
dateUpdated: Date;
}
@@ -22,6 +23,7 @@ const ExpenseSchema: Schema = new Schema({
date: { type: Date, required: true },
receiptUrl: { type: String },
notes: { type: String },
+ userId: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true },
dateCreated: { type: Date, default: Date.now },
dateUpdated: { type: Date, default: Date.now },
});
diff --git a/server/src/models/Order.ts b/server/src/models/Order.ts
index 340c0b9..66ec14f 100644
--- a/server/src/models/Order.ts
+++ b/server/src/models/Order.ts
@@ -33,6 +33,7 @@ export interface IOrder extends Document {
dateOrdered: Date;
dateShipped?: Date;
dateDelivered?: Date;
+ userId: mongoose.Types.ObjectId;
dateCreated: Date;
dateUpdated: Date;
}
@@ -78,6 +79,7 @@ const OrderSchema: Schema = new Schema({
dateOrdered: { type: Date, required: true },
dateShipped: { type: Date },
dateDelivered: { type: Date },
+ userId: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true },
dateCreated: { type: Date, default: Date.now },
dateUpdated: { type: Date, default: Date.now }
});
diff --git a/server/src/models/Product.ts b/server/src/models/Product.ts
index aeab547..02b2997 100644
--- a/server/src/models/Product.ts
+++ b/server/src/models/Product.ts
@@ -29,6 +29,7 @@ export interface IProduct extends Document {
materials: string[];
isActive: boolean;
etsyListingId?: string;
+ userId: mongoose.Types.ObjectId;
dateCreated: Date;
dateUpdated: Date;
}
@@ -62,6 +63,7 @@ const ProductSchema: Schema = new Schema({
materials: [{ type: String }],
isActive: { type: Boolean, default: true },
etsyListingId: { type: String },
+ userId: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true },
dateCreated: { type: Date, default: Date.now },
dateUpdated: { type: Date, default: Date.now }
});
diff --git a/server/src/routes/analytics.ts b/server/src/routes/analytics.ts
index 9d0ffa4..2a7d11e 100644
--- a/server/src/routes/analytics.ts
+++ b/server/src/routes/analytics.ts
@@ -1,40 +1,42 @@
-import { Router, Request, Response } from 'express';
+import { Router, Response } from 'express';
+import mongoose from 'mongoose';
import Order from '../models/Order';
import Product from '../models/Product';
import Customer from '../models/Customer';
import Expense from '../models/Expense';
+import { AuthRequest } from '../middleware/authenticate';
const router = Router();
-router.get('/dashboard', async (req: Request, res: Response) => {
+router.get('/dashboard', async (req: AuthRequest, res: Response) => {
try {
+ const userId = new mongoose.Types.ObjectId(req.userId);
+
const [totalOrders, totalProducts, totalCustomers, revenueResult, expenseResult, recentOrders] = await Promise.all([
- Order.countDocuments({ paymentStatus: 'paid' }),
- Product.countDocuments({ isActive: true }),
- Customer.countDocuments(),
+ Order.countDocuments({ userId, paymentStatus: 'paid' }),
+ Product.countDocuments({ userId, isActive: true }),
+ Customer.countDocuments({ userId }),
Order.aggregate([
- { $match: { paymentStatus: 'paid' } },
+ { $match: { userId, paymentStatus: 'paid' } },
{ $group: { _id: null, total: { $sum: '$total' } } },
]),
Expense.aggregate([
+ { $match: { userId } },
{ $group: { _id: null, total: { $sum: '$amount' } } },
]),
- Order.find({ paymentStatus: 'paid' })
+ Order.find({ userId, paymentStatus: 'paid' })
.populate('customerId', 'name email')
.sort({ dateOrdered: -1 })
.limit(5),
]);
- const totalRevenue = revenueResult[0]?.total ?? 0;
- const totalExpenses = expenseResult[0]?.total ?? 0;
-
const twelveMonthsAgo = new Date();
twelveMonthsAgo.setMonth(twelveMonthsAgo.getMonth() - 11);
twelveMonthsAgo.setDate(1);
twelveMonthsAgo.setHours(0, 0, 0, 0);
const salesChart = await Order.aggregate([
- { $match: { paymentStatus: 'paid', dateOrdered: { $gte: twelveMonthsAgo } } },
+ { $match: { userId, paymentStatus: 'paid', dateOrdered: { $gte: twelveMonthsAgo } } },
{
$group: {
_id: { year: { $year: '$dateOrdered' }, month: { $month: '$dateOrdered' } },
@@ -46,8 +48,8 @@ router.get('/dashboard', async (req: Request, res: Response) => {
]);
res.json({
- totalRevenue,
- totalExpenses,
+ totalRevenue: revenueResult[0]?.total ?? 0,
+ totalExpenses: expenseResult[0]?.total ?? 0,
totalOrders,
totalProducts,
totalCustomers,
@@ -59,10 +61,11 @@ router.get('/dashboard', async (req: Request, res: Response) => {
}
});
-router.get('/sales', async (req: Request, res: Response) => {
+router.get('/sales', async (req: AuthRequest, res: Response) => {
try {
+ const userId = new mongoose.Types.ObjectId(req.userId);
const { from, to } = req.query;
- const match: any = { paymentStatus: 'paid' };
+ const match: any = { userId, paymentStatus: 'paid' };
if (from || to) {
match.dateOrdered = {};
if (from) match.dateOrdered.$gte = new Date(from as string);
@@ -87,10 +90,11 @@ router.get('/sales', async (req: Request, res: Response) => {
}
});
-router.get('/products', async (req: Request, res: Response) => {
+router.get('/products', async (req: AuthRequest, res: Response) => {
try {
+ const userId = new mongoose.Types.ObjectId(req.userId);
const topProducts = await Order.aggregate([
- { $match: { paymentStatus: 'paid' } },
+ { $match: { userId, paymentStatus: 'paid' } },
{ $unwind: '$items' },
{
$group: {
@@ -103,20 +107,18 @@ router.get('/products', async (req: Request, res: Response) => {
{ $sort: { totalRevenue: -1 } },
{ $limit: 10 },
]);
-
res.json(topProducts);
} catch (err) {
res.status(500).json({ message: 'Failed to fetch product analytics', error: err });
}
});
-router.get('/customers', async (req: Request, res: Response) => {
+router.get('/customers', async (req: AuthRequest, res: Response) => {
try {
- const topCustomers = await Customer.find()
+ const topCustomers = await Customer.find({ userId: req.userId })
.sort({ totalSpent: -1 })
.limit(10)
.select('name email totalOrders totalSpent');
-
res.json(topCustomers);
} catch (err) {
res.status(500).json({ message: 'Failed to fetch customer analytics', error: err });
diff --git a/server/src/routes/customers.ts b/server/src/routes/customers.ts
index 664de29..7b6f7c7 100644
--- a/server/src/routes/customers.ts
+++ b/server/src/routes/customers.ts
@@ -1,25 +1,26 @@
-import { Router, Request, Response } from 'express';
+import { Router, Response } from 'express';
import Customer from '../models/Customer';
+import { AuthRequest } from '../middleware/authenticate';
const router = Router();
-router.get('/', async (req: Request, res: Response) => {
+router.get('/', async (req: AuthRequest, res: Response) => {
try {
const { page = 1, limit = 20 } = req.query;
- const customers = await Customer.find()
+ const customers = await Customer.find({ userId: req.userId })
.sort({ dateCreated: -1 })
.limit(Number(limit))
.skip((Number(page) - 1) * Number(limit));
- const total = await Customer.countDocuments();
+ const total = await Customer.countDocuments({ userId: req.userId });
res.json({ customers, total, page: Number(page), limit: Number(limit) });
} catch (err) {
res.status(500).json({ message: 'Failed to fetch customers', error: err });
}
});
-router.post('/', async (req: Request, res: Response) => {
+router.post('/', async (req: AuthRequest, res: Response) => {
try {
- const customer = new Customer(req.body);
+ const customer = new Customer({ ...req.body, userId: req.userId });
await customer.save();
res.status(201).json(customer);
} catch (err) {
@@ -27,9 +28,9 @@ router.post('/', async (req: Request, res: Response) => {
}
});
-router.get('/:id', async (req: Request, res: Response) => {
+router.get('/:id', async (req: AuthRequest, res: Response) => {
try {
- const customer = await Customer.findById(req.params.id);
+ const customer = await Customer.findOne({ _id: req.params.id, userId: req.userId });
if (!customer) return res.status(404).json({ message: 'Customer not found' });
res.json(customer);
} catch (err) {
@@ -37,9 +38,13 @@ router.get('/:id', async (req: Request, res: Response) => {
}
});
-router.put('/:id', async (req: Request, res: Response) => {
+router.put('/:id', async (req: AuthRequest, res: Response) => {
try {
- const customer = await Customer.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
+ const customer = await Customer.findOneAndUpdate(
+ { _id: req.params.id, userId: req.userId },
+ req.body,
+ { new: true, runValidators: true }
+ );
if (!customer) return res.status(404).json({ message: 'Customer not found' });
res.json(customer);
} catch (err) {
diff --git a/server/src/routes/expenses.ts b/server/src/routes/expenses.ts
index 252f4ca..bcab618 100644
--- a/server/src/routes/expenses.ts
+++ b/server/src/routes/expenses.ts
@@ -1,12 +1,13 @@
-import { Router, Request, Response } from 'express';
+import { Router, Response } from 'express';
import Expense from '../models/Expense';
+import { AuthRequest } from '../middleware/authenticate';
const router = Router();
-router.get('/', async (req: Request, res: Response) => {
+router.get('/', async (req: AuthRequest, res: Response) => {
try {
const { page = 1, limit = 20, category } = req.query;
- const filter: any = {};
+ const filter: any = { userId: req.userId };
if (category) filter.category = category;
const expenses = await Expense.find(filter)
@@ -21,9 +22,9 @@ router.get('/', async (req: Request, res: Response) => {
}
});
-router.post('/', async (req: Request, res: Response) => {
+router.post('/', async (req: AuthRequest, res: Response) => {
try {
- const expense = new Expense(req.body);
+ const expense = new Expense({ ...req.body, userId: req.userId });
await expense.save();
res.status(201).json(expense);
} catch (err) {
@@ -31,9 +32,9 @@ router.post('/', async (req: Request, res: Response) => {
}
});
-router.get('/:id', async (req: Request, res: Response) => {
+router.get('/:id', async (req: AuthRequest, res: Response) => {
try {
- const expense = await Expense.findById(req.params.id);
+ const expense = await Expense.findOne({ _id: req.params.id, userId: req.userId });
if (!expense) return res.status(404).json({ message: 'Expense not found' });
res.json(expense);
} catch (err) {
@@ -41,9 +42,13 @@ router.get('/:id', async (req: Request, res: Response) => {
}
});
-router.put('/:id', async (req: Request, res: Response) => {
+router.put('/:id', async (req: AuthRequest, res: Response) => {
try {
- const expense = await Expense.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
+ const expense = await Expense.findOneAndUpdate(
+ { _id: req.params.id, userId: req.userId },
+ req.body,
+ { new: true, runValidators: true }
+ );
if (!expense) return res.status(404).json({ message: 'Expense not found' });
res.json(expense);
} catch (err) {
@@ -51,9 +56,9 @@ router.put('/:id', async (req: Request, res: Response) => {
}
});
-router.delete('/:id', async (req: Request, res: Response) => {
+router.delete('/:id', async (req: AuthRequest, res: Response) => {
try {
- const expense = await Expense.findByIdAndDelete(req.params.id);
+ const expense = await Expense.findOneAndDelete({ _id: req.params.id, userId: req.userId });
if (!expense) return res.status(404).json({ message: 'Expense not found' });
res.json({ message: 'Expense deleted' });
} catch (err) {
diff --git a/server/src/routes/orders.ts b/server/src/routes/orders.ts
index e7eb909..ec5ff79 100644
--- a/server/src/routes/orders.ts
+++ b/server/src/routes/orders.ts
@@ -1,13 +1,14 @@
-import { Router, Request, Response } from 'express';
+import { Router, Response } from 'express';
import Order from '../models/Order';
import Customer from '../models/Customer';
+import { AuthRequest } from '../middleware/authenticate';
const router = Router();
-router.get('/', async (req: Request, res: Response) => {
+router.get('/', async (req: AuthRequest, res: Response) => {
try {
const { page = 1, limit = 20, status, paymentStatus } = req.query;
- const filter: any = {};
+ const filter: any = { userId: req.userId };
if (status) filter.status = status;
if (paymentStatus) filter.paymentStatus = paymentStatus;
@@ -24,14 +25,15 @@ router.get('/', async (req: Request, res: Response) => {
}
});
-router.post('/', async (req: Request, res: Response) => {
+router.post('/', async (req: AuthRequest, res: Response) => {
try {
- const order = new Order(req.body);
+ const order = new Order({ ...req.body, userId: req.userId });
await order.save();
- await Customer.findByIdAndUpdate(order.customerId, {
- $inc: { totalOrders: 1, totalSpent: order.total },
- });
+ await Customer.findOneAndUpdate(
+ { _id: order.customerId, userId: req.userId },
+ { $inc: { totalOrders: 1, totalSpent: order.total } }
+ );
res.status(201).json(order);
} catch (err) {
@@ -39,9 +41,10 @@ router.post('/', async (req: Request, res: Response) => {
}
});
-router.get('/:id', async (req: Request, res: Response) => {
+router.get('/:id', async (req: AuthRequest, res: Response) => {
try {
- const order = await Order.findById(req.params.id).populate('customerId', 'name email');
+ const order = await Order.findOne({ _id: req.params.id, userId: req.userId })
+ .populate('customerId', 'name email');
if (!order) return res.status(404).json({ message: 'Order not found' });
res.json(order);
} catch (err) {
@@ -49,9 +52,13 @@ router.get('/:id', async (req: Request, res: Response) => {
}
});
-router.put('/:id', async (req: Request, res: Response) => {
+router.put('/:id', async (req: AuthRequest, res: Response) => {
try {
- const order = await Order.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
+ const order = await Order.findOneAndUpdate(
+ { _id: req.params.id, userId: req.userId },
+ req.body,
+ { new: true, runValidators: true }
+ );
if (!order) return res.status(404).json({ message: 'Order not found' });
res.json(order);
} catch (err) {
diff --git a/server/src/routes/products.ts b/server/src/routes/products.ts
index 98361a7..894bbf1 100644
--- a/server/src/routes/products.ts
+++ b/server/src/routes/products.ts
@@ -1,12 +1,13 @@
-import { Router, Request, Response } from 'express';
+import { Router, Response } from 'express';
import Product from '../models/Product';
+import { AuthRequest } from '../middleware/authenticate';
const router = Router();
-router.get('/', async (req: Request, res: Response) => {
+router.get('/', async (req: AuthRequest, res: Response) => {
try {
const { page = 1, limit = 20, category, active } = req.query;
- const filter: any = {};
+ const filter: any = { userId: req.userId };
if (category) filter.category = category;
if (active !== undefined) filter.isActive = active === 'true';
@@ -22,9 +23,9 @@ router.get('/', async (req: Request, res: Response) => {
}
});
-router.post('/', async (req: Request, res: Response) => {
+router.post('/', async (req: AuthRequest, res: Response) => {
try {
- const product = new Product(req.body);
+ const product = new Product({ ...req.body, userId: req.userId });
await product.save();
res.status(201).json(product);
} catch (err) {
@@ -32,9 +33,9 @@ router.post('/', async (req: Request, res: Response) => {
}
});
-router.get('/:id', async (req: Request, res: Response) => {
+router.get('/:id', async (req: AuthRequest, res: Response) => {
try {
- const product = await Product.findById(req.params.id);
+ const product = await Product.findOne({ _id: req.params.id, userId: req.userId });
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json(product);
} catch (err) {
@@ -42,9 +43,13 @@ router.get('/:id', async (req: Request, res: Response) => {
}
});
-router.put('/:id', async (req: Request, res: Response) => {
+router.put('/:id', async (req: AuthRequest, res: Response) => {
try {
- const product = await Product.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
+ const product = await Product.findOneAndUpdate(
+ { _id: req.params.id, userId: req.userId },
+ req.body,
+ { new: true, runValidators: true }
+ );
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json(product);
} catch (err) {
@@ -52,9 +57,9 @@ router.put('/:id', async (req: Request, res: Response) => {
}
});
-router.delete('/:id', async (req: Request, res: Response) => {
+router.delete('/:id', async (req: AuthRequest, res: Response) => {
try {
- const product = await Product.findByIdAndDelete(req.params.id);
+ const product = await Product.findOneAndDelete({ _id: req.params.id, userId: req.userId });
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json({ message: 'Product deleted' });
} catch (err) {