Implement Phase 5: reconciliation, SignalR notifications, payees, splits & plugins
Add full frontend UI for five backend features: bank reconciliation (3-step stepper workflow), payee management (CRUD with alias chips), transaction splits (expandable rows + split editor), plugins (card grid), and real-time SignalR notifications (bell dropdown with badge). Fix backend PayeeResponse to expose alias IDs for deletion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { HubConnectionBuilder, HubConnection, LogLevel } from '@microsoft/signalr'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import type { AppNotification, FileImportNotification } from '@/types'
|
||||
|
||||
const notifications = ref<AppNotification[]>([])
|
||||
const isConnected = ref(false)
|
||||
let connection: HubConnection | null = null
|
||||
|
||||
const unreadCount = computed(() => notifications.value.filter(n => !n.read).length)
|
||||
|
||||
function connect() {
|
||||
if (connection) return
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
connection = new HubConnectionBuilder()
|
||||
.withUrl('/hubs/notifications', {
|
||||
accessTokenFactory: () => authStore.token || ''
|
||||
})
|
||||
.withAutomaticReconnect()
|
||||
.configureLogging(LogLevel.Warning)
|
||||
.build()
|
||||
|
||||
connection.on('FileImportReady', (data: FileImportNotification) => {
|
||||
notifications.value.unshift({
|
||||
id: crypto.randomUUID(),
|
||||
type: 'FileImportReady',
|
||||
data,
|
||||
timestamp: new Date().toISOString(),
|
||||
read: false
|
||||
})
|
||||
})
|
||||
|
||||
connection.onclose(() => {
|
||||
isConnected.value = false
|
||||
})
|
||||
|
||||
connection.onreconnected(() => {
|
||||
isConnected.value = true
|
||||
})
|
||||
|
||||
connection.start()
|
||||
.then(() => { isConnected.value = true })
|
||||
.catch(() => { isConnected.value = false })
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (connection) {
|
||||
connection.stop()
|
||||
connection = null
|
||||
}
|
||||
isConnected.value = false
|
||||
notifications.value = []
|
||||
}
|
||||
|
||||
function markAsRead(id: string) {
|
||||
const notification = notifications.value.find(n => n.id === id)
|
||||
if (notification) notification.read = true
|
||||
}
|
||||
|
||||
function markAllAsRead() {
|
||||
notifications.value.forEach(n => { n.read = true })
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
notifications.value = []
|
||||
}
|
||||
|
||||
export function useNotifications() {
|
||||
return {
|
||||
notifications,
|
||||
unreadCount,
|
||||
isConnected,
|
||||
connect,
|
||||
disconnect,
|
||||
markAsRead,
|
||||
markAllAsRead,
|
||||
clearAll
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user