Skip to content

Commit edb932c

Browse files
[Enhancement] Setup Home page functional & Interactive (#1114)
* created: search projects route * drafted: no data msg * created projects count routes * feat: load more projects * feat: search functionality * created: search/user route * feat: user search functionality * fixes code formatting
1 parent 92d395f commit edb932c

File tree

12 files changed

+358
-45
lines changed

12 files changed

+358
-45
lines changed

backend/Controllers/auth.controller.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import bcrypt from "bcrypt";
2-
import {readFileSync} from "fs";
2+
import { readFileSync } from "fs";
33

44
import admin from "firebase-admin";
55
import { getAuth } from "firebase-admin/auth";
@@ -106,4 +106,21 @@ export const googleAuth = async (req, res) => {
106106
} catch (err) {
107107
return res.status(500).json({ "error": err.message });
108108
}
109+
}
110+
111+
// Search for users
112+
113+
export const searchUsers = async (req, res) => {
114+
115+
let { query } = req.body;
116+
117+
User.find({ "personal_info.username": new RegExp(query, 'i') })
118+
.limit(50)
119+
.select("personal_info.fullname personal_info.username personal_info.profile_img -_id")
120+
.then(users => {
121+
return res.status(200).json({ users });
122+
})
123+
.catch(err => {
124+
return res.status(500).json({ error: err.message });
125+
})
109126
}

