feat: implement feedback filter for liked/favorited photos (Issue #17)
Implemented Feature Request 1 from github.com/the-luap/picpeak/issues/17: - Added filter functionality to display only liked or favorited photos - Integrated feedback filter directly into PhotoFilterBar component - Implemented responsive design with proper mobile/tablet/desktop layouts - Filter only shows when feedback is enabled for the gallery - Added proper count display for liked and favorited photos Improvements: - Fixed responsive breakpoints (mobile <768px, tablet 768-1023px, desktop ≥1024px) - Feedback filter shows inline with categories on desktop with vertical divider - On mobile/tablet, filter appears below categories to prevent layout issues - Added horizontal scrolling for category buttons to prevent cut-off Code cleanup: - Removed all debug console.log statements from production code - Removed test route from backend gallery.js - Cleaned up unnecessary logging in frontend components 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -390,6 +390,76 @@ class FeedbackService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered photos based on feedback criteria
|
||||
* @param {number} eventId - Event ID
|
||||
* @param {string} guestIdentifier - Guest identifier
|
||||
* @param {object} filters - Filter criteria
|
||||
* @param {boolean} filters.liked - Include liked photos
|
||||
* @param {boolean} filters.favorited - Include favorited photos
|
||||
* @param {string} filters.operator - 'AND' or 'OR' for multiple filters
|
||||
* @returns {Promise<number[]>} Array of photo IDs that match criteria
|
||||
*/
|
||||
async getFilteredPhotos(eventId, guestIdentifier, filters = {}) {
|
||||
try {
|
||||
const { liked, favorited, operator = 'OR' } = filters;
|
||||
|
||||
// If no filters specified, return all photos
|
||||
if (!liked && !favorited) {
|
||||
const allPhotos = await db('photos')
|
||||
.where('event_id', eventId)
|
||||
.select('id');
|
||||
return allPhotos.map(p => p.id);
|
||||
}
|
||||
|
||||
// Build query based on filters
|
||||
let query = db('photo_feedback')
|
||||
.where('event_id', eventId)
|
||||
.where('guest_identifier', guestIdentifier)
|
||||
.where('is_hidden', false);
|
||||
|
||||
// Apply filter logic
|
||||
if (operator === 'AND' && liked && favorited) {
|
||||
// For AND operation, we need photos that have both types of feedback
|
||||
const likedPhotos = await db('photo_feedback')
|
||||
.where('event_id', eventId)
|
||||
.where('guest_identifier', guestIdentifier)
|
||||
.where('feedback_type', 'like')
|
||||
.where('is_hidden', false)
|
||||
.select('photo_id');
|
||||
|
||||
const favoritedPhotos = await db('photo_feedback')
|
||||
.where('event_id', eventId)
|
||||
.where('guest_identifier', guestIdentifier)
|
||||
.where('feedback_type', 'favorite')
|
||||
.where('is_hidden', false)
|
||||
.select('photo_id');
|
||||
|
||||
const likedIds = new Set(likedPhotos.map(p => p.photo_id));
|
||||
const favoritedIds = new Set(favoritedPhotos.map(p => p.photo_id));
|
||||
|
||||
// Return intersection of both sets
|
||||
return Array.from(likedIds).filter(id => favoritedIds.has(id));
|
||||
} else {
|
||||
// OR operation or single filter
|
||||
const feedbackTypes = [];
|
||||
if (liked) feedbackTypes.push('like');
|
||||
if (favorited) feedbackTypes.push('favorite');
|
||||
|
||||
query.whereIn('feedback_type', feedbackTypes);
|
||||
}
|
||||
|
||||
const filteredPhotos = await query
|
||||
.distinct('photo_id')
|
||||
.select('photo_id');
|
||||
|
||||
return filteredPhotos.map(p => p.photo_id);
|
||||
} catch (error) {
|
||||
logger.error('Error getting filtered photos:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new FeedbackService();
|
||||
Reference in New Issue
Block a user