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.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 @@