From f334f6e4e7dd8f76b7e65d3a5d5c0e0fba17aa27 Mon Sep 17 00:00:00 2001 From: Panayiotis Georgiou Date: Sat, 18 Oct 2025 17:48:41 +0300 Subject: [PATCH 1/2] added search input functionality --- frontend/src/api/questionApi.js | 93 ++++++++++++++++++++++++++++--- frontend/src/pages/Questions.jsx | 94 +++++++++++++++++++++++++++----- 2 files changed, 165 insertions(+), 22 deletions(-) diff --git a/frontend/src/api/questionApi.js b/frontend/src/api/questionApi.js index 09a4e3c..d83d8f6 100644 --- a/frontend/src/api/questionApi.js +++ b/frontend/src/api/questionApi.js @@ -59,9 +59,34 @@ import api from './axios'; */ export const getAllQuestions = async (filters = {}) => { - // TODO: Implement get all questions with filters - console.log('Get all questions API not implemented yet'); - throw new Error('Get all questions API not implemented'); + // Simulate API call with mock data + return new Promise((resolve) => { + setTimeout(() => { + let questions = [...MOCK_QUESTIONS]; + + // Apply sorting + if (filters.sort === 'oldest') { + questions.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); + } else if (filters.sort === 'upvotes') { + questions.sort((a, b) => b.upvotes - a.upvotes); + } else { // latest (default) + questions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + } + + // Apply filters + if (filters.company) { + questions = questions.filter(q => q.company === filters.company); + } + if (filters.topic) { + questions = questions.filter(q => q.topic === filters.topic); + } + if (filters.difficulty) { + questions = questions.filter(q => q.difficulty === filters.difficulty); + } + + resolve({ questions }); + }, 300); + }); }; /** @@ -166,10 +191,53 @@ export const getQuestionUpvotes = async (id) => { * Searches in questionText, company, and topic fields */ + +// Mock data for demo purposes +const MOCK_QUESTIONS = [ + { + _id: '1', + questionText: 'What is React?', + company: 'Facebook', + topic: 'Frontend', + role: 'Developer', + difficulty: 'Easy', + upvotes: 10, + createdAt: '2025-10-01T12:00:00Z', + }, + { + _id: '2', + questionText: 'Explain useEffect hook.', + company: 'Google', + topic: 'Frontend', + role: 'Engineer', + difficulty: 'Medium', + upvotes: 7, + createdAt: '2025-09-28T12:00:00Z', + }, + { + _id: '3', + questionText: 'How does Node.js handle async?', + company: 'Amazon', + topic: 'Backend', + role: 'Backend Developer', + difficulty: 'Hard', + upvotes: 15, + createdAt: '2025-09-20T12:00:00Z', + }, +]; + export const searchQuestions = async (keyword) => { - // TODO: Implement search - console.log('Search questions API not implemented yet'); - throw new Error('Search questions API not implemented'); + // Simulate API search + return new Promise((resolve) => { + setTimeout(() => { + const filtered = MOCK_QUESTIONS.filter(q => + q.questionText.toLowerCase().includes(keyword.toLowerCase()) || + q.company.toLowerCase().includes(keyword.toLowerCase()) || + q.topic.toLowerCase().includes(keyword.toLowerCase()) + ); + resolve({ questions: filtered }); + }, 400); + }); }; /** @@ -187,7 +255,14 @@ export const searchQuestions = async (keyword) => { */ export const getCategories = async () => { - // TODO: Implement get categories - console.log('Get categories API not implemented yet'); - throw new Error('Get categories API not implemented'); + // Simulate API call with mock data + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + companies: ['Facebook', 'Google', 'Amazon', 'Microsoft', 'Apple'], + topics: ['Frontend', 'Backend', 'Database', 'DevOps', 'System Design'], + roles: ['Developer', 'Engineer', 'Backend Developer', 'Frontend Developer', 'Full Stack'] + }); + }, 200); + }); }; diff --git a/frontend/src/pages/Questions.jsx b/frontend/src/pages/Questions.jsx index f889835..c0b691c 100644 --- a/frontend/src/pages/Questions.jsx +++ b/frontend/src/pages/Questions.jsx @@ -27,10 +27,10 @@ * - Pagination */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; // TODO: Import API functions import { getAllQuestions, getCategories, searchQuestions } from '../api/questionApi'; -// import QuestionCard from '../components/QuestionCard'; +import QuestionCard from '../components/QuestionCard'; // import Loading from '../components/Loading'; /** @@ -85,11 +85,59 @@ const Questions = () => { roles: [], }); - // TODO: Fetch questions on mount and when filters change + + // Fetch questions on mount and when filters change + useEffect(() => { + // Only fetch if not searching + if (!searchQuery) { + fetchQuestions(); + } + }, [fetchQuestions, searchQuery]); + + // Debounced search effect useEffect(() => { - // fetchQuestions(); + if (!searchQuery) { + fetchQuestions(); + return; + } + setLoading(true); + const handler = setTimeout(() => { + handleSearch(); + }, 500); // 500ms debounce + return () => clearTimeout(handler); + // eslint-disable-next-line + }, [searchQuery]); + + // Fetch questions function + const fetchQuestions = useCallback(async () => { + setLoading(true); + setError(''); + try { + // Using mock data since backend is not ready + const response = await getAllQuestions(filters); + setQuestions(response.questions || []); + } catch (err) { + setError('Failed to load questions. Please try again later.'); + console.error('Error fetching questions:', err); + } finally { + setLoading(false); + } }, [filters]); + // Search handler + const handleSearch = async () => { + setError(''); + try { + const response = await searchQuestions(searchQuery); + setQuestions(response.questions || []); + } catch (err) { + setError('Failed to search questions.'); + setQuestions([]); + } finally { + setLoading(false); + } + }; + //Fetch categories function for filters const fetchCategories = async () => { setCategoriesLoading(true); @@ -146,7 +194,11 @@ const Questions = () => { onChange={(e) => setFilters({ ...filters, company: e.target.value })} > - {/* TODO: Map categories.companies */} + {categories.companies.map((company) => ( + + ))} + {/* Error Display */} + {error && ( +
+ {error} +
+ )} + {/* Questions Grid */}
- {/* TODO: Map questions and render QuestionCard */} - {/* Placeholder */} {loading ? (
@@ -191,13 +252,20 @@ const Questions = () => {
) : questions.length === 0 ? (
-

No questions found. Try adjusting your filters.

+

No questions found. Try adjusting your filters or search terms.

) : ( - // Map questions here -
-

Question cards will appear here once API is implemented

-
+ questions.map((question) => ( + { + console.log('Upvote question:', questionId); + // TODO: Implement upvote functionality + }} + showActions={true} + /> + )) )}
From 3c1ad2eed57bf3cee385f62afb15a132630b6f01 Mon Sep 17 00:00:00 2001 From: Panayiotis Georgiou Date: Sun, 19 Oct 2025 17:52:47 +0300 Subject: [PATCH 2/2] Refactor question fetching logic to improve clarity and add search query condition --- frontend/src/pages/Questions.jsx | 52 +++++++++++++++----------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/frontend/src/pages/Questions.jsx b/frontend/src/pages/Questions.jsx index 044c138..23365f8 100644 --- a/frontend/src/pages/Questions.jsx +++ b/frontend/src/pages/Questions.jsx @@ -87,40 +87,38 @@ const Questions = () => { }); - // TODO: Fetch questions on mount and when filters change - useEffect(() => { - - const fetchQuestions = async () => { - setLoading(true); - setError(''); - try { - const queryParams = {}; - if (filters.company) queryParams.company = filters.company; - if (filters.topic) queryParams.topic = filters.topic; - if (filters.role) queryParams.role = filters.role; - if (filters.difficulty) queryParams.difficulty = filters.difficulty; - if (filters.sort) queryParams.sort = filters.sort; + // Fetch questions function + const fetchQuestions = useCallback(async () => { + setLoading(true); + setError(''); + try { + const queryParams = {}; + if (filters.company) queryParams.company = filters.company; + if (filters.topic) queryParams.topic = filters.topic; + if (filters.role) queryParams.role = filters.role; + if (filters.difficulty) queryParams.difficulty = filters.difficulty; + if (filters.sort) queryParams.sort = filters.sort; - const questionData = await getAllQuestions(queryParams); + const questionData = await getAllQuestions(queryParams); - setQuestions(questionData.questions || questionData || []) - } - catch (err) { - setError('Failed to load questions. Please try again later.'); - console.error('Error fetching questions:', err); - } - finally { - setLoading(false); - } + setQuestions(questionData.questions || questionData || []) + } + catch (err) { + setError('Failed to load questions. Please try again later.'); + console.error('Error fetching questions:', err); + } + finally { + setLoading(false); } - - fetchQuestions(); }, [filters]); // Fetch questions on mount and when filters change useEffect(() => { - fetchQuestions(); - }, [fetchQuestions]); + // Only fetch if not searching + if (!searchQuery) { + fetchQuestions(); + } + }, [fetchQuestions, searchQuery]); //Fetch categories function for filters const fetchCategories = async () => {