refactor: add useInitialQueries composable to replace ViewBase queries handling

This commit is contained in:
axolotle 2024-07-06 15:57:47 +02:00
parent 3c3f50ca60
commit 25482b67ca
2 changed files with 53 additions and 52 deletions

View file

@ -1,22 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Component } from 'vue' import type { Component } from 'vue'
import { computed, ref } from 'vue'
import api from '@/api' defineOptions({ inheritAttrs: false })
withDefaults(
// FIXME type queries
const props = withDefaults(
defineProps<{ defineProps<{
queries?: any[]
queriesWait?: boolean
skeleton?: string | Component
loading?: boolean loading?: boolean
skeleton?: string | Component
}>(), }>(),
{ {
queries: undefined, loading: false,
queriesWait: false, skeleton: 'CardFormSkeleton',
skeleton: undefined,
loading: undefined,
}, },
) )
@ -24,44 +17,11 @@ const slots = defineSlots<{
'top-bar-group-left': any 'top-bar-group-left': any
'top-bar-group-right': any 'top-bar-group-right': any
'top-bar': any 'top-bar': any
top(props: { loading: boolean }): any top: any
default(props: { loading: boolean }): any default: any
bot(props: { loading: boolean }): any bot: any
skeleton: any skeleton: any
}>() }>()
const emit = defineEmits<{
'queries-response': any[]
}>()
defineExpose({ fetchQueries })
const fallbackLoading = ref(
props.loading === undefined && props.queries !== undefined ? true : null,
)
const isLoading = computed(() => {
if (props.loading !== undefined) return props.loading
return fallbackLoading.value
})
function fetchQueries({ triggerLoading = false } = {}) {
if (triggerLoading) {
fallbackLoading.value = true
}
return api
.fetchAll(props.queries, { wait: props.queriesWait, initial: true })
.then((responses) => {
emit('queries-response', ...responses)
fallbackLoading.value = false
return responses
})
}
if (props.queries) {
fetchQueries()
}
</script> </script>
<template> <template>
@ -76,9 +36,9 @@ if (props.queries) {
</TopBar> </TopBar>
<slot v-else name="top-bar" /> <slot v-else name="top-bar" />
<slot name="top" v-bind="{ loading: isLoading }" /> <slot name="top" />
<BSkeletonWrapper :loading="isLoading"> <BSkeletonWrapper :loading="loading">
<template #loading> <template #loading>
<slot name="skeleton"> <slot name="skeleton">
<Component :is="skeleton" /> <Component :is="skeleton" />
@ -87,10 +47,10 @@ if (props.queries) {
<!-- Empty div to be able to receive multiple components --> <!-- Empty div to be able to receive multiple components -->
<div> <div>
<slot name="default" v-bind="{ loading: isLoading }" /> <slot name="default" />
</div> </div>
</BSkeletonWrapper> </BSkeletonWrapper>
<slot name="bot" v-bind="{ loading: isLoading }" /> <slot name="bot" />
</div> </div>
</template> </template>

View file

@ -0,0 +1,41 @@
import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue'
import { ref, toValue } from 'vue'
import type { APIQuery } from '@/api/api'
import api from '@/api/api'
import type { Obj } from '@/types/commons'
export function useInitialQueries<
ResponsesType extends (Obj | string)[] = Obj[],
>(
queries: MaybeRefOrGetter<APIQuery[]> | ComputedRef<APIQuery[]>,
{
onQueriesResponse,
wait = false,
}: {
onQueriesResponse?: (...responses: ResponsesType) => Promise<void> | void
wait?: boolean
} = {},
) {
const loading = ref(true)
const responses: Ref<ResponsesType | null> = ref(null)
// FIXME watch `queries` to call on change?
function call(triggerLoading = true) {
if (triggerLoading) loading.value = true
return api
.fetchAll(toValue(queries), { wait, initial: true })
.then(async (responses_) => {
responses.value = responses_ as ResponsesType
if (onQueriesResponse) {
await onQueriesResponse(...(responses_ as ResponsesType))
}
loading.value = false
return responses
})
}
call()
return { loading, responses, refetch: call }
}