diff --git a/frontend/app/app/questions/create/page.tsx b/frontend/app/app/questions/create/page.tsx new file mode 100644 index 0000000000..383b26daee --- /dev/null +++ b/frontend/app/app/questions/create/page.tsx @@ -0,0 +1,5 @@ +import QuestionCreate from "@/components/questions/question-create"; + +export default function QuestionCreatePage() { + return ; +} diff --git a/frontend/components/questions/question-create.tsx b/frontend/components/questions/question-create.tsx new file mode 100644 index 0000000000..e7baee5f69 --- /dev/null +++ b/frontend/components/questions/question-create.tsx @@ -0,0 +1,64 @@ +"use client"; + +import { Question } from "@/lib/schemas/question-schema"; +import QuestionForm from "@/components/questions/question-form"; +import { useAuth } from "@/app/auth/auth-context"; +import { useRouter } from "next/navigation"; +import { useToast } from "@/components/hooks/use-toast"; + +export default function QuestionCreate() { + const auth = useAuth(); + const router = useRouter(); + const { toast } = useToast(); + + const handleCreate = async (newQuestion: Question) => { + try { + const response = await fetch("http://localhost:8000/questions", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + title: newQuestion.title, + description: newQuestion.description, + category: newQuestion.category, + complexity: newQuestion.complexity, + }), + }); + + if (!response.ok) { + if (response.status == 409) { + throw new Error("A question with this title already exists."); + } + } + + toast({ + title: "Success", + description: "Question created successfully!", + variant: "success", + duration: 3000, + }); + + router.push(`/app/questions/`); + } catch (err) { + toast({ + title: "An error occured!", + description: + err instanceof Error ? err.message : "An unknown error occurred", + variant: "destructive", + duration: 5000, + }); + } + }; + + return ( +
+

Create a New Question

+ +
+ ); +} diff --git a/frontend/components/questions/question-form.tsx b/frontend/components/questions/question-form.tsx index 3950f7434b..b8719515ff 100644 --- a/frontend/components/questions/question-form.tsx +++ b/frontend/components/questions/question-form.tsx @@ -22,31 +22,49 @@ import { Label } from "@/components/ui/label"; import { AutosizeTextarea } from "../ui/autosize-textarea"; interface QuestionFormProps { - data: Question | undefined; + initialData?: Question; isAdmin: boolean | undefined; - handleSubmit?: (question: Question) => void; + handleSubmit: (question: Question) => void; + submitButtonText: string; } const QuestionForm: React.FC = ({ ...props }) => { - const [question, setQuestion] = useState(); + const [question, setQuestion] = useState( + props.initialData || { + id: "", + title: "", + category: "", + complexity: "easy", + description: "", + } + ); useEffect(() => { - setQuestion(props.data); - }, [props.data]); + if (props.initialData) { + setQuestion(props.initialData); + } + }, [props.initialData]); + + const onSubmit = (e: React.FormEvent) => { + e.preventDefault(); + props.handleSubmit(question); + }; return ( -
+ - question && setQuestion({ ...question, title: e.target.value }) + setQuestion({ ...question, title: e.target.value }) } disabled={!props.isAdmin} + required /> @@ -54,13 +72,14 @@ const QuestionForm: React.FC = ({ ...props }) => {
- question && setQuestion({ ...question, category: e.target.value }) } disabled={!props.isAdmin} + required />
@@ -68,9 +87,9 @@ const QuestionForm: React.FC = ({ ...props }) => {
{props.isAdmin ? ( ) : ( - question && setQuestion({ ...question, complexity: e.target.value }) } disabled={!props.isAdmin} @@ -98,27 +117,21 @@ const QuestionForm: React.FC = ({ ...props }) => {
- question && setQuestion({ ...question, description: e.target.value }) } disabled={!props.isAdmin} + required />
{props.isAdmin && ( - + )} diff --git a/frontend/components/questions/question-view-edit.tsx b/frontend/components/questions/question-view-edit.tsx index ac3e2b72b3..6064dc9c13 100644 --- a/frontend/components/questions/question-view-edit.tsx +++ b/frontend/components/questions/question-view-edit.tsx @@ -7,6 +7,7 @@ import { useAuth } from "@/app/auth/auth-context"; import { useEffect, useState } from "react"; import { updateQuestion } from "@/lib/update-question"; import { useToast } from "@/components/hooks/use-toast"; +import LoadingScreen from "@/components/common/loading-screen"; const fetcher = async (url: string): Promise => { const token = localStorage.getItem("jwtToken"); @@ -38,7 +39,7 @@ export default function QuestionViewEdit({ const auth = useAuth(); const { toast } = useToast(); - const { data, mutate } = useSWR( + const { data, isLoading, mutate } = useSWR( `http://localhost:8000/questions/${questionId}`, fetcher ); @@ -82,13 +83,18 @@ export default function QuestionViewEdit({ mutate(); }; + if (isLoading) { + return ; + } + return (

{question?.title}

); diff --git a/frontend/components/questions/questions-listing.tsx b/frontend/components/questions/questions-listing.tsx index 579539ebb5..e798c2bcb1 100644 --- a/frontend/components/questions/questions-listing.tsx +++ b/frontend/components/questions/questions-listing.tsx @@ -9,7 +9,7 @@ import LoadingScreen from "@/components/common/loading-screen"; import DeleteQuestionModal from "@/components/questions/delete-question-modal"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; -import { Upload } from "lucide-react"; +import { PlusIcon, Upload } from "lucide-react"; import { useToast } from "@/components/hooks/use-toast"; import { CreateQuestion, @@ -61,6 +61,25 @@ export default function QuestionListing() { router.push(`/app/questions/${question.id}`); }; + const handleCreateNewQuestion = () => { + router.push(`/app/questions/create`); + }; + + const createNewQuestion = () => { + return ( +
+ +
+ ); + }; + const handleFileSelect = (event: ChangeEvent) => { const file = event.target.files?.[0]; if (file) { @@ -176,22 +195,25 @@ export default function QuestionListing() {

Question Listing

{auth?.user?.isAdmin && ( -
- - +
+
+ + +
+
{createNewQuestion()}
)}