'use client'; import Link from 'next/link'; import { useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { toast } from 'sonner'; import { Icons } from '@/components/icons'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { Textarea } from '@/components/ui/textarea'; import { approveApprovalMutation, cancelApprovalMutation, rejectApprovalMutation, returnApprovalMutation } from '../mutations'; import type { ApprovalDetailRecord } from '../types'; import { ApprovalStatusBadge } from './approval-status-badge'; function FieldItem({ label, value }: { label: string; value: string | null | undefined }) { return (
{label}
{value || '-'}
); } export function ApprovalRequestPanel({ approval, canApprove, canReject, canReturn, canCancel, activeBusinessRole, isOrgAdmin, currentUserId, entityHref }: { approval: ApprovalDetailRecord; canApprove: boolean; canReject: boolean; canReturn: boolean; canCancel: boolean; activeBusinessRole: string | null; isOrgAdmin: boolean; currentUserId: string; entityHref?: string; }) { const [remark, setRemark] = useState(''); const isPending = approval.request.status === 'pending'; const canHandleCurrentStep = !!approval.currentStep && (isOrgAdmin || activeBusinessRole === approval.currentStep.roleCode); const canCancelCurrentRequest = canCancel && isPending && (isOrgAdmin || approval.request.requestedBy === currentUserId); const approveAction = useMutation({ ...approveApprovalMutation, onSuccess: () => { toast.success('Approval step completed'); setRemark(''); }, onError: (error) => toast.error(error instanceof Error ? error.message : 'Unable to approve request') }); const rejectAction = useMutation({ ...rejectApprovalMutation, onSuccess: () => { toast.success('Approval request rejected'); setRemark(''); }, onError: (error) => toast.error(error instanceof Error ? error.message : 'Unable to reject request') }); const returnAction = useMutation({ ...returnApprovalMutation, onSuccess: () => { toast.success('Approval request returned to draft'); setRemark(''); }, onError: (error) => toast.error(error instanceof Error ? error.message : 'Unable to return request') }); const cancelAction = useMutation({ ...cancelApprovalMutation, onSuccess: () => toast.success('Approval request cancelled'), onError: (error) => toast.error(error instanceof Error ? error.message : 'Unable to cancel request') }); const isActing = approveAction.isPending || rejectAction.isPending || returnAction.isPending || cancelAction.isPending; return (
Request Information Current workflow state for this approval request.
Status
{entityHref ? (
) : null}
Workflow Sequential approver chain configured for this document. {approval.steps.map((step) => { const isCurrent = approval.currentStep?.id === step.id && isPending; const isCompleted = approval.request.currentStep > step.stepNumber || approval.request.status === 'approved'; return (
Step {step.stepNumber} - {step.roleName}
{step.roleCode}
{isCurrent ? 'Current' : isCompleted ? 'Completed' : 'Pending'}
); })}
Actions Approvers can approve, reject, or return on their assigned step.