create-myexam-app 1.0.24 → 1.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/index.js +28 -26
  2. package/package.json +1 -1
  3. package/projects/Elysee File/# Full-Stack [SUBJECT] Management S.txt +200 -0
  4. package/projects/SRMS/backend/config/db.js +12 -0
  5. package/projects/SRMS/backend/controllers/authController.js +90 -0
  6. package/projects/SRMS/backend/controllers/customerController.js +45 -0
  7. package/projects/SRMS/backend/controllers/productController.js +44 -0
  8. package/projects/SRMS/backend/controllers/reportsController.js +44 -0
  9. package/projects/SRMS/backend/controllers/salesController.js +88 -0
  10. package/projects/SRMS/backend/middleware/auth.js +28 -13
  11. package/projects/SRMS/backend/models/User.js +26 -6
  12. package/projects/SRMS/backend/models/customer.js +36 -0
  13. package/projects/SRMS/backend/models/product.js +30 -0
  14. package/projects/SRMS/backend/models/sales.js +44 -0
  15. package/projects/SRMS/backend/package-lock.json +2190 -1568
  16. package/projects/SRMS/backend/package.json +23 -23
  17. package/projects/SRMS/backend/routes/authRoutes.js +11 -0
  18. package/projects/SRMS/backend/routes/customerRoutes.js +12 -0
  19. package/projects/SRMS/backend/routes/productRoutes.js +12 -0
  20. package/projects/SRMS/backend/routes/protectedRoutes.js +13 -0
  21. package/projects/SRMS/backend/routes/reportsRoutes.js +10 -0
  22. package/projects/SRMS/backend/routes/salesRoutes.js +15 -0
  23. package/projects/SRMS/backend/server.js +22 -17
  24. package/projects/SRMS/frontend/index.html +1 -1
  25. package/projects/SRMS/frontend/package-lock.json +24 -24
  26. package/projects/SRMS/frontend/package.json +1 -1
  27. package/projects/SRMS/frontend/src/App.jsx +28 -32
  28. package/projects/SRMS/frontend/src/components/Dashboard.jsx +32 -0
  29. package/projects/SRMS/frontend/src/components/Layout.jsx +104 -0
  30. package/projects/SRMS/frontend/src/components/ProtectedRoute.jsx +22 -0
  31. package/projects/SRMS/frontend/src/index.css +57 -1
  32. package/projects/SRMS/frontend/src/pages/Customer.jsx +127 -104
  33. package/projects/SRMS/frontend/src/pages/Login.jsx +76 -52
  34. package/projects/SRMS/frontend/src/pages/Product.jsx +116 -95
  35. package/projects/SRMS/frontend/src/pages/Profile.jsx +67 -0
  36. package/projects/SRMS/frontend/src/pages/Register.jsx +111 -56
  37. package/projects/SRMS/frontend/src/pages/Reports.jsx +72 -229
  38. package/projects/SRMS/frontend/src/pages/Sales.jsx +269 -0
  39. package/projects/SRMS/frontend/vite.config.js +1 -4
  40. package/projects/SRMS/backend/.env +0 -4
  41. package/projects/SRMS/backend/controllers/CustomerControllers.js +0 -29
  42. package/projects/SRMS/backend/controllers/ProductControllers.js +0 -31
  43. package/projects/SRMS/backend/controllers/SaleControllers.js +0 -49
  44. package/projects/SRMS/backend/controllers/UserControllers.js +0 -40
  45. package/projects/SRMS/backend/db/connectDB.js +0 -11
  46. package/projects/SRMS/backend/models/Customer.js +0 -13
  47. package/projects/SRMS/backend/models/Product.js +0 -9
  48. package/projects/SRMS/backend/models/Sale.js +0 -12
  49. package/projects/SRMS/backend/routes/CustomerRoutes.js +0 -11
  50. package/projects/SRMS/backend/routes/ProductRoutes.js +0 -11
  51. package/projects/SRMS/backend/routes/SaleRoutes.js +0 -13
  52. package/projects/SRMS/backend/routes/UserRoutes.js +0 -11
  53. package/projects/SRMS/frontend/App.jsx +0 -6
  54. package/projects/SRMS/frontend/README.md +0 -16
  55. package/projects/SRMS/frontend/public/icons.svg +0 -24
  56. package/projects/SRMS/frontend/src/App.css +0 -184
  57. package/projects/SRMS/frontend/src/assets/hero.png +0 -0
  58. package/projects/SRMS/frontend/src/assets/react.svg +0 -1
  59. package/projects/SRMS/frontend/src/assets/vite.svg +0 -1
  60. package/projects/SRMS/frontend/src/axiosInstance.js +0 -11
  61. package/projects/SRMS/frontend/src/components/Navbar.jsx +0 -30
  62. package/projects/SRMS/frontend/src/pages/Dashboard.jsx +0 -31
  63. package/projects/SRMS/frontend/src/pages/Sale.jsx +0 -228
