Skip to content

Commit c4e204f

Browse files
committed
Finish up the entire create modal for new question
1 parent ccede96 commit c4e204f

File tree

2 files changed

+150
-137
lines changed

2 files changed

+150
-137
lines changed

apps/question-service/src/app/page.tsx

Lines changed: 122 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
Tabs,
1616
Tag,
1717
Modal,
18+
Form,
1819
} from "antd";
1920
import { Content } from "antd/es/layout/layout";
2021
import {
@@ -30,7 +31,7 @@ import {
3031
GetQuestions,
3132
Question,
3233
CreateQuestion,
33-
NewQuestion
34+
NewQuestion,
3435
} from "./services/question";
3536
import {
3637
CategoriesOption,
@@ -102,50 +103,25 @@ export default function Home() {
102103
const [messageApi, contextHolder] = message.useMessage();
103104

104105
// States for Create New Problem Modal
106+
const [form] = Form.useForm();
105107
const [isNewProblemModalOpen, setIsNewProblemModelOpen] = useState(false);
106-
const [newProblemCategories, setNewProblemCategories] = useState<string[]>([]);
107-
const [newProblemDifficulty, setNewProblemDifficulty] = useState<string[]>([]); // Store the selected difficulty level
108108

109-
const [newTitle, setNewTitle] = useState('sampleTitle');
110-
const [newDescription, setNewDescription] = useState('sampleDescription');
111-
const [newCategories, setNewCategories] = useState<string[]>(['Algorithms']);
112-
const [newComplexity, setNewComplexity] = useState(1);
113-
const [newProblemError, setNewProblemError] = useState<string | null>(null);
114-
115-
const handleCreateQuestion = async () => {
116-
const newQuestion: NewQuestion = {
117-
newTitle,
118-
newDescription,
119-
newCategories,
120-
newComplexity,
121-
// Add assets and testCases if needed
122-
};
123-
try {
124-
const createdQuestion: Question = await CreateQuestion(newQuestion);
125-
console.log("Question created successfully:", createdQuestion);
126-
// Reset form or update UI as needed
127-
} catch (err: any) {
128-
setNewProblemError(err.message);
129-
}
130-
};
109+
const handleCreateQuestion = async (values: NewQuestion) => {
110+
try {
111+
const createdQuestion = await CreateQuestion(values);
112+
// Reset form or update UI as needed
113+
setIsNewProblemModelOpen(false);
114+
form.resetFields();
115+
success("New Problem Created!");
116+
} catch (err: any) {
117+
error(err.message);
118+
}
119+
};
131120

132121
const showNewProblemModal = () => {
133122
setIsNewProblemModelOpen(true);
134123
};
135124

136-
const handleNewProblemSubmit = () => {
137-
setIsNewProblemModelOpen(false);
138-
};
139-
140-
const handleNewProblemReturn = () => {
141-
setIsNewProblemModelOpen(false);
142-
};
143-
144-
// Handler for change in multi-select categories option
145-
const handleNewProblemCategoriesChange = (value: string[]) => {
146-
setNewProblemCategories(value);
147-
};
148-
149125
const success = (message: string) => {
150126
messageApi.open({
151127
type: "success",
@@ -258,7 +234,7 @@ export default function Home() {
258234
render: (_: number, question: Question) => (
259235
<div>
260236
{/* TODO (Sean): Include Logic to handle retrieving of editable data here and display in a modal component */}
261-
237+
262238
<Button className="edit-button" icon={<EditOutlined />}></Button>
263239
{/* TODO (Ryan): Include Pop-up confirmation for delete when clicked and link to delete API --> can also explore success notification or look into react-toast*/}
264240
<Button
@@ -334,6 +310,12 @@ export default function Home() {
334310
}
335311
setDeletionStage({});
336312
};
313+
314+
const layout = {
315+
labelCol: { span: 4 },
316+
wrapperCol: { span: 20 },
317+
};
318+
337319
return (
338320
<div>
339321
{contextHolder}
@@ -345,71 +327,112 @@ export default function Home() {
345327
<div className="content-title">Problems</div>
346328
<div className="create-button">
347329
{/* TODO (Sean): Launch a popup modal that links to the backend api to create a new entry in db, --> look into success/error notification/react toast */}
348-
<Button type="primary" icon={<PlusCircleOutlined />} onClick={showNewProblemModal}>
330+
<Button
331+
type="primary"
332+
icon={<PlusCircleOutlined />}
333+
onClick={showNewProblemModal}
334+
>
349335
Create New Problem
350336
</Button>
351-
<Modal
352-
353-
title="Create New Problem"
354-
open={isNewProblemModalOpen}
355-
onOk={handleNewProblemSubmit}
356-
onCancel={handleNewProblemReturn}
357-
// footer={[
358-
// <Button key="back" onClick={handleNewProblemReturn}>
359-
// Return
360-
// </Button>,
361-
// <Button key="submit" type="primary" onClick={handleNewProblemSubmit}>
362-
// Submit
363-
// </Button>,
364-
// ]}
365-
>
366-
<input
367-
type="text"
368-
placeholder="Title"
369-
value={newTitle}
370-
onChange={(e) => setNewTitle(e.target.value)}
371-
/>
372-
{/* Add other input fields for description, categories, complexity, etc. */}
373-
<button onClick={handleCreateQuestion}>Create Question</button>
374-
375-
</Modal>
376-
{/* <Modal
337+
<Modal
377338
title="Create New Problem"
378-
open={isNewProblemModalOpen}
379-
onOk={handleNewProblemSubmit}
380-
onCancel={handleNewProblemReturn}
381-
footer={[
382-
<Button key="back" onClick={handleNewProblemReturn}>
383-
Return
384-
</Button>,
385-
<Button key="submit" type="primary" onClick={handleNewProblemSubmit}>
386-
Submit
387-
</Button>,
388-
]}
339+
open={isNewProblemModalOpen}
340+
// onOk={() => setIsNewProblemModelOpen(false)} // Replace with handleSubmit
341+
onCancel={() => setIsNewProblemModelOpen(false)}
342+
footer={null}
343+
width={600}
389344
>
390-
<TextArea className="create-title" placeholder="Problem Title" rows={1} maxLength={1}></TextArea>
391-
<Select
392-
allowClear
393-
placeholder="Difficulty"
394-
onChange={(value: string[]) => {
395-
setNewProblemDifficulty(value);
345+
<Form
346+
name="create-form"
347+
{...layout}
348+
form={form}
349+
onFinish={(values) => {
350+
handleCreateQuestion(values);
396351
}}
397-
options={DifficultyOption}
398-
className="new-problem-difficulty-select"
399-
value={newProblemDifficulty}
400-
/>
401-
<Select
402-
mode="multiple"
403-
allowClear
404-
placeholder="Categories"
405-
onChange={handleNewProblemCategoriesChange}
406-
options={CategoriesOption}
407-
className="new-problem-categories-multi-select"
408-
value={newProblemCategories}
409-
/>
410-
<TextArea className="create-description" placeholder="Description"></TextArea>
411-
<TextArea className="create-problem-id" placeholder="Problem ID"></TextArea>
412-
</Modal> */}
352+
>
353+
<Form.Item
354+
name="title"
355+
label="Title"
356+
rules={[
357+
{
358+
required: true,
359+
message: "Please enter question title!",
360+
},
361+
]}
362+
>
363+
<Input name="title" />
364+
</Form.Item>
365+
<Form.Item
366+
name="description"
367+
label="Description"
368+
rules={[
369+
{
370+
required: true,
371+
message: "Please enter question description!",
372+
},
373+
]}
374+
>
375+
<TextArea name="description" />
376+
</Form.Item>
377+
<Form.Item
378+
name="complexity"
379+
label="Complexity"
380+
rules={[
381+
{
382+
required: true,
383+
message: "Please select a complexity!",
384+
},
385+
]}
386+
>
387+
<Select
388+
options={[
389+
{
390+
label: "Easy",
391+
value: "easy",
392+
},
393+
{
394+
label: "Medium",
395+
value: "medium",
396+
},
397+
{
398+
label: "Hard",
399+
value: "hard",
400+
},
401+
]}
402+
onChange={(value) =>
403+
form.setFieldValue("complexity", value)
404+
}
405+
allowClear
406+
/>
407+
</Form.Item>
408+
<Form.Item
409+
name="categories"
410+
label="Categories"
411+
rules={[
412+
{
413+
required: true,
414+
message: "Please select the relevant categories!",
415+
},
416+
]}
417+
>
418+
<Select
419+
mode="multiple"
420+
options={CategoriesOption}
421+
onChange={(value) =>
422+
form.setFieldValue("categories", value)
423+
}
424+
allowClear
425+
/>
426+
</Form.Item>
427+
<Form.Item
428+
style={{ display: "flex", justifyContent: "flex-end" }}
429+
>
430+
<Button type="primary" htmlType="submit">
431+
Create
432+
</Button>
433+
</Form.Item>
434+
</Form>
435+
</Modal>
413436
</div>
414437
</div>
415438
{/* TODO (Ben/Ryan): Include and link search & filter parameters */}

apps/question-service/src/app/services/question.ts

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export interface QuestionListResponse {
2222
}
2323

2424
export interface NewQuestion {
25-
newTitle: string;
26-
newDescription: string;
27-
newCategories: string[];
28-
newComplexity: string;
25+
title: string;
26+
description: string;
27+
categories: string[];
28+
complexity: string;
2929
}
3030

3131
// GET request to fetch all the questions (TODO: Ben --> Fetch with filtering/sorting etc)
@@ -88,47 +88,37 @@ export const GetSingleQuestion = async (docRef: string): Promise<Question> => {
8888
};
8989

9090
// Upload single question (TODO: Sean)
91-
export const CreateQuestion = async (question: NewQuestion): Promise<Question> => {
92-
try {
93-
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}questions`, {
94-
method: "POST",
95-
headers: {
96-
'Content-Type': 'application/json',
97-
},
98-
body: JSON.stringify(question),
99-
});
100-
101-
if (!response.ok) {
102-
// Attempt to parse error message from server
103-
let errorMessage = `Error creating question: ${response.status} ${response.statusText}`;
104-
try {
105-
const errorData = await response.json();
106-
if (errorData && errorData.error) {
107-
errorMessage = `Error creating question: ${errorData.error}`;
108-
}
109-
} catch (e) {
110-
// If response is not JSON, keep the default error message
111-
}
112-
throw new Error(errorMessage);
113-
}
114-
115-
const createdQuestion: Question = await response.json();
116-
return createdQuestion;
117-
} catch (error) {
118-
console.error("CreateQuestion failed:", error);
119-
throw error;
91+
export const CreateQuestion = async (
92+
question: NewQuestion
93+
): Promise<Question> => {
94+
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}questions`, {
95+
method: "POST",
96+
headers: {
97+
"Content-Type": "application/json",
98+
},
99+
body: JSON.stringify(question),
100+
});
101+
102+
if (response.status === 200) {
103+
return response.json();
104+
} else {
105+
throw new Error(
106+
`Error creating question: ${response.status} ${response.statusText}`
107+
);
120108
}
121109
};
122110

123111
// Update single question (TODO: Sean)
124112

125-
126113
// Delete single question (TODO: Ryan)
127114
export async function DeleteQuestion(docRef: String): Promise<void> {
128-
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}questions/${docRef}`, {
129-
method: "DELETE"
130-
})
131-
// error handling later
115+
const res = await fetch(
116+
`${process.env.NEXT_PUBLIC_API_URL}questions/${docRef}`,
117+
{
118+
method: "DELETE",
119+
}
120+
);
121+
// error handling later
132122
// if (!res.ok) {
133123
// throw new Error(`Delete request responded with ${res.status}: ${res.body}`)
134124
// }

0 commit comments

Comments
 (0)