Composables

Altri Composables


title: Altri Composables description: useAttivitaDashboard, useAttivitaCalendario, useAttivitaContext, useTipiAttivita, useConcatenamento, useRicorrenza, useDocumento, useRichiestafirma.

useAttivitaDashboard

Composable per la dashboard personale dell'utente corrente. Aggrega attività, riepilogo utente e contatori badge da tre chiamate parallele al repository.

Auto-refresh (v1.0.0): watcha refreshSignal per ri-eseguire fetchDashboard() quando un'attività viene creata/completata/annullata altrove nell'app.

import { useAttivitaDashboard } from '@pzeta/vue-attivita'

const {
  attivita, utente, contatori, loading, error, filtriAttivi,
  fetchDashboard, fetchContatori, applyFiltri,
  groupByTipo, groupByScadenza
} = useAttivitaDashboard()

onMounted(fetchDashboard)

// Raggruppamento per scadenza
const { in_ritardo, oggi, futuro } = groupByScadenza()

// Filtra per tipo
await applyFiltri({ codtipoattivita: 'telefonata', stato: 'pianificata' })

Stato reattivo

ProprietàTipoDescrizione
attivitaRef<AttivitaView[]>Lista attività utente corrente
utenteRef<AttivitaUtente | null>Statistiche da v_attivita_utente
contatoriRef<ContatoreAttivita | null>Badge contatori da rpc/conta_attivita_utente
loadingRef<boolean>Caricamento in corso
errorRef<string | null>Messaggio errore (last call)
filtriAttiviRef<AttivitaFilters>Filtri attualmente applicati

Evento automatico

Se contatori.in_ritardo > 0 o contatori.oggi > 0, fetchDashboard emette automaticamente:

attivita:scadenza-imminente { totale_in_ritardo, oggi }

via onEvent del context — utile per badge in header globali.


useAttivitaCalendario

Composable per la vista calendario con drag-and-drop sulle scadenze. Gestisce aggiornamento ottimistico con rollback in caso di errore PostgREST.

Auto-refresh (v1.0.0): watcha refreshSignal per ri-fetchare currentRange quando un'altra parte dell'app effettua CRUD su attività.

import { useAttivitaCalendario } from '@pzeta/vue-attivita'

const {
  attivita, loading, currentRange, viewMode, error,
  fetchForRange, updateScadenza, setViewMode, navigateMonth
} = useAttivitaCalendario()

await fetchForRange({ start: '2026-05-01', end: '2026-05-31' })

// Drag-and-drop — UI aggiornata subito, rollback automatico se fallisce
await updateScadenza(idattivita, '2026-05-20')

// Navigazione (guard anti-race-condition: ignora click mentre fetch è in corso)
await navigateMonth(1)   // mese successivo
await navigateMonth(-1)  // mese precedente

setViewMode('week')      // ref informativa — il rendering è responsabilità del consumer/View

Stato reattivo

ProprietàTipo
attivitaRef<AttivitaView[]>
loadingRef<boolean>
currentRangeRef<DateRange>
viewModeRef<'month' | 'week' | 'day'>
errorRef<string | null>

useAttivitaContext

Accede al contesto iniettato da AttivitaPlugin o da provide manuale.

import { useAttivitaContext } from '@pzeta/vue-attivita'

const { repository, getToken, onEvent, apiBaseUrl, refreshSignal } = useAttivitaContext()
CampoTipoDescrizione
repositoryIAttivitaRepositoryPunto di accesso unico ai dati (CRUD + RPC)
serviceIAttivitaRepositoryAlias deprecato di repository — stesso oggetto, sarà rimosso nella prossima major
getToken() => string | nullJWT corrente per chiamate autenticate
onEvent(name, payload?) => voidHandler eventi cross-app
apiBaseUrlstringURL base Fastify (upload documento, firma)
refreshSignalRef<number>v1.0.0 — Signal reattivo incrementato dai componenti data-aware dopo CRUD su attività. I composables (useAttivita, useAttivitaCalendario, useAttivitaDashboard) e i componenti data-aware (AttivitaTimeline, AttivitaBadge) lo watch-ano per rinfrescare automaticamente i propri dati

