@bildvitta/quasar-ui-asteroid 3.17.0-beta.28 → 3.17.0-beta.29
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 +67 -14
- package/src/components/app-menu/QasAppMenu.yml +5 -5
- 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.17.0-beta.
|
|
4
|
+
"version": "3.17.0-beta.29",
|
|
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",
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
|
|
80
80
|
<div v-if="showAppUser">
|
|
81
81
|
<!-- Chat Ajuda -->
|
|
82
|
-
<q-list v-if="
|
|
83
|
-
<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">
|
|
84
84
|
<q-item-section avatar>
|
|
85
85
|
<q-icon name="sym_r_chat" />
|
|
86
86
|
</q-item-section>
|
|
@@ -92,8 +92,6 @@
|
|
|
92
92
|
</div>
|
|
93
93
|
</q-item-label>
|
|
94
94
|
</q-item-section>
|
|
95
|
-
|
|
96
|
-
<pv-app-menu-help-chat :link="props.helpChatLink" :mini-brand="props.miniBrand" @update:model-value="setHasOpenedHelpChat" />
|
|
97
95
|
</q-item>
|
|
98
96
|
</q-list>
|
|
99
97
|
|
|
@@ -108,7 +106,6 @@
|
|
|
108
106
|
</template>
|
|
109
107
|
|
|
110
108
|
<script setup>
|
|
111
|
-
import PvAppMenuHelpChat from './private/PvAppMenuHelpChat.vue'
|
|
112
109
|
import PvAppMenuDropdown from './private/PvAppMenuDropdown.vue'
|
|
113
110
|
import QasAppUser from '../app-user/QasAppUser.vue'
|
|
114
111
|
|
|
@@ -116,8 +113,12 @@ import useAppMenuDropdown from './composables/use-app-menu-dropdown'
|
|
|
116
113
|
import useAppUser from './composables/use-app-user'
|
|
117
114
|
import useDevelopmentBadge from './composables/use-development-badge'
|
|
118
115
|
import { useScreen } from '../../composables'
|
|
116
|
+
import { useAuthUser } from '../../composables/private'
|
|
117
|
+
|
|
118
|
+
import { handleProcess } from '../../helpers'
|
|
119
119
|
|
|
120
|
-
import
|
|
120
|
+
import Gleap from 'gleap'
|
|
121
|
+
import { ref, computed, watch, onMounted } from 'vue'
|
|
121
122
|
import { useRouter } from 'vue-router'
|
|
122
123
|
|
|
123
124
|
defineOptions({
|
|
@@ -138,11 +139,6 @@ const props = defineProps({
|
|
|
138
139
|
type: String
|
|
139
140
|
},
|
|
140
141
|
|
|
141
|
-
helpChatLink: {
|
|
142
|
-
type: String,
|
|
143
|
-
default: ''
|
|
144
|
-
},
|
|
145
|
-
|
|
146
142
|
items: {
|
|
147
143
|
default: () => [],
|
|
148
144
|
type: Array
|
|
@@ -172,6 +168,10 @@ const props = defineProps({
|
|
|
172
168
|
title: {
|
|
173
169
|
default: '',
|
|
174
170
|
type: String
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
useChat: {
|
|
174
|
+
type: Boolean
|
|
175
175
|
}
|
|
176
176
|
})
|
|
177
177
|
|
|
@@ -180,6 +180,8 @@ const emit = defineEmits(['sign-out', 'update:modelValue', 'toggle-notifications
|
|
|
180
180
|
const screen = useScreen()
|
|
181
181
|
const router = useRouter()
|
|
182
182
|
|
|
183
|
+
const { toggleChat } = useChatMenu()
|
|
184
|
+
|
|
183
185
|
const rootRoute = router.hasRoute('Root') ? { name: 'Root' } : { path: '/' }
|
|
184
186
|
|
|
185
187
|
const hasOpenedMenu = ref(false)
|
|
@@ -216,7 +218,7 @@ const isMiniMode = computed(() => {
|
|
|
216
218
|
return screen.isLarge && isMini.value && !hasOpenedMenu.value && !hasOpenedHelpChat.value
|
|
217
219
|
})
|
|
218
220
|
|
|
219
|
-
const menuClasses = computed(() => ({ 'qas-app-menu__menu--spaced': !props.
|
|
221
|
+
const menuClasses = computed(() => ({ 'qas-app-menu__menu--spaced': !props.useChat }))
|
|
220
222
|
|
|
221
223
|
const classes = computed(() => {
|
|
222
224
|
return {
|
|
@@ -301,8 +303,59 @@ function setHasOpenedMenu (value) {
|
|
|
301
303
|
hasOpenedMenu.value = value
|
|
302
304
|
}
|
|
303
305
|
|
|
304
|
-
|
|
305
|
-
|
|
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
|
+
}
|
|
306
359
|
}
|
|
307
360
|
</script>
|
|
308
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>
|