Skip to content

Commit 1de40ea

Browse files
authored
Merge pull request #166 from CS3219-AY2425S1/chore/server-constants
Remove all hardcoded localhost
2 parents cdb7119 + 5be93cc commit 1de40ea

File tree

20 files changed

+182
-92
lines changed

20 files changed

+182
-92
lines changed

.env.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
55

66
## Frontend variables
77
FRONTEND_PORT=3000
8+
# BASE_URI only needs to be provided if hosting outside of cluster
9+
BASE_URI=
810

911
## Question service variables
1012
QUESTION_SVC_PORT=

docker-compose.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@ services:
22
frontend:
33
build:
44
context: ./frontend
5+
args:
6+
- BASE_URI=$BASE_URI
7+
- USER_SVC_PORT=$USER_SVC_PORT
8+
- QUESTION_SVC_PORT=$QUESTION_SVC_PORT
9+
- MATCHING_SVC_PORT=$MATCHING_SVC_PORT
510
ports:
611
- $FRONTEND_PORT:$FRONTEND_PORT
712
depends_on:
813
- question-service
914
- user-service
15+
environment:
16+
- PORT=$FRONTEND_PORT
1017

1118
question-service:
1219
build:
@@ -16,6 +23,7 @@ services:
1623
environment:
1724
- PORT=$QUESTION_SVC_PORT
1825
- DB_URI=$QUESTION_SVC_DB_URI
26+
- FRONTEND_PORT=$FRONTEND_PORT
1927

2028
user-service:
2129
build:

frontend/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
2+
package-lock.json
23
.next

frontend/Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
# Base stage
22
FROM node:20-alpine AS base
3+
ARG BASE_URI \
4+
USER_SVC_PORT \
5+
QUESTION_SVC_PORT \
6+
MATCHING_SVC_PORT
37
WORKDIR /app
48
COPY package.json .
59
COPY yarn.lock .
610
RUN yarn install --frozen-lockfile
11+
ENV NEXT_PUBLIC_BASE_URI=$BASE_URI \
12+
NEXT_PUBLIC_USER_SVC_PORT=$USER_SVC_PORT \
13+
NEXT_PUBLIC_QUESTION_SVC_PORT=$QUESTION_SVC_PORT \
14+
NEXT_PUBLIC_MATCHING_SVC_PORT=$MATCHING_SVC_PORT
715

816
# Production build stage
917
FROM base AS build

