Skip to content

Commit 3f9c7cc

Browse files
authored
Merge pull request #21 from jolynloh/FE/homepage
Implement Homepage
2 parents 672cf5f + 01972e0 commit 3f9c7cc

File tree

11 files changed

+383
-40
lines changed

11 files changed

+383
-40
lines changed

backend/question-service/README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,31 @@
2222

2323
5. In the `question-service` directory, create a copy of the `.env.sample` file and name it `.env`.
2424

25-
6. Update the `MONGO_URI` of the `.env` file, and paste the string we copied earlier in step 4.
25+
6. Update the `MONGO_URI` of the `.env` file, and paste the string we copied earlier in step 4.
2626

2727
## Setting-up Firebase
2828

2929
1. Go to https://console.firebase.google.com/u/0/.
3030

3131
2. Create a project and choose a project name. Navigate to `Storage` and click on it to activate it.
3232

33-
3. Select `Start in production mode` and your preferred cloud storage region.
33+
3. Select `Start in production mode` and your preferred cloud storage region.
3434

3535
4. After Storage is created, go to `Rules` section and set rule to:
36-
```
37-
rules_version = '2';
38-
service firebase.storage {
39-
match /b/{bucket}/o {
40-
match /{allPaths=**} {
41-
allow read: if true;
42-
allow write: if request.auth != null;
43-
}
44-
}
45-
}
46-
```
47-
This rule ensures that only verified users can upload images while ensuring that URLs of images are public. Remember to click `Publish` to save changes.
36+
37+
```
38+
rules_version = '2';
39+
service firebase.storage {
40+
match /b/{bucket}/o {
41+
match /{allPaths=**} {
42+
allow read: if true;
43+
allow write: if request.auth != null;
44+
}
45+
}
46+
}
47+
```
48+
49+
This rule ensures that only verified users can upload images while ensuring that URLs of images are public. Remember to click `Publish` to save changes.
4850

4951
5. Go to `Settings`, `Project settings`, `Service accounts` and click `Generate new private key`. This will download a `.json` file, which will contain your credentials.
5052

@@ -54,7 +56,6 @@
5456
- `FIREBASE_CLIENT_EMAIL` with `client_email` found in the downloaded json file.
5557
- `FIREBASE_STORAGE_BUCKET` with the folder path of the Storage. It should look something like `gs://<appname>.appspot.com`.
5658

57-
5859
## Running Question Service
5960

6061
1. Open Command Line/Terminal and navigate into the `question-service` directory.
@@ -63,6 +64,6 @@
6364

6465
3. Run the command `npm start` to start the Question Service in production mode, or use `npm run dev` for development mode, which includes features like automatic server restart when you make code changes.
6566

66-
4. To view Question Service documentation, go to http://localhost:3001/docs.
67+
4. To view Question Service documentation, go to http://localhost:3000/docs.
6768

6869
5. Using applications like Postman, you can interact with the Question Service on port 3000. If you wish to change this, please update the `.env` file.

backend/question-service/package-lock.json

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

