Skip to content

Commit

Permalink
Merge pull request #1782 from Sawan-Kushwah/add/discussionForum
Browse files Browse the repository at this point in the history
Interactive Discussion Forum with CURD operation & Responsive Design
  • Loading branch information
ANSHIKA-26 authored Nov 8, 2024
2 parents 229e493 + c29da5e commit 9a6d538
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 7 deletions.
1 change: 1 addition & 0 deletions frontend/src/components/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function renderNavbar() {
<a href="/about" class="py-2 px-3 text-gray-900 dark:text-white">About</a>
<a href="/contact" class="py-2 px-3 text-gray-900 dark:text-white">Contact</a>
<a href="/feedback" class="py-2 px-3 text-gray-900 dark:text-white">Feedback</a>
<a href="/discussion" class="py-2 px-3 text-gray-900 dark:text-white">Discussion Forum</a>
<button id="theme-toggle" type="button" class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:focus:ring-gray-600 rounded-lg text-sm p-2.5">
<!-- Theme Toggle Icons -->
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20"><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path></svg>
Expand Down
209 changes: 209 additions & 0 deletions frontend/src/pages/DiscussionForum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
export async function renderDiscussionForum(container) {
// Initialize questions data
let questions = JSON.parse(localStorage.getItem('questions')) || [];

// Helper function to save questions to localStorage
const saveQuestions = () => {
localStorage.setItem('questions', JSON.stringify(questions));
};

// Function to handle adding a new question
const addQuestion = (content) => {
const newQuestion = {
id: Date.now(),
content: content,
answered: false,
answer: '',
};
questions.push(newQuestion);
saveQuestions();
render();
};

// Function to handle adding an answer to a question
const addAnswer = (questionId, answerContent) => {
questions = questions.map(q =>
q.id === questionId ? { ...q, answered: true, answer: answerContent } : q
);
saveQuestions();
render();
};

// Function to render the Question Card
const renderQuestionCard = (question) => {
const card = document.createElement('div');
card.classList.add('bg-white', 'dark:bg-gray-800', 'p-4', 'rounded-md', 'shadow-md', 'mb-4', 'w-[30%]');

const questionText = document.createElement('p');
questionText.textContent = question.content;
questionText.classList.add('text-lg', 'text-gray-800', 'dark:text-gray-100');

card.appendChild(questionText);

if (question.answered) {
const answerSection = document.createElement('div');
answerSection.classList.add('mt-4', 'text-gray-600', 'dark:text-gray', 'dark:bg-gray-700', 'p-5', 'rounded-lg')
const answerTitle = document.createElement('h3');
answerTitle.textContent = 'Answer:';
answerTitle.classList.add('text-indigo-600', 'dark:text-indigo-400');

const answerText = document.createElement('p');
answerText.textContent = question.answer;
answerText.classList.add('text-gray-700', 'dark:text-gray-300');

answerSection.appendChild(answerTitle);
answerSection.appendChild(answerText);
card.appendChild(answerSection);
} else {
const answerForm = renderAnswerForm(question.id);
card.appendChild(answerForm);
}

return card;
};
// Function to render the Question Form
const renderQuestionForm = () => {
const formContainer = document.createElement('div');
formContainer.classList.add('bg-white', 'dark:bg-gray-800', 'p-4', 'rounded-md', 'shadow-md', 'mb-6');

const textarea = document.createElement('textarea');
textarea.placeholder = 'Ask your question...';
textarea.classList.add('w-full', 'p-3', 'border', 'rounded-md', 'dark:bg-gray-700', 'dark:text-white', 'focus:outline-none', 'focus:ring-2', 'focus:ring-indigo-500');

const button = document.createElement('button');
button.textContent = 'Ask Question';
button.classList.add('mt-4', 'bg-indigo-500', 'text-white', 'px-4', 'py-2', 'rounded-md', 'hover:bg-indigo-600', 'focus:outline-none', 'focus:ring-2', 'focus:ring-indigo-500');

formContainer.appendChild(textarea);
formContainer.appendChild(button);

button.addEventListener('click', (e) => {
e.preventDefault();
const content = textarea.value.trim();
if (content) {
addQuestion(content);
textarea.value = '';
}
});

return formContainer;
};

// Function to render the Answer Form
const renderAnswerForm = (questionId) => {
const formContainer = document.createElement('div');
formContainer.classList.add('bg-white', 'dark:bg-gray-800', 'p-4', 'rounded-md', 'shadow-md', 'mt-4');

const textarea = document.createElement('textarea');
textarea.placeholder = 'Write your answer...';
textarea.classList.add('w-full', 'p-3', 'border', 'rounded-md', 'dark:bg-gray-700', 'dark:text-white', 'focus:outline-none', 'focus:ring-2', 'focus:ring-indigo-500');

const button = document.createElement('button');
button.textContent = 'Submit Answer';
button.classList.add('mt-4', 'bg-green-500', 'text-white', 'px-4', 'py-2', 'rounded-md', 'hover:bg-green-600', 'focus:outline-none', 'focus:ring-2', 'focus:ring-green-500');

formContainer.appendChild(textarea);
formContainer.appendChild(button);

button.addEventListener('click', (e) => {
e.preventDefault();
const answerContent = textarea.value.trim();
if (answerContent) {
addAnswer(questionId, answerContent);
textarea.value = '';
}
});

return formContainer;
};



// Function to render the list of questions
const renderQuestionList = () => {
// Create container divs for unanswered and answered sections
const unansweredContainer = document.createElement('div');
const answeredContainer = document.createElement('div');

// Create titles for unanswered and answered questions
const unansweredTitle = document.createElement('h2');
unansweredTitle.textContent = 'Unanswered Questions';
unansweredTitle.classList.add('text-2xl', 'font-semibold', 'mb-4', 'text-gray-800', 'dark:text-white');

const answeredTitle = document.createElement('h2');
answeredTitle.textContent = 'Answered Questions';
answeredTitle.classList.add('text-2xl', 'font-semibold', 'mb-4', 'text-gray-800', 'dark:text-white', 'mt-8');

// Append the titles to their respective containers
unansweredContainer.appendChild(unansweredTitle);
answeredContainer.appendChild(answeredTitle);

// Filter questions into answered and unanswered arrays
const unansweredQuestions = questions.filter(q => !q.answered);
const answeredQuestions = questions.filter(q => q.answered);

// Create a wrapper div for unanswered questions
const unansweredCardsContainer = document.createElement('div');
unansweredCardsContainer.classList.add('flex', 'gap-9', 'flex-wrap'); // Add space between cards

// Handle unanswered questions
if (unansweredQuestions.length === 0) {
const noUnansweredMessage = document.createElement('p');
noUnansweredMessage.textContent = 'No unanswered questions yet.';
unansweredCardsContainer.appendChild(noUnansweredMessage);
} else {
unansweredQuestions.forEach(q => {
const questionCard = renderQuestionCard(q);
unansweredCardsContainer.appendChild(questionCard);
});
}

// Create a wrapper div for answered questions
const answeredCardsContainer = document.createElement('div');
answeredCardsContainer.classList.add('flex', 'gap-9', 'flex-wrap'); // Add space between cards

// Handle answered questions
if (answeredQuestions.length === 0) {
const noAnsweredMessage = document.createElement('p');
noAnsweredMessage.textContent = 'No answered questions yet.';
answeredCardsContainer.appendChild(noAnsweredMessage);
} else {
answeredQuestions.forEach(q => {
const questionCard = renderQuestionCard(q);
answeredCardsContainer.appendChild(questionCard);
});
}

// Append the card containers to their respective sections
unansweredContainer.appendChild(unansweredCardsContainer);
answeredContainer.appendChild(answeredCardsContainer);

// Append both sections to the container
container.appendChild(unansweredContainer);
container.appendChild(answeredContainer);
};



const render = () => {
container.innerHTML = ''; // Clear the container

// Create the heading for the forum
const heading = document.createElement('h1');
heading.textContent = 'Wordwise Discussion Forum';
heading.classList.add('text-3xl', 'font-bold', 'mb-6', 'text-gray-800', 'dark:text-white');
container.appendChild(heading);

// First, append the question form at the top
const questionForm = renderQuestionForm();
container.appendChild(questionForm);

// Then, append the question list (answered and unanswered)
const questionList = renderQuestionList();
container.appendChild(questionList);
};



render(); // Initial render
}
92 changes: 90 additions & 2 deletions frontend/src/styles/output.css
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,10 @@ video {
height: 2rem;
}

.min-h-screen {
min-height: 100vh;
}

.w-1\/3 {
width: 33.333333%;
}
Expand Down Expand Up @@ -835,6 +839,22 @@ video {
width: 100%;
}

.w-\[27\%\] {
width: 27%;
}

.w-\[28\%\] {
width: 28%;
}

.w-\[29\%\] {
width: 29%;
}

.w-\[30\%\] {
width: 30%;
}

.max-w-4xl {
max-width: 56rem;
}
Expand All @@ -843,6 +863,7 @@ video {
max-width: 1280px;
}


.transform {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
Expand Down Expand Up @@ -903,6 +924,14 @@ video {
gap: 2rem;
}

.gap-2 {
gap: 0.5rem;
}

.gap-9 {
gap: 2.25rem;
}

.space-x-3 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.75rem * var(--tw-space-x-reverse));
Expand Down Expand Up @@ -1132,6 +1161,30 @@ video {
background-color: rgb(254 249 195 / var(--tw-bg-opacity));
}

.bg-green-500 {
--tw-bg-opacity: 1;
background-color: rgb(34 197 94 / var(--tw-bg-opacity));
}

.bg-indigo-500 {
--tw-bg-opacity: 1;
background-color: rgb(99 102 241 / var(--tw-bg-opacity));
}

.bg-gradient-to-r {
background-image: linear-gradient(to right, var(--tw-gradient-stops));
}

.from-indigo-100 {
--tw-gradient-from: #e0e7ff var(--tw-gradient-from-position);
--tw-gradient-to: rgb(224 231 255 / 0) var(--tw-gradient-to-position);
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
}

.to-purple-100 {
--tw-gradient-to: #f3e8ff var(--tw-gradient-to-position);
}

.object-cover {
-o-object-fit: cover;
object-fit: cover;
Expand Down Expand Up @@ -1161,9 +1214,11 @@ video {
padding: 2rem;
}

.p-1 {
.p-5 {
padding: 1.25rem;
.p-1 {
padding: 0.25rem;
}
}

.px-12 {
padding-left: 3rem;
Expand Down Expand Up @@ -1440,6 +1495,12 @@ video {
color: rgb(133 77 14 / var(--tw-text-opacity));
}

.text-indigo-400 {
--tw-text-opacity: 1;
color: rgb(129 140 248 / var(--tw-text-opacity));
}


.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
Expand All @@ -1458,6 +1519,12 @@ video {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.shadow-gray-200 {
--tw-shadow-color: #e5e7eb;
--tw-shadow: var(--tw-shadow-colored);
Expand Down Expand Up @@ -1541,6 +1608,12 @@ body.dark-mode {
padding: 20px;
}

.hover\:scale-105:hover {
--tw-scale-x: 1.05;
--tw-scale-y: 1.05;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.hover\:bg-\[\#753ff1\]:hover {
--tw-bg-opacity: 1;
background-color: rgb(117 63 241 / var(--tw-bg-opacity));
Expand Down Expand Up @@ -1596,6 +1669,16 @@ body.dark-mode {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}

.hover\:bg-green-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(22 163 74 / var(--tw-bg-opacity));
}

.hover\:bg-indigo-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(79 70 229 / var(--tw-bg-opacity));
}

.hover\:text-blue-700:hover {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
Expand Down Expand Up @@ -1702,6 +1785,11 @@ body.dark-mode {
--tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity));
}

.focus\:ring-green-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(34 197 94 / var(--tw-ring-opacity));
}

.focus\:ring-opacity-50:focus {
--tw-ring-opacity: 0.5;
}
Expand Down
Loading

1 comment on commit 9a6d538

@vercel
Copy link

@vercel vercel bot commented on 9a6d538 Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.