/** * Approval Requests Composable * Fetch and manage approval requests */ import { ref, computed } from 'vue' import type { ApprovalRequest, ApprovalFilter } from '../types' export function useApprovalRequests() { const requests = ref([]) const selectedRequestId = ref(null) const isLoading = ref(false) const error = ref(null) const filter = ref({}) const mockRequests: ApprovalRequest[] = [ { requestId: 'APR-2026-001', modelId: '00000000-0000-0000-0000-000000000001', modelName: 'Hawkeye-Alpha v2.1', action: 'activate', metadata: { pbo: 15.2, dsr: 96.5, oos: 1.8, }, status: 'pending', requesterName: 'kjh2064', requestedAt: '2026-08-14T10:30:00Z', }, { requestId: 'APR-2026-002', modelId: '00000000-0000-0000-0000-000000000002', modelName: 'Falcon-Beta v1.8', action: 'transition-phase', metadata: { currentPhase: 'Review', targetPhase: 'Manual Activation', pbo: 18.3, dsr: 94.2, oos: 2.1, }, status: 'approved', requesterName: 'kjh2064', requestedAt: '2026-08-12T14:22:00Z', reviewerName: 'admin', reviewedAt: '2026-08-13T09:15:00Z', reviewComment: 'Metrics acceptable for transition. Approved.', }, { requestId: 'APR-2026-003', modelId: '00000000-0000-0000-0000-000000000003', modelName: 'Eagle-Gamma v3.0', action: 'transition-phase', metadata: { currentPhase: 'Validate', targetPhase: 'Review', pbo: 20.5, dsr: 92.1, oos: 2.8, }, status: 'rejected', requesterName: 'kjh2064', requestedAt: '2026-08-10T11:45:00Z', reviewerName: 'admin', reviewedAt: '2026-08-11T16:20:00Z', reviewComment: 'PBO exceeds 20% threshold. Needs further optimization.', }, ] const selectedRequest = computed(() => { return requests.value.find(r => r.requestId === selectedRequestId.value) || null }) const filteredRequests = computed(() => { let result = requests.value if (filter.value.status) { result = result.filter(r => r.status === filter.value.status) } if (filter.value.action) { result = result.filter(r => r.action === filter.value.action) } return result.sort( (a, b) => new Date(b.requestedAt).getTime() - new Date(a.requestedAt).getTime() ) }) const statusStats = computed(() => ({ pending: requests.value.filter(r => r.status === 'pending').length, approved: requests.value.filter(r => r.status === 'approved').length, rejected: requests.value.filter(r => r.status === 'rejected').length, total: requests.value.length, })) async function fetchRequests() { isLoading.value = true error.value = null try { await new Promise(resolve => setTimeout(resolve, 600)) requests.value = mockRequests } catch (err) { error.value = err instanceof Error ? err.message : 'Failed to fetch requests' } finally { isLoading.value = false } } function selectRequest(requestId: string) { selectedRequestId.value = requestId } function clearSelection() { selectedRequestId.value = null } function setFilter(newFilter: ApprovalFilter) { filter.value = newFilter } async function approveRequest(requestId: string, comment: string) { const req = requests.value.find(r => r.requestId === requestId) if (req) { req.status = 'approved' req.reviewerName = 'current-user' req.reviewedAt = new Date().toISOString() req.reviewComment = comment } } async function rejectRequest(requestId: string, comment: string) { const req = requests.value.find(r => r.requestId === requestId) if (req) { req.status = 'rejected' req.reviewerName = 'current-user' req.reviewedAt = new Date().toISOString() req.reviewComment = comment } } return { requests, filteredRequests, selectedRequest, selectedRequestId, isLoading, error, statusStats, fetchRequests, selectRequest, clearSelection, setFilter, approveRequest, rejectRequest, } }