@@ -29,127 +29,85 @@ This component displays a user status icon.
2929```
3030</docs >
3131
32- <template >
33- <span v-if =" activeStatus"
34- class =" user-status-icon"
35- :class =" {
36- 'user-status-icon--invisible': ['invisible', 'offline'].includes(status),
37- }"
38- role =" img"
39- :aria-hidden =" ariaHidden"
40- :aria-label =" ariaLabel"
41- v-html =" activeSvg" /> <!-- eslint-disable-line vue/no-v-html -->
42- </template >
43-
44- <script >
32+ <script setup lang="ts">
4533import axios from ' @nextcloud/axios'
4634import { generateOcsUrl } from ' @nextcloud/router'
4735import { getCapabilities } from ' @nextcloud/capabilities'
36+ import { computed , watch } from ' vue'
37+ import { getUserStatusText } from ' ../../utils/UserStatus.ts'
38+ import { t } from ' ../../l10n.js'
4839
4940import onlineSvg from ' ../../assets/status-icons/user-status-online.svg?raw'
5041import awaySvg from ' ../../assets/status-icons/user-status-away.svg?raw'
5142import dndSvg from ' ../../assets/status-icons/user-status-dnd.svg?raw'
5243import 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 ,
44+ import logger from ' ../../utils/logger.ts'
45+
46+ const props = withDefaults (defineProps <{
47+ /**
48+ * Set the user id to fetch the status
49+ */
50+ user? : string
51+
52+ /**
53+ * Set the `aria-hidden` attribute
54+ */
55+ ariaHidden? : boolean | ' true' | ' false'
56+ }>(), {
57+ user: undefined ,
58+ ariaHidden: false ,
59+ })
60+
61+ /**
62+ * The user preloaded user status.
63+ */
64+ const status = defineModel <' online' | ' away' | ' busy' | ' dnd' | ' invisible' | ' offline' >(' status' , { default: undefined })
65+ const isInvisible = computed (() => status .value && [' invisible' , ' offline' ].includes (status .value ))
66+
67+ /**
68+ * Aria label to set on the element (will be set when ariaHidden is not set)
69+ */
70+ const ariaLabel = computed (() => (
71+ status .value && (! props .ariaHidden || props .ariaHidden === ' false' )
72+ ? t (' User status: {status}' , { status: getUserStatusText (status .value ) })
73+ : undefined
74+ ))
75+
76+ watch (() => props .user , async (user ) => {
77+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78+ if (! status .value && user && (getCapabilities () as any )?.user_status ?.enabled ) {
79+ try {
80+ const { data } = await axios .get (generateOcsUrl (' /apps/user_status/api/v1/statuses/{user}' , { user }))
81+ status .value = data .ocs ?.data ?.status
82+ } catch (error ) {
83+ logger .debug (' Error while fetching user status' , { error })
10584 }
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- },
85+ }
86+ }, { immediate: true })
87+
88+ const matchSvg = {
89+ online: onlineSvg ,
90+ away: awaySvg ,
91+ busy: awaySvg ,
92+ dnd: dndSvg ,
93+ invisible: invisibleSvg ,
94+ offline: invisibleSvg ,
15095}
96+ const activeSvg = computed (() => status .value && matchSvg [status .value ])
15197 </script >
15298
99+ <template >
100+ <span v-if =" status"
101+ class =" user-status-icon"
102+ :class =" {
103+ 'user-status-icon--invisible': isInvisible,
104+ }"
105+ :aria-hidden =" !ariaLabel || undefined"
106+ :aria-label
107+ role =" img"
108+ v-html =" activeSvg" /> <!-- eslint-disable-line vue/no-v-html -->
109+ </template >
110+
153111<style lang="scss" scoped>
154112.user-status-icon {
155113 display : flex ;
0 commit comments