UserMenu.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <template>
  2. <div>
  3. <Button
  4. v-if="isSignedIn"
  5. class="border-none px-6! py-2.75"
  6. variant="text"
  7. aria-haspopup="true"
  8. aria-controls="user_menu"
  9. @click="toggleMenu"
  10. >
  11. <span class="font-semibold">
  12. {{ user.username }}
  13. </span>
  14. <Icon
  15. name="ph:user-circle-fill"
  16. size="1.25rem"
  17. />
  18. </Button>
  19. <Button
  20. v-else
  21. class="border-none px-6! py-2.75"
  22. variant="text"
  23. @click="showSignInDialog"
  24. >
  25. <span class="font-semibold">Sign In</span>
  26. <Icon
  27. name="ph:user-circle-light"
  28. size="1.25rem"
  29. />
  30. </Button>
  31. <Menu
  32. class="mt-0"
  33. id="user_menu"
  34. :model="model"
  35. :popup="true"
  36. ref="menu"
  37. >
  38. <template #item="{ item, props }">
  39. <NuxtLink
  40. v-if="item.route"
  41. v-slot="{ href, navigate }"
  42. :to="item.route"
  43. custom
  44. >
  45. <a
  46. :href="href"
  47. v-bind="props.action"
  48. @click="navigate"
  49. >
  50. {{ item.label }}
  51. </a>
  52. </NuxtLink>
  53. <a
  54. v-else
  55. :href="item?.url"
  56. :target="item?.target"
  57. v-bind="props.action"
  58. >
  59. {{ item.label }}
  60. </a>
  61. </template>
  62. </Menu>
  63. </div>
  64. </template>
  65. <script setup>
  66. import { hydrateOnVisible } from "vue"
  67. const SignInDialog = defineAsyncComponent({
  68. loader: () => import("~/components/SignInDialog.vue"),
  69. hydrate: hydrateOnVisible()
  70. })
  71. const ChangePasswordDialog = defineAsyncComponent({
  72. loader: () => import("~/components/ChangePasswordDialog.vue"),
  73. hydrate: hydrateOnVisible()
  74. })
  75. const { isSignedIn, signOut, user } = useAuthClient()
  76. const dynamicDialog = useDynamicDialog()
  77. const toast = useToast()
  78. const menu = useTemplateRef("menu")
  79. const model = computed(() => {
  80. const menu = [
  81. { label: "Change Password", command: showChangePasswordDialog },
  82. { label: "Sign Out", command: doSignOut }
  83. ]
  84. if (isSignedIn.value && user.value.role === "admin") {
  85. menu.unshift({
  86. label: "Dashboard",
  87. command: async () => await navigateTo({ name: "admin:users" })
  88. })
  89. }
  90. return menu
  91. })
  92. async function doSignOut() {
  93. await signOut()
  94. closeMenu()
  95. toast.add({
  96. severity: "success",
  97. summary: "Signed Out.",
  98. detail: "You've been signed out.",
  99. life: 3000
  100. })
  101. }
  102. function toggleMenu(event) {
  103. menu.value.toggle(event)
  104. }
  105. function closeMenu(_) {
  106. menu.value.hide()
  107. }
  108. function showSignInDialog() {
  109. closeMenu()
  110. // noinspection JSUnresolvedReference
  111. dynamicDialog.open(SignInDialog)
  112. }
  113. function showChangePasswordDialog() {
  114. closeMenu()
  115. // noinspection JSUnresolvedReference
  116. dynamicDialog.open(ChangePasswordDialog)
  117. }
  118. </script>
  119. <style scoped></style>