Skip to content

Commit 2e36cba

Browse files
committed
display image for each user in activities
1 parent cedbe91 commit 2e36cba

5 files changed

Lines changed: 67 additions & 11 deletions

File tree

rocket-backend/internal/database/activities_table.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ func (s *service) GetActivitiesForUserAndFriends(userID uuid.UUID) ([]types.Acti
5353
var activities []types.ActivityWithUser
5454
for rows.Next() {
5555
var activity types.ActivityWithUser
56-
var uid uuid.UUID
57-
if err := rows.Scan(&uid, &activity.Name, &activity.Time, &activity.Message); err != nil {
56+
if err := rows.Scan(&activity.UserID, &activity.Name, &activity.Time, &activity.Message); err != nil {
5857
logger.Error(fmt.Sprintf("Failed to scan activity row: %v", err))
5958
return nil, custom_error.ErrDatabaseQuery
6059
}

rocket-backend/internal/server/activity_handlers.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package server
22

33
import (
4+
"encoding/base64"
45
"net/http"
56

7+
"rocket-backend/internal/types"
8+
"rocket-backend/pkg/logger"
9+
610
"github.com/gin-gonic/gin"
711
"github.com/google/uuid"
812
)
@@ -31,5 +35,36 @@ func (s *Server) GetActivityHandler(c *gin.Context) {
3135
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user data"})
3236
return
3337
}
34-
c.JSON(http.StatusOK, gin.H{"username": user.Username ,"activities": activities})
38+
39+
var activitiesWithImages []types.ActivityWithUserAndImage
40+
for _, activity := range activities {
41+
img, err := s.db.GetUserImage(activity.UserID)
42+
if err != nil {
43+
logger.Error("Failed to get image", err)
44+
img = nil
45+
}
46+
47+
if img != nil {
48+
encodedImage := base64.StdEncoding.EncodeToString(img.Data)
49+
activitiesWithImages = append(activitiesWithImages, types.ActivityWithUserAndImage{
50+
Name: activity.Name,
51+
Time: activity.Time,
52+
Message: activity.Message,
53+
ImageName: img.Name,
54+
ImageType: http.DetectContentType(img.Data),
55+
ImageData: encodedImage,
56+
})
57+
} else {
58+
activitiesWithImages = append(activitiesWithImages, types.ActivityWithUserAndImage{
59+
Name: activity.Name,
60+
Time: activity.Time,
61+
Message: activity.Message,
62+
ImageName: "",
63+
ImageType: "",
64+
ImageData: "",
65+
})
66+
}
67+
}
68+
69+
c.JSON(http.StatusOK, gin.H{"username": user.Username, "activities": activitiesWithImages})
3570
}

rocket-backend/internal/types/dto.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ type RunDTO struct {
5858
CreatedAt string `json:"created_at"`
5959
}
6060

61-
type ActivityWithUser struct {
62-
Name string `json:"name"`
63-
Time time.Time `json:"time"`
64-
Message string `json:"message"`
61+
62+
type ActivityWithUserAndImage struct {
63+
Name string `json:"name"`
64+
Time time.Time `json:"time"`
65+
Message string `json:"message"`
66+
ImageName string `json:"image_name"`
67+
ImageType string `json:"image_type"`
68+
ImageData string `json:"image_data"`
6569
}
6670

6771
type ChatMessage struct {

rocket-backend/internal/types/models.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,10 @@ type Activity struct {
3939
Time time.Time `json:"time"`
4040
Message string `json:"message"`
4141
}
42+
43+
type ActivityWithUser struct {
44+
UserID uuid.UUID `json:"user_id"`
45+
Name string `json:"name"`
46+
Time time.Time `json:"time"`
47+
Message string `json:"message"`
48+
}

website/src/components/dashboard/ActivityPanel.vue

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
<h2 class="panel-title">Activity Feed</h2>
44
<ul class="activity-list">
55
<li v-for="(activity, idx) in activities" :key="idx" class="activity-item" :class="{ 'user-activity': activity.isUser }">
6-
<div class="avatar" :style="{ backgroundColor: activity.color }">
6+
<span v-if="activity.image_data" class="avatar avatar-img">
7+
<img
8+
:src="`data:${activity.image_type || 'image/jpeg'};base64,${activity.image_data}`"
9+
alt="User"
10+
style="width: 40px; height: 40px; border-radius: 50%; object-fit: cover;"
11+
/>
12+
</span>
13+
<div v-else class="avatar" :style="{ backgroundColor: activity.color }">
714
<span>{{ activity.initials }}</span>
815
</div>
916
<div class="activity-content">
@@ -28,6 +35,8 @@ interface Activity {
2835
description: string
2936
time: string
3037
isUser?: boolean
38+
image_data?: string | null
39+
image_type?: string
3140
}
3241
3342
function formatRelativeTime(iso: string): string {
@@ -47,15 +56,17 @@ const activities = ref<Activity[]>([])
4756
onMounted(async () => {
4857
try {
4958
const { username, activities: backendActivities } = (await api.getActivityFeed()).data
50-
activities.value = backendActivities.map(({ name, time, message }) => {
51-
const displayName = name === 'You' ? username: name
59+
activities.value = backendActivities.map(({ name, time, message, image_data, image_type }) => {
60+
const displayName = name === 'You' ? username : name
5261
return {
5362
name: displayName,
5463
initials: getInitials(displayName),
5564
color: getColor(displayName),
5665
description: message,
5766
time: formatRelativeTime(time),
58-
isUser: name === 'You'
67+
isUser: name === 'You',
68+
image_data,
69+
image_type
5970
}
6071
})
6172
} catch {

0 commit comments

Comments
 (0)