backend/question-service/src/controllers/questionController.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Request, Response } from "express";
22
import Question, { IQuestion } from "../models/Question.ts";
33
import { checkIsExistingQuestion } from "../utils/utils.ts";
44
import {
5-
DUPLICATE_QUESTION_RESPONSE_MESSAGE,
6-
QN_DESC_EXCEED_CHAR_LIMIT_RESPONSE_MESSAGE,
5+
DUPLICATE_QUESTION_MESSAGE,
6+
QN_DESC_EXCEED_CHAR_LIMIT_MESSAGE,
77
QN_DESC_CHAR_LIMIT,
88
QN_CREATED_MESSAGE,
99
QN_NOT_FOUND_MESSAGE,
@@ -13,6 +13,8 @@ import {
1313
PAGE_LIMIT_REQUIRED_MESSAGE,
1414
PAGE_LIMIT_INCORRECT_FORMAT_MESSAGE,
1515
CATEGORIES_RETRIEVED_MESSAGE,
16+
MONGO_OBJ_ID_FORMAT,
17+
MONGO_OBJ_ID_MALFORMED_MESSAGE,
1618
} from "../utils/constants.ts";
1719

1820
import { upload } from "../../config/multer";
@@ -28,14 +30,14 @@ export const createQuestion = async (
2830
const existingQuestion = await checkIsExistingQuestion(title);
2931
if (existingQuestion) {
3032
res.status(400).json({
31-
message: DUPLICATE_QUESTION_RESPONSE_MESSAGE,
33+
message: DUPLICATE_QUESTION_MESSAGE,
3234
});
3335
return;
3436
}
3537

3638
if (description.length > QN_DESC_CHAR_LIMIT) {
3739
res.status(400).json({
38-
message: QN_DESC_EXCEED_CHAR_LIMIT_RESPONSE_MESSAGE,
40+
message: QN_DESC_EXCEED_CHAR_LIMIT_MESSAGE,
3941
});
4042
return;
4143
}
@@ -78,6 +80,7 @@ export const createImageLink = async (
7880

7981
const uploadPromises = files.map((file) => uploadFileToFirebase(file));
8082
const imageUrls = await Promise.all(uploadPromises);
83+
console.log(imageUrls);
8184
res
8285
.status(200)
8386
.json({ message: "Images uploaded successfully", imageUrls });
@@ -95,7 +98,13 @@ export const updateQuestion = async (
9598
const { id } = req.params;
9699
const { title, description } = req.body;
97100

101+
if (!id.match(MONGO_OBJ_ID_FORMAT)) {
102+
res.status(400).json({ message: MONGO_OBJ_ID_MALFORMED_MESSAGE });
103+
return;
104+
}
105+
98106
const currentQuestion = await Question.findById(id);
107+
99108
if (!currentQuestion) {
100109
res.status(404).json({ message: QN_NOT_FOUND_MESSAGE });
101110
return;
@@ -104,14 +113,14 @@ export const updateQuestion = async (
104113
const existingQuestion = await checkIsExistingQuestion(title, id);
105114
if (existingQuestion) {
106115
res.status(400).json({
107-
message: DUPLICATE_QUESTION_RESPONSE_MESSAGE,
116+
message: DUPLICATE_QUESTION_MESSAGE,
108117
});
109118
return;
110119
}
111120

112121
if (description && description.length > QN_DESC_CHAR_LIMIT) {
113122
res.status(400).json({
114-
message: QN_DESC_EXCEED_CHAR_LIMIT_RESPONSE_MESSAGE,
123+
message: QN_DESC_EXCEED_CHAR_LIMIT_MESSAGE,
115124
});
116125
return;
117126
}

backend/question-service/src/utils/constants.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
export const QN_DESC_CHAR_LIMIT = 6000;
22

3-
export const QN_DESC_EXCEED_CHAR_LIMIT_RESPONSE_MESSAGE =
4-
"Question description must be at most 6000 characters";
3+
export const QN_DESC_EXCEED_CHAR_LIMIT_MESSAGE = `Question description must be at most ${QN_DESC_CHAR_LIMIT} characters`;
54

6-
export const DUPLICATE_QUESTION_RESPONSE_MESSAGE =
5+
export const DUPLICATE_QUESTION_MESSAGE =
76
"Duplicate question: A question with the same title already exists.";
87

98
export const QN_CREATED_MESSAGE = "Question created successfully.";
@@ -24,3 +23,7 @@ export const PAGE_LIMIT_INCORRECT_FORMAT_MESSAGE =
2423

2524
export const CATEGORIES_RETRIEVED_MESSAGE =
2625
"Categories retrieved successfully.";
26+
27+
export const MONGO_OBJ_ID_FORMAT = /^[0-9a-fA-F]{24}$/;
28+
29+
export const MONGO_OBJ_ID_MALFORMED_MESSAGE = "The question ID is not valid";

frontend/public/homepage_image.svg

Lines changed: 1 addition & 0 deletions
Loading

frontend/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import PageNotFound from "./pages/PageNotFound";
77
import ProfilePage from "./pages/Profile";
88
import AuthProvider from "./contexts/AuthContext";
99
import QuestionList from "./pages/QuestionList";
10+
import Home from "./pages/Home";
1011
import SignUp from "./pages/SignUp";
1112
import LogIn from "./pages/LogIn";
1213
import ProtectedRoutes from "./components/ProtectedRoutes";
@@ -16,6 +17,7 @@ function App() {
1617
<AuthProvider>
1718
<Routes>
1819
<Route path="/" element={<Layout />}>
20+
<Route index element={<Home />} />
1921
<Route path="questions">
2022
<Route index element={<QuestionList />} />
2123
<Route path=":questionId" element={<QuestionDetail />} />
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react";
2+
import { Chip } from "@mui/material";
3+
import CloseIcon from "@mui/icons-material/Close";
4+
5+
const CustomChip: React.FC<{
6+
label: string;
7+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8+
onDelete: (event: any) => void;
9+
}> = ({ label, onDelete }) => {
10+
return (
11+
<Chip
12+
size="medium"
13+
label={label}
14+
deleteIcon={
15+
<CloseIcon onMouseDown={(event) => event.stopPropagation()} />
16+
}
17+
onDelete={onDelete}
18+
sx={(theme) => ({
19+
backgroundColor: theme.palette.primary.main,
20+
color: theme.palette.primary.contrastText,
21+
marginRight: theme.spacing(1),
22+
"& .MuiChip-deleteIcon": {
23+
color: theme.palette.primary.contrastText,
24+
},
25+
})}
26+
/>
27+
);
28+
};
29+
30+
export default CustomChip;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.fullheight {
2+
flex: 1;
3+
}
4+
5+
.center {
6+
display: flex;
7+
flex-direction: column;
8+
align-items: center;
9+
justify-content: center;
10+
}
11+
12+
.margins {
13+
margin-top: 25px;
14+
margin-bottom: 25px;
15+
}

0 commit comments

Comments
 (0)