Lancia un errore se chiamato fuori da un componente che ha il contesto. Usato internamente da tutti gli altri composables.

Auto-refresh viste data-aware (v1.0.0): ogni operazione CRUD effettuata tramite useAttivita (pianifica/completa/annulla/ripristina/elimina/aggiungi-rimuoviAssegnatario) e AttivitaForm (handleSave / handleSegnaComeFatto) incrementa refreshSignal. Tutte le 6 viste di dominio — AttivitaBadge, AttivitaListaEntita, AttivitaConsolidata, AttivitaKanbanTipo, AttivitaCalendario, AttivitaTimeline — si auto-aggiornano senza page refresh, anche se montate in alberi diversi. Per integrare un componente custom, basta watch(refreshSignal, () => reload()).
Migrazione servicerepository: il campo service resta esposto per backward-compat e punta allo stesso oggetto. Negli esempi nuovi preferisci repository. Vedi IAttivitaRepository.

useTipiAttivita

Carica e filtra i tipi attività disponibili. Cache in-memory: fetchTipi() non ri-fetcha se già loaded a meno che forceRefresh=true.

import { useTipiAttivita } from '@pzeta/vue-attivita'

const {
  tipi, loading, loaded,
  fetchTipi, createTipo, updateTipo, deleteTipo,
  getTipoById, getTipoByCode, getTipiAttivi, getTipoRiunione
} = useTipiAttivita()

await fetchTipi()              // primo load
await fetchTipi(true)          // force refresh

const attivi = getTipiAttivi()                    // solo `attivo === true`
const tipo = getTipoById(3)
const email = getTipoByCode('email')
const riunione = getTipoRiunione()                // primo tipo con `azione === 'riunione'`

// Admin
const created = await createTipo({
  nome: 'Visita ispettiva',
  codtipoattivita: 'visita',
  // ... resto dei campi
})
const updated = await updateTipo(idtipoattivita, { nome: 'Visita ispettiva (revisione)' })

// Hard delete (v1.0.0) — lancia errore FK se ci sono attività referenziate
try {
  await deleteTipo(idtipoattivita)
} catch (e) {
  // Tipico: violazione FK perché esistono attività di questo tipo.
  // Considera updateTipo({ attivo: false }) come soft delete alternativo.
}
MetodoDescrizione
fetchTipi(forceRefresh?)Carica repository.getTipiAttivita(true) (solo attivi). No-op se loaded.value === true e forceRefresh === false
createTipo(data)Crea + ricarica cache
updateTipo(id, data)Aggiorna + ricarica cache
deleteTipo(id)v1.0.0 — Hard delete + ricarica cache. Lancia errore se ci sono attività referenziate (FK violation)
getTipoById(id)Ricerca locale (cache)
getTipoByCode(cod)Ricerca locale per codtipoattivita
getTipiAttivi()Filtro locale attivo === true
getTipoRiunione()Primo tipo con azione === 'riunione'

useConcatenamento

Gestisce il flusso post-completamento con attività suggerite. Riceve un Ref<AttivitaSuccessiva[]> (tipicamente popolato da processResponse(completaAttivitaResponse)) e presenta i suggerimenti uno a uno tramite popup.

import { ref } from 'vue'
import { useConcatenamento } from '@pzeta/vue-attivita'
import type { AttivitaSuccessiva } from '@pzeta/vue-attivita'

const attivitaSuggerite = ref<AttivitaSuccessiva[]>([])

