Composables

useDialog

[object Object]

Signature

function useDialog(options?: UseDialogOptions): UseDialogResult

Astrazione minima per un dialog: visibilità, stato loading interno, messaggio di errore. Pensato per dialog di conferma + azione async (es. "Sei sicuro?" → POST → chiudi).

Opzioni UseDialogOptions

interface UseDialogOptions {
  initialVisible?: boolean
  initialLoading?: boolean
  initialError?: string | null
}
OpzioneTipoDefault
initialVisiblebooleanfalse
initialLoadingbooleanfalse
initialErrorstring | nullnull

Risultato UseDialogResult

interface UseDialogResult {
  visible: Ref<boolean>
  loading: Ref<boolean>
  error: Ref<string | null>
  hasError: ComputedRef<boolean>
  open: () => void
  close: () => void
  setLoading: (isLoading: boolean) => void
  setError: (message: string | null) => void
  reset: () => void
}
CampoDescrizione
visiblev-model per <Dialog>
loadingStato operazione in corso
errorMessaggio errore corrente (null se nessuno)
hasErrorcomputed(() => error.value !== null)
open()Imposta visible = true e resetta error = null (parti puliti a ogni apertura)
close()Imposta visible = false (non tocca error/loading)
setLoading(b)Setter esplicito
setError(msg)Setter esplicito (passa null per pulire)
reset()Riporta tutti i campi ai valori iniziali
open() pulisce gli errori: ogni apertura è "fresca". Se vuoi mantenere lo stato di errore tra aperture, gestiscilo manualmente con visible.value = true.

Esempio: conferma + azione async

<script setup lang="ts">
import { useMfeContext, useDialog } from '@pzeta/mfe-contracts/composables'

const props = defineProps<{ clienteId: string }>()
const emit = defineEmits<{ deleted: [id: string] }>()

const ctx = useMfeContext()
const dialog = useDialog()

async function confermaElimina() {
  dialog.setLoading(true)
  dialog.setError(null)

  try {
    await ctx.http.delete(`/api/clienti/${props.clienteId}`)
    dialog.close()
    emit('deleted', props.clienteId)
  } catch (err) {
    dialog.setError(err instanceof Error ? err.message : 'Errore sconosciuto')
  } finally {
    dialog.setLoading(false)
  }
}
</script>

<template>
  <button @click="dialog.open">Elimina cliente</button>

  <Dialog v-model:visible="dialog.visible.value" header="Conferma eliminazione">
    <p>Sei sicuro di voler eliminare questo cliente?</p>

    <div v-if="dialog.hasError" class="text-red-600">
      ⚠ {{ dialog.error.value }}
    </div>

    <template #footer>
      <button @click="dialog.close" :disabled="dialog.loading.value">
        Annulla
      </button>
      <button
        @click="confermaElimina"
        :disabled="dialog.loading.value"
        class="bg-red-600 text-white"
      >
        {{ dialog.loading.value ? 'Eliminazione...' : 'Elimina' }}
      </button>
    </template>
  </Dialog>
</template>

Pattern: stati multipli con tipo DialogState

interface DialogState {
  visible: boolean
  loading: boolean
  error: string | null
}

Tipo esportato per snapshot del dialog (utile in test o store):

import type { DialogState } from '@pzeta/mfe-contracts'

function getDialogSnapshot(dialog: UseDialogResult): DialogState {
  return {
    visible: dialog.visible.value,
    loading: dialog.loading.value,
    error: dialog.error.value,
  }
}

Differenza con useDetailForm

AspettouseDialoguseDetailForm
ScopoDialog modale singoloForm di pagina dettaglio
Trackingvisible, loading, errorloading, isFormDirty, canSave
Errorierror: Ref<string | null> espostoNon gestiti (catcha nel chiamante)
saving() wrapperNo (setter espliciti)Sì (auto loading on/off)
Dirty trackingNo

Usa useDialog per dialog isolati (conferma, info, prompt). Usa useDetailForm per pagine di edit con dirty tracking.

Tipi correlati