@bildvitta/quasar-ui-asteroid 3.17.0-beta.23 → 3.17.0-beta.24

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.17.0-beta.23",
4
+ "version": "3.17.0-beta.24",
5
5
  "author": "Bild & Vitta <systemteam@bild.com.br>",
6
6
  "license": "MIT",
7
7
  "main": "dist/asteroid.cjs.min.js",
@@ -108,23 +108,29 @@ const props = defineProps({
108
108
  }
109
109
  })
110
110
 
111
+ // emits
111
112
  const emit = defineEmits(['sign-out', 'toggle-notifications'])
112
113
 
113
- // vindo direto do boot api.js
114
+ // globals
114
115
  const axios = inject('axios')
115
116
 
117
+ // composables
116
118
  const router = useRouter()
117
119
 
118
120
  const { isNotificationsEnabled, unreadNotificationsCount } = useNotifications()
119
121
 
120
122
  const { reset } = useQueryCache()
121
123
 
124
+ const { avatarNotificationCountProps } = useAvatarNotifications()
125
+
126
+ // refs
122
127
  const companiesModel = ref('')
123
128
  const loading = ref(false)
124
129
 
125
- const { avatarNotificationCountProps } = useAvatarNotifications()
130
+ // consts
131
+ const IS_ME_VERSION_2 = process.env.ME_VERSION === 2
126
132
 
