AccountOverview.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. /* eslint-disable vue/no-v-html */
  4. import { storeToRefs } from 'pinia'
  5. import { computed, ref } from 'vue'
  6. import { useRouter } from 'vue-router'
  7. import { useRawHTMLIcon } from '#shared/components/CommonIcon/useRawHTMLIcon.ts'
  8. import CommonUserAvatar from '#shared/components/CommonUserAvatar/CommonUserAvatar.vue'
  9. import FormGroup from '#shared/components/Form/FormGroup.vue'
  10. import { useForceDesktop } from '#shared/composables/useForceDesktop.ts'
  11. import { useLocaleUpdate } from '#shared/composables/useLocaleUpdate.ts'
  12. import { useProductAboutQuery } from '#shared/graphql/queries/about.api.ts'
  13. import { i18n } from '#shared/i18n.ts'
  14. import { QueryHandler } from '#shared/server/apollo/handler/index.ts'
  15. import { useSessionStore } from '#shared/stores/session.ts'
  16. import { browser, os } from '#shared/utils/browser.ts'
  17. import { usePWASupport, isStandalone } from '#shared/utils/pwa.ts'
  18. import CommonSectionMenu from '#mobile/components/CommonSectionMenu/CommonSectionMenu.vue'
  19. import CommonSectionMenuItem from '#mobile/components/CommonSectionMenu/CommonSectionMenuItem.vue'
  20. import CommonSectionMenuLink from '#mobile/components/CommonSectionMenu/CommonSectionMenuLink.vue'
  21. import CommonSectionPopup from '#mobile/components/CommonSectionPopup/CommonSectionPopup.vue'
  22. import { useHeader } from '#mobile/composables/useHeader.ts'
  23. const router = useRouter()
  24. const logout = () => {
  25. router.push('/logout')
  26. }
  27. useHeader({
  28. title: __('Account'),
  29. backUrl: '/',
  30. backAvoidHomeButton: true,
  31. })
  32. const session = useSessionStore()
  33. const { user } = storeToRefs(session)
  34. const { modelCurrentLocale, localeOptions, isSavingLocale, translation } =
  35. useLocaleUpdate()
  36. const hasVersionPermission = session.hasPermission('admin')
  37. const productAboutQuery = new QueryHandler(
  38. useProductAboutQuery({
  39. enabled: hasVersionPermission,
  40. fetchPolicy: 'cache-first',
  41. }),
  42. { errorNotificationMessage: __('The product version could not be fetched.') },
  43. )
  44. const productAbout = productAboutQuery.result()
  45. const isMobileIOS = browser.name?.includes('Safari') && os.name?.includes('iOS')
  46. const { canInstallPWA, installPWA } = usePWASupport()
  47. const showInstallButton = computed(
  48. () => !isStandalone() && (canInstallPWA.value || isMobileIOS),
  49. )
  50. const showInstallIOSPopup = ref(false)
  51. const installPWAMessage = computed(() => {
  52. const iconShare = useRawHTMLIcon({
  53. class: 'inline-flex text-blue',
  54. decorative: true,
  55. size: 'small',
  56. name: 'ios-share',
  57. })
  58. const iconAdd = useRawHTMLIcon({
  59. class: 'inline-flex',
  60. decorative: true,
  61. size: 'small',
  62. name: 'add-square',
  63. })
  64. return i18n.t(
  65. __(
  66. 'To install %s as an app, press the %s "Share" button and then the %s "Add to Home Screen" button.',
  67. ),
  68. __('Zammad'),
  69. iconShare,
  70. iconAdd,
  71. )
  72. })
  73. const installZammadPWA = () => {
  74. if (isStandalone()) return
  75. // on chromium this will show a chrome popup with native "install" button
  76. if (canInstallPWA.value) {
  77. installPWA()
  78. return
  79. }
  80. // on iOS we cannot install it with native functionality, so we show
  81. // instructions on how to install it
  82. // let's pray Apple will add native functionality in the future
  83. if (isMobileIOS) {
  84. showInstallIOSPopup.value = true
  85. }
  86. }
  87. const { forceDesktop } = useForceDesktop()
  88. </script>
  89. <template>
  90. <div class="px-4">
  91. <div v-if="user" class="flex flex-col items-center justify-center py-6">
  92. <div>
  93. <CommonUserAvatar :entity="user" size="xl" personal />
  94. </div>
  95. <div class="mt-2 text-xl font-bold">
  96. {{ user.firstname }} {{ user.lastname }}
  97. </div>
  98. </div>
  99. <CommonSectionMenu>
  100. <CommonSectionMenuLink
  101. v-if="session.hasPermission('user_preferences.avatar')"
  102. :icon="{ name: 'person', size: 'base' }"
  103. icon-bg="bg-pink"
  104. link="/account/avatar"
  105. >
  106. {{ $t('Avatar') }}
  107. </CommonSectionMenuLink>
  108. <CommonSectionMenuLink
  109. v-if="showInstallButton"
  110. :icon="{ name: 'install', size: 'small' }"
  111. icon-bg="bg-blue"
  112. @click="installZammadPWA"
  113. >
  114. {{ $t('Install App') }}
  115. </CommonSectionMenuLink>
  116. <CommonSectionMenuLink
  117. link="/"
  118. link-external
  119. :icon="{ name: 'desktop', size: 'base' }"
  120. icon-bg="bg-orange"
  121. @click="forceDesktop"
  122. >
  123. {{ $t('Continue to desktop') }}
  124. </CommonSectionMenuLink>
  125. </CommonSectionMenu>
  126. <!--
  127. The shorthand "no-options-label-translation" is not working currently because of a FormKit limitation,
  128. therefore we need to explicitly set it to true.
  129. -->
  130. <FormGroup v-if="session.hasPermission('user_preferences.language')">
  131. <FormKit
  132. v-model="modelCurrentLocale"
  133. type="treeselect"
  134. :label="__('Language')"
  135. :options="localeOptions"
  136. :disabled="isSavingLocale"
  137. :no-options-label-translation="true"
  138. sorting="label"
  139. />
  140. <template #help>
  141. {{ $t('Did you know?') }}
  142. <CommonLink class="text-blue" target="_blank" :link="translation.link">
  143. {{ $t('You can help translating Zammad.') }}
  144. </CommonLink>
  145. </template>
  146. </FormGroup>
  147. <CommonSectionMenu v-if="hasVersionPermission">
  148. <CommonSectionMenuItem :label="__('Version')">
  149. {{
  150. $t('This is Zammad version %s', productAbout?.productAbout as string)
  151. }}
  152. </CommonSectionMenuItem>
  153. </CommonSectionMenu>
  154. <div class="mb-4">
  155. <FormKit
  156. variant="danger"
  157. wrapper-class="mt-4 text-base flex grow justify-center items-center"
  158. input-class="py-2 px-4 w-full h-14 rounded-xl select-none"
  159. type="submit"
  160. name="signout"
  161. @click="logout"
  162. >
  163. {{ $t('Sign out') }}
  164. </FormKit>
  165. </div>
  166. <CommonSectionPopup v-model:state="showInstallIOSPopup" :messages="[]">
  167. <template #header>
  168. <section class="inline-flex min-h-[54px] items-center p-3">
  169. <span v-html="installPWAMessage" />
  170. </section>
  171. </template>
  172. </CommonSectionPopup>
  173. </div>
  174. </template>