Implementazioni varie

This commit is contained in:
2026-03-27 20:59:06 +01:00
parent 047990811f
commit 46784aca4c
40 changed files with 4090 additions and 34 deletions
+65
View File
@@ -0,0 +1,65 @@
import apiClient from './client'
export interface PecContactResponse {
id: string
tenant_id: string
email: string
name: string | null
organization: string | null
notes: string | null
is_favorite: boolean
auto_saved: boolean
created_by: string | null
created_at: string
updated_at: string
}
export interface PecContactCreate {
email: string
name?: string | null
organization?: string | null
notes?: string | null
is_favorite?: boolean
}
export interface PecContactUpdate {
name?: string | null
organization?: string | null
notes?: string | null
is_favorite?: boolean
}
export interface ContactImportResult {
created: number
updated: number
skipped: number
errors: string[]
}
export const contactsApi = {
list: (params?: { q?: string; page?: number; page_size?: number }) =>
apiClient.get<{ items: PecContactResponse[]; total: number }>('/contacts', { params }).then((r) => r.data),
autocomplete: (q: string) =>
apiClient.get<PecContactResponse[]>('/contacts/autocomplete', { params: { q } }).then((r) => r.data),
get: (id: string) =>
apiClient.get<PecContactResponse>(`/contacts/${id}`).then((r) => r.data),
create: (data: PecContactCreate) =>
apiClient.post<PecContactResponse>('/contacts', data).then((r) => r.data),
update: (id: string, data: PecContactUpdate) =>
apiClient.put<PecContactResponse>(`/contacts/${id}`, data).then((r) => r.data),
delete: (id: string) =>
apiClient.delete(`/contacts/${id}`).then((r) => r.data),
importCsv: (file: File) => {
const formData = new FormData()
formData.append('file', file)
return apiClient.post<ContactImportResult>('/contacts/import', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
}).then((r) => r.data)
},
}
+31
View File
@@ -0,0 +1,31 @@
import apiClient from './client'
export interface DeadlineMessageResponse {
id: string
subject: string | null
from_address: string | null
to_addresses: string[] | null
direction: 'inbound' | 'outbound'
pec_type: string
state: string
mailbox_id: string
deadline_at: string | null
deadline_note: string | null
is_overdue: boolean
received_at: string | null
sent_at: string | null
created_at: string
}
export interface DeadlineSetRequest {
deadline_at: string | null
deadline_note?: string | null
}
export const deadlinesApi = {
list: (params?: { days_ahead?: number; include_overdue?: boolean }) =>
apiClient.get<DeadlineMessageResponse[]>('/deadlines', { params }).then((r) => r.data),
setDeadline: (messageId: string, data: DeadlineSetRequest) =>
apiClient.post<DeadlineMessageResponse>(`/messages/${messageId}/deadline`, data).then((r) => r.data),
}
+23
View File
@@ -128,6 +128,29 @@ export const messagesApi = {
getReceipts: (id: string) =>
apiClient.get<MessageResponse[]>(`/messages/${id}/receipts`).then((r) => r.data),
// ─── Feature 3: Thread ────────────────────────────────────────────────────
getThread: (id: string) =>
apiClient.get<MessageResponse[]>(`/messages/${id}/thread`).then((r) => r.data),
// ─── Feature 7: Preview allegati ─────────────────────────────────────────
getAttachmentPreviewUrl: (messageId: string, attachmentId: string) =>
apiClient.get<{
previewable: boolean
content_type: string
filename: string
url?: string
}>(`/messages/${messageId}/attachments/${attachmentId}/preview-url`).then((r) => r.data),
// ─── Feature 8: Stampa ────────────────────────────────────────────────────
/** Apre la vista di stampa HTML in una nuova tab. */
openPrint: (messageId: string, token: string) => {
const baseUrl = (window as any).__API_BASE_URL__ || '/api/v1'
window.open(`${baseUrl}/messages/${messageId}/print?token=${token}`, '_blank')
},
/**
* Scarica il pacchetto ZIP completo della PEC (postacert.eml, daticert.xml,
* ricevute di accettazione/consegna per le mail outbound).
+65
View File
@@ -0,0 +1,65 @@
import apiClient from './client'
export type ConditionField = 'from_address' | 'to_address' | 'subject' | 'mailbox_id' | 'pec_type'
export type ConditionOperator = 'contains' | 'equals' | 'starts_with' | 'ends_with' | 'regex' | 'not_contains'
export type ActionType = 'apply_label' | 'assign_vbox' | 'mark_read' | 'mark_starred' | 'notify_webhook'
export interface RoutingRuleCondition {
id: string
field: ConditionField
operator: ConditionOperator
value: string
}
export interface RoutingRuleAction {
id: string
action_type: ActionType
action_value: string | null
}
export interface RoutingRuleResponse {
id: string
tenant_id: string
name: string
description: string | null
is_active: boolean
priority: number
stop_processing: boolean
conditions: RoutingRuleCondition[]
actions: RoutingRuleAction[]
created_by: string | null
created_at: string
updated_at: string
}
export interface RoutingRuleCreate {
name: string
description?: string | null
is_active?: boolean
priority?: number
stop_processing?: boolean
conditions?: Array<{ field: ConditionField; operator: ConditionOperator; value: string }>
actions?: Array<{ action_type: ActionType; action_value?: string | null }>
}
export type RoutingRuleUpdate = Partial<RoutingRuleCreate>
export const routingRulesApi = {
list: () =>
apiClient.get<{ items: RoutingRuleResponse[]; total: number }>('/routing-rules').then((r) => r.data),
get: (id: string) =>
apiClient.get<RoutingRuleResponse>(`/routing-rules/${id}`).then((r) => r.data),
create: (data: RoutingRuleCreate) =>
apiClient.post<RoutingRuleResponse>('/routing-rules', data).then((r) => r.data),
update: (id: string, data: RoutingRuleUpdate) =>
apiClient.put<RoutingRuleResponse>(`/routing-rules/${id}`, data).then((r) => r.data),
delete: (id: string) =>
apiClient.delete(`/routing-rules/${id}`).then((r) => r.data),
toggle: (id: string) =>
apiClient.post<RoutingRuleResponse>(`/routing-rules/${id}/toggle`).then((r) => r.data),
}
+49
View File
@@ -0,0 +1,49 @@
import apiClient from './client'
export interface TemplateResponse {
id: string
tenant_id: string
name: string
description: string | null
subject: string
body_text: string | null
body_html: string | null
created_by: string | null
created_at: string
updated_at: string
}
export interface TemplateCreate {
name: string
description?: string | null
subject?: string
body_text?: string | null
body_html?: string | null
}
export interface TemplateUpdate {
name?: string
description?: string | null
subject?: string
body_text?: string | null
body_html?: string | null
}
export const templatesApi = {
list: (q?: string) =>
apiClient.get<{ items: TemplateResponse[]; total: number }>('/templates', {
params: { q },
}).then((r) => r.data),
get: (id: string) =>
apiClient.get<TemplateResponse>(`/templates/${id}`).then((r) => r.data),
create: (data: TemplateCreate) =>
apiClient.post<TemplateResponse>('/templates', data).then((r) => r.data),
update: (id: string, data: TemplateUpdate) =>
apiClient.put<TemplateResponse>(`/templates/${id}`, data).then((r) => r.data),
delete: (id: string) =>
apiClient.delete(`/templates/${id}`).then((r) => r.data),
}