package/index.js CHANGED
@@ -10,19 +10,20 @@ const rl = readline.createInterface({
10
10
  output: process.stdout
11
11
  })
12
12
  console.log('\n[1] Car Repair Parking Managemnt System')
13
- console.log('[2]Employee Payroll Management System')
14
- console.log('[3]Employee Payroll Management System Elysee')
15
- console.log('[4]middleware')
16
- console.log('[5] Parking Management System')
17
- console.log('[6]Supply Chain Managemnt System')
18
- console.log('[7]Supply Chain Management System Elysee')
19
- console.log('[8] School fee Management System')
20
- console.log('[9]Stock Hub Management System')
21
- console.log('[10]Stock Invetory Management System')
22
- console.log('[11]Stock Management System')
23
- console.log('[12]Sales Record Management System')
24
- console.log('[13]Sales Record Management System Elysee')
25
- console.log('[14]userController.js')
13
+ console.log('[2]Elysee File Prompt')
14
+ console.log('[3]Employee Payroll Management System')
15
+ console.log('[4]Employee Payroll Management System Elysee')
16
+ console.log('[5]middleware')
17
+ console.log('[6] Parking Management System')
18
+ console.log('[7]Supply Chain Managemnt System')
19
+ console.log('[8]Supply Chain Management System Elysee')
20
+ console.log('[9] School fee Management System')
21
+ console.log('[10]Stock Hub Management System')
22
+ console.log('[11]Stock Invetory Management System')
23
+ console.log('[12]Stock Management System')
24
+ console.log('[13]Sales Record Management System')
25
+ console.log('[14]Sales Record Management System Elysee')
26
+ console.log('[15]userController.js')
26
27
 
27
28
 
28
29
 