const {
  showSuggerimento,    // visibilità popup corrente
  suggeritaCorrente,   // AttivitaSuccessiva | null
  processResponse,     // (response: CompletaAttivitaResponse) => void
  accetta,             // () => Partial<AttivitaFormState>  ← per pre-fillare AttivitaForm
  rifiuta,             // () => void  ← passa al successivo o chiude
  modifica,            // () => Partial<AttivitaFormState>  ← alias di accetta
  hasNext,             // () => boolean
} = useConcatenamento(attivitaSuggerite)

// Dopo un completamento
async function completa(idattivita: number, risultato: string) {
  const response = await repository.completaAttivita({ p_idattivita: idattivita, p_risultato: risultato })
  processResponse(response)   // popola attivitaSuggerite e apre popup se ci sono `suggerita`
}

// Nel template del popup
function onAccetta() {
  const prefillState = accetta()   // pre-compila AttivitaForm
  apriAttivitaFormCon(prefillState)
}
Solo i suggerita aprono popup. Le attività con tipo: 'attivata' sono già state create dalla RPC completa_attivitaprocessResponse le ignora.

useRicorrenza

Gestisce form e persistenza della ricorrenza per un'attività template. Nessun parametro — l'idattivita viene passato a fetchRicorrenza / saveRicorrenza.

import { useRicorrenza } from '@pzeta/vue-attivita'

const {
  ricorrenzaAbilitata,        // Ref<boolean> — toggle UI
  ricorrenzaForm,             // Ref<RicorrenzaForm> — campi form
  mostraGiorniAnticipo,       // ComputedRef<boolean> — true se trigger='data_fissa'
  reset, loadFromExisting, buildPayload,
  fetchRicorrenza, saveRicorrenza, disattivaRicorrenza,
} = useRicorrenza()

await fetchRicorrenza(idattivita)            // popola form se esiste
const ricorrenza = await saveRicorrenza(idattivita)  // create o update
await disattivaRicorrenza(idricorrenza)
MetodoDescrizione
fetchRicorrenza(idattivita)Carica via repository.getRicorrenza e popola form se esiste
saveRicorrenza(idattivita)Crea o aggiorna; ritorna Ricorrenza | null (null se ricorrenzaAbilitata.value === false)
disattivaRicorrenza(idricorrenza)Chiama repository.disattivaRicorrenza e setta ricorrenzaAbilitata = false
loadFromExisting(r)Popola form da Ricorrenza esistente
buildPayload()Snapshot del form (null se disabilitata)
reset()Riporta a default

useDocumento

Upload documento su MinIO via endpoint Fastify. Nessun parametro al composable — idattivita e file passati a uploadFile.

import { useDocumento } from '@pzeta/vue-attivita'

const { isUploading, documento, error, uploadFile } = useDocumento()

await uploadFile(idattivita, file, 'descrizione opzionale')
// → POST {apiBaseUrl}/api/attivita/{idattivita}/upload-documento  (multipart/form-data)
// documento.value → UploadDocumentoResult { iddocumento, nome, url, dimensione }
StatoTipo
isUploadingRef<boolean>
documentoRef<UploadDocumentoResult | null>
errorRef<string | null>

useRichiestafirma

Invia richiesta di firma digitale via endpoint Fastify. Nessun parametro al composable.

import { useRichiestafirma } from '@pzeta/vue-attivita'

const { isInviando, risultato, error, inviaRichiesta } = useRichiestafirma()

await inviaRichiesta(idattivita, {
  iddocumento: 10,
  firmatari: [{ email: 'mario@example.com', nome: 'Mario Rossi', ordine: 1 }],
  messaggio: 'Firma il contratto',
  scadenzafirma: '2026-12-31',
  firmadelrichiedente: null,
})
// → POST {apiBaseUrl}/api/attivita/{idattivita}/richiedi-firma
// risultato.value → RichiestafirmaResult { idrichiestafirma, stato, urlfirma }
StatoTipo
isInviandoRef<boolean>
risultatoRef<RichiestafirmaResult | null>
errorRef<string | null>