feat(model-types): add related-items modal and guard category edits
This commit is contained in:
101
app/composables/useCategoryEditGuard.ts
Normal file
101
app/composables/useCategoryEditGuard.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
|
||||
type GuardLabels = {
|
||||
singular: string
|
||||
plural: string
|
||||
verifying: string
|
||||
}
|
||||
|
||||
type GuardConfig = {
|
||||
endpoint: string
|
||||
filterKey: string
|
||||
labels: GuardLabels
|
||||
}
|
||||
|
||||
const extractTotal = (payload: any, fallbackLength: number) => {
|
||||
if (typeof payload?.totalItems === 'number') {
|
||||
return payload.totalItems
|
||||
}
|
||||
if (typeof payload?.['hydra:totalItems'] === 'number') {
|
||||
return payload['hydra:totalItems']
|
||||
}
|
||||
if (Array.isArray(payload?.member)) {
|
||||
return payload.member.length
|
||||
}
|
||||
if (Array.isArray(payload?.['hydra:member'])) {
|
||||
return payload['hydra:member'].length
|
||||
}
|
||||
return fallbackLength
|
||||
}
|
||||
|
||||
export function useCategoryEditGuard (config: GuardConfig) {
|
||||
const { get } = useApi()
|
||||
const { showError } = useToast()
|
||||
|
||||
const linkedCount = ref(0)
|
||||
const linkedLoading = ref(false)
|
||||
|
||||
const loadLinkedCount = async (modelTypeId: string) => {
|
||||
linkedLoading.value = true
|
||||
try {
|
||||
const params = new URLSearchParams()
|
||||
params.set('itemsPerPage', '1')
|
||||
params.set(config.filterKey, `/api/model_types/${modelTypeId}`)
|
||||
|
||||
const result = await get(`${config.endpoint}?${params.toString()}`)
|
||||
if (!result.success) {
|
||||
linkedCount.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
const fallbackLength = Array.isArray(result.data?.member)
|
||||
? result.data.member.length
|
||||
: Array.isArray(result.data?.['hydra:member'])
|
||||
? result.data['hydra:member'].length
|
||||
: 0
|
||||
|
||||
linkedCount.value = extractTotal(result.data, fallbackLength)
|
||||
} catch (error) {
|
||||
linkedCount.value = 0
|
||||
} finally {
|
||||
linkedLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const isSubmitBlocked = computed(
|
||||
() => linkedLoading.value || linkedCount.value > 0,
|
||||
)
|
||||
|
||||
const submitBlockMessage = computed(() => {
|
||||
if (linkedLoading.value) {
|
||||
return config.labels.verifying
|
||||
}
|
||||
if (linkedCount.value <= 0) {
|
||||
return ''
|
||||
}
|
||||
if (linkedCount.value === 1) {
|
||||
return `Modification bloquée : 1 ${config.labels.singular} est déjà lié à cette catégorie.`
|
||||
}
|
||||
return `Modification bloquée : ${linkedCount.value} ${config.labels.plural} sont déjà liés à cette catégorie.`
|
||||
})
|
||||
|
||||
const guardSubmitOrNotify = () => {
|
||||
if (!isSubmitBlocked.value) {
|
||||
return false
|
||||
}
|
||||
showError(submitBlockMessage.value || 'Modification bloquée pour cette catégorie.')
|
||||
return true
|
||||
}
|
||||
|
||||
return {
|
||||
linkedCount,
|
||||
linkedLoading,
|
||||
isSubmitBlocked,
|
||||
submitBlockMessage,
|
||||
loadLinkedCount,
|
||||
guardSubmitOrNotify,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user