@bildvitta/quasar-ui-asteroid 3.16.1 → 3.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
3
  "description": "Asteroid",
4
- "version": "3.16.1",
4
+ "version": "3.16.3",
5
5
  "author": "Bild & Vitta <systemteam@bild.com.br>",
6
6
  "license": "MIT",
7
7
  "main": "dist/asteroid.cjs.min.js",
@@ -50,6 +50,7 @@
50
50
  "date-fns": "^2.30.0",
51
51
  "debug": "^4.3.4",
52
52
  "fuse.js": "^6.6.2",
53
+ "gleap": "^14.2.7",
53
54
  "humps": "^2.0.1",
54
55
  "lodash-es": "^4.17.21",
55
56
  "pica": "^9.0.1",
@@ -58,7 +58,9 @@
58
58
  </div>
59
59
  </div>
60
60
 
61
- <q-item v-else :key="index" :active="isActive(menuItem)" active-class="q-router-link--active" class="qas-app-menu__item" :to="getRouterRedirect(menuItem)">
61
+ <!-- quando tem children vazio, não deve mostrar label do item, e a label do item
62
+ não tem "to", então validar se tem "to" para mostrar o item -->
63
+ <q-item v-else-if="menuItem.to" :key="index" :active="isActive(menuItem)" active-class="q-router-link--active" class="qas-app-menu__item" :to="getRouterRedirect(menuItem)">
62
64
  <q-item-section v-if="menuItem.icon" avatar>
63
65
  <q-icon :name="menuItem.icon" />
64
66
  </q-item-section>
@@ -77,8 +79,8 @@
77
79
 
78
80
  <div v-if="showAppUser">
79
81
  <!-- Chat Ajuda -->
80
- <q-list v-if="helpChatLink" class="q-mt-xl">
81
- <q-item class="q-mb-md text-primary" clickable>
82
+ <q-list v-if="useChat" class="q-mt-xl">
83
+ <q-item class="q-mb-md text-primary" clickable @click="toggleChat">
82
84
  <q-item-section avatar>
83
85
  <q-icon name="sym_r_chat" />
84
86
  </q-item-section>
@@ -90,8 +92,6 @@
90
92
  </div>
91
93
  </q-item-label>
92
94
  </q-item-section>
93
-
94
- <pv-app-menu-help-chat :link="props.helpChatLink" :mini-brand="props.miniBrand" @update:model-value="setHasOpenedHelpChat" />
95
95
  </q-item>
96
96
  </q-list>
97
97
 
@@ -106,7 +106,6 @@
106
106
  </template>
107
107
 
108
108
  <script setup>
109
- import PvAppMenuHelpChat from './private/PvAppMenuHelpChat.vue'
110
109
  import PvAppMenuDropdown from './private/PvAppMenuDropdown.vue'
111
110
  import QasAppUser from '../app-user/QasAppUser.vue'
112
111
 
@@ -114,8 +113,12 @@ import useAppMenuDropdown from './composables/use-app-menu-dropdown'
114
113
  import useAppUser from './composables/use-app-user'
115
114
  import useDevelopmentBadge from './composables/use-development-badge'
116
115
  import { useScreen } from '../../composables'
116
+ import { useAuthUser } from '../../composables/private'
117
+
118
+ import { handleProcess } from '../../helpers'
117
119
 
118
- import { ref, computed, watch } from 'vue'
120
+ import Gleap from 'gleap'
121
+ import { ref, computed, watch, onMounted } from 'vue'
119
122
  import { useRouter } from 'vue-router'
120
123
 
