Skip to content

Commit

Permalink
Faq forum Page added (#520)
Browse files Browse the repository at this point in the history
* ADDED FORUM

* added testing for faqForum

* half baked

* Frontend for forum
  • Loading branch information
ShivanshPlays authored Nov 8, 2024
1 parent e6519c7 commit 5a5744d
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use client';

import { createQuestion } from '@/actions/forum/Question';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Spinner } from '@/components/ui/spinner';
import { Textarea } from '@/components/ui/textarea';
import { useSession } from 'next-auth/react';
import { SyntheticEvent, useEffect, useState } from 'react';

const NewQuestionForm = () => {
const [questionContent, setQuestionContent] = useState('');
const [submissionError, setSubmissionError] = useState('');

const [isMounted, setIsMounted] = useState(false);
const [isAuthenticated, setIsAuthenticated] = useState(false);

const session = useSession();

useEffect(() => {
setIsMounted(true);
if (!(session.status === 'loading')) {
if (session.status === 'authenticated') {
setIsAuthenticated(true);
// console.log("hereeeeeeeeee"+isAuthenticated+session.status)
}
}
}, [session.status]);

if (!isMounted) {
return <Spinner />;
}

const handleSubmit = async (e: SyntheticEvent) => {
e.preventDefault();
try {
const response = await createQuestion(questionContent);
if (!response.success && response.error) {
setSubmissionError(response.error);
} else {
setQuestionContent('');
setSubmissionError('');
}
} catch (error) {
setSubmissionError(
'An error occurred while submitting your question. Please try again.'
);
}
};

return (
<>
{isAuthenticated ? (
<form onSubmit={handleSubmit} className="space-y-4">
<Label htmlFor="new-question" className="text-gray-700 font-medium">
Your Question
</Label>
<Textarea
id="new-question"
value={questionContent}
onChange={e => setQuestionContent(e.target.value)}
placeholder="Type your question here..."
className="resize-none w-full rounded-md border-gray-300 focus:border-indigo-500"
required
/>
{submissionError && <p className="text-red-600">{submissionError}</p>}
<Button type="submit" className="w-full bg-green-500 text-white">
Submit Question
</Button>
</form>
) : (
<p className="text-red-500 text-sm">
Please authenticate yourself to post a question.
</p>
)}
</>
);
};

export default NewQuestionForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use client";

import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Spinner } from "@/components/ui/spinner";
import { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import toast from "react-hot-toast"; // Assuming you're using React Hot Toast for notifications
import { createAnswer } from "@/actions/forum/Answer"; // Import the server action

interface UnansweredQuestionCardProps {
question: {
id: string;
content: string;
};
}

const UnansweredQuestionCard: React.FC<UnansweredQuestionCardProps> = ({ question }) => {
const [answer, setAnswer] = useState("");
const [isMounted, setIsMounted] = useState(false);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);

const { status: sessionStatus } = useSession();

useEffect(() => {
setIsMounted(true);
if (sessionStatus === "authenticated") {
setIsAuthenticated(true);
}
}, [sessionStatus]);

if (!isMounted) {
return <Spinner />;
}

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);

try {
const response = await createAnswer(question.id, answer);

if (response.success) {
toast.success("Answer submitted successfully!");
setAnswer(""); // Clear the textarea on success
} else {
toast.error(response.error || "An error occurred while submitting your answer.");
}
} catch (error) {
toast.error("An error occurred while submitting your answer. Please try again.");
} finally {
setIsSubmitting(false);
}
};

return (
<Card key={question.id} className="shadow-lg">
<CardHeader>
<CardTitle>{question.content}</CardTitle>
</CardHeader>
<CardContent>
{isAuthenticated ? (
<form onSubmit={handleSubmit}>
<div className="space-y-4">
<Label htmlFor={`answer-${question.id}`} className="block text-sm font-medium text-gray-600">
Your Answer
</Label>
<Textarea
id={`answer-${question.id}`}
value={answer}
onChange={(e) => setAnswer(e.target.value)}
placeholder="Type your answer here..."
className="resize-none w-full rounded-md border-gray-300 focus:border-indigo-500"
required
disabled={isSubmitting}
/>
</div>
<Button type="submit" className="mt-4 w-full bg-blue-500 text-white" disabled={isSubmitting}>
{isSubmitting ? "Submitting..." : "Submit Answer"}
</Button>
</form>
) : (
<p className="text-red-500 text-sm">Please authenticate yourself to answer the question.</p>
)}
</CardContent>
</Card>
);
};