backend/Controllers/project.controller.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@ export const createProject = async (req, res) => {
7070

7171
export const getProjects = async (req, res) => {
7272

73+
let { page } = req.body;
7374
let maxLimit = 5;
7475

7576
Project.find({ draft: false })
7677
.populate("author", "personal_info.profile_img personal_info.username personal_info.fullname -_id")
7778
.sort({ "publishedAt": -1 })
7879
.select("project_id title des banner tags activity publishedAt -_id")
80+
.skip((page - 1) * maxLimit)
7981
.limit(maxLimit)
8082
.then(projects => {
8183
return res.status(200).json({ projects });
@@ -98,4 +100,64 @@ export const trendingProjects = async (req, res) => {
98100
.catch(err => {
99101
return res.status(500).json({ error: err.message });
100102
})
103+
}
104+
105+
export const searchProjects = async (req, res) => {
106+
107+
let { tag, query, page } = req.body;
108+
109+
let findQuery;
110+
111+
if (tag) {
112+
findQuery = { tags: tag, draft: false };
113+
} else if (query) {
114+
findQuery = { draft: false, title: new RegExp(query, 'i') };
115+
}
116+
117+
let maxLimit = 5;
118+
119+
Project.find(findQuery)
120+
.populate("author", "personal_info.profile_img personal_info.username personal_info.fullname -_id")
121+
.sort({ "publishedAt": -1 })
122+
.select("project_id title des banner tags activity publishedAt -_id")
123+
.skip((page - 1) * maxLimit)
124+
.limit(maxLimit)
125+
.then(projects => {
126+
return res.status(200).json({ projects });
127+
})
128+
.catch(err => {
129+
return res.status(500).json({ error: err.message });
130+
})
131+
}
132+
133+
export const allLatestProjectsCount = async (req, res) => {
134+
135+
Project.countDocuments({ draft: false })
136+
.then(count => {
137+
return res.status(200).json({ totalDocs: count });
138+
})
139+
.catch(err => {
140+
return res.status(500).json({ error: err.message });
141+
})
142+
}
143+
144+
export const searchProjectsCount = async (req, res) => {
145+
146+
let { tag, query } = req.body;
147+
148+
let findQuery;
149+
150+
if (tag) {
151+
findQuery = { tags: tag, draft: false };
152+
} else if (query) {
153+
findQuery = { draft: false, title: new RegExp(query, 'i') };
154+
}
155+
156+
Project.countDocuments(findQuery)
157+
.then(count => {
158+
return res.status(200).json({ totalDocs: count });
159+
})
160+
.catch(err => {
161+
return res.status(500).json({ error: err.message });
162+
})
101163
}

backend/Routes/api/auth.routes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import express from "express";
2-
import { signup, login, googleAuth } from "../../Controllers/auth.controller.js";
2+
import { signup, login, googleAuth, searchUsers } from "../../Controllers/auth.controller.js";
33

44
const authRoutes = express.Router();
55

66
authRoutes.post("/signup", signup);
77
authRoutes.post("/login", login);
88
authRoutes.post("/google-auth", googleAuth);
9+
authRoutes.post("/search", searchUsers);
910

1011
export default authRoutes;
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import express from "express";
2-
import { createProject, getProjects, trendingProjects } from "../../Controllers/project.controller.js";
2+
import { allLatestProjectsCount, createProject, getProjects, searchProjects, searchProjectsCount, trendingProjects } from "../../Controllers/project.controller.js";
33
import { authenticateUser } from "../../Middlewares/auth.middleware.js";
44

55
const projectRoutes = express.Router();
66

77
projectRoutes.post("/create", authenticateUser, createProject);
8-
projectRoutes.get("/get", getProjects);
8+
projectRoutes.post("/get", getProjects);
99
projectRoutes.get("/trending", trendingProjects);
10+
projectRoutes.post("/search", searchProjects);
11+
projectRoutes.post("/all-latest-count", allLatestProjectsCount);
12+
projectRoutes.post("/search-count", searchProjectsCount);
1013

1114
export default projectRoutes;

frontend/src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { createContext, useEffect, useState } from "react";
55
import { lookInSession } from "./common/session";
66
import Editor from "./pages/Editor";
77
import Home from "./pages/Home";
8+
import SearchPage from "./pages/Search";
89

910
export const UserContext = createContext({});
1011

@@ -25,6 +26,7 @@ function App() {
2526
<Route index element={<Home />} />
2627
<Route path="login" element={<UserAuthForm type="login" />} />
2728
<Route path="signup" element={<UserAuthForm type="signup" />} />
29+
<Route path="search/:query" element={<SearchPage />} />
2830
</Route>
2931
</Routes>
3032
</UserContext.Provider>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import axios from "axios";
2+
3+
export const filterPaginationData = async ({ create_new_arr = false, state, data, page, countRoute, data_to_send = {} }) => {
4+
5+
let obj;
6+
7+
if (state !== null && !create_new_arr) {
8+
obj = { ...state, results: [...state.results, ...data], page: page }
9+
} else {
10+
await axios.post(import.meta.env.VITE_SERVER_DOMAIN + countRoute, data_to_send)
11+
.then(({ data: { totalDocs } }) => {
12+
obj = { results: data, page: 1, totalDocs }
13+
})
14+
.catch(err => {
15+
console.log(err);
16+
})
17+
}
18+
19+
return obj;
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const LoadMoreDataBtn = ({ state, fetchDataFun }) => {
2+
3+
if (state && state.totalDocs > state.results.length) {
4+
return (
5+
<button
6+
onClick={() => fetchDataFun({ page: state.page + 1 })}
7+
className="text-gray-800 p-2 px-3 hover:bg-gray-50 rounded-md flex items-center gap-2"
8+
>
9+
Load More
10+
</button>
11+
)
12+
}
13+
}
14+
15+
export default LoadMoreDataBtn;

frontend/src/components/Navbar.jsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useContext, useState } from "react";
2-
import { Link, Outlet } from "react-router-dom";
2+
import { Link, Outlet, useNavigate } from "react-router-dom";
33
import { UserContext } from "../App";
44
import UserNavigationPanel from "./UserNavigationPanel";
55

@@ -8,12 +8,22 @@ const Navbar = () => {
88
const [searchBoxVisibility, setSearchBoxVisibility] = useState(false);
99
const [userNavPanel, setUserNavPanel] = useState(false);
1010

11+
let navigate = useNavigate();
12+
1113
const { userAuth, userAuth: { access_token, profile_img } } = useContext(UserContext);
1214

1315
const handleUserNavPanel = () => {
1416
setUserNavPanel(currentVal => !currentVal);
1517
}
1618

19+
const handleSearch = (e) => {
20+
let query = e.target.value;
21+
22+
if (e.keyCode === 13 && query.length) {
23+
navigate(`/search/${query}`);
24+
}
25+
}
26+
1727
const handleBlur = () => {
1828
setTimeout(() => {
1929
setUserNavPanel(false);
@@ -32,6 +42,7 @@ const Navbar = () => {
3242
type="text"
3343
placeholder="Search"
3444
className="w-full md:w-auto bg-gray-100 p-4 pl-6 pr-[12%] md:pr-6 rounded-full placeholder:text-dark-grey md:pl-12"
45+
onKeyDown={handleSearch}
3546
/>
3647
<i className="fi fi-rr-search absolute right-[10%] md:pointer-events-none md:left-5 top-1/2 -translate-y-1/2 text-xl text-dark-grey"></i>
3748
</div>

frontend/src/components/NoData.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const NoDataMessage = ({ message }) => {
2+
return (
3+
<div className="text-center w-full p-4 rounded-full bg-gray-50 mt-4">
4+
<p>{message}</p>
5+
</div>
6+
)
7+
}
8+
9+
export default NoDataMessage;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Link } from "react-router-dom";
2+
3+
const UserCard = ({ user }) => {
4+
5+
let { personal_info: { fullname, username, profile_img } } = user;
6+
7+
return (
8+
<Link to={`/user/${username}`} className="flex gap-5 items-center mb-5">
9+
<img src={profile_img} alt="" className="w-14 h-14 rounded-full" />
10+
11+
<div>
12+
<h1 className="font-medium text-xl line-clamp-2">{fullname}</h1>
13+
<p className="text-gray-600">@{username}</p>
14+
</div>
15+
</Link>
16+
);
17+
}
18+
19+
export default UserCard;

0 commit comments

Comments
 (0)