diff --git a/nuxt4/app/components/MsnAvatar.vue b/nuxt4/app/components/MsnAvatar.vue new file mode 100644 index 0000000..ffa2811 --- /dev/null +++ b/nuxt4/app/components/MsnAvatar.vue @@ -0,0 +1,262 @@ + + + + + diff --git a/nuxt4/app/components/UserHeader.vue b/nuxt4/app/components/UserHeader.vue index b06f0ce..7ceb507 100644 --- a/nuxt4/app/components/UserHeader.vue +++ b/nuxt4/app/components/UserHeader.vue @@ -2,14 +2,14 @@
- +
-
@@ -22,6 +22,20 @@

{{ user?.email }}

+ + +
+ +
const { user } = useAuthentik() const { isNight, toggleTheme } = useTheme() +const { status: presenceStatus, setStatus: setPresenceStatus, initActivityListeners } = usePresence() // Emits defineEmits(['edit-profile']) + +// Inicializar listeners de actividad +onMounted(() => { + initActivityListeners() +}) + +// Estados disponibles para el selector +const presenceOptions = [ + { value: 'online', label: 'Disponible', icon: 'i-heroicons-check-circle' }, + { value: 'away', label: 'Ausente', icon: 'i-heroicons-clock' }, + { value: 'busy', label: 'Ocupado', icon: 'i-heroicons-minus-circle' }, + { value: 'offline', label: 'Desconectado', icon: 'i-heroicons-x-circle' } +] diff --git a/nuxt4/app/composables/usePresence.ts b/nuxt4/app/composables/usePresence.ts new file mode 100644 index 0000000..3b5c78b --- /dev/null +++ b/nuxt4/app/composables/usePresence.ts @@ -0,0 +1,124 @@ +/** + * Composable para manejar el estado de presencia del usuario + * Inspirado en Windows Live Messenger + */ + +export type PresenceStatus = 'online' | 'away' | 'busy' | 'offline' + +interface PresenceConfig { + light: string // Color para el highlight (top-left) + medium: string // Color medio + dark: string // Color para la sombra (bottom-right) +} + +export const PRESENCE_COLORS: Record = { + online: { + light: '#CCFF99', + medium: '#66CC33', + dark: '#339900' + }, + away: { + light: '#FFE699', + medium: '#FFCC33', + dark: '#FF9900' + }, + busy: { + light: '#FF9999', + medium: '#FF3333', + dark: '#CC0000' + }, + offline: { + light: '#CCCCCC', + medium: '#999999', + dark: '#666666' + } +} + +export const usePresence = () => { + const status = useState('userPresenceStatus', () => 'online') + const lastActivity = useState('lastActivity', () => Date.now()) + + // Configuración de tiempos (en milisegundos) + const AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutos de inactividad = Away + + let inactivityTimer: NodeJS.Timeout | null = null + + // Actualizar última actividad + const updateActivity = () => { + lastActivity.value = Date.now() + + // Si estaba away y el usuario vuelve a estar activo, ponerlo online + if (status.value === 'away') { + status.value = 'online' + } + + resetInactivityTimer() + } + + // Resetear el timer de inactividad + const resetInactivityTimer = () => { + if (inactivityTimer) { + clearTimeout(inactivityTimer) + } + + // Solo en el cliente + if (import.meta.client) { + inactivityTimer = setTimeout(() => { + // Solo cambiar a away si está online + if (status.value === 'online') { + status.value = 'away' + } + }, AWAY_TIMEOUT) + } + } + + // Cambiar estado manualmente + const setStatus = (newStatus: PresenceStatus) => { + status.value = newStatus + + // Si se cambia manualmente, resetear el timer + if (newStatus === 'online') { + resetInactivityTimer() + } else if (inactivityTimer) { + // Si se pone busy o offline manualmente, cancelar el timer de away + clearTimeout(inactivityTimer) + inactivityTimer = null + } + } + + // Obtener los colores del estado actual + const colors = computed(() => PRESENCE_COLORS[status.value]) + + // Inicializar listeners de actividad (solo en cliente) + const initActivityListeners = () => { + if (import.meta.client) { + const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'] + + events.forEach(event => { + document.addEventListener(event, updateActivity, { passive: true }) + }) + + // Iniciar el timer + resetInactivityTimer() + + // Cleanup cuando se desmonte + onUnmounted(() => { + events.forEach(event => { + document.removeEventListener(event, updateActivity) + }) + if (inactivityTimer) { + clearTimeout(inactivityTimer) + } + }) + } + } + + return { + status: readonly(status), + colors, + setStatus, + updateActivity, + initActivityListeners, + PRESENCE_COLORS + } +}