@@ -31,19 +32,20 @@ rl.question('Pick (1-14): ', (answer) => {
31
32
 
32
33
  const projects = {
33
34
  '1':'crpms',
34
- '2':'EPMS',
35
- '3':'EPMS(Ely)',
36
- '4':'middleware',
37
- '5': 'parking managementt system',
38
-
39
- '7':'SCMS(Ely)',
40
- '8': 'sfms-app',
41
- '9':'SHMS(Ely)',
42
- '10':'sims',
43
- '11': 'SMS-',
44
- '12':'SRMS',
45
- '13':'SRMS(Ely)',
46
- '14':'user',
35
+ '2':'Elysee File',
36
+ '3':'EPMS',
37
+ '4':'EPMS(Ely)',
38
+ '5':'middleware',
39
+ '6': 'parking managementt system',
40
+ '7':'SCMS',
41
+ '8':'SCMS(Ely)',
42
+ '9': 'sfms-app',
43
+ '10':'SHMS(Ely)',
44
+ '11':'sims',
45
+ '12': 'SMS-',
46
+ '13':'SRMS',
47
+ '14':'SRMS(Ely)',
48
+ '15':'user',
47
49
 
48
50
 
49
51
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "name": "create-myexam-app",
4
4
 
5
- "version": "1.0.24",
5
+ "version": "1.0.26",
6
6
 
7
7
  "description": "My exam projects",
8
8
 
@@ -0,0 +1,200 @@
1
+ # Full-Stack [SUBJECT] Management System
2
+
3
+ ## Project Overview
4
+ A full-stack web application for managing **[SUBJECT]** records. The system provides CRUD operations, authentication, and reporting functionality through a RESTful API backend and a React-based single-page frontend.
5
+
6
+ ## Tech Stack
7
+ - **Frontend:** React 18 + Vite + React Router v6 + Axios
8
+ - **Backend:** Node.js + Express 4 + JWT authentication + bcrypt
9
+ - **Database:** MongoDB + Mongoose ODM
10
+ - **Styling:** Custom CSS (no framework)
11
+ - **Build:** Vite (frontend), Nodemon (backend dev)
12
+
13
+ ## Architecture
14
+ Full-stack MERN pattern:
15
+
16
+ ```
17
+ Frontend (React/Vite) --HTTP--> Backend (Express API) --Mongoose--> MongoDB
18
+ localhost:5173 localhost:5000 localhost:27017
19
+ ```
20
+
21
+ ## Backend Structure
22
+
23
+ ### Entry Point: `server.js`
24
+ - Express app setup with CORS (origins: localhost:5173, 5174)
25
+ - Connects to MongoDB, starts listening on PORT (default 5000)
26
+ - Mounts all route groups under `/api/`
27
+
28
+ ### Authentication (`middleware/authMiddleware.js`)
29
+ - JWT-based bearer token verification
30
+ - Extracts token from `Authorization: Bearer <token>` header
31
+ - Attaches decoded user (`{ id, username }`) to `req.user`
32
+ - Returns 401 on missing/invalid/expired token
33
+
34
+ ### Data Models (`models/`)
35
+ | Model | Key Fields |
36
+ |---------|---------------------------------------------------------------------------|
37
+ | User | username (unique), password (hashed with bcrypt) |
38
+ | [A] | code (unique), name, additional fields per subject |
39
+ | [B] | code (unique), name, quantity, unit price |
40
+ | [C] | invoice number (unique), date, payment method, total amount, customer ref, line items |
41
+
42
+ ### API Routes
43
+ | Method | Endpoint | Auth | Description |
44
+ |--------|---------------------|------|---------------------------------|
45
+ | POST | /api/auth/register | No | Register new user |
46
+ | POST | /api/auth/login | No | Login, returns JWT token |
47
+ | GET | /api/[A] | JWT | List all [A] records |
48
+ | POST | /api/[A] | JWT | Create new [A] record |
49
+ | GET | /api/[B] | JWT | List all [B] records |
50
+ | POST | /api/[B] | JWT | Create new [B] record |
51
+ | GET | /api/[C] | JWT | List all [C] records |
52
+ | GET | /api/[C]/:id | JWT | Get single [C] record |
53
+ | POST | /api/[C] | JWT | Create [C] record |
54
+ | PUT | /api/[C]/:id | JWT | Update [C] record |
55
+ | DELETE | /api/[C]/:id | JWT | Delete [C] record |
56
+ | GET | /api/reports/daily | JWT | Daily report (date filter) |
57
+ | GET | /api/reports/weekly | JWT | Weekly report (week filter) |
58
+ | GET | /api/reports/monthly| JWT | Monthly report (year/month) |
59
+
60
+ ### Controllers (`controllers/`)
61
+ Each controller handles request validation, database interaction, and response formatting:
62
+ - **authController** — register (hash password, create user, return JWT), login (verify credentials, return JWT)
63
+ - **[A]Controller** — list (all sorted by newest), create (validate fields, check duplicate code)
64
+ - **[B]Controller** — list (all sorted by newest), create (validate fields, check duplicate code)
65
+ - **[C]Controller** — full CRUD: list, getById, create, update, delete; populates related [A] reference
66
+ - **reportController** — daily/weekly/monthly aggregation with date range filtering, totals calculation
67
+
68
+ ## Frontend Structure
69
+
70
+ ### Entry: `index.html` → `main.jsx` → `App.jsx`
71
+ - React StrictMode wrapping root App component
72
+ - Global CSS import
73
+
74
+ ### App Component (`App.jsx`)
75
+ - **State:** session (localStorage-persisted token + user), notice (notification messages)
76
+ - **Session management:** saveSession (localStorage + state), logout (clear both)
77
+ - **Routing (React Router v6):**
78
+ - `/login` — Login page
79
+ - `/register` — Register page
80
+ - `/dashboard` — Protected dashboard with stats overview
81
+ - `/[A]` — Protected [A] list/create page
82
+ - `/[B]` — Protected [B] list/create page
83
+ - `/[C]` — Protected [C] full CRUD page
84
+ - `/reports` — Protected reports page (daily/weekly/monthly)
85
+ - `/` — Redirects to dashboard or login
86
+ - `*` — Catch-all redirect
87
+ - **Protected wrapper:** Redirects to `/login` if no session
88
+ - **TopNav:** Navigation bar with links, username, logout button (hidden on print via `.no-print`)
89
+ - **Notice bar:** Dismissible notification messages
90
+ - API base URL: `http://localhost:5000/api` (hardcoded)
91
+
92
+ ### Pages (`src/pages/`)
93
+
94
+ #### Login (`Login.jsx`)
95
+ - Username/password form
96
+ - Validates non-empty fields
97
+ - POSTs to `/api/auth/login`, stores session, redirects to dashboard
98
+ - Link to register page
99
+
100
+ #### Register (`Register.jsx`)
101
+ - Username/password/confirm password form
102
+ - Validates non-empty fields, password match, password >= 4 chars
103
+ - POSTs to `/api/auth/register`, stores session, redirects to dashboard
104
+ - Link back to login
105
+
106
+ #### Dashboard (`Dashboard.jsx`)
107
+ - Fetches counts from all 3 record types on mount (parallel GET requests)
108
+ - Displays 4 stat cards: Total [A], Total [B], Total [C], Total Revenue in [CURRENCY]
109
+ - Quick action links to add new records
110
+
111
+ #### [A] Records (`[A].jsx`)
112
+ - Form with fields per [A] schema + submit button
113
+ - Validates all fields, POSTs to create endpoint
114
+ - Table listing all records with their fields
115
+ - Currency formatting where applicable
116
+
117
+ #### [B] Records (`[B].jsx`)
118
+ - Form with fields per [B] schema + submit button
119
+ - Validates fields (including numeric), POSTs to create endpoint
120
+ - Table listing all records with computed totals
121
+ - Currency formatting in [CURRENCY]
122
+
123
+ #### [C] Records (`[C].jsx`)
124
+ - Form with fields per [C] schema + [A] dropdown selector + submit/update/cancel buttons
125
+ - Full CRUD: create (POST), edit (PUT with populated form), delete (DELETE with confirmation)
126
+ - Fetches both [C] records and [A] list on mount
127
+ - Table with all [C] fields and action buttons (Edit/Delete)
128
+
129
+ #### Reports (`Reports.jsx`)
130
+ - Daily / Weekly / Monthly toggle buttons
131
+ - Date picker (daily/weekly) or month picker (monthly)
132
+ - "Generate Report" button triggers filtered API call
133
+ - "Print" button uses `window.print()`, nav hidden via CSS `@media print`
134
+ - Report summary: Total Transactions, Total Revenue, Average per [C]
135
+ - Report table with [C] details
136
+
137
+ ### Styling (`index.css`)
138
+ - Global reset, blue primary color `#1E3A8A`
139
+ - Responsive layout with max-width 1100px
140
+ - 4-column stat card grid
141
+ - Form grids (5-column, variants for 3/4 fields)
142
+ - Scrollable tables with striped headers and hover rows
143
+ - Centered auth card layout
144
+ - Report filters and summary sections
145
+ - Print media query hiding navigation
146
+ - Responsive breakpoints at 950px and 620px
147
+
148
+ ## Configuration
149
+
150
+ ### Backend (`.env`)
151
+ ```
152
+ PORT=5000
153
+ MONGO_URI=mongodb://127.0.0.1:27017/[DB_NAME]
154
+ JWT_SECRET=[JWT_SECRET_KEY]
155
+ ```
156
+
157
+ ### Frontend (`package.json`)
158
+ - Scripts: `dev` (vite), `build` (vite build), `preview` (vite preview)
159
+ - Port: 5173 (Vite dev server)
160
+
161
+ ## Authentication Flow
162
+ 1. User registers or logs in → backend returns JWT (expires 1 day, payload: `{ id, username }`)
163
+ 2. Frontend stores token + user in `localStorage` under key `[SESSION_KEY]`
164
+ 3. All API calls include `Authorization: Bearer <token>` header
165
+ 4. Backend `authMiddleware` verifies JWT on every protected route
166
+ 5. 401 response → frontend redirects to login
167
+
168
+ ## Key Design Decisions
169
+ - No JSX in App.jsx (uses `React.createElement`); page components use JSX
170
+ - No state management library (plain React state + localStorage)
171
+ - No form validation library (manual validation)
172
+ - No pagination (all records fetched at once)
173
+ - No testing framework
174
+ - Currency displayed in [CURRENCY]
175
+ - Print support via CSS `@media print` and `window.print()`
176
+ - Passwords hashed with bcrypt (10 salt rounds)
177
+ - CORS restricted to localhost:5173/5174
178
+ - No input sanitization library
179
+
180
+ ## Setup Instructions
181
+
182
+ ### Backend
183
+ ```bash
184
+ cd backend-project
185
+ npm install
186
+ # Configure .env with your MongoDB URI and JWT secret
187
+ npm run dev # or npm start
188
+ ```
189
+
190
+ ### Frontend
191
+ ```bash
192
+ cd frontend-project
193
+ npm install
194
+ npm run dev
195
+ ```
196
+
197
+ ### First Use
198
+ 1. Open `http://localhost:5173`
199
+ 2. Register a new account
200
+ 3. Start managing [SUBJECT] records
@@ -0,0 +1,12 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const connectDB = async () => {
4
+ try {
5
+ await mongoose.connect('mongodb://localhost:27017/SRMS');
6
+ console.log('MongoDB connected');
7
+ } catch (error) {
8
+ console.error('MongoDB connection error:', error);
9
+ }
10
+ };
11
+
12
+ module.exports = connectDB;
@@ -0,0 +1,90 @@
1
+ const bcrypt = require('bcrypt');
2
+ const jwt = require('jsonwebtoken');
3
+ const User = require('../models/User');
4
+ const JWT_SECRET = 'change_this_to_a_long_random_secret';
5
+
6
+
7
+
8
+ function createToken(userId) {
9
+ return jwt.sign({ userId },JWT_SECRET, { expiresIn: '7d' });
10
+ }
11
+
12
+ function formatUser(user) {
13
+ return {
14
+ id: user._id,
15
+ name: user.name,
16
+ email: user.email,
17
+ };
18
+ }
19
+
20
+ exports.register = async (req, res) => {
21
+ try {
22
+ const { name, email, password } = req.body;
23
+
24
+ if (!name || !email || !password) {
25
+ return res.status(400).json({ message: 'Name, email, and password are required' });
26
+ }
27
+
28
+ if (password.length < 6) {
29
+ return res.status(400).json({ message: 'Password must be at least 6 characters' });
30
+ }
31
+
32
+ const existing = await User.findOne({ email: email.toLowerCase() });
33
+ if (existing) {
34
+ return res.status(409).json({ message: 'Email already registered' });
35
+ }
36
+
37
+ const hashedPassword = await bcrypt.hash(password, 10);
38
+ const user = await User.create({
39
+ name,
40
+ email: email.toLowerCase(),//to ensure the email is always lowercase
41
+ password: hashedPassword,
42
+ });
43
+
44
+ const token = createToken(user._id);
45
+
46
+ res.status(201).json({
47
+ token,
48
+ user: formatUser(user),
49
+ });
50
+ } catch (err) {
51
+ res.status(500).json({ message: err.message });
52
+ }
53
+ }
54
+
55
+ exports.login = async (req, res) => {
56
+ try {
57
+ const { email, password } = req.body;
58
+
59
+ if (!email || !password) {
60
+ return res.status(400).json({ message: 'Email and password are required' });
61
+ }
62
+
63
+ const user = await User.findOne({ email: email.toLowerCase() });
64
+ if (!user) {
65
+ return res.status(401).json({ message: 'Invalid email or password' });
66
+ }
67
+
68
+ const match = await bcrypt.compare(password, user.password);
69
+ if (!match) {
70
+ return res.status(401).json({ message: 'Invalid email or password' });
71
+ }
72
+
73
+ const token = createToken(user._id);
74
+
75
+ res.json({
76
+ token,
77
+ user: formatUser(user),
78
+ });
79
+ } catch (err) {
80
+ res.status(500).json({ message: err.message });
81
+ }
82
+ }
83
+
84
+ exports.getMe = async (req, res) => {
85
+ try {
86
+ res.json({ user: formatUser(req.user) });
87
+ } catch (err) {
88
+ res.status(500).json({ message: err.message });
89
+ }
90
+ };
@@ -0,0 +1,45 @@
1
+ const Customer = require('../models/customer');
2
+
3
+ exports.addcustomer = async (req, res) => {
4
+ try {
5
+ const { customerNumber, firstName, lastName, telephone, address } = req.body;
6
+
7
+ const existingCustomer = await Customer.findOne({ customerNumber });
8
+ if (existingCustomer) {
9
+ return res.status(409).json({ message: 'Customer number already exists' });
10
+ }
11
+
12
+ const customer = await Customer.create({
13
+ customerNumber,
14
+ firstName,
15
+ lastName,
16
+ telephone,
17
+ address,
18
+ });
19
+
20
+ res.status(201).json(customer);
21
+ } catch (err) {
22
+ res.status(500).json({ message: err.message });
23
+ }
24
+ };
25
+
26
+ exports.getcustomers = async (req, res) => {
27
+ try {
28
+ const customers = await Customer.find().sort({ createdAt: -1 });
29
+ res.json(customers);
30
+ } catch (err) {
31
+ res.status(500).json({ message: err.message });
32
+ }
33
+ };
34
+
35
+ exports.getcustomerbyid = async (req, res) => {
36
+ try {
37
+ const customer = await Customer.findById(req.params.id);
38
+ if (!customer) {
39
+ return res.status(404).json({ message: 'Customer not found' });
40
+ }
41
+ res.json(customer);
42
+ } catch (err) {
43
+ res.status(500).json({ message: err.message });
44
+ }
45
+ };
@@ -0,0 +1,44 @@
1
+ const Product = require('../models/product');
2
+
3
+ exports.getproduct = async (req, res) => {
4
+ try {
5
+ const products = await Product.find().sort({ createdAt: -1 });
6
+ res.json(products);
7
+ } catch (err) {
8
+ res.status(500).json({ message: err.message });
9
+ }
10
+ };
11
+
12
+ exports.getproductbyid = async (req, res) => {
13
+ try {
14
+ const product = await Product.findById(req.params.id);
15
+ if (!product) {
16
+ return res.status(404).json({ message: 'Product not found' });
17
+ }
18
+ res.json(product);
19
+ } catch (err) {
20
+ res.status(500).json({ message: err.message });
21
+ }
22
+ };
23
+
24
+ exports.addproduct = async (req, res) => {
25
+ try {
26
+ const { productCode, productName, quantitySold, unitPrice } = req.body;
27
+
28
+ const existing = await Product.findOne({ productCode });
29
+ if (existing) {
30
+ return res.status(409).json({ message: 'Product code already exists' });
31
+ }
32
+
33
+ const newproduct = await Product.create({
34
+ productCode,
35
+ productName,
36
+ quantitySold,
37
+ unitPrice,
38
+ });
39
+
40
+ res.status(201).json(newproduct);
41
+ } catch (err) {
42
+ res.status(500).json({ message: err.message });
43
+ }
44
+ };
@@ -0,0 +1,44 @@
1
+ const Sales = require('../models/sales');
2
+ const Product = require('../models/product');
3
+ const Customer = require('../models/customer');
4
+
5
+ const sumTotal = (items, field) => items.reduce((total, item) => total + (item[field] || 0), 0);
6
+
7
+ exports.summary = async (req, res) => {
8
+ try {
9
+ const now = new Date();
10
+ const startOfDay = new Date(now);
11
+ startOfDay.setHours(0, 0, 0, 0);
12
+
13
+ const startOfWeek = new Date(startOfDay);
14
+ startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay());
15
+
16
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
17
+
18
+ const [productCount, customerCount, salesCount] = await Promise.all([
19
+ Product.countDocuments(),
20
+ Customer.countDocuments(),
21
+ Sales.countDocuments(),
22
+ ]);
23
+
24
+ const [dailySales, weeklySales, monthlySales] = await Promise.all([
25
+ Sales.find({ salesDate: { $gte: startOfDay } }),
26
+ Sales.find({ salesDate: { $gte: startOfWeek } }),
27
+ Sales.find({ salesDate: { $gte: startOfMonth } }),
28
+ ]);
29
+
30
+ res.json({
31
+ productCount,
32
+ customerCount,
33
+ salesCount,
34
+ dailySalesTotal: sumTotal(dailySales, 'totalAmountPaid'),
35
+ weeklySalesTotal: sumTotal(weeklySales, 'totalAmountPaid'),
36
+ monthlySalesTotal: sumTotal(monthlySales, 'totalAmountPaid'),
37
+ dailySalesCount: dailySales.length,
38
+ weeklySalesCount: weeklySales.length,
39
+ monthlySalesCount: monthlySales.length,
40
+ });
41
+ } catch (err) {
42
+ res.status(500).json({ message: err.message });
43
+ }
44
+ };
@@ -0,0 +1,88 @@
1
+ const Sales = require('../models/sales');
2
+ const Product = require('../models/product');
3
+ const Customer = require('../models/customer');
4
+
5
+ exports.addsales = async (req, res) => {
6
+ try {
7
+ const { invoiceNumber, salesDate, paymentMethod, totalAmountPaid, quantitySold, productId, customerId } = req.body;
8
+
9
+ const product = await Product.findById(productId);
10
+ const customer = await Customer.findById(customerId);
11
+
12
+ if (!product) return res.status(400).json({ message: 'Product selection is required' });
13
+ if (!customer) return res.status(400).json({ message: 'Customer selection is required' });
14
+
15
+ const existing = await Sales.findOne({ invoiceNumber });
16
+ if (existing) {
17
+ return res.status(409).json({ message: 'Invoice number already exists' });
18
+ }
19
+
20
+ const sales = await Sales.create({
21
+ invoiceNumber,
22
+ salesDate,
23
+ paymentMethod,
24
+ totalAmountPaid,
25
+ quantitySold,
26
+ product_FK: productId,
27
+ customer_FK: customerId,
28
+ });
29
+
30
+ res.status(201).json(sales);
31
+ } catch (error) {
32
+ res.status(500).json({ message: error.message });
33
+ }
34
+ };
35
+
36
+ exports.getsales = async (req, res) => {
37
+ try {
38
+ const sales = await Sales.find().populate('product_FK').populate('customer_FK').sort({ salesDate: -1 });
39
+ res.status(200).json(sales);
40
+ } catch (error) {
41
+ res.status(404).json({ message: 'Sales not found' });
42
+ }
43
+ };
44
+
45
+ exports.getsalesbyid = async (req, res) => {
46
+ try {
47
+ const sale = await Sales.findById(req.params.id).populate('product_FK').populate('customer_FK');
48
+ if (!sale) {
49
+ return res.status(404).json({ message: 'Sale not found' });
50
+ }
51
+ res.status(200).json(sale);
52
+ } catch (error) {
53
+ res.status(404).json({ message: 'Failed to fetch sale' });
54
+ }
55
+ };
56
+
57
+ exports.updatesales = async (req, res) => {
58
+ try {
59
+ const { invoiceNumber, salesDate, paymentMethod, totalAmountPaid, quantitySold, productId, customerId } = req.body;
60
+ const sale = await Sales.findById(req.params.id);
61
+ if (!sale) return res.status(404).json({ message: 'Sale not found' });
62
+
63
+ sale.invoiceNumber = invoiceNumber;
64
+ sale.salesDate = salesDate;
65
+ sale.paymentMethod = paymentMethod;
66
+ sale.totalAmountPaid = totalAmountPaid;
67
+ sale.quantitySold = quantitySold;
68
+ sale.product_FK = productId;
69
+ sale.customer_FK = customerId;
70
+
71
+ await sale.save();
72
+
73
+ const updatedSale = await Sales.findById(req.params.id).populate('product_FK').populate('customer_FK');
74
+ res.status(200).json(updatedSale);
75
+ } catch (error) {
76
+ res.status(500).json({ message: error.message });
77
+ }
78
+ };
79
+
80
+ exports.deletesales = async (req, res) => {
81
+ try {
82
+ const deleted = await Sales.findByIdAndDelete(req.params.id);
83
+ if (!deleted) return res.status(404).json({ message: 'Sale not found' });
84
+ res.status(200).json({ message: 'Sale deleted successfully' });
85
+ } catch (error) {
86
+ res.status(500).json({ message: error.message });
87
+ }
88
+ };
@@ -1,17 +1,32 @@
1
+ // this middleware is helping us to protect our routes so that only authenticated users can access the routes
2
+ //it is checking if the user is authenticated by checking the token in the header(the header is the part of the request that contains the token)
3
+ //if the user is not authenticated, it will return a 401 status code and a message that the user is not authorized
4
+ //if the user is authenticated, it will return the user object
5
+ //and the user object is the user that is authenticated
1
6
 
2
- import jwt from 'jsonwebtoken'
7
+ const jwt = require('jsonwebtoken');
8
+ const User = require('../models/User');
9
+ const JWT_SECRET = 'change_this_to_a_long_random_secret';
3
10
 
4
- const protect = (req, res, next) => {
5
- const token = req.headers.authorization?.split(" ")[1];
6
- if (!token) return res.status(401).json({ message: "Not authorized" });
7
-
8
- try {
9
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
10
- req.user = decoded;
11
- next();
12
- } catch {
13
- res.status(401).json({ message: "Invalid token" });
11
+ exports.protect = async (req, res, next) => {
12
+ try {
13
+ const header = req.headers.authorization;
14
+
15
+ if (!header || !header.startsWith('Bearer ')) {
16
+ return res.status(401).json({ message: 'Not authorized' });
17
+ }
18
+
19
+ const token = header.split(' ')[1];
20
+ const decoded = jwt.verify(token, JWT_SECRET);
21
+ const user = await User.findById(decoded.userId).select('-password');
22
+
23
+ if (!user) {
24
+ return res.status(401).json({ message: 'Not authorized' });
14
25
  }
15
- }
16
26
 
17
- export default protect;
27
+ req.user = user;
28
+ next();
29
+ } catch (err) {
30
+ return res.status(401).json({ message: 'Not authorized' });
31
+ }
32
+ };
@@ -1,8 +1,28 @@
1
- import mongoose from 'mongoose'
1
+ const mongoose = require('mongoose');
2
2
 
3
- const userSchema = new mongoose.Schema({
4
- username:{type:String, required:true},
5
- password:{type:String, required:true}
6
- });
3
+ const userSchema = new mongoose.Schema(
4
+ {
5
+ name: {
6
+ type: String,
7
+ required: true,
8
+ trim: true,
9
+ },
10
+ email: {
11
+ type: String,
12
+ required: true,
13
+ unique: true,
14
+ lowercase: true,
15
+ trim: true,
16
+ },
17
+ password: {
18
+ type: String,
19
+ required: true,
20
+ minlength: 6,
21
+ },
22
+ },
23
+ { timestamps: true }
24
+ );
7
25
 
8
- export default mongoose.model("User", userSchema);
26
+ const User = mongoose.model('User', userSchema);
27
+
28
+ module.exports = User;