7 KiB
Reactions Feature Implementation & Troubleshooting
Overview
This document covers the complete implementation and troubleshooting of the reactions feature in the Sojorn application, including both backend (Go) and frontend (Flutter) components.
Problem Statement
The reactions feature had multiple issues:
- Backend 500 errors when toggling reactions
- Frontend not showing reactions on initial load (showing
null) - UI not updating immediately after toggling reactions
- Need to refresh page to see reaction changes
Backend Issues & Solutions
Issue 1: pgx.ErrNoRows vs sql.ErrNoRows
Problem: The Go backend was using sql.ErrNoRows to check for no rows in database queries, but pgx returns pgx.ErrNoRows.
Error:
ERR DEBUG: Failed to check existing reaction - unexpected error error="no rows in result set"
Solution: Update error handling in internal/repository/post_repository.go:
import (
"github.com/jackc/pgx/v5" // Add this import
)
// Change from:
} else if err != sql.ErrNoRows {
// To:
} else if err != pgx.ErrNoRows {
Issue 2: JSON Serialization Omitting Empty Fields
Problem: The Post model had omitempty tags on reaction fields, causing them to be omitted from JSON responses when empty.
Solution: Remove omitempty from reaction JSON tags in internal/models/post.go:
// Before:
Reactions map[string]int `json:"reactions,omitempty"`
MyReactions []string `json:"my_reactions,omitempty"`
ReactionUsers map[string][]string `json:"reaction_users,omitempty"`
// After:
Reactions map[string]int `json:"reactions"`
MyReactions []string `json:"my_reactions"`
ReactionUsers map[string][]string `json:"reaction_users"`
Frontend Issues & Solutions
Issue 1: UI Not Updating Immediately
Problem: The _reactionCountsFor and _myReactionsFor methods prioritized post.reactions over local state, but after toggle reactions, local state had updated data while post.reactions still had old data.
Solution: Change priority to prefer local state for immediate updates in lib/screens/post/threaded_conversation_screen.dart:
Map<String, int> _reactionCountsFor(Post post) {
// Prefer local state for immediate updates after toggle reactions
final localState = _reactionCountsByPost[post.id];
if (localState != null) {
return localState;
}
// Fall back to post model if no local state
return post.reactions ?? {};
}
Set<String> _myReactionsFor(Post post) {
// Prefer local state for immediate updates after toggle reactions
final localState = _myReactionsByPost[post.id];
if (localState != null) {
return localState;
}
// Fall back to post model if no local state
return post.myReactions?.toSet() ?? <String>{};
}
Implementation Steps
Backend Implementation
-
Fix Error Handling:
cd go-backend # Edit internal/repository/post_repository.go # Add pgx import and change error handling git add . && git commit -m "Fix ToggleReaction error handling - use pgx.ErrNoRows" -
Fix JSON Serialization:
# Edit internal/models/post.go # Remove omitempty from reaction fields git add . && git commit -m "Remove omitempty from reaction JSON fields" -
Deploy Backend:
cd /opt/sojorn/go-backend git pull origin ThreadRestoration sudo systemctl stop sojorn-api go build -o ../bin/api ./cmd/api sudo systemctl start sojorn-api
Frontend Implementation
- Fix UI Update Priority:
cd sojorn_app # Edit lib/screens/post/threaded_conversation_screen.dart # Update _reactionCountsFor and _myReactionsFor methods git add . && git commit -m "Fix reaction UI updates - prioritize local state"
Debugging Techniques
Backend Debugging
-
Add Debug Logging:
log.Info().Str("postID", postID).Str("userID", userID).Msg("DEBUG: No existing reaction found (expected)") log.Error().Err(err).Str("postID", postID).Str("userID", userID).Msg("DEBUG: Failed to check existing reaction - unexpected error") -
Monitor Logs:
sudo tail -f /var/log/syslog | grep api
Frontend Debugging
-
Add Debug Logging:
print('DEBUG: Toggle reaction response: $response'); print('DEBUG: Updated local reaction counts: ${_reactionCountsByPost[postId]}'); print('DEBUG: Using local state: ${localState}'); -
Check API Response:
final response = await api.toggleReaction(postId, emoji); print('DEBUG: API response: $response');
Testing Checklist
Backend Tests
- Toggle reaction returns 200 (not 500)
- Reaction is saved to database
- API response includes updated counts and user reactions
- Empty reaction fields return
{}and[]instead ofnull
Frontend Tests
- Reactions show on initial load
- Toggle reaction updates UI immediately
- No refresh needed to see changes
- Selected emoji shows as selected
- Reaction count updates correctly
Common Issues & Solutions
Issue: "no rows in result set" Error
Cause: Using sql.ErrNoRows instead of pgx.ErrNoRows
Fix: Update error handling to use pgx.ErrNoRows
Issue: Frontend Shows null for Reactions
Cause: omitempty in JSON tags omits empty fields
Fix: Remove omitempty from reaction field JSON tags
Issue: UI Not Updating After Toggle
Cause: UI prioritizes old post data over updated local state Fix: Change priority to prefer local state for immediate updates
Issue: Need to Refresh to See Changes
Cause: Same as above - UI not using updated local state Fix: Same solution - prioritize local state
Key Files Modified
Backend
internal/repository/post_repository.go- Error handling fixinternal/models/post.go- JSON serialization fix
Frontend
lib/screens/post/threaded_conversation_screen.dart- UI update priority fix
Verification Commands
Backend Verification
# Check if service is running
sudo systemctl status sojorn-api
# Check logs for errors
sudo tail -f /var/log/syslog | grep api
# Test API endpoint
curl -X POST "http://194.238.28.122:8080/api/v1/posts/{post-id}/reactions/toggle" \
-H "Authorization: Bearer {jwt-token}" \
-H "Content-Type: application/json" \
-d '{"emoji": "❤️"}'
Frontend Verification
# Check Flutter logs
flutter run --verbose
# Look for debug messages
grep "DEBUG:" flutter_logs.txt
Success Criteria
✅ Backend: Toggle reactions return 200, no 500 errors ✅ Frontend: Reactions show immediately, no refresh needed ✅ UI: Selected emojis display correctly ✅ Data: Empty reactions show as empty, not null
Future Improvements
- Optimistic Updates: Implement proper optimistic UI updates
- Error Handling: Better error messages for failed reactions
- Performance: Cache reaction data to reduce API calls
- Real-time: WebSocket updates for live reaction changes