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à | Tipo | Descrizione |
|---|---|---|
attivita | Ref<AttivitaView[]> | Lista attività utente corrente |
utente | Ref<AttivitaUtente | null> | Statistiche da v_attivita_utente |
contatori | Ref<ContatoreAttivita | null> | Badge contatori da rpc/conta_attivita_utente |
loading | Ref<boolean> | Caricamento in corso |
error | Ref<string | null> | Messaggio errore (last call) |
filtriAttivi | Ref<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 |
|---|---|
attivita | Ref<AttivitaView[]> |
loading | Ref<boolean> |
currentRange | Ref<DateRange> |
viewMode | Ref<'month' | 'week' | 'day'> |
error | Ref<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()
| Campo | Tipo | Descrizione |
|---|---|---|
repository | IAttivitaRepository | Punto di accesso unico ai dati (CRUD + RPC) |
service | IAttivitaRepository | Alias deprecato di repository — stesso oggetto, sarà rimosso nella prossima major |
getToken | () => string | null | JWT corrente per chiamate autenticate |
onEvent | (name, payload?) => void | Handler eventi cross-app |
apiBaseUrl | string | URL base Fastify (upload documento, firma) |
refreshSignal | Ref<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.
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()).service → repository: 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.
}
| Metodo | Descrizione |
|---|---|
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)
}
suggerita aprono popup. Le attività con tipo: 'attivata' sono già state create dalla RPC completa_attivita — processResponse 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)
| Metodo | Descrizione |
|---|---|
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 }
| Stato | Tipo |
|---|---|
isUploading | Ref<boolean> |
documento | Ref<UploadDocumentoResult | null> |
error | Ref<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 }
| Stato | Tipo |
|---|---|
isInviando | Ref<boolean> |
risultato | Ref<RichiestafirmaResult | null> |
error | Ref<string | null> |