Skip to content

Commit 291a657

Browse files
committed
Adding services
1 parent 97cd3c1 commit 291a657

File tree

7 files changed

+273
-220
lines changed

7 files changed

+273
-220
lines changed

frontend/src/App.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ import NotFound from "./pages/error/404";
5555

5656
export default function App() {
5757
return (
58-
<AuthProvider>
59-
<Router>
58+
<Router>
59+
<AuthProvider>
6060
<Background />
6161
<NavbarWrapper />
6262

@@ -103,7 +103,7 @@ export default function App() {
103103
<Route path='*' element={<NotFound />} />
104104
</Routes>
105105
<Footer />
106-
</Router>
107-
</AuthProvider>
106+
</AuthProvider>
107+
</Router>
108108
);
109109
}

frontend/src/components/Navbar.tsx

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import { useAuth } from "../hooks/useAuth";
77
import { useNavigate } from "react-router-dom";
88
import axios from "axios";
99
import { apiURL } from "../scripts/api";
10-
import SearchList from "./search/SearchList";
1110

1211
import Cookies from "js-cookie";
1312
import NotificationList from "./notification/NotificationList";
13+
import { SubscriptionService } from "../services/SubscriptionService";
14+
import { SearchService } from "../services/SearchService";
15+
import SearchList from "./search/SearchListContent";
1416

1517
export default function Navbar() {
1618
// ---------------------------------------
@@ -106,34 +108,41 @@ export default function Navbar() {
106108
*/
107109
const handleSearch = async (e: { preventDefault: () => void }) => {
108110
e.preventDefault();
109-
if (query) {
110-
// Redirect to the search results page, where the actual searching happens.
111-
// router.push(`/search?query=${encodeURIComponent(query)}`);
112-
// window.location.href = `/search?query=${encodeURIComponent(query)}`;
113-
114-
const userSearchResults = await axios.get(`${apiURL}/search/users/`, {
115-
params: {
116-
searchText: query,
117-
},
118-
});
119-
120-
const contentSearchResults = await axios.get(
121-
`${apiURL}/search/content/`,
122-
{
123-
params: {
124-
searchText: query,
125-
},
126-
}
127-
);
128111

129-
setUserSearchResults(userSearchResults.data.documents);
130-
setContentSearchResults(contentSearchResults.data.documents);
131-
setShowSearchResults(true);
132-
setShowMenu(false);
133-
setShowNotificationList(false);
112+
// Validation
113+
if (!query) {
114+
setShowSearchResults(false);
115+
return;
116+
}
117+
118+
const trimmedQuery = query.trim();
119+
120+
// Search Queries
121+
const userSearchResults = await SearchService.searchUsers(trimmedQuery);
122+
const contentSearchResults = await SearchService.searchContents(
123+
trimmedQuery
124+
);
125+
126+
// Display Search Results
127+
if (userSearchResults instanceof Error) {
128+
console.error("Error fetching user search results:", userSearchResults);
134129
} else {
135-
alert("You didn't search for anything.");
130+
setUserSearchResults(userSearchResults.users);
136131
}
132+
133+
if (contentSearchResults instanceof Error) {
134+
console.error(
135+
"Error fetching content search results:",
136+
contentSearchResults
137+
);
138+
} else {
139+
setContentSearchResults(contentSearchResults.contents);
140+
}
141+
142+
// Update states
143+
setShowSearchResults(true);
144+
setShowMenu(false);
145+
setShowNotificationList(false);
137146
};
138147

139148
const fetchNotifications = async (): Promise<void> => {
@@ -172,21 +181,18 @@ export default function Navbar() {
172181
const checkSubscriptionStatus = async (): Promise<void> => {
173182
if (!auth.isAuthenticated) return;
174183

175-
try {
176-
const response = await axios.get(`${apiURL}/subscription/status`, {
177-
withCredentials: true,
178-
});
184+
const subscriptionStatus =
185+
await SubscriptionService.getSubscriptionStatus();
179186

180-
// Check if user has an active subscription
181-
const subscriptionData = response.data;
187+
if (subscriptionStatus instanceof Error) {
188+
console.error("Error fetching subscription status:", subscriptionStatus);
189+
setIsProUser(false);
190+
} else {
182191
setIsProUser(
183-
subscriptionData &&
184-
subscriptionData.status === "active" &&
185-
!subscriptionData.canceledAt
192+
subscriptionStatus &&
193+
subscriptionStatus.status === "active" &&
194+
!subscriptionStatus.canceledAt
186195
);
187-
} catch (error) {
188-
console.error("Error checking subscription status:", error);
189-
setIsProUser(false);
190196
}
191197
};
192198

frontend/src/components/search/searchList.tsx renamed to frontend/src/components/search/SearchListContent.tsx

Lines changed: 69 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import { Suspense, useEffect, useState } from "react";
22
import { User } from "../../models/User";
33
import { Content } from "../../models/Content";
44
import { useSearchParams } from "react-router-dom";
5-
import axios from "axios";
6-
import { apiURL } from "../../scripts/api";
75
import ContentSearchResult from "./ContentSearchResult";
86
import UserSearchResults from "./UserSearchResult";
7+
import { SearchService } from "../../services/SearchService";
98

109
function SearchListContent({
1110
userSearchResults,
@@ -20,14 +19,15 @@ function SearchListContent({
2019

2120
// Retrieve the search text from the url.
2221
const [searchParams] = useSearchParams();
23-
const param = searchParams.get("query");
22+
const query = searchParams.get("query");
23+
2424
const [usersReturned, setUsersReturned] = useState<User[]>([]);
2525
const [userDisabled, setUserDisabled] = useState(true);
26-
const [contentReturned, setContentReturned] = useState<Content[]>([]);
27-
2826
const [userStartingPoint, setUserStartingPoint] = useState<string | null>(
2927
null
3028
);
29+
30+
const [contentReturned, setContentReturned] = useState<Content[]>([]);
3131
// const [contentStartingPoint, setContentStartingPoint] = useState<
3232
// string | null
3333
// >(null);
@@ -44,75 +44,71 @@ function SearchListContent({
4444
useEffect(() => {
4545
if (userSearchResults) {
4646
setUsersReturned(userSearchResults);
47-
} else if (param) {
47+
} else if (query) {
4848
fetchUserData();
4949
}
5050

5151
if (contentSearchResults) {
5252
setContentReturned(contentSearchResults);
53-
} else if (param) {
53+
} else if (query) {
5454
fetchContentData();
5555
}
56-
}, [userSearchResults, contentSearchResults, param]);
56+
}, [userSearchResults, contentSearchResults, query]);
5757

5858
/**
5959
* fetchUserData() -> void
6060
*
6161
* @description
62-
*Send a get request to the api endpoint for searching for users.
62+
* Sends a GET request to the API endpoint for searching users.
6363
*
6464
* @returns void
6565
*/
6666
const fetchUserData = async () => {
67-
if (!param) {
68-
return;
69-
}
67+
if (!query) return;
7068

7169
if (fetching) {
72-
alert("Already Fetching!!!!");
70+
alert("Already Fetching!");
7371
return;
7472
}
73+
7574
setFetching(true);
7675

77-
try {
78-
const response = await axios.get(`${apiURL}/search/users/`, {
79-
params: {
80-
searchText: param,
81-
userStartingPoint: userStartingPoint,
82-
},
83-
});
84-
85-
const newDocuments = response.data.documents;
86-
// Create a set to easily check if the last query has duplicates
87-
const usersSet = new Set(usersReturned.map((doc: User) => doc.uid));
88-
// Create a get each user document id from the GET response, then check
89-
// for whether at least one is not in the stored user set.
90-
const uniqueDocuments = newDocuments.filter(
91-
(doc: { uid: string }) => !usersSet.has(doc.uid)
92-
);
76+
const userSearchResults = await SearchService.searchUsers(
77+
query,
78+
userStartingPoint
79+
);
9380

94-
// If there are unique documents, update the state
95-
if (uniqueDocuments.length > 0 && !fetching) {
96-
setUsersReturned((prev) => [...prev, ...uniqueDocuments]);
97-
// Update the starting point for the next fetch
98-
setUserStartingPoint(
99-
uniqueDocuments[uniqueDocuments.length - 1].usernameLower
100-
);
101-
102-
if (usersReturned.length < 5) {
103-
setUserDisabled(true);
104-
} else {
105-
setUserDisabled(false);
106-
}
107-
} else {
108-
// If there are no unique documents, disable the button
109-
setUserDisabled(true);
110-
}
111-
} catch (error) {
112-
throw new Error(error instanceof Error ? error.message : String(error));
113-
} finally {
81+
if (userSearchResults instanceof Error) {
82+
console.error("Error fetching user data:", userSearchResults);
11483
setFetching(false);
84+
return;
11585
}
86+
87+
const users = userSearchResults.users || [];
88+
const existingUserIds = new Set(
89+
usersReturned.map((user: User) => user.uid)
90+
);
91+
92+
// Filter out duplicate users
93+
const uniqueUsers = users.filter(
94+
(user: { uid: string }) => !existingUserIds.has(user.uid)
95+
);
96+
97+
if (uniqueUsers && uniqueUsers.length > 0) {
98+
setUsersReturned((prev) => [...prev, ...uniqueUsers]);
99+
100+
// Update the starting point for the next fetch
101+
setUserStartingPoint(
102+
uniqueUsers[uniqueUsers.length - 1]?.username.toLowerCase() || null
103+
);
104+
105+
// Enable or disable the "Fetch more" button based on the number of users
106+
setUserDisabled(usersReturned.length + uniqueUsers.length < 5);
107+
} else {
108+
setUserDisabled(true); // Disable the button if no unique users are found
109+
}
110+
111+
setFetching(false);
116112
};
117113

118114
/**
@@ -124,56 +120,44 @@ function SearchListContent({
124120
* @returns void
125121
*/
126122
const fetchContentData = async () => {
127-
if (!param) {
123+
if (!query) {
128124
return;
129125
}
130126

131-
if (fetching) {
132-
alert("Already Fetching!!!!");
133-
return;
134-
}
135127
setFetching(true);
136128

137-
try {
138-
const response = await axios.get(`${apiURL}/search/content/`, {
139-
params: {
140-
searchText: param,
141-
},
142-
});
143-
144-
// Obtain the documents from the response data.
145-
const newDocuments = response.data.documents;
146-
// Create a set to easily check if the last query has duplicates
147-
const contentSet = new Set(
148-
contentReturned.map((doc: Content) => doc.uid)
149-
);
150-
// Get each document id from the GET response, then check
151-
// for whether at least one is not in the stored content set.
152-
const uniqueDocuments = newDocuments.filter(
153-
(doc: { id: string }) => !contentSet.has(doc.id)
154-
);
129+
const searchContentResults = await SearchService.searchContents(query);
155130

156-
// If there are unique documents, update the state
157-
if (uniqueDocuments.length > 0 && !fetching) {
158-
// Append the new data to the list of stored articles.
159-
setContentReturned((prev) => [...prev, ...uniqueDocuments]);
160-
// Update the starting point for the next fetch.
161-
// setContentStartingPoint(
162-
// uniqueDocuments[uniqueDocuments.length - 1].titleLower
163-
// );
164-
}
165-
} catch (error) {
166-
throw new Error(error instanceof Error ? error.message : String(error));
167-
} finally {
131+
if (searchContentResults instanceof Error) {
132+
console.error("Error fetching content data:", searchContentResults);
168133
setFetching(false);
134+
return;
169135
}
136+
137+
const contents = searchContentResults.contents || [];
138+
const existingContentIds = new Set(
139+
contentReturned.map((content: Content) => content.uid)
140+
);
141+
142+
// Filter out duplicate users
143+
const uniqueContents = contents.filter(
144+
(content: { uid: string }) => !existingContentIds.has(content.uid)
145+
);
146+
147+
if (uniqueContents && uniqueContents.length > 0) {
148+
setContentReturned((prev) => [...prev, ...uniqueContents]);
149+
} else {
150+
setUserDisabled(true); // Disable the button if no unique users are found
151+
}
152+
153+
setFetching(false);
170154
};
171155

172156
return (
173157
<>
174158
{/* <div className='main-content'> */}
175159
<div className='searchResults'>
176-
{param && <h1>Search Results for: {param}</h1>}
160+
{query && <h1>Search Results for: {query}</h1>}
177161
<h2>Users</h2>
178162
{usersReturned?.length === 0 ? (
179163
<p>Nothing found...</p>

0 commit comments

Comments
 (0)