-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9ed2a45
Showing
94 changed files
with
38,468 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules | ||
jspm_packages | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
.DS_Store | ||
|
||
#Excluding build directory | ||
public/ | ||
|
||
.env | ||
.env.test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
const express = require('express'); | ||
const morgan = require('morgan'); | ||
const cors = require('cors'); | ||
const { swaggerUi, specs } = require('./swagger'); | ||
|
||
const app = express(); | ||
|
||
// Middleware | ||
app.use(express.json()); | ||
app.use(cors()); | ||
app.use(morgan('dev')); | ||
|
||
// Routes | ||
const userRoutes = require('./routes/userRoutes'); | ||
const expenseRoutes = require('./routes/expenseRoutes'); | ||
const incomeRoutes = require('./routes/incomeRoutes'); | ||
const budgetRoutes = require('./routes/budgetRoutes'); | ||
app.use('/api/users', userRoutes); | ||
app.use('/api/expense', expenseRoutes); | ||
app.use('/api/income', incomeRoutes); | ||
app.use('/api/budget', budgetRoutes); | ||
|
||
// Swagger docs | ||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs)); | ||
|
||
// Error Handling Middleware | ||
const { notFound, errorHandler } = require('./middleware/errorMiddleware'); | ||
app.use(notFound); | ||
app.use(errorHandler); | ||
|
||
|
||
module.exports = app; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const mongoose = require('mongoose'); | ||
|
||
const connectDB = async () => { | ||
try { | ||
const conn = await mongoose.connect(process.env.MONGO_URI, { | ||
}); | ||
console.log(`MongoDB Connected: ${conn.connection.host}`); | ||
} catch (error) { | ||
console.error(`Error: ${error.message}`); | ||
process.exit(1); | ||
} | ||
}; | ||
|
||
module.exports = connectDB; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
const asyncHandler = require('express-async-handler'); | ||
const Budget = require('../models/Budget'); | ||
|
||
// @desc Add a new budget | ||
// @route POST /api/budgets | ||
// @access Private | ||
const addBudget = asyncHandler(async (req, res) => { | ||
const { name, totalAmount, categories, startDate, endDate } = req.body; | ||
|
||
const budget = new Budget({ | ||
user: req.user._id, | ||
name, | ||
totalAmount, | ||
categories, | ||
startDate, | ||
endDate, | ||
}); | ||
|
||
const createdBudget = await budget.save(); | ||
res.status(201).json(createdBudget); | ||
}); | ||
|
||
// @desc Get all budgets | ||
// @route GET /api/budgets | ||
// @access Private | ||
const getBudgets = asyncHandler(async (req, res) => { | ||
const { startDate, endDate, category, name } = req.query; | ||
const query = { user: req.user._id }; | ||
|
||
if (startDate) { | ||
query.startDate = { ...query.startDate, $gte: new Date(startDate) }; | ||
} | ||
if (endDate) { | ||
query.endDate = { ...query.endDate, $lte: new Date(endDate) }; | ||
} | ||
if (category) { | ||
query.categories = { $elemMatch: { category } }; | ||
} | ||
if (name) { | ||
query.name = name; | ||
} | ||
|
||
const budgets = await Budget.find(query); | ||
res.json(budgets); | ||
}); | ||
|
||
|
||
// @desc Update budget | ||
// @route PUT /api/budgets/:id | ||
// @access Private | ||
const updateBudget = asyncHandler(async (req, res) => { | ||
const { name, totalAmount, categories, startDate, endDate } = req.body; | ||
const budget = await Budget.findById(req.params.id); | ||
|
||
if (budget) { | ||
budget.name = name || budget.name; | ||
budget.totalAmount = totalAmount || budget.totalAmount; | ||
budget.categories = categories || budget.categories; | ||
budget.startDate = startDate || budget.startDate; | ||
budget.endDate = endDate || budget.endDate; | ||
|
||
const updatedBudget = await budget.save(); | ||
res.json(updatedBudget); | ||
} else { | ||
res.status(404); | ||
throw new Error('Budget not found'); | ||
} | ||
}); | ||
|
||
|
||
// @desc Delete budget | ||
// @route DELETE /api/budgets/:id | ||
// @access Private | ||
const deleteBudget = asyncHandler(async (req, res) => { | ||
const budget = await Budget.findById(req.params.id); | ||
if (budget) { | ||
await budget.deleteOne(); | ||
res.json({ message: 'Budget removed' }); | ||
} else { | ||
res.status(404); | ||
throw new Error('Budget not found'); | ||
} | ||
}); | ||
|
||
module.exports = { | ||
addBudget, | ||
getBudgets, | ||
updateBudget, | ||
deleteBudget, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// backend/controllers/expenseController.js | ||
const asyncHandler = require('express-async-handler'); | ||
const Expense = require('../models/Expense'); | ||
|
||
// @desc Add new expense | ||
// @route POST /api/expense | ||
// @access Private | ||
const addExpense = asyncHandler(async (req, res) => { | ||
const { date, category, amount, tag, notes } = req.body; | ||
|
||
if (!date || !category || !amount || !tag) { | ||
res.status(400); | ||
throw new Error('Date, category, amount, and tag are required'); | ||
} | ||
|
||
const expense = new Expense({ | ||
user: req.user._id, | ||
date, | ||
category, | ||
amount, | ||
tag, | ||
notes, | ||
}); | ||
|
||
const createdExpense = await expense.save(); | ||
res.status(201).json(createdExpense); | ||
}); | ||
|
||
// @desc Get all expenses | ||
// @route GET /api/expense | ||
// @access Private | ||
const getExpenses = asyncHandler(async (req, res) => { | ||
const { category, startDate, endDate, minAmount, maxAmount, tag } = req.query; | ||
|
||
const query = { user: req.user._id }; | ||
|
||
if (category) { | ||
query.category = category; | ||
} | ||
|
||
if (startDate || endDate) { | ||
query.date = {}; | ||
if (startDate) { | ||
query.date.$gte = new Date(startDate); | ||
} | ||
if (endDate) { | ||
query.date.$lte = new Date(endDate); | ||
} | ||
} | ||
|
||
if (minAmount || maxAmount) { | ||
query.amount = {}; | ||
if (minAmount) { | ||
query.amount.$gte = Number(minAmount); | ||
} | ||
if (maxAmount) { | ||
query.amount.$lte = Number(maxAmount); | ||
} | ||
} | ||
|
||
if (tag) { | ||
query.tag = tag; | ||
} | ||
|
||
const expenses = await Expense.find(query); | ||
res.json(expenses); | ||
}); | ||
|
||
// @desc Update expense | ||
// @route PUT /api/expense/:id | ||
// @access Private | ||
const updateExpense = asyncHandler(async (req, res) => { | ||
const { date, category, amount, tag, notes } = req.body; | ||
if (!date || !category || !tag || isNaN(amount) || amount < 0) { | ||
res.status(400); | ||
throw new Error('Invalid data'); | ||
} | ||
|
||
const expense = await Expense.findById(req.params.id); | ||
|
||
if (expense) { | ||
expense.date = date || expense.date; | ||
expense.category = category || expense.category; | ||
expense.amount = amount || expense.amount; | ||
expense.tag = tag || expense.tag; | ||
expense.notes = notes || expense.notes; | ||
|
||
const updatedExpense = await expense.save(); | ||
res.json(updatedExpense); | ||
} else { | ||
res.status(404); | ||
throw new Error('Expense not found'); | ||
} | ||
}); | ||
|
||
// @desc Delete expense | ||
// @route DELETE /api/expense/:id | ||
// @access Private | ||
const deleteExpense = asyncHandler(async (req, res) => { | ||
const expense = await Expense.findById(req.params.id); | ||
|
||
if (expense) { | ||
await expense.deleteOne(); | ||
res.json({ message: 'Expense removed' }); | ||
} else { | ||
res.status(404); | ||
throw new Error('Expense not found'); | ||
} | ||
}); | ||
|
||
module.exports = { | ||
addExpense, | ||
getExpenses, | ||
updateExpense, | ||
deleteExpense, | ||
}; | ||
|
Oops, something went wrong.