Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions frontend/src/api/mockData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/**
* MOCK DATA FOR DEVELOPMENT
*
* This file provides mock data to test the frontend without a backend server.
* Remove this file when the actual backend API is implemented.
*/

export const mockQuestions = [
{
_id: '1',
questionText: 'What is the difference between var, let, and const in JavaScript?',
company: 'Google',
topic: 'JavaScript',
role: 'Frontend Developer',
difficulty: 'Medium',
upvotes: 42,
createdAt: '2024-10-15T10:30:00Z',
updatedAt: '2024-10-15T10:30:00Z'
},
{
_id: '2',
questionText: 'Explain the concept of closures in JavaScript with an example.',
company: 'Meta',
topic: 'JavaScript',
role: 'Full Stack Developer',
difficulty: 'Hard',
upvotes: 38,
createdAt: '2024-10-14T14:20:00Z',
updatedAt: '2024-10-14T14:20:00Z'
},
{
_id: '3',
questionText: 'What is React Virtual DOM and how does it work?',
company: 'Netflix',
topic: 'React',
role: 'Frontend Developer',
difficulty: 'Medium',
upvotes: 56,
createdAt: '2024-10-13T09:15:00Z',
updatedAt: '2024-10-13T09:15:00Z'
},
{
_id: '4',
questionText: 'How do you implement authentication in a React application?',
company: 'Airbnb',
topic: 'React',
role: 'Frontend Developer',
difficulty: 'Hard',
upvotes: 73,
createdAt: '2024-10-12T16:45:00Z',
updatedAt: '2024-10-12T16:45:00Z'
},
{
_id: '5',
questionText: 'What are React Hooks and why were they introduced?',
company: 'Uber',
topic: 'React',
role: 'Frontend Developer',
difficulty: 'Easy',
upvotes: 29,
createdAt: '2024-10-11T11:30:00Z',
updatedAt: '2024-10-11T11:30:00Z'
},
{
_id: '6',
questionText: 'Explain the difference between SQL and NoSQL databases.',
company: 'Amazon',
topic: 'Database',
role: 'Backend Developer',
difficulty: 'Medium',
upvotes: 45,
createdAt: '2024-10-10T13:20:00Z',
updatedAt: '2024-10-10T13:20:00Z'
},
{
_id: '7',
questionText: 'What is RESTful API design and what are its principles?',
company: 'Microsoft',
topic: 'API Design',
role: 'Backend Developer',
difficulty: 'Medium',
upvotes: 51,
createdAt: '2024-10-09T15:10:00Z',
updatedAt: '2024-10-09T15:10:00Z'
},
{
_id: '8',
questionText: 'How do you optimize database queries for better performance?',
company: 'Oracle',
topic: 'Database',
role: 'Database Administrator',
difficulty: 'Hard',
upvotes: 67,
createdAt: '2024-10-08T12:00:00Z',
updatedAt: '2024-10-08T12:00:00Z'
}
];

export const mockCategories = {
companies: ['Google', 'Meta', 'Netflix', 'Airbnb', 'Uber', 'Amazon', 'Microsoft', 'Oracle'],
topics: ['JavaScript', 'React', 'Database', 'API Design', 'Node.js', 'Python', 'System Design'],
roles: ['Frontend Developer', 'Backend Developer', 'Full Stack Developer', 'Database Administrator', 'DevOps Engineer']
};

