@bildvitta/quasar-ui-asteroid 3.16.0-beta.3 → 3.16.0-beta.4
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.0-beta.
|
|
4
|
+
"version": "3.16.0-beta.4",
|
|
5
5
|
"author": "Bild & Vitta <systemteam@bild.com.br>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/asteroid.cjs.min.js",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"sass": "^1.62.1"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
+
"@bildvitta/composables": "^1.0.0-beta.7",
|
|
46
47
|
"@bildvitta/store-adapter": "^1.0.0",
|
|
47
48
|
"autonumeric": "^4.9.0",
|
|
48
49
|
"axios": "^1.4.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="
|
|
3
|
-
<header v-if="
|
|
2
|
+
<div :class="componentClass">
|
|
3
|
+
<header v-if="hasHeaderSlot">
|
|
4
4
|
<slot name="header" />
|
|
5
5
|
</header>
|
|
6
6
|
|
|
@@ -8,117 +8,160 @@
|
|
|
8
8
|
<slot />
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
|
-
<qas-empty-result-text v-else-if="!
|
|
11
|
+
<qas-empty-result-text v-else-if="!viewState.fetching" class="q-my-xl" />
|
|
12
12
|
|
|
13
|
-
<footer v-if="
|
|
13
|
+
<footer v-if="hasFooterSlot">
|
|
14
14
|
<slot name="footer" />
|
|
15
15
|
</footer>
|
|
16
16
|
|
|
17
|
-
<q-inner-loading :showing="
|
|
17
|
+
<q-inner-loading :showing="viewState.fetching">
|
|
18
18
|
<q-spinner color="grey" size="3em" />
|
|
19
19
|
</q-inner-loading>
|
|
20
20
|
</div>
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
|
-
<script>
|
|
24
|
-
import
|
|
23
|
+
<script setup>
|
|
24
|
+
import useView, { baseProps, baseEmits } from '../../composables/private/use-view'
|
|
25
25
|
|
|
26
|
-
import { markRaw } from 'vue'
|
|
27
|
-
import { getGetter, getAction } from '@bildvitta/store-adapter'
|
|
28
26
|
import debug from 'debug'
|
|
27
|
+
import { decamelize } from 'humps'
|
|
28
|
+
import { markRaw, computed, watch, inject } from 'vue'
|
|
29
|
+
import { useRoute } from 'vue-router'
|
|
29
30
|
|
|
30
31
|
const log = debug('asteroid-ui:qas-single-view')
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
name: 'QasSingleView',
|
|
33
|
+
defineOptions({ name: 'QasSingleView' })
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const props = defineProps({
|
|
36
|
+
...baseProps,
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
type: [Number, String]
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
result: {
|
|
44
|
-
default: () => ({}),
|
|
45
|
-
type: Object
|
|
46
|
-
}
|
|
38
|
+
customId: {
|
|
39
|
+
default: '',
|
|
40
|
+
type: [Number, String]
|
|
47
41
|
},
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
result: {
|
|
44
|
+
default: () => ({}),
|
|
45
|
+
type: Object
|
|
46
|
+
}
|
|
47
|
+
})
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return !!this.resultModel
|
|
58
|
-
},
|
|
49
|
+
const emit = defineEmits([
|
|
50
|
+
...baseEmits,
|
|
59
51
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
'update:result',
|
|
53
|
+
'fetch-success',
|
|
54
|
+
'fetch-error'
|
|
55
|
+
])
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
return getGetter.call(this, { entity: this.entity, key: 'byId' })(this.id) || {}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
57
|
+
const slots = defineSlots()
|
|
68
58
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.mx_fetchHandler({ id: this.id, url: this.url }, this.fetchSingle)
|
|
73
|
-
}
|
|
74
|
-
},
|
|
59
|
+
// globals
|
|
60
|
+
const axios = inject('axios')
|
|
61
|
+
const qas = inject('qas')
|
|
75
62
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
},
|
|
63
|
+
// composables
|
|
64
|
+
const route = useRoute()
|
|
80
65
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
const {
|
|
67
|
+
// state
|
|
68
|
+
viewState,
|
|
69
|
+
|
|
70
|
+
// computed
|
|
71
|
+
componentClass,
|
|
72
|
+
hasHeaderSlot,
|
|
73
|
+
hasFooterSlot,
|
|
74
|
+
|
|
75
|
+
// functions
|
|
76
|
+
errorHandler,
|
|
77
|
+
fetchHandler,
|
|
78
|
+
setErrors,
|
|
79
|
+
setFields,
|
|
80
|
+
setMetadata,
|
|
81
|
+
setResult,
|
|
82
|
+
updateModels
|
|
83
|
+
} = useView({ emit, props, slots, mode: 'single' })
|
|
84
|
+
|
|
85
|
+
// computed
|
|
86
|
+
const id = computed(() => props.customId || route.params.id)
|
|
87
|
+
|
|
88
|
+
const resultModel = computed(() => {
|
|
89
|
+
if (props.useStore) return qas.getGetter({ entity: props.entity, key: 'byId' })(id.value) || {}
|
|
90
|
+
|
|
91
|
+
return viewState.value.result || {}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const hasResult = computed(() => !!resultModel.value)
|
|
95
|
+
|
|
96
|
+
// watch
|
|
97
|
+
watch(() => route, (to, from) => {
|
|
98
|
+
if (to.name === from.name) {
|
|
99
|
+
fetchHandler({ id: id.value, url: props.url }, fetchSingle)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
watch(() => resultModel.value, value => emit('update:result', markRaw({ ...value })))
|
|
104
|
+
|
|
105
|
+
// created
|
|
106
|
+
fetchHandler({ id: id.value, url: props.url }, fetchSingle)
|
|
107
|
+
|
|
108
|
+
// functions
|
|
109
|
+
async function fetchSingle (externalPayload = {}) {
|
|
110
|
+
viewState.value.fetching = true
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const payload = { id: id.value, url: props.url, ...externalPayload }
|
|
114
|
+
|
|
115
|
+
const response = await getAction(payload)
|
|
84
116
|
|
|
85
|
-
|
|
86
|
-
async fetchSingle (externalPayload = {}) {
|
|
87
|
-
this.mx_isFetching = true
|
|
117
|
+
const { errors, fields, metadata, result } = response.data
|
|
88
118
|
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
setErrors(errors)
|
|
120
|
+
setFields(fields)
|
|
121
|
+
setMetadata(metadata)
|
|
91
122
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
123
|
+
/**
|
|
124
|
+
* result só precisa ser adicionado ao estado se não estiver usando store,
|
|
125
|
+
* pois com a store é usado o getter.
|
|
126
|
+
*/
|
|
127
|
+
!props.useStore && setResult(result)
|
|
97
128
|
|
|
98
|
-
|
|
129
|
+
updateModels({
|
|
130
|
+
errors: viewState.value.errors,
|
|
131
|
+
fields: viewState.value.fields,
|
|
132
|
+
metadata: viewState.value.metadata,
|
|
99
133
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.mx_setMetadata(metadata)
|
|
134
|
+
...(!props.useStore && { result: viewState.value.result })
|
|
135
|
+
})
|
|
103
136
|
|
|
104
|
-
|
|
105
|
-
errors: this.mx_errors,
|
|
106
|
-
fields: this.mx_fields,
|
|
107
|
-
metadata: this.mx_metadata
|
|
108
|
-
})
|
|
137
|
+
emit('fetch-success', response)
|
|
109
138
|
|
|
110
|
-
|
|
139
|
+
log(`[${props.entity}]:fetchSingle:success`, response)
|
|
140
|
+
} catch (error) {
|
|
141
|
+
errorHandler(error)
|
|
142
|
+
emit('fetch-error', error)
|
|
111
143
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
144
|
+
log(`[${props.entity}]:fetchSingle:error`, error)
|
|
145
|
+
} finally {
|
|
146
|
+
viewState.value.fetching = false
|
|
147
|
+
}
|
|
148
|
+
}
|
|
116
149
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
150
|
+
function getAction (payload) {
|
|
151
|
+
if (props.useStore) {
|
|
152
|
+
return qas.getAction({
|
|
153
|
+
entity: props.entity,
|
|
154
|
+
key: 'fetchSingle',
|
|
155
|
+
payload
|
|
156
|
+
})
|
|
122
157
|
}
|
|
158
|
+
|
|
159
|
+
const { id: unusedID, url: unusedURL, ...externalPayload } = payload
|
|
160
|
+
|
|
161
|
+
const decamelizedEntity = decamelize(props.entity, { separator: '-' })
|
|
162
|
+
|
|
163
|
+
const url = props.url || `${decamelizedEntity}/${id.value}`
|
|
164
|
+
|
|
165
|
+
return axios.get(url, { ...externalPayload })
|
|
123
166
|
}
|
|
124
167
|
</script>
|
|
@@ -62,6 +62,11 @@ props:
|
|
|
62
62
|
default: true
|
|
63
63
|
type: Boolean
|
|
64
64
|
|
|
65
|
+
use-route:
|
|
66
|
+
desc: Controla se o componente usará internamente uma store do vuex/pinia ou se vai ser utilizado o axios diretamente.
|
|
67
|
+
default: true
|
|
68
|
+
type: Boolean
|
|
69
|
+
|
|
65
70
|
slots:
|
|
66
71
|
default:
|
|
67
72
|
desc: 'Slot para ter o conteúdo principal (dentro do main).'
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { NotifyError } from '../../plugins'
|
|
2
|
+
import { camelizeFieldsName } from '../../helpers'
|
|
3
|
+
|
|
4
|
+
import { useView as useViewComposable } from '@bildvitta/composables'
|
|
5
|
+
import { ref, computed, watch, markRaw } from 'vue'
|
|
6
|
+
import { useRouter } from 'vue-router'
|
|
7
|
+
|
|
8
|
+
export const baseProps = {
|
|
9
|
+
beforeFetch: {
|
|
10
|
+
default: null,
|
|
11
|
+
type: Function
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
errors: {
|
|
15
|
+
default: () => ({}),
|
|
16
|
+
type: Object
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
entity: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: ''
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
fetching: {
|
|
25
|
+
type: Boolean
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
fields: {
|
|
29
|
+
default: () => ({}),
|
|
30
|
+
type: Object
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
metadata: {
|
|
34
|
+
default: () => ({}),
|
|
35
|
+
type: Object
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
url: {
|
|
39
|
+
default: '',
|
|
40
|
+
type: String
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
useBoundary: {
|
|
44
|
+
default: true,
|
|
45
|
+
type: Boolean
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
useStore: {
|
|
49
|
+
default: true,
|
|
50
|
+
type: Boolean
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const baseEmits = [
|
|
55
|
+
'update:fields',
|
|
56
|
+
'update:errors',
|
|
57
|
+
'update:metadata',
|
|
58
|
+
'update:fetching'
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {{
|
|
63
|
+
* mode: import('@bildvitta/composables').ViewModeTypes,
|
|
64
|
+
* props: baseProps,
|
|
65
|
+
* emit: (baseEmits: string) => void,
|
|
66
|
+
* slots: import('vue').Slots
|
|
67
|
+
* }} config
|
|
68
|
+
*/
|
|
69
|
+
export default function useView (config) {
|
|
70
|
+
const {
|
|
71
|
+
emit,
|
|
72
|
+
mode,
|
|
73
|
+
slots,
|
|
74
|
+
props
|
|
75
|
+
} = config
|
|
76
|
+
|
|
77
|
+
// composables
|
|
78
|
+
const router = useRouter()
|
|
79
|
+
const { viewState } = useViewComposable({ mode })
|
|
80
|
+
|
|
81
|
+
// refs
|
|
82
|
+
const cancelBeforeFetch = ref(false)
|
|
83
|
+
|
|
84
|
+
// constants
|
|
85
|
+
const fetchErrorMessage = 'Ops… Não conseguimos acessar as informações. Por favor, tente novamente em alguns minutos.'
|
|
86
|
+
|
|
87
|
+
// computed
|
|
88
|
+
const componentClass = computed(() => props.useBoundary && 'container spaced')
|
|
89
|
+
const hasFooterSlot = computed(() => !!slots.footer)
|
|
90
|
+
const hasHeaderSlot = computed(() => !!slots.header)
|
|
91
|
+
|
|
92
|
+
// watch
|
|
93
|
+
watch(() => viewState.value.fetching, value => emit('update:fetching', value))
|
|
94
|
+
|
|
95
|
+
// functions
|
|
96
|
+
function errorHandler (error) {
|
|
97
|
+
const { response } = error
|
|
98
|
+
|
|
99
|
+
const status = response?.status
|
|
100
|
+
|
|
101
|
+
const redirect = status >= 500
|
|
102
|
+
? 'ServerError'
|
|
103
|
+
: ({ 403: 'Forbidden', 404: 'NotFound' })[status]
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* caso exista um desses status será redirecionado sem aparecer o "notify"
|
|
107
|
+
*/
|
|
108
|
+
if (redirect) {
|
|
109
|
+
router.replace({ name: redirect })
|
|
110
|
+
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
NotifyError(fetchErrorMessage)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setErrors (errors = {}) {
|
|
118
|
+
viewState.value.errors = markRaw(errors)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setFields (fields = {}) {
|
|
122
|
+
const camelizedFields = camelizeFieldsName(fields)
|
|
123
|
+
|
|
124
|
+
viewState.value.fields = markRaw(camelizedFields)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function setMetadata (metadata = {}) {
|
|
128
|
+
viewState.value.metadata = markRaw(metadata)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function setResult (result = {}) {
|
|
132
|
+
viewState.value.result = result
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function updateModels (models) {
|
|
136
|
+
for (const key in models) {
|
|
137
|
+
if (!models[key]) continue
|
|
138
|
+
|
|
139
|
+
emit(`update:${key}`, models[key])
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function fetchHandler (payload, resolve) {
|
|
144
|
+
const hasBeforeFetch = typeof props.beforeFetch === 'function'
|
|
145
|
+
|
|
146
|
+
if (hasBeforeFetch && !cancelBeforeFetch.value) {
|
|
147
|
+
return props.beforeFetch({
|
|
148
|
+
payload,
|
|
149
|
+
resolve: payload => resolve(payload),
|
|
150
|
+
done: () => {
|
|
151
|
+
cancelBeforeFetch.value = true
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
resolve()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
// state
|
|
161
|
+
viewState,
|
|
162
|
+
|
|
163
|
+
// constants
|
|
164
|
+
fetchErrorMessage,
|
|
165
|
+
|
|
166
|
+
// computed
|
|
167
|
+
componentClass,
|
|
168
|
+
hasFooterSlot,
|
|
169
|
+
hasHeaderSlot,
|
|
170
|
+
|
|
171
|
+
// functions
|
|
172
|
+
errorHandler,
|
|
173
|
+
fetchHandler,
|
|
174
|
+
setErrors,
|
|
175
|
+
setFields,
|
|
176
|
+
setResult,
|
|
177
|
+
setMetadata,
|
|
178
|
+
updateModels
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/vue-plugin.js
CHANGED
|
@@ -72,7 +72,7 @@ import QasWhatsappLink from './components/whatsapp-link/QasWhatsappLink.vue'
|
|
|
72
72
|
|
|
73
73
|
import { Notify, Loading, Quasar, Dialog as QuasarDialog } from 'quasar'
|
|
74
74
|
|
|
75
|
-
import { getAction } from '@bildvitta/store-adapter'
|
|
75
|
+
import { getAction, getGetter } from '@bildvitta/store-adapter'
|
|
76
76
|
|
|
77
77
|
// Plugins
|
|
78
78
|
import {
|
|
@@ -176,7 +176,8 @@ async function install (app) {
|
|
|
176
176
|
app.provide('qas', {
|
|
177
177
|
delete: params => Delete.call(app.config.globalProperties, params),
|
|
178
178
|
|
|
179
|
-
getAction: params => getAction.call(app.config.globalProperties, params)
|
|
179
|
+
getAction: params => getAction.call(app.config.globalProperties, params),
|
|
180
|
+
getGetter: params => getGetter.call(app.config.globalProperties, params)
|
|
180
181
|
})
|
|
181
182
|
|
|
182
183
|
app.directive(Test.name, Test)
|