@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 +2 -1
- package/src/components/app-menu/QasAppMenu.vue +73 -15
- package/src/components/app-menu/QasAppMenu.yml +5 -5
- package/src/components/chart-view/QasChartView.vue +1 -1
- package/src/composables/private/index.js +1 -0
- package/src/composables/private/use-auth-user.js +20 -0
- package/src/components/app-menu/private/PvAppMenuHelpChat.vue +0 -222
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.
|
|
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
|
-
|
|
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="
|
|
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
|
|
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.
|
|
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
|
-
|
|
300
|
-
|
|
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.
|
|
@@ -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>
|