frontend/app/auth/auth-context.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { userServiceUri } from "@/lib/api-uri";
34
import { User, UserSchema } from "@/lib/schemas/user-schema";
45
import { useRouter } from "next/navigation";
56
import {
@@ -32,7 +33,7 @@ const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
3233
// Login using locally stored JWT token
3334
useEffect(() => {
3435
if (token) {
35-
fetch("http://localhost:3001/auth/verify-token", {
36+
fetch(`${userServiceUri(window.location.hostname)}/auth/verify-token`, {
3637
method: "GET",
3738
headers: {
3839
Authorization: `Bearer ${token}`,
@@ -51,16 +52,19 @@ const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
5152

5253
// Login using email and password
5354
const login = async (email: string, password: string): Promise<User> => {
54-
const response = await fetch("http://localhost:3001/auth/login", {
55-
method: "POST",
56-
headers: {
57-
"Content-Type": "application/json",
58-
},
59-
body: JSON.stringify({
60-
email,
61-
password,
62-
}),
63-
});
55+
const response = await fetch(
56+
`${userServiceUri(window.location.hostname)}/auth/login`,
57+
{
58+
method: "POST",
59+
headers: {
60+
"Content-Type": "application/json",
61+
},
62+
body: JSON.stringify({
63+
email,
64+
password,
65+
}),
66+
}
67+
);
6468

6569
if (!response.ok) {
6670
throw new Error("Not OK");

frontend/components/admin-user-management/admin-user-management.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import LoadingScreen from "@/components/common/loading-screen";
1616
import AdminEditUserModal from "@/components/admin-user-management/admin-edit-user-modal";
1717
import { PencilIcon, Trash2Icon } from "lucide-react";
1818
import { User, UserArraySchema } from "@/lib/schemas/user-schema";
19+
import { userServiceUri } from "@/lib/api-uri";
1920

2021
const fetcher = async (url: string): Promise<User[]> => {
2122
const token = localStorage.getItem("jwtToken");
@@ -43,7 +44,7 @@ export default function AdminUserManagement() {
4344
const auth = useAuth();
4445

4546
const { data, isLoading, mutate } = useSWR(
46-
"http://localhost:3001/users",
47+
`${userServiceUri(window.location.hostname)}/users`,
4748
fetcher
4849
);
4950

@@ -67,12 +68,15 @@ export default function AdminUserManagement() {
6768
throw new Error("No authentication token found");
6869
}
6970

70-
const response = await fetch(`http://localhost:3001/users/${userId}`, {
71-
method: "DELETE",
72-
headers: {
73-
Authorization: `Bearer ${token}`,
74-
},
75-
});
71+
const response = await fetch(
72+
`${userServiceUri(window.location.hostname)}/users/${userId}`,
73+
{
74+
method: "DELETE",
75+
headers: {
76+
Authorization: `Bearer ${token}`,
77+
},
78+
}
79+
);
7680

7781
if (!response.ok) {
7882
throw new Error("Failed to delete user");

frontend/components/forget-password.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Label } from "@/components/ui/label";
1515
import { Button } from "@/components/ui/button";
1616
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
1717
import { AlertCircle } from "lucide-react";
18+
import { userServiceUri } from "@/lib/api-uri";
1819

1920
const ForgetPassword: React.FC = () => {
2021
const [email, setEmail] = useState("");
@@ -35,7 +36,7 @@ const ForgetPassword: React.FC = () => {
3536

3637
try {
3738
const response = await fetch(
38-
"http://localhost:3001/users/forget-password",
39+
`${userServiceUri(window.location.hostname)}/users/forget-password`,
3940
{
4041
method: "POST",
4142
headers: {

frontend/components/questions/questions-listing.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from "@/lib/schemas/question-schema";
1919
import QuestionFormModal from "./question-form-modal";
2020
import { updateQuestion } from "@/lib/update-question";
21+
import { questionServiceUri } from "@/lib/api-uri";
2122

2223
const fetcher = async (url: string): Promise<Question[]> => {
2324
const token = localStorage.getItem("jwtToken");
@@ -55,7 +56,7 @@ export default function QuestionListing() {
5556
const [search, setSearch] = useState(searchParams.get("search") || "");
5657

5758
const { data, isLoading, mutate } = useSWR(
58-
`http://localhost:8000/questions?category=${encodeURIComponent(category)}&complexity=${encodeURIComponent(complexity)}&search=${encodeURIComponent(search)}`,
59+
`${questionServiceUri(window.location.hostname)}/questions?category=${encodeURIComponent(category)}&complexity=${encodeURIComponent(complexity)}&search=${encodeURIComponent(search)}`,
5960
fetcher,
6061
{
6162
keepPreviousData: true,
@@ -144,7 +145,7 @@ export default function QuestionListing() {
144145
try {
145146
const token = localStorage.getItem("jwtToken");
146147
const response = await fetch(
147-
"http://localhost:8000/questions/batch-upload",
148+
`${questionServiceUri(window.location.hostname)}/questions/batch-upload`,
148149
{
149150
method: "POST",
150151
headers: {
@@ -189,7 +190,7 @@ export default function QuestionListing() {
189190

190191
try {
191192
const response = await fetch(
192-
`http://localhost:8000/questions/${selectedQuestion.id}`,
193+
`${questionServiceUri(window.location.hostname)}/questions/${selectedQuestion.id}`,
193194
{
194195
method: "DELETE",
195196
}
@@ -262,18 +263,21 @@ export default function QuestionListing() {
262263

263264
const handleCreate = async (newQuestion: Question) => {
264265
try {
265-
const response = await fetch("http://localhost:8000/questions", {
266-
method: "POST",
267-
headers: {
268-
"Content-Type": "application/json",
269-
},
270-
body: JSON.stringify({
271-
title: newQuestion.title,
272-
description: newQuestion.description,
273-
category: newQuestion.category,
274-
complexity: newQuestion.complexity,
275-
}),
276-
});
266+
const response = await fetch(
267+
`${questionServiceUri(window.location.hostname)}/questions`,
268+
{
269+
method: "POST",
270+
headers: {
271+
"Content-Type": "application/json",
272+
},
273+
body: JSON.stringify({
274+
title: newQuestion.title,
275+
description: newQuestion.description,
276+
category: newQuestion.category,
277+
complexity: newQuestion.complexity,
278+
}),
279+
}
280+
);
277281

278282
if (!response.ok) {
279283
if (response.status == 409) {

frontend/components/user-settings/user-settings.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import LoadingScreen from "@/components/common/loading-screen";
2424
import { useAuth } from "@/app/auth/auth-context";
2525
import { cn } from "@/lib/utils";
2626
import { User, UserSchema } from "@/lib/schemas/user-schema";
27+
import { userServiceUri } from "@/lib/api-uri";
2728

2829
const fetcher = async (url: string): Promise<User> => {
2930
// Retrieve the JWT token from localStorage
@@ -54,7 +55,7 @@ export default function UserSettings({ userId }: { userId: string }) {
5455
const fileInputRef = useRef<HTMLInputElement>(null);
5556

5657
const { data, error, isLoading, mutate } = useSWR(
57-
`http://localhost:3001/users/${userId}`,
58+
`${userServiceUri(window.location.hostname)}/users/${userId}`,
5859
fetcher
5960
);
6061
const [user, setUser] = useState<User | null>(null);
@@ -139,14 +140,17 @@ export default function UserSettings({ userId }: { userId: string }) {
139140
}
140141

141142
try {
142-
const response = await fetch(`http://localhost:3001/users/${userId}`, {
143-
method: "PATCH",
144-
headers: {
145-
Authorization: `Bearer ${token}`,
146-
"Content-Type": "application/json",
147-
},
148-
body: JSON.stringify(user),
149-
});
143+
const response = await fetch(
144+
`${userServiceUri(window.location.hostname)}/users/${userId}`,
145+
{
146+
method: "PATCH",
147+
headers: {
148+
Authorization: `Bearer ${token}`,
149+
"Content-Type": "application/json",
150+
},
151+
body: JSON.stringify(user),
152+
}
153+
);
150154
if (!response.ok) {
151155
throw new Error("Failed to save changes");
152156
} else {
@@ -177,13 +181,16 @@ export default function UserSettings({ userId }: { userId: string }) {
177181
}
178182

179183
try {
180-
const response = await fetch(`http://localhost:3001/users/${userId}`, {
181-
method: "DELETE",
182-
headers: {
183-
Authorization: `Bearer ${token}`,
184-
"Content-Type": "application/json",
185-
},
186-
});
184+
const response = await fetch(
185+
`${userServiceUri(window.location.hostname)}/users/${userId}`,
186+
{
187+
method: "DELETE",
188+
headers: {
189+
Authorization: `Bearer ${token}`,
190+
"Content-Type": "application/json",
191+
},
192+
}
193+
);
187194
if (!response.ok) throw new Error("Failed to delete account");
188195

189196
console.log("Account deleted successfully!");
@@ -237,7 +244,7 @@ export default function UserSettings({ userId }: { userId: string }) {
237244

238245
try {
239246
const response = await fetch(
240-
`http://localhost:3001/users/${userId}/change-password`,
247+
`${userServiceUri(window.location.hostname)}/users/${userId}/change-password`,
241248
{
242249
method: "PATCH",
243250
headers: {

frontend/lib/api-uri.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const constructUri = (baseUri: string, port: string | undefined) =>
2+
`http://${process.env.NEXT_PUBLIC_BASE_URI || baseUri}:${port}`;
3+
4+
export const userServiceUri: (baseUri: string) => string = (baseUri) =>
5+
constructUri(baseUri, process.env.NEXT_PUBLIC_USER_SVC_PORT);
6+
export const questionServiceUri: (baseUri: string) => string = (baseUri) =>
7+
constructUri(baseUri, process.env.NEXT_PUBLIC_QUESTION_SVC_PORT);
8+
export const matchingServiceUri: (baseUri: string) => string = (baseUri) =>
9+
constructUri(baseUri, process.env.NEXT_PUBLIC_MATCHING_SVC_PORT);

0 commit comments

Comments
 (0)