5.7 KiB
Enhancement Summary: Tag Selection & Photo Filtering
Overview
Successfully enhanced the travel planning application with improved photo tagging UI and photo filtering capabilities on the explore map.
Changes Implemented
1. Enhanced TagSelectModal Component ✅
File: frontend/src/components/TagSelectModal.tsx
Features Added:
- Image Preview: Shows the uploaded photo at the top of the modal (max-height: 192px, with rounded corners)
- Custom Tag Input: Text input with "Nhập thẻ mới..." placeholder
- Add Custom Tags: Button and Enter key support to add user-defined tags
- Remove Custom Tags: Trash icon on hover to delete custom tags
- Visual Feedback: Selected tags highlighted in different colors (blue for predefined, emerald for custom)
- Summary Section: Displays count and list of all selected tags before confirmation
UI Improvements:
- Sticky header and footer for easy access
- Separate sections for predefined tags and custom input
- Max-height with scrolling for long tag lists
- Smooth animations and transitions
2. LandingPage Integration ✅
File: frontend/src/pages/LandingPage.tsx
Updates:
- Added
photoPreviewUrlstate for temporary preview image - Created object URL using
URL.createObjectURL()when file is selected - Pass preview URL to TagSelectModal component
- Proper cleanup with
URL.revokeObjectURL()on modal close or after upload - Included custom tags in upload formData as JSON
State Management:
const [photoPreviewUrl, setPhotoPreviewUrl] = useState<string>('');
3. ExploreMap Photo Tag Filtering ✅
File: frontend/src/pages/ExploreMap.tsx
Features Added:
- Photo Tag Filter State:
selectedPhotoFilterTagsfor tracking active filters - Available Photo Tags:
availablePhotoTagscomputed from all public photos' metadata - Enhanced Filter Dropdown: Two-section filter UI:
- Tour Section (🧳 Chuyến đi): Existing tour tags (single selection)
- Photo Section (📸 Ảnh công khai): Photo tags from uploads (multiple selection)
- Filtering Logic:
groupedPhotosuseMemo filters photos based on selected tags - Dynamic Tag Population: Photo tags automatically extracted from
photo.metadata.tags
Filtering Behavior:
- Multiple photo tags can be selected simultaneously
- Photos matching ANY selected tag are displayed (OR logic)
- "Tất cả" button clears photo filters
- Filter is independent from tour tag filtering
Technical Details
Tag Storage
- Backend stores tags in
photo.metadata.tagsas JSON array - No database schema changes required
- Flexible for custom tags without pre-definition
Frontend State Management
// State
const [selectedPhotoFilterTags, setSelectedPhotoFilterTags] = useState<string[]>([]);
// Computed
const availablePhotoTags = React.useMemo(() => {
const tagsSet = new Set<string>();
publicPhotos.forEach(photo => {
const tags = photo.metadata?.tags as string[] | undefined;
if (Array.isArray(tags)) {
tags.forEach(tag => tagsSet.add(tag));
}
});
return Array.from(tagsSet).sort();
}, [publicPhotos]);
// Filtered Results
const groupedPhotos = React.useMemo(() => {
let filteredPhotos = publicPhotos;
if (selectedPhotoFilterTags.length > 0) {
filteredPhotos = publicPhotos.filter((photo) => {
const photoTags = photo.metadata?.tags as string[] | undefined;
if (!Array.isArray(photoTags)) return false;
return selectedPhotoFilterTags.some(tag => photoTags.includes(tag));
});
}
// ... grouping and sorting logic
}, [publicPhotos, selectedPhotoFilterTags]);
Testing Results
Verified Functionality
✅ Image preview displays in TagSelectModal
✅ Custom tag input accepts user text
✅ Custom tags can be added with button or Enter key
✅ Custom tags can be removed with trash icon
✅ All selected tags display in summary
✅ Photo tag filtering works on ExploreMap
✅ Multiple photo tags can be selected
✅ "Tất cả" button clears filters
✅ Docker build successful (0 errors)
✅ All services running healthy
Build Status
- Frontend build: ✅ Success
- Backend build: ✅ Success
- Container deployment: ✅ All 4 services running
- Browser testing: ✅ Filter dropdown functional
User Workflow
Photo Upload with Tags
- User clicks "Chụp ảnh" button
- Selects image from device
- Image is displayed in TagSelectModal preview
- User selects predefined tags from 11 categories
- User can add custom tags in textbox
- Confirms and photo is uploaded with all tags
- Tags stored in database for filtering
Photo Discovery with Filtering
- User navigates to "Khám phá" (Explore)
- Clicks filter button to open dropdown
- Sees available photo tags from community uploads
- Selects one or more tags to filter
- Map refreshes showing only photos with selected tags
- Clear selection with "Tất cả" button to see all photos again
Files Modified
- ✅
frontend/src/components/TagSelectModal.tsx- Enhanced with preview and custom tags - ✅
frontend/src/pages/LandingPage.tsx- Integration with preview URL - ✅
frontend/src/pages/ExploreMap.tsx- Photo tag filtering implementation
Browser Compatibility
- Modern browsers with ES6+ support
- Tested on latest Chrome/Firefox/Safari
- Mobile responsive design with touch support
Performance Considerations
- Photo tag extraction done in useMemo (cached)
- Filter operations are optimized with Set for uniqueness
- Lazy filtering applied only to grouped photos
- No additional API calls needed (uses existing photo data)
Future Enhancements
- Tag search/autocomplete in filter
- Tag popularity sorting
- Tag suggestions based on similar photos
- User tag preferences/favorites
- Tag analytics dashboard