121
124
  defineOptions({
@@ -136,11 +139,6 @@ const props = defineProps({
136
139
  type: String
137
140
  },
138
141
 
139
- helpChatLink: {
140
- type: String,
141
- default: ''
142
- },
143
-
144
142
  items: {
145
143
  default: () => [],
146
144
  type: Array
@@ -170,6 +168,10 @@ const props = defineProps({
170
168
  title: {
171
169
  default: '',
172
170
  type: String
171
+ },
172
+
173
+ useChat: {
174
+ type: Boolean
173
175
  }
174
176
  })
175
177
 
@@ -178,6 +180,8 @@ const emit = defineEmits(['sign-out', 'update:modelValue', 'toggle-notifications
178
180
  const screen = useScreen()
179
181
  const router = useRouter()
180
182
 
183
+ const { toggleChat } = useChatMenu()
184
+
181
185
  const rootRoute = router.hasRoute('Root') ? { name: 'Root' } : { path: '/' }
182
186
 
183
187
  const hasOpenedMenu = ref(false)
@@ -214,7 +218,7 @@ const isMiniMode = computed(() => {
214
218
  return screen.isLarge && isMini.value && !hasOpenedMenu.value && !hasOpenedHelpChat.value
215
219
  })
216
220
 
217
- const menuClasses = computed(() => ({ 'qas-app-menu__menu--spaced': !props.helpChatLink }))
221
+ const menuClasses = computed(() => ({ 'qas-app-menu__menu--spaced': !props.useChat }))
218
222
 
219
223
  const classes = computed(() => {
220
224
  return {
@@ -276,6 +280,9 @@ function hasSeparator (index) {
276
280
  }
277
281
 
278
282
  function isActive ({ to }) {
283
+ // quando o children vem vazio, "to" é "undefined", então precisa ser feito esta trativa.
284
+ if (!to) return false
285
+
279
286
  const currentPath = getNormalizedPath(router.currentRoute.value.path)
280
287
  const itemPath = typeof to === 'string' ? getNormalizedPath(to) : getPathFromObject(to)
281
288
 
@@ -296,8 +303,59 @@ function setHasOpenedMenu (value) {
296
303
  hasOpenedMenu.value = value
297
304
  }
298
305
 
299
- function setHasOpenedHelpChat (value) {
300
- hasOpenedHelpChat.value = value
306
+ // composables definitions
307
+ function useChatMenu () {
308
+ // composables
309
+ const { user, hasUser } = useAuthUser()
310
+
311
+ // consts
312
+ const isMeVersionTwo = process.env.ME_VERSION === 2
313
+
314
+ // hooks
315
+ onMounted(initializeChat)
316
+
317
+ // functions
318
+ function initializeChat () {
319
+ const gleapEnv = handleProcess(() => process.env.GLEAP)
320
+
321
+ if (!props.useChat || !gleapEnv || !hasUser.value) return
322
+
323
+ Gleap.initialize(gleapEnv)
324
+ Gleap.setLanguage('pt-BR')
325
+
326
+ const {
327
+ uuid,
328
+ name,
329
+ email,
330
+ callingCode,
331
+ phone,
332
+ companyLink,
333
+ companyLinksOptions,
334
+ mainCompanyOptions, // somente na v2
335
+ currentMainCompany // somente na v2
336
+ } = user.value
337
+
338
+ const companyId = isMeVersionTwo ? currentMainCompany : companyLink
339
+ const companyNameList = isMeVersionTwo ? mainCompanyOptions : companyLinksOptions
340
+ const companyName = companyNameList?.find(({ value }) => value === companyId)?.label
341
+
342
+ Gleap.identify(uuid, {
343
+ name,
344
+ email,
345
+ phone: `+${callingCode || '55'}${phone}`,
346
+ companyId,
347
+ companyName
348
+ })
349
+ }
350
+
351
+ function toggleChat () {
352
+ Gleap.isOpened() ? Gleap.close() : Gleap.open()
353
+ }
354
+
355
+ return {
356
+ initializeChat,
357
+ toggleChat
358
+ }
301
359
  }
302
360
  </script>
303
361
 
@@ -15,11 +15,6 @@ props:
15
15
  type: String
16
16
  required: true
17
17
 
18
- help-chat-link:
19
- desc: Link para ser usado no iframe do chat, caso não passe nada, o chat não será exibido.
20
- type: String
21
- default: ''
22
-
23
18
  items:
24
19
  desc: Itens do menu.
25
20
  type: Array
@@ -49,6 +44,11 @@ props:
49
44
  desc: Título que vai ficar no label do select de módulos.
50
45
  type: String
51
46
 
47
+ use-chat:
48
+ desc: Componente para controlar se vai ter ou não o chat.
49
+ type: Boolean
50
+ default: true
51
+
52
52
  slots:
53
53
  user:
54
54
  desc: Slot para acessar o menu de usuário.
@@ -326,7 +326,7 @@ export default {
326
326
  this.handleFetchData()
327
327
  },
328
328
 
329
- unmounted () {
329
+ beforeUnmount () {
330
330
  this.unregisterChartJS()
331
331
  },
332
332
 
@@ -1,3 +1,4 @@
1
1
  export { default as useView } from './use-view'
2
2
  export { default as useGenerator } from './use-generator'
3
3
  export { default as useToggleVisibility } from './use-toggle-visibility'
4
+ export { default as useAuthUser } from './use-auth-user'
@@ -0,0 +1,20 @@
1
+ import { LocalStorage } from 'quasar'
2
+
3
+ import { computed, ref } from 'vue'
4
+
5
+ const user = ref(LocalStorage.getItem('user'))
6
+
7
+ export default function useAuthUser () {
8
+ window.addEventListener('message', ({ data }) => {
9
+ if (data.type !== 'updateUser') return
10
+
11
+ user.value = data.user
12
+ })
13
+
14
+ const hasUser = computed(() => !!user.value)
15
+
16
+ return {
17
+ user,
18
+ hasUser
19
+ }
20
+ }
@@ -1,222 +0,0 @@
1
- <!-- O chat em si é renderizado em um iframe, o que QMenu, toda vez que fecha se auto destroy, então não podemos usar o
2
- iframe dentro do QMenu, pois toda vez que um iframe é destruído ele perde o seu estado, e teria que iniciar um novo chat,
3
- pra isto é criado um iframe no body, e posicionado com JS + CSS para ficar sobre o QMenu. -->
4
-
5
- <template>
6
- <q-menu class="pv-app-menu-help-chat shadow-2" v-bind="menuProps">
7
- <header class="q-pa-md">
8
- <q-img class="q-mb-md" :src="props.miniBrand" width="36px" />
9
-
10
- <h3 class="text-h3">
11
- Bem-vindo!
12
- </h3>
13
-
14
- <div class="text-body1">
15
- Deixe a sua mensagem para o suporte técnico da Nave.
16
- </div>
17
- </header>
18
-
19
- <qas-box class="full-width pv-app-menu-help-chat__content relative-position" :class="boxClasses">
20
- <div v-if="showIframe" ref="chatContent" class="full-width" />
21
-
22
- <div v-else class="full-width self-end">
23
- <div class="q-mb-sm text-subtitle2">
24
- Estamos conectados
25
- </div>
26
-
27
- <div class="text-body2">
28
- Normalmente responde em alguns minutos
29
- </div>
30
-
31
- <qas-btn class="full-width q-mt-lg" label="Iniciar conversa" variant="primary" @click="initializeChat" />
32
- </div>
33
-
34
- <q-inner-loading :showing="showInnerLoading">
35
- <q-spinner color="grey" size="2rem" />
36
- </q-inner-loading>
37
- </qas-box>
38
- </q-menu>
39
- </template>
40
-
41
- <script setup>
42
- import { useScreen } from '../../../composables'
43
-
44
- import { onMounted, onUnmounted, ref, nextTick, computed } from 'vue'
45
-
46
- defineOptions({ name: 'PvAppMenuHelpChat' })
47
-
48
- const props = defineProps({
49
- link: {
50
- type: String,
51
- default: ''
52
- },
53
-
54
- miniBrand: {
55
- type: String,
56
- default: ''
57
- }
58
- })
59
-
60
- const screen = useScreen()
61
-
62
- // refs
63
- const chatContent = ref(null)
64
- const isOpened = ref(false)
65
- const showIframe = ref(false)
66
- const showInnerLoading = ref(false)
67
-
68
- // computed
69
- const boxClasses = computed(() => {
70
- return {
71
- flex: !showIframe.value,
72
- 'pv-app-menu-help-chat__content--is-opened': showIframe.value
73
- }
74
- })
75
-
76
- const menuProps = computed(() => {
77
- return {
78
- anchor: screen.isSmall ? 'top middle' : 'top right',
79
- maxWidth: screen.isSmall ? '300px' : '400px',
80
- self: screen.isSmall ? 'bottom middle' : 'top left',
81
- touchPosition: !screen.isSmall,
82
-
83
- onBeforeHide: hideIframe,
84
- onShow
85
- }
86
- })
87
-
88
- // hooks
89
-
90
- /**
91
- * Toda vez que a prop "behavior" do componente "QasAppMenu" é alterada, este componente
92
- * é renderizado novamente, então é necessário esconder o iframe caso ele ja esteja aberto.
93
- */
94
- onMounted(hideIframe)
95
-
96
- onUnmounted(() => {
97
- if (showIframe.value) {
98
- window.removeEventListener('scroll', onScroll)
99
- window.removeEventListener('resize', onScroll)
100
- }
101
- })
102
-
103
- // functions
104
-
105
- /**
106
- * Define o estilo do iframe de acordo com a posição do "chatContent" dentro
107
- * do QMenu.
108
- */
109
- async function setIframeStyle () {
110
- await nextTick()
111
-
112
- const iframe = getIframe()
113
-
114
- if (!iframe || !chatContent.value) return
115
-
116
- const { bottom, left, top } = chatContent.value.getBoundingClientRect()
117
-
118
- const width = chatContent.value.offsetWidth
119
-
120
- const styles = {
121
- display: 'block',
122
- top: `${bottom + window.scrollY}px`,
123
- left: `${left + window.scrollX}px`,
124
- bottom: `${top}px`,
125
- width: `${width}px`
126
- }
127
-
128
- Object.assign(iframe.style, styles)
129
- }
130
-
131
- function onShow () {
132
- isOpened.value = true
133
-
134
- if (showIframe.value) setIframeStyle()
135
- }
136
-
137
- function hideIframe () {
138
- isOpened.value = false
139
-
140
- const iframe = getIframe()
141
-
142
- if (!iframe) return
143
-
144
- iframe.style.display = 'none'
145
- }
146
-
147
- function onScroll () {
148
- if (isOpened.value) setIframeStyle()
149
- }
150
-
151
- function createIframe () {
152
- const iframe = document.createElement('iframe')
153
-
154
- iframe.id = 'chat-iframe'
155
- iframe.className = 'pv-app-menu-help-chat__iframe'
156
- iframe.style.display = 'none'
157
- iframe.src = props.link
158
-
159
- document.body.appendChild(iframe)
160
- }
161
-
162
- function getIframe () {
163
- return document.getElementById('chat-iframe')
164
- }
165
-
166
- function initializeChat () {
167
- createIframe()
168
-
169
- window.addEventListener('scroll', onScroll)
170
- window.addEventListener('resize', onScroll)
171
-
172
- toggleIframe()
173
- }
174
-
175
- function toggleIframe () {
176
- showIframe.value = !showIframe.value
177
-
178
- showInnerLoading.value = true
179
-
180
- /**
181
- * É adicionado um loading por 3 motivos:
182
- * - o iframe demora um pouco para ser carregado
183
- * - o loading é um feedback visual para o usuário enquanto o iframe é carregado
184
- * - não é possível adicionar uma animação aparecendo o iframe, então desta
185
- * forma fica suavizado
186
- */
187
- setTimeout(async () => {
188
- showInnerLoading.value = false
189
-
190
- await nextTick()
191
-
192
- onShow()
193
- }, 2000)
194
- }
195
- </script>
196
-
197
- <style lang="scss">
198
- .pv-app-menu-help-chat {
199
- overflow-y: hidden;
200
-
201
- &__content {
202
- height: 260px;
203
- background-color: var(--qas-background-color) !important;
204
- }
205
-
206
- &__iframe {
207
- border: 0;
208
- border-radius: var(--qas-generic-border-radius);
209
- outline: none;
210
- position: absolute;
211
- height: calc(260px - calc(var(--qas-spacing-md) * 2));
212
- z-index: 9999;
213
- }
214
-
215
- // Media: isSmall
216
- @media (max-width: $breakpoint-sm-min) {
217
- &__content--is-opened {
218
- padding: var(--qas-spacing-sm) !important;
219
- }
220
- }
221
- }
222
- </style>