Skip to content

Commit 95680c2

Browse files
soleil00soleil00
authored andcommitted
added report api which will be used to fetch user,seller stats
1 parent c7ac790 commit 95680c2

File tree

14 files changed

+671
-3
lines changed

14 files changed

+671
-3
lines changed

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"cloudinary": "^2.4.0",
2323
"cookie-parser": "^1.4.7",
2424
"cors": "^2.8.5",
25+
"date-fns": "^4.1.0",
2526
"dotenv": "^16.4.5",
2627
"express": "^4.21.1",
2728
"jsonwebtoken": "^9.0.2",
@@ -56,4 +57,4 @@
5657
"ts-node": "^10.9.2",
5758
"typescript": "^5.4.5"
5859
}
59-
}
60+
}

src/controllers/admin/index.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Request, Response } from "express";
2+
import Admin from "../../models/Admin";
3+
import { decodeAdminToken, generateAdminToken } from "../../helpers/jwt";
4+
5+
export const registerAdmin = async (req: Request, res: Response) => {
6+
const { email, password } = req.body;
7+
8+
try {
9+
const existingAdmin = await Admin.findOne({ email });
10+
if (existingAdmin) {
11+
return res.status(400).json({ message: "Admin already exists." });
12+
}
13+
14+
const newAdmin = await Admin.create({ email, password });
15+
return res.status(201).json({ message: "Admin registered successfully.", admin: newAdmin });
16+
} catch (error) {
17+
return res.status(500).json({ message: "An error occurred.", error });
18+
}
19+
};
20+
21+
export const loginAdmin = async (req: Request, res: Response) => {
22+
const { email, password } = req.body;
23+
24+
try {
25+
const admin = await Admin.findOne({ email });
26+
if (!admin) {
27+
return res.status(404).json({ message: "Admin not found." });
28+
}
29+
30+
const isPasswordMatch = admin.password === password
31+
if (!isPasswordMatch) {
32+
return res.status(401).json({ message: "Invalid credentials." });
33+
}
34+
35+
const token = generateAdminToken(admin)
36+
return res.status(200).json({ message: "Login successful.", token,admin });
37+
} catch (error) {
38+
return res.status(500).json({ message: "An error occurred.", error });
39+
}
40+
};
41+
42+
export const deactivateAdmin = async (req: Request, res: Response) => {
43+
const { id } = req.params;
44+
try {
45+
const admin = await Admin.findByIdAndUpdate(id, { isActive: false }, { new: true });
46+
if (!admin) {
47+
return res.status(404).json({ message: "Admin not found." });
48+
}
49+
50+
return res.status(200).json({ message: "Admin deactivated successfully.", admin });
51+
} catch (error) {
52+
return res.status(500).json({ message: "An error occurred.", error });
53+
}
54+
};
55+
56+
export const activateAdmin = async (req: Request, res: Response) => {
57+
const { id } = req.params;
58+
59+
try {
60+
const admin = await Admin.findByIdAndUpdate(id, { isActive: true }, { new: true });
61+
if (!admin) {
62+
return res.status(404).json({ message: "Admin not found." });
63+
}
64+
65+
return res.status(200).json({ message: "Admin activated successfully.", admin });
66+
} catch (error) {
67+
return res.status(500).json({ message: "An error occurred.", error });
68+
}
69+
};
70+
71+
export const getAdminInfo = async (req: Request, res: Response) => {
72+
const token = req.headers.authorization?.split(" ")[1];
73+
74+
if (!token) {
75+
return res.status(401).json({ message: "Authorization token missing." });
76+
}
77+
78+
try {
79+
const admin = await decodeAdminToken(token)
80+
81+
if (!admin) {
82+
return res.status(404).json({ message: "Admin not found." });
83+
}
84+
85+
return res.status(200).json(admin);
86+
} catch (error) {
87+
return res.status(401).json({ message: "Invalid or expired token.", error });
88+
}
89+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Request, Response } from "express";
2+
import SanctionedRegion from "../../models/misc/SanctionedRegion";
3+
4+
5+
export const getRestrictedAreaStats = async (req: Request, res: Response) => {
6+
try {
7+
const restrictedAreas = await SanctionedRegion.find()
8+
return res.status(200).json({
9+
restrictedAreas
10+
});
11+
} catch (error) {
12+
return res.status(500).json({
13+
success: false,
14+
message: "Error fetching restricted areas",
15+
error: error
16+
});
17+
}
18+
}
19+
20+
export const createSanctionedRegion = async (req: Request, res: Response) => {
21+
try {
22+
const { location, boundary } = req.body;
23+
24+
const newSanctionedRegion = await SanctionedRegion.create({
25+
location,
26+
boundary: {
27+
type: "Polygon",
28+
coordinates: boundary
29+
}
30+
});
31+
32+
return res.status(201).json({
33+
success: true,
34+
message: "Sanctioned region created successfully",
35+
data: newSanctionedRegion
36+
});
37+
} catch (error) {
38+
return res.status(500).json({
39+
success: false,
40+
message: "Error creating sanctioned region",
41+
error: error
42+
});
43+
}
44+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Request, Response } from "express";
2+
import ReviewFeedback from "../../models/ReviewFeedback";
3+
import User from "../../models/User";
4+
5+
export const getReviewStatistics = async (req: Request, res: Response) => {
6+
try {
7+
const page = parseInt(req.query.page as string) || 1;
8+
const limit = parseInt(req.query.limit as string) || 20;
9+
10+
const skip = (page - 1) * limit;
11+
const totalReviews = await ReviewFeedback.countDocuments();
12+
const reviews = await ReviewFeedback.find()
13+
.sort({ createdAt: -1 })
14+
.skip(skip)
15+
.limit(limit);
16+
17+
const totalPages = Math.ceil(totalReviews / limit);
18+
const hasNextPage = page < totalPages;
19+
const hasPrevPage = page > 1;
20+
21+
const mappedReviews = await Promise.all(
22+
reviews.map(async (review) => {
23+
const reviewerUser = await User.findOne({ pi_uid: review.review_giver_id });
24+
const sellerUser = await User.findOne({ pi_uid: review.review_receiver_id });
25+
26+
return {
27+
id: review._id,
28+
reviewer: reviewerUser?.pi_username ||review.review_giver_id,
29+
seller: sellerUser?.pi_username || review.review_receiver_id ,
30+
rating: review.rating,
31+
comment: review.comment,
32+
date: review.review_date.toISOString().split("T")[0],
33+
};
34+
})
35+
);
36+
37+
38+
const mostReviewedUser = await ReviewFeedback.aggregate([
39+
{ $group: { _id: "$review_receiver_id", count: { $sum: 1 } } },
40+
{ $sort: { count: -1 } },
41+
{ $limit: 1 },
42+
]);
43+
44+
const user = await User.findOne({
45+
pi_uid: mostReviewedUser[0]?._id,
46+
});
47+
48+
49+
const now = new Date();
50+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
51+
const startOfNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
52+
53+
const currentMonthReviews = await ReviewFeedback.countDocuments({
54+
review_date: { $gte: startOfMonth, $lt: startOfNextMonth },
55+
});
56+
57+
const currentMonthReviewPercentage =
58+
totalReviews > 0
59+
? ((currentMonthReviews / totalReviews) * 100).toFixed(2)
60+
: "0.00";
61+
62+
res.status(200).json({
63+
reviews:mappedReviews,
64+
totalReviews,
65+
mostReviewedUser: {
66+
user: user || null,
67+
count: mostReviewedUser[0]?.count || 0,
68+
},
69+
currentMonthReviews,
70+
currentMonthReviewPercentage: `${currentMonthReviewPercentage}`,
71+
pagination: {
72+
currentPage: page,
73+
totalPages,
74+
hasNextPage,
75+
hasPrevPage,
76+
totalReviews
77+
},
78+
});
79+
} catch (error) {
80+
res.status(500).json({ message: "Failed to fetch review statistics", error });
81+
}
82+
};
83+
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
2+
3+
import { Request, Response } from "express";
4+
import Seller from "../../models/Seller";
5+
// import logger from "../../config/loggingConfig";
6+
7+
export const getSellerStatistics = async (req: Request, res: Response) => {
8+
try {
9+
const page = parseInt(req.query.page as string) || 1;
10+
const limit = parseInt(req.query.limit as string) || 15;
11+
12+
const skip = (page - 1) * limit;
13+
const totalSellers = await Seller.countDocuments();
14+
const sellers = await Seller.find()
15+
.sort({ createdAt: -1 })
16+
.skip(skip)
17+
.limit(limit);
18+
19+
const totalPages = Math.ceil(totalSellers / limit);
20+
const hasNextPage = page < totalPages;
21+
const hasPrevPage = page > 1;
22+
23+
24+
const now = new Date();
25+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
26+
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0);
27+
28+
const activeSellersCount = await Seller.countDocuments({ seller_type: "activeSeller" });
29+
const inactiveSellers = await Seller.countDocuments({ seller_type: "inactiveSeller" });
30+
const testSellers = await Seller.countDocuments({ seller_type: "testSeller" });
31+
32+
const sellerGrowthThisMonth = await Seller.aggregate([
33+
{
34+
$match: {
35+
createdAt: { $gte: startOfMonth, $lte: endOfMonth },
36+
},
37+
},
38+
{
39+
$group: {
40+
_id: "$seller_type",
41+
count: { $sum: 1 },
42+
},
43+
},
44+
]);
45+
46+
const sellerGrowthByTypeThisMonth = sellerGrowthThisMonth.reduce((acc, item) => {
47+
acc[item._id] = item.count;
48+
return acc;
49+
}, {});
50+
51+
const newSellersThisMonth = sellerGrowthThisMonth.reduce((sum, item) => sum + item.count, 0);
52+
53+
const percentageGrowthThisMonth =
54+
totalSellers > 0 ? (newSellersThisMonth / totalSellers) * 100 : 0;
55+
56+
const months = [
57+
"January",
58+
"February",
59+
"March",
60+
"April",
61+
"May",
62+
"June",
63+
"July",
64+
"August",
65+
"September",
66+
"October",
67+
"November",
68+
"December",
69+
];
70+
71+
const sellerGrowth = await Seller.aggregate([
72+
{
73+
$group: {
74+
_id: { $month: "$createdAt" },
75+
count: { $sum: 1 },
76+
},
77+
},
78+
{ $sort: { "_id": 1 } },
79+
]);
80+
81+
const data = sellerGrowth.map((growth) => {
82+
return {
83+
month: months[growth._id - 1],
84+
count: growth.count,
85+
};
86+
});
87+
88+
const shopDetails = sellers.map(seller => ({
89+
name: seller.name,
90+
owner: seller.seller_id,
91+
category: seller.seller_type,
92+
rating: parseFloat(seller.average_rating.toString()),
93+
status: seller.order_online_enabled_pref ? "Active" : "Inactive",
94+
address: seller.address,
95+
coordinates: seller.sell_map_center.coordinates,
96+
}));
97+
98+
99+
const statistics = {
100+
totalSellers,
101+
sellers:shopDetails,
102+
activeSellers: activeSellersCount,
103+
inactiveSellers,
104+
testSellers,
105+
newSellersThisMonth,
106+
percentageGrowthThisMonth: percentageGrowthThisMonth.toFixed(2),
107+
sellerGrowthByTypeThisMonth: {
108+
activeSeller: sellerGrowthByTypeThisMonth["activeSeller"] || 0,
109+
inactiveSeller: sellerGrowthByTypeThisMonth["inactiveSeller"] || 0,
110+
testSeller: sellerGrowthByTypeThisMonth["testSeller"] || 0,
111+
},
112+
sellerGrowth: data,
113+
pagination: {
114+
currentPage: page,
115+
totalPages,
116+
hasNextPage,
117+
hasPrevPage,
118+
},
119+
};
120+
121+
// logger.info("Fetched seller statistics for the current month successfully", statistics);
122+
123+
return res.status(200).json(statistics);
124+
} catch (error) {
125+
// logger.error("Failed to fetch seller statistics:", error);
126+
return res
127+
.status(500)
128+
.json({ message: "An error occurred while fetching seller statistics; please try again later." });
129+
}
130+
};

0 commit comments

Comments
 (0)