@@ -30,124 +30,85 @@ This component displays a user status icon.
3030</docs >
3131
3232<template >
33- <span v-if =" activeStatus "
33+ <span v-if =" status "
3434 class =" user-status-icon"
3535 :class =" {
36- 'user-status-icon--invisible': ['invisible', 'offline'].includes(status) ,
36+ 'user-status-icon--invisible': isInvisible ,
3737 }"
38+ :aria-hidden =" !ariaLabel || undefined"
39+ :aria-label
3840 role =" img"
39- :aria-hidden =" ariaHidden"
40- :aria-label =" ariaLabel"
4141 v-html =" activeSvg" /> <!-- eslint-disable-line vue/no-v-html -->
4242</template >
4343
44- <script >
44+ <script setup lang="ts" >
4545import axios from ' @nextcloud/axios'
4646import { generateOcsUrl } from ' @nextcloud/router'
4747import { getCapabilities } from ' @nextcloud/capabilities'
48+ import { computed , watch } from ' vue'
49+ import { getUserStatusText } from ' ../../utils/UserStatus.ts'
50+ import { t } from ' ../../l10n.js'
4851
4952import onlineSvg from ' ../../assets/status-icons/user-status-online.svg?raw'
5053import awaySvg from ' ../../assets/status-icons/user-status-away.svg?raw'
5154import dndSvg from ' ../../assets/status-icons/user-status-dnd.svg?raw'
5255import invisibleSvg from ' ../../assets/status-icons/user-status-invisible.svg?raw'
53-
54- import { getUserStatusText } from ' ../../utils/UserStatus.ts'
55- import { t } from ' ../../l10n.js'
56-
57- export default {
58- name: ' NcUserStatusIcon' ,
59-
60- props: {
61- /**
62- * Set the user id to fetch the status
63- */
64- user: {
65- type: String ,
66- default: null ,
67- },
68-
69- /**
70- * Set the status
71- *
72- * @type {'online' | 'away' | 'busy' | 'dnd' | 'invisible' | 'offline'}
73- */
74- status: {
75- type: String ,
76- default: null ,
77- validator : (value ) => [
78- ' online' ,
79- ' away' ,
80- ' busy' ,
81- ' dnd' ,
82- ' invisible' ,
83- ' offline' ,
84- ].includes (value),
85- },
86-
87- /**
88- * Set the `aria-hidden` attribute
89- *
90- * @type {'true' | 'false'}
91- */
92- ariaHidden: {
93- type: String ,
94- default: null ,
95- validator : (value ) => [
96- ' true' ,
97- ' false' ,
98- ].includes (value),
99- },
100- },
101-
102- data () {
103- return {
104- fetchedUserStatus: null ,
56+ import logger from ' ../../utils/logger.ts'
57+
58+ const props = withDefaults (defineProps <{
59+ /**
60+ * Set the user id to fetch the status
61+ */
62+ user? : string ,
63+
64+ /**
65+ * The user preloaded user status.
66+ */
67+ status? : ' online' | ' away' | ' busy' | ' dnd' | ' invisible' | ' offline'
68+
69+ /**
70+ * Set the `aria-hidden` attribute
71+ */
72+ ariaHidden? : boolean | ' true' | ' false'
73+ }>(), {
74+ user: undefined ,
75+ status: undefined ,
76+ ariaHidden: false ,
77+ })
78+
79+ const status = defineModel <typeof props .status >(' status' , { default: null })
80+ const isInvisible = computed (() => status .value && [' invisible' , ' offline' ].includes (status .value ))
81+
82+ watch (() => props .user , async (user ) => {
83+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84+ if (! status .value && user && (getCapabilities () as any )?.user_status ?.enabled ) {
85+ try {
86+ const { data } = await axios .get (generateOcsUrl (' /apps/user_status/api/v1/statuses/{user}' , { user }))
87+ status .value = data .ocs ?.data ?.status
88+ } catch (error ) {
89+ logger .debug (' Error while fetching user status' , { error })
10590 }
106- },
107-
108- computed: {
109- activeStatus () {
110- return this .status ?? this .fetchedUserStatus
111- },
112-
113- activeSvg () {
114- const matchSvg = {
115- online: onlineSvg,
116- away: awaySvg,
117- busy: awaySvg,
118- dnd: dndSvg,
119- invisible: invisibleSvg,
120- offline: invisibleSvg,
121- }
122- return matchSvg[this .activeStatus ] ?? null
123- },
124-
125- ariaLabel () {
126- if (this .ariaHidden === ' true' ) {
127- return null
128- }
129- return t (' User status: {status}' , { status: getUserStatusText (this .activeStatus ) })
130- },
131- },
132-
133- watch: {
134- user: {
135- immediate: true ,
136- async handler (user ) {
137- if (! user || ! getCapabilities ()? .user_status ? .enabled ) {
138- this .fetchedUserStatus = null
139- return
140- }
141- try {
142- const { data } = await axios .get (generateOcsUrl (' /apps/user_status/api/v1/statuses/{user}' , { user }))
143- this .fetchedUserStatus = data .ocs ? .data ? .status
144- } catch (error) {
145- this .fetchedUserStatus = null
146- }
147- },
148- },
149- },
91+ }
92+ }, { immediate: true })
93+
94+ /**
95+ * Aria label to set on the element (will be set when ariaHidden is not set)
96+ */
97+ const ariaLabel = computed (() => (
98+ status .value && (! props .ariaHidden || props .ariaHidden === ' false' )
99+ ? t (' User status: {status}' , { status: getUserStatusText (status .value ) })
100+ : undefined
101+ ))
102+
103+ const matchSvg = {
104+ online: onlineSvg ,
105+ away: awaySvg ,
106+ busy: awaySvg ,
107+ dnd: dndSvg ,
108+ invisible: invisibleSvg ,
109+ offline: invisibleSvg ,
150110}
111+ const activeSvg = computed (() => status .value && matchSvg [status .value ])
151112 </script >
152113
153114<style lang="scss" scoped>
0 commit comments