export default UnansweredQuestionCard;
77 changes: 77 additions & 0 deletions scruter-nextjs/app/(routes)/(footerPages)/forum/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

import { getAnsweredQuestions, getUnansweredQuestions, createQuestion } from "@/actions/forum/Question";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { SyntheticEvent, useState } from "react"; // Import useState for client-side form handling
import NewQuestionForm from "./components/NewQuestionForm";
import UnansweredQuestionCard from "./components/unAnsweredQuestions";

const Forum = async () => {
// Fetch unanswered and answered questions using server actions
const unansweredResp = await getUnansweredQuestions();
const answeredResp = await getAnsweredQuestions();

return (
<div className="container mx-auto p-6 space-y-8">
{/* Page Title */}
<h1 className="text-3xl font-bold text-center text-gray-800">Forum</h1>

{/* Ask a New Question Section */}
<section className="space-y-4">
<h2 className="text-2xl font-semibold text-gray-700">Ask a Question</h2>
<NewQuestionForm />
</section>

{/* Unanswered Questions Section */}
<section className="space-y-6">
<h2 className="text-2xl font-semibold text-gray-700">Unanswered Questions</h2>

{unansweredResp.success ? (
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{unansweredResp.data?.map((question) => (
<UnansweredQuestionCard
key={question.id}
question={question}
/>
))}
</div>
) : (
<p className="text-gray-600">{unansweredResp.error || "No unanswered questions available."}</p>
)}
</section>

{/* Answered Questions Section */}
<section className="space-y-6">
<h2 className="text-2xl font-semibold text-gray-700">Answered Questions</h2>

{answeredResp.success ? (
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{answeredResp.data?.map((question) => (
<Card key={question.id} className="shadow-lg">
<CardHeader>
<CardTitle>{question.content}</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<p className="text-sm font-medium text-gray-700">Answers:</p>
{question.answers?.map((answer) => (
<div key={answer.id} className="p-3 bg-gray-100 rounded-md">
<p className="text-gray-800">{answer.content}</p>
</div>
))}
</div>
</CardContent>
</Card>
))}
</div>
) : (
<p className="text-gray-600">{answeredResp.error || "No answered questions available."}</p>
)}
</section>
</div>
);
};

export default Forum
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const ContributorCardd: React.FC<ContributorCardProps> = ({ contributor , hasNex
/>
</div>
<div className="mt-2">
<span className="cursor-pointer" onClick={() => window.open(`https://github.com/mdazfar2/Ezyshop/commits/main/?author=${contributor.login}`, "_blank")}>Contributions {contributor.contributions}</span>
<span className="cursor-pointer" onClick={() => window.open(`https://github.com/swarooppatilx/scruter/commits/main/?author=${contributor.login}`, "_blank")}>Contributions {contributor.contributions}</span>
<div className="bg-customTeal md:mt-3 dark:bg-gradient-to-r dark:from-[#4caf50] dark:to-[#e9be1e] text-black font-bold py-1 px-4 rounded-full whitespace-nowrap">
<button onClick={() => window.open(contributor.html_url, "_blank")}>{contributor.login}</button>

Expand Down
1 change: 1 addition & 0 deletions scruter-nextjs/components/common/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const Helpdesk: LinkItem[] = [
{ name: 'FAQ', id: 2, href: '/faq' },
{ name: 'ContactUs', id: 3, href: '/contact' },
{ name: 'Support', id: 4, href: '/support' },
{ name: 'Forum', id: 5, href: '/forum' },
];

// Types for social links
Expand Down
Binary file removed scruter-nextjs/favicon.ico
Binary file not shown.

0 comments on commit 5a5744d

Please sign in to comment.