/**
* Mock API functions that simulate server responses
*/
export const mockGetAllQuestions = (filters = {}) => {
return new Promise((resolve) => {
setTimeout(() => {
let filteredQuestions = [...mockQuestions];

// Filter by company
if (filters.company) {
filteredQuestions = filteredQuestions.filter(q =>
q.company.toLowerCase().includes(filters.company.toLowerCase())
);
}

// Filter by topic
if (filters.topic) {
filteredQuestions = filteredQuestions.filter(q =>
q.topic.toLowerCase().includes(filters.topic.toLowerCase())
);
}

// Filter by role
if (filters.role) {
filteredQuestions = filteredQuestions.filter(q =>
q.role.toLowerCase().includes(filters.role.toLowerCase())
);
}

// Filter by difficulty
if (filters.difficulty) {
filteredQuestions = filteredQuestions.filter(q =>
q.difficulty === filters.difficulty
);
}

// Sort questions
if (filters.sort) {
switch (filters.sort) {
case 'latest':
filteredQuestions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
break;
case 'oldest':
filteredQuestions.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
break;
case 'upvotes':
filteredQuestions.sort((a, b) => b.upvotes - a.upvotes);
break;
default:
// Default to latest
filteredQuestions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
}
}

resolve({
success: true,
questions: filteredQuestions,
total: filteredQuestions.length
});
}, 500); // Simulate network delay
});
};

export const mockGetCategories = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
success: true,
...mockCategories
});
}, 300);
});
};

export const mockSearchQuestions = (keyword) => {
return new Promise((resolve) => {
setTimeout(() => {
const searchResults = mockQuestions.filter(q =>
q.questionText.toLowerCase().includes(keyword.toLowerCase()) ||
q.company.toLowerCase().includes(keyword.toLowerCase()) ||
q.topic.toLowerCase().includes(keyword.toLowerCase())
);

resolve({
success: true,
questions: searchResults,
total: searchResults.length
});
}, 400);
});
};
43 changes: 34 additions & 9 deletions frontend/src/api/questionApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

import api from './axios';
import { mockGetAllQuestions, mockGetCategories, mockSearchQuestions } from './mockData';

/**
* TODO: IMPLEMENT GET ALL QUESTIONS
Expand Down Expand Up @@ -59,9 +60,23 @@ 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');
try {
const params = new URLSearchParams();

// Add all filter parameters to the URL
Object.keys(filters).forEach(key => {
if (filters[key]) {
params.append(key, filters[key]);
}
});

const response = await api.get(`/questions?${params.toString()}`);
return response.data;
} catch (error) {
console.error('Error fetching questions from API, falling back to mock data:', error);
// Fall back to mock data when backend is not available
return mockGetAllQuestions(filters);
}
};

/**
Expand Down Expand Up @@ -167,9 +182,14 @@ export const getQuestionUpvotes = async (id) => {
*/

export const searchQuestions = async (keyword) => {
// TODO: Implement search
console.log('Search questions API not implemented yet');
throw new Error('Search questions API not implemented');
try {
const response = await api.get(`/questions/search?q=${encodeURIComponent(keyword)}`);
return response.data;
} catch (error) {
console.error('Error searching questions from API, falling back to mock data:', error);
// Fall back to mock data when backend is not available
return mockSearchQuestions(keyword);
}
};

/**
Expand All @@ -187,7 +207,12 @@ 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');
try {
const response = await api.get('/categories');
return response.data;
} catch (error) {
console.error('Error fetching categories from API, falling back to mock data:', error);
// Fall back to mock data when backend is not available
return mockGetCategories();
}
};
14 changes: 10 additions & 4 deletions frontend/src/components/QuestionCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,13 @@ const QuestionCard = ({ question, onUpvote, showActions = true }) => {
return colors[difficulty] || 'bg-gray-100 text-gray-800';
};

// TODO: Implement upvote handler
// Implement upvote handler
const handleUpvote = (e) => {

e.preventDefault(); // Prevent navigation when clicking upvote
e.stopPropagation(); // Prevent event bubbling
if (onUpvote) {
onUpvote(question._id);
}
};

// TODO: Format relative time (e.g., "2 days ago")
Expand All @@ -99,8 +103,10 @@ const QuestionCard = ({ question, onUpvote, showActions = true }) => {
onClick={handleUpvote}
className="flex items-center space-x-1 text-gray-600 hover:text-red-500 transition"
>
{/* TODO: Add heart or arrow icon */}

{/* Heart icon */}
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clipRule="evenodd" />
</svg>
<span className="text-sm font-semibold">{question.upvotes || 0}</span>
</button>
)}
Expand Down
Loading