diff --git a/cmd/main.go b/cmd/main.go
index 0c226c2a..0aa6cd59 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -241,7 +241,11 @@ func main() {
go sla.Run(ctx, slaEvaluationInterval)
go sla.SendNotifications(ctx)
go media.DeleteUnlinkedMedia(ctx)
- go user.MonitorAgentAvailability(ctx)
+ go user.MonitorUserAvailability(ctx, func(userIDs []int) {
+ for _, id := range userIDs {
+ conversation.BroadcastContactStatus(id, "offline")
+ }
+ })
go conversation.RunDraftCleaner(ctx, draftRetentionDuration)
go userNotification.RunNotificationCleaner(ctx)
diff --git a/cmd/widget_ws.go b/cmd/widget_ws.go
index 4ece09e8..1b86d6a8 100644
--- a/cmd/widget_ws.go
+++ b/cmd/widget_ws.go
@@ -104,10 +104,16 @@ func handleWidgetWS(r *fastglue.Request) error {
if msg.JWT != "" && inboxID != 0 {
if claims, err := validateWidgetMessageJWT(app, msg.JWT, inboxID); err == nil {
if userID, err := resolveUserIDFromClaims(app, claims); err == nil {
+ // Check if user was offline before updating
+ wasOffline := app.user.IsOffline(userID)
if err := app.user.UpdateLastActive(userID); err != nil {
app.lo.Error("error updating user last active timestamp", "user_id", userID, "error", err)
} else {
app.lo.Debug("updated user last active timestamp", "user_id", userID)
+ // Broadcast online status if user just came online
+ if wasOffline {
+ app.conversation.BroadcastContactStatus(userID, "online")
+ }
}
}
}
diff --git a/frontend/apps/main/src/components/sidebar/SidebarNavUser.vue b/frontend/apps/main/src/components/sidebar/SidebarNavUser.vue
index a71ab47b..d269666a 100644
--- a/frontend/apps/main/src/components/sidebar/SidebarNavUser.vue
+++ b/frontend/apps/main/src/components/sidebar/SidebarNavUser.vue
@@ -5,23 +5,19 @@
size="md"
class="p-0"
>
-
-
-
- {{ userStore.getInitials }}
-
-
-
+
{{ userStore.getFullName }}
{{ userStore.email }}
@@ -121,6 +117,7 @@ import {
} from '@shared-ui/components/ui/dropdown-menu'
import { SidebarMenuButton } from '@shared-ui/components/ui/sidebar'
import { Avatar, AvatarFallback, AvatarImage } from '@shared-ui/components/ui/avatar'
+import StatusDot from '@shared-ui/components/StatusDot.vue'
import { Switch } from '@shared-ui/components/ui/switch'
import { ChevronsUpDown, CircleUserRound, LogOut, Moon, Sun } from 'lucide-vue-next'
import { useUserStore } from '../../stores/user'
diff --git a/frontend/apps/main/src/features/conversation/sidebar/ConversationSideBarContact.vue b/frontend/apps/main/src/features/conversation/sidebar/ConversationSideBarContact.vue
index 4622af57..06c69ece 100644
--- a/frontend/apps/main/src/features/conversation/sidebar/ConversationSideBarContact.vue
+++ b/frontend/apps/main/src/features/conversation/sidebar/ConversationSideBarContact.vue
@@ -1,12 +1,20 @@
-
-
-
- {{ conversation?.contact?.first_name?.toUpperCase().substring(0, 2) }}
-
-
+
+
+
+
+ {{ conversation?.contact?.first_name?.toUpperCase().substring(0, 2) }}
+
+
+
+