127
- // computed
133
+ // computeds
128
134
  const defaultCompanyProps = computed(() => {
129
135
  return {
130
136
  loading: loading.value,
@@ -148,42 +154,7 @@ watch(() => props.companyProps.modelValue, value => {
148
154
  companiesModel.value = value
149
155
  }, { immediate: true })
150
156
 
151
- // composable
152
- function useAvatarNotifications () {
153
- const hasAnimated = ref(false)
154
-
155
- watch(() => unreadNotificationsCount.value, () => {
156
- hasAnimated.value = true
157
-
158
- setTimeout(() => {
159
- hasAnimated.value = false
160
- }, 1000)
161
- })
162
-
163
- const avatarNotificationCountProps = computed(() => {
164
- const classes = [
165
- 'qas-app-user__notification-avatar',
166
- 'animated',
167
- {
168
- rubberBand: hasAnimated.value
169
- }
170
- ]
171
-
172
- return {
173
- class: classes,
174
- color: 'red-14',
175
- size: 'xs',
176
- title: unreadNotificationsToString.value,
177
- useCropTitle: false
178
- }
179
- })
180
-
181
- return {
182
- avatarNotificationCountProps
183
- }
184
- }
185
-
186
- // métodos
157
+ // functions
187
158
  function signOut () {
188
159
  emit('sign-out')
189
160
  }
@@ -194,7 +165,10 @@ async function setCompanies (value) {
194
165
  loading.value = true
195
166
 
196
167
  try {
197
- await axios.patch('users/me', { companies: value })
168
+ await axios.patch('users/me', {
169
+ [IS_ME_VERSION_2 ? 'currentMainCompany' : 'companies']: value
170
+ })
171
+
198
172
  setTimeout(() => location.reload(), 1500)
199
173
 
200
174
  NotifySuccess('Vínculo alterado com sucesso.')
@@ -224,6 +198,41 @@ function onMenuHide () {
224
198
  function toggleNotificationsDrawer () {
225
199
  emit('toggle-notifications')
226
200
  }
201
+
202
+ // composables definitions
203
+ function useAvatarNotifications () {
204
+ const hasAnimated = ref(false)
205
+
206
+ watch(() => unreadNotificationsCount.value, () => {
207
+ hasAnimated.value = true
208
+
209
+ setTimeout(() => {
210
+ hasAnimated.value = false
211
+ }, 1000)
212
+ })
213
+
214
+ const avatarNotificationCountProps = computed(() => {
215
+ const classes = [
216
+ 'qas-app-user__notification-avatar',
217
+ 'animated',
218
+ {
219
+ rubberBand: hasAnimated.value
220
+ }
221
+ ]
222
+
223
+ return {
224
+ class: classes,
225
+ color: 'red-14',
226
+ size: 'xs',
227
+ title: unreadNotificationsToString.value,
228
+ useCropTitle: false
229
+ }
230
+ })
231
+
232
+ return {
233
+ avatarNotificationCountProps
234
+ }
235
+ }
227
236
  </script>
228
237
 
229
238
  <style lang="scss">
@@ -46,8 +46,9 @@ import zoomPlugin from 'chartjs-plugin-zoom'
46
46
  import chartDataLabels from 'chartjs-plugin-datalabels'
47
47
 
48
48
  // Outras importações
49
- import { extend } from 'quasar'
50
49
  import { filterListByHandle } from '../../helpers'
50
+
51
+ import { extend, is } from 'quasar'
51
52
  import { getAction } from '@bildvitta/store-adapter'
52
53
 
53
54
  const ChartTypes = {
@@ -131,6 +132,11 @@ export default {
131
132
  type: String
132
133
  },
133
134
 
135
+ urlQueryList: {
136
+ default: () => (['company']),
137
+ type: Array
138
+ },
139
+
134
140
  useBox: {
135
141
  type: Boolean,
136
142
  default: true
@@ -332,6 +338,10 @@ export default {
332
338
  ...(this.useBox && { ...this.boxProps })
333
339
  }
334
340
  }
341
+ },
342
+
343
+ queryFromURL () {
344
+ return this.getQueryFromURL(this.$route.query)
335
345
  }
336
346
  },
337
347
 
@@ -342,6 +352,10 @@ export default {
342
352
 
343
353
  isFetching (value) {
344
354
  this.$emit('update:fetching', value)
355
+ },
356
+
357
+ $route (to, from) {
358
+ this.onRouteChange(to, from)
345
359
  }
346
360
  },
347
361
 
@@ -357,9 +371,10 @@ export default {
357
371
  methods: {
358
372
  handleFetchData () {
359
373
  const hasBeforeFetch = typeof this.beforeFetch === 'function'
374
+
360
375
  const payload = {
361
376
  url: this.url,
362
- filters: this.filters
377
+ filters: { ...this.filters, ...this.queryFromURL }
363
378
  }
364
379
 
365
380
  if (hasBeforeFetch && !this.cancelBeforeFetch) {
@@ -435,6 +450,44 @@ export default {
435
450
  ...this.defaultChartItems,
436
451
  ...this.elementsChartItems[this.type]
437
452
  )
453
+ },
454
+
455
+ onRouteChange (to, from) {
456
+ const { query } = to
457
+
458
+ const isSameRoute = to.name === from.name
459
+ const hasQueryInURLQueryList = this.urlQueryList.some(urlQuery => query[urlQuery])
460
+
461
+ /**
462
+ * feito com função para evitar um deepEqual desnecessário, uma vez que
463
+ * caso "isSameRoute" seja falso, ou "hasQueryInURLQueryList" seja falso,
464
+ * não é necessário fazer a comparação.
465
+ */
466
+ const hasQueryChanged = () => !is.deepEqual(this.queryFromURL, this.getQueryFromURL(from.query))
467
+
468
+ /**
469
+ * Verifica se a rota atual é a mesma, se há uma query na URL que corresponde à queryList,
470
+ * e se a query correspondente à queryList foi alterada. Se todas essas condições forem
471
+ * verdadeiras, faz a requisição de dados.
472
+ */
473
+ if (isSameRoute && hasQueryInURLQueryList && hasQueryChanged()) this.handleFetchData()
474
+ },
475
+
476
+ /**
477
+ * "urlQueryList" é uma lista de query que o componente deve pegar da URL.
478
+ */
479
+ getQueryFromURL (query = {}) {
480
+ const newQuery = {}
481
+
482
+ this.urlQueryList.forEach(urlQuery => {
483
+ const queryValue = query[urlQuery]
484
+
485
+ if (queryValue) {
486
+ newQuery[urlQuery] = queryValue
487
+ }
488
+ })
489
+
490
+ return newQuery
438
491
  }
439
492
  }
440
493
  }
@@ -70,6 +70,12 @@ props:
70
70
  desc: Envia como parâmetro para a action "fetchList" do modulo correspondente a "entity".
71
71
  type: String
72
72
 
73
+ url-query-list:
74
+ desc: Lista de query que serão recuperadas da URL e enviadas como parâmetro para a action "fetchList" do modulo correspondente a "entity".
75
+ type: Array
76
+ default:
77
+ - company
78
+
73
79
  use-box:
74
80
  desc: Controla se o componente vai ter o QasBox englobando ou não.
75
81
  default: true
@@ -43,10 +43,12 @@
43
43
  <script>
44
44
  import QasFilters from '../filters/QasFilters.vue'
45
45
  import QasPagination from '../pagination/QasPagination.vue'
46
+
47
+ import { viewMixin, contextMixin } from '../../mixins'
48
+
46
49
  import debug from 'debug'
47
50
  import { extend } from 'quasar'
48
51
  import { getState, getAction } from '@bildvitta/store-adapter'
49
- import { viewMixin, contextMixin } from '../../mixins'
50
52
  import { computed } from 'vue'
51
53
 
52
54
  const log = debug('asteroid-ui:qas-list-view')
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <qas-select v-model="internalModel" :label="props.label" :options="props.options" use-filter-mode @update:model-value="onUpdateModel" />
3
+ </template>
4
+
5
+ <script setup>
6
+ import useDefaultFilters from '../../composables/use-default-filters'
7
+
8
+ import { extend } from 'quasar'
9
+ import { watch, ref, nextTick } from 'vue'
10
+ import { useRouter, useRoute } from 'vue-router'
11
+
12
+ defineOptions({ name: 'QasSelectFilter' })
13
+
14
+ const props = defineProps({
15
+ label: {
16
+ type: String,
17
+ default: 'Selecione uma empresa vinculada'
18
+ },
19
+
20
+ name: {
21
+ type: String,
22
+ default: 'company'
23
+ },
24
+
25
+ options: {
26
+ type: Array,
27
+ default: () => []
28
+ }
29
+ })
30
+
31
+ // composables
32
+ const router = useRouter()
33
+ const route = useRoute()
34
+ const { setFilterQuery, triggerDefaultFiltersChange, filterQuery } = useDefaultFilters()
35
+
36
+ // models
37
+ const model = defineModel({ type: String, default: '' })
38
+
39
+ // refs
40
+ const internalModel = ref(route.query[props.name] || model.value)
41
+
42
+ // watch
43
+ watch(() => route.query[props.name], setModels)
44
+
45
+ // functions
46
+ /**
47
+ * Adiciona o valor na URL, atualizando a rota, isto vai fazer com que o componente
48
+ * seja atualizado com o novo valor, pois cai no watch que atualiza o model interno e externo.
49
+ */
50
+ function onUpdateModel (value) {
51
+ const { ...query } = route.query
52
+
53
+ router.push({ query: { ...query, [props.name]: value } })
54
+ }
55
+
56
+ function setModels (value) {
57
+ model.value = value
58
+ internalModel.value = value
59
+
60
+ const oldFilters = extend(true, {}, filterQuery.value)
61
+
62
+ setFilterQuery(value, props.name)
63
+ nextTick(() => triggerDefaultFiltersChange(filterQuery.value, oldFilters))
64
+ }
65
+ </script>
@@ -0,0 +1,36 @@
1
+ type: component
2
+
3
+ meta:
4
+ desc: Componente para gerar dinamicamente checkbox agrupados.
5
+
6
+ props:
7
+ inline:
8
+ desc: Controla se o componente vai aparece em linha ou em bloco.
9
+ default: true
10
+ type: Boolean
11
+
12
+ label:
13
+ desc: Label utilizada em casos de ser checkbox-group.
14
+ default: ''
15
+ type: String
16
+
17
+ model-value:
18
+ desc: Model do componente, usado para v-model.
19
+ default: []
20
+ type: Array
21
+ examples: [v-model"value"]
22
+ model: true
23
+
24
+ options:
25
+ desc: Opções para gerar os checkbox.
26
+ default: []
27
+ type: Array
28
+
29
+ events:
30
+ '@update:model-value -> function(value)':
31
+ desc: Dispara quando o model-value altera, também usado para v-model.
32
+ params:
33
+ value:
34
+ desc: Novo valor do model.
35
+ default: []
36
+ type: Array
@@ -1,8 +1,10 @@
1
1
  export { default as useContext } from './use-context.js'
2
+ export { default as useDefaultFilters } from './use-default-filters.js'
2
3
  export { default as useForm } from './use-form.js'
3
4
  export { default as useHistory } from './use-history.js'
5
+ export { default as useNotifications } from './use-notifications.js'
4
6
  export { default as useQueryCache } from './use-query-cache.js'
5
7
  export { default as useScreen } from './use-screen.js'
6
- export { default as useNotifications } from './use-notifications.js'
7
8
 
8
9
  export * from './use-notifications.js'
10
+ export * from './use-default-filters.js'
@@ -0,0 +1,106 @@
1
+ import { computed, ref } from 'vue'
2
+ import { LocalStorage, is } from 'quasar'
3
+
4
+ const filterQuery = ref({})
5
+
6
+ const defaultFiltersHooks = {
7
+ defaultFiltersChange: []
8
+ }
9
+
10
+ /**
11
+ * Define os filtros padrão antes de entrar na rota.
12
+ *
13
+ * Prioridade de aplicação dos filtros:
14
+ * 1 - Se o filtro estiver salvo no estado global, então utiliza ele.
15
+ * 2 - Se o filtro já estiver na query, então utiliza ele.
16
+ * 3 - Se o filtro já estiver salvo no LocalStorage, então utiliza ele.
17
+ *
18
+ * @param {Object} to - Rota de destino.
19
+ * @param {Object} _from - Rota de origem.
20
+ * @param {Function} next - Função de redirecionamento.
21
+ * @param {Array} queryList='company' - Lista de filtros a serem aplicados.
22
+ */
23
+ export function setDefaultFiltersBeforeEnter (to, _from, next, queryList = ['company']) {
24
+ const { getDefaultFiltersFromStorage, setFilterQuery } = useDefaultFilters()
25
+
26
+ const { query } = to
27
+ const newQuery = { ...query }
28
+
29
+ // recupera os filtros padrão do LocalStorage
30
+ const defaultFiltersFromStorage = getDefaultFiltersFromStorage()
31
+
32
+ queryList.forEach(name => {
33
+ // 1. se o filtro já estiver salvo no estado, então utiliza ele
34
+ if (filterQuery.value[name]) {
35
+ newQuery[name] = filterQuery.value[name]
36
+ return
37
+ }
38
+
39
+ // 2. se o filtro já estiver na query, então utiliza ele
40
+ if (query[name]) {
41
+ setFilterQuery(query[name], name)
42
+
43
+ return
44
+ }
45
+
46
+ const storedFilter = defaultFiltersFromStorage[name]
47
+
48
+ // 3. se o filtro já estiver salvo no LocalStorage, então utiliza ele
49
+ if (storedFilter) {
50
+ setFilterQuery(storedFilter, name)
51
+ newQuery[name] = storedFilter
52
+ }
53
+ })
54
+
55
+ /**
56
+ * Verifica se houve mudanças na query antes de redirecionar, sem essa validação
57
+ * o redirecionamento ocorre mesmo que a query seja a mesma, gerando loop infinito.
58
+ */
59
+ if (!is.deepEqual(newQuery, query)) return next({ ...to, query: newQuery, replace: true })
60
+
61
+ next()
62
+ }
63
+
64
+ /**
65
+ * Este composable recupera os filtros default salvos no LocalStorage na chave 'defaultFilters'.
66
+ */
67
+ export default function useDefaultFilters () {
68
+ const hasFilterQuery = computed(() => !!Object.keys(filterQuery.value).length)
69
+
70
+ function setFilterQuery (query, name = 'company') {
71
+ filterQuery.value[name] = query
72
+ }
73
+
74
+ function getDefaultFiltersFromStorage () {
75
+ const defaultFiltersFromStorage = LocalStorage.getItem('defaultFilters') || {}
76
+
77
+ return defaultFiltersFromStorage
78
+ }
79
+
80
+ function triggerDefaultFiltersChange (newFilters, oldFilters) {
81
+ // necessário verificar se houve mudanças antes de disparar o evento para não duplicar.
82
+ if (is.deepEqual(newFilters, oldFilters)) return
83
+
84
+ defaultFiltersHooks.defaultFiltersChange.forEach(hook => hook(newFilters, oldFilters))
85
+ }
86
+
87
+ function onDefaultFiltersChange (callback) {
88
+ defaultFiltersHooks.defaultFiltersChange.push(callback)
89
+ }
90
+
91
+ function removeOnDefaultFiltersChange (callback) {
92
+ const index = defaultFiltersHooks.defaultFiltersChange.indexOf(callback)
93
+
94
+ if (~index) defaultFiltersHooks.defaultFiltersChange.splice(index, 1)
95
+ }
96
+
97
+ return {
98
+ filterQuery,
99
+ hasFilterQuery,
100
+ getDefaultFiltersFromStorage,
101
+ onDefaultFiltersChange,
102
+ removeOnDefaultFiltersChange,
103
+ setFilterQuery,
104
+ triggerDefaultFiltersChange
105
+ }
106
+ }
@@ -19,7 +19,7 @@ export default function () {
19
19
  }
20
20
 
21
21
  function findOne (key, filter) {
22
- return cachedFilters[key][filter]
22
+ return cachedFilters[key]?.[filter]
23
23
  }
24
24
 
25
25
  function findAll (key) {
package/src/vue-plugin.js CHANGED
@@ -14,6 +14,7 @@ import QasBtnDropdown from './components/btn-dropdown/QasBtnDropdown.vue'
14
14
  import QasCard from './components/card/QasCard.vue'
15
15
  import QasCardImage from './components/card-image/QasCardImage.vue'
16
16
  import QasCheckbox from './components/checkbox/QasCheckbox.vue'
17
+ import QasSelectFilter from './components/select-filter/QasSelectFilter.vue'
17
18
  import QasCopy from './components/copy/QasCopy.vue'
18
19
  import QasDate from './components/date/QasDate.vue'
19
20
  import QasDateTimeInput from './components/date-time-input/QasDateTimeInput.vue'
@@ -112,6 +113,7 @@ async function install (app) {
112
113
  app.component('QasCard', QasCard)
113
114
  app.component('QasCardImage', QasCardImage)
114
115
  app.component('QasCheckbox', QasCheckbox)
116
+ app.component('QasSelectFilter', QasSelectFilter)
115
117
  app.component('QasCopy', QasCopy)
116
118
  app.component('QasDate', QasDate)
117
119
  app.component('QasDateTimeInput', QasDateTimeInput)
@@ -213,6 +215,7 @@ export {
213
215
  QasCard,
214
216
  QasCheckbox,
215
217
  QasCopy,
218
+ QasSelectFilter,
216
219
  QasDate,
217
220
  QasDateTimeInput,
218
221
  QasDebugger,