profile.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <template>
  2. <div>
  3. <div class="container">
  4. <div class="p-4">
  5. <div
  6. v-if="currentUser === null"
  7. class="flex flex-col items-center justify-center"
  8. >
  9. <img
  10. :src="`/images/states/${$colorMode.value}/login.svg`"
  11. loading="lazy"
  12. class="
  13. flex-col
  14. my-4
  15. object-contain object-center
  16. h-24
  17. w-24
  18. inline-flex
  19. "
  20. :alt="$t('empty.parameters')"
  21. />
  22. <p class="text-center pb-4 text-secondaryLight">
  23. {{ $t("empty.profile") }}
  24. </p>
  25. <ButtonPrimary
  26. :label="$t('auth.login')"
  27. class="mb-4"
  28. @click.native="showLogin = true"
  29. />
  30. </div>
  31. <div v-else class="space-y-8">
  32. <div
  33. class="bg-primaryLight h-24 md:h-32 -mb-11 rounded"
  34. style="background-image: url('/images/cover.svg')"
  35. ></div>
  36. <div class="flex px-4 flex-col md:flex-row space-y-8 justify-between">
  37. <div class="flex items-end">
  38. <img
  39. v-if="currentUser.photoURL"
  40. :src="currentUser.photoURL"
  41. class="rounded-lg ring-4 ring-primary h-16 w-16"
  42. :alt="currentUser.displayName"
  43. />
  44. <SmartIcon v-else name="user" class="svg-icons" />
  45. <div class="ml-4">
  46. <label class="heading">
  47. {{ currentUser.displayName || $t("state.nothing_found") }}
  48. </label>
  49. <p class="flex text-secondaryLight items-center">
  50. {{ currentUser.email }}
  51. <SmartIcon
  52. v-if="currentUser.emailVerified"
  53. name="verified"
  54. class="ml-2 text-green-500 svg-icons"
  55. />
  56. </p>
  57. </div>
  58. </div>
  59. <div class="flex space-x-2 items-end">
  60. <div>
  61. <SmartItem
  62. to="/settings"
  63. svg="settings"
  64. :label="$t('profile.app_settings')"
  65. outline
  66. />
  67. </div>
  68. <FirebaseLogout outline />
  69. </div>
  70. </div>
  71. <SmartTabs>
  72. <SmartTab
  73. :id="'sync'"
  74. :label="$t('settings.account')"
  75. :selected="true"
  76. >
  77. <section class="p-4">
  78. <h4 class="font-semibold text-secondaryDark">
  79. {{ $t("settings.profile") }}
  80. </h4>
  81. <div class="mt-1 text-secondaryLight">
  82. {{ $t("settings.profile_description") }}
  83. </div>
  84. <div class="py-4">
  85. <label for="displayName">
  86. {{ $t("settings.profile_name") }}
  87. </label>
  88. <form
  89. class="flex md:max-w-sm mt-2"
  90. @submit.prevent="updateDisplayName"
  91. >
  92. <input
  93. id="displayName"
  94. v-model="displayName"
  95. class="input"
  96. :placeholder="$t('settings.profile_name')"
  97. type="text"
  98. autocomplete="off"
  99. required
  100. />
  101. <ButtonPrimary
  102. :label="$t('action.save').toString()"
  103. class="ml-2 min-w-16"
  104. type="submit"
  105. :loading="updatingDisplayName"
  106. />
  107. </form>
  108. </div>
  109. </section>
  110. <section class="p-4">
  111. <h4 class="font-semibold text-secondaryDark">
  112. {{ $t("settings.sync") }}
  113. </h4>
  114. <div class="mt-1 text-secondaryLight">
  115. {{ $t("settings.sync_description") }}
  116. </div>
  117. <div class="space-y-4 py-4">
  118. <div class="flex items-center">
  119. <SmartToggle
  120. :on="SYNC_COLLECTIONS"
  121. @change="toggleSetting('syncCollections')"
  122. >
  123. {{ $t("settings.sync_collections") }}
  124. </SmartToggle>
  125. </div>
  126. <div class="flex items-center">
  127. <SmartToggle
  128. :on="SYNC_ENVIRONMENTS"
  129. @change="toggleSetting('syncEnvironments')"
  130. >
  131. {{ $t("settings.sync_environments") }}
  132. </SmartToggle>
  133. </div>
  134. <div class="flex items-center">
  135. <SmartToggle
  136. :on="SYNC_HISTORY"
  137. @change="toggleSetting('syncHistory')"
  138. >
  139. {{ $t("settings.sync_history") }}
  140. </SmartToggle>
  141. </div>
  142. </div>
  143. </section>
  144. </SmartTab>
  145. <SmartTab :id="'teams'" :label="$t('team.title')">
  146. <AppSection label="teams">
  147. <Teams :modal="false" />
  148. </AppSection>
  149. </SmartTab>
  150. </SmartTabs>
  151. </div>
  152. </div>
  153. <FirebaseLogin :show="showLogin" @hide-modal="showLogin = false" />
  154. </div>
  155. </div>
  156. </template>
  157. <script setup lang="ts">
  158. import {
  159. ref,
  160. useContext,
  161. useMeta,
  162. defineComponent,
  163. } from "@nuxtjs/composition-api"
  164. import { currentUser$, setDisplayName } from "~/helpers/fb/auth"
  165. import { useReadonlyStream } from "~/helpers/utils/composables"
  166. import { toggleSetting, useSetting } from "~/newstore/settings"
  167. const {
  168. app: { i18n },
  169. } = useContext()
  170. const t = i18n.t.bind(i18n)
  171. const showLogin = ref(false)
  172. const SYNC_COLLECTIONS = useSetting("syncCollections")
  173. const SYNC_ENVIRONMENTS = useSetting("syncEnvironments")
  174. const SYNC_HISTORY = useSetting("syncHistory")
  175. const currentUser = useReadonlyStream(currentUser$, null)
  176. const displayName = ref(currentUser$.value?.displayName)
  177. const updatingDisplayName = ref(false)
  178. const updateDisplayName = () => {
  179. updatingDisplayName.value = true
  180. setDisplayName(displayName.value).finally(() => {
  181. updatingDisplayName.value = false
  182. })
  183. }
  184. useMeta({
  185. title: `${t("navigation.profile")} • Hoppscotch`,
  186. })
  187. </script>
  188. <script lang="ts">
  189. export default defineComponent({
  190. head: {},
  191. })
  192. </script>