wfm file push indicator re-added in workflow step

This commit is contained in:
laxmanhalaki 2026-03-11 12:31:04 +05:30
parent a4662c99f3
commit 8940a8981e
6 changed files with 84 additions and 35 deletions

View File

@ -658,6 +658,7 @@ function CustomRequestDetailInner({ requestId: propRequestId, onBack, dynamicReq
pausedByUserId={request?.pauseInfo?.pausedBy?.userId} pausedByUserId={request?.pauseInfo?.pausedBy?.userId}
currentUserId={(user as any)?.userId} currentUserId={(user as any)?.userId}
apiRequest={apiRequest} apiRequest={apiRequest}
hideApproveReject={isDealer}
/> />
</div> </div>
)} )}

View File

@ -10,7 +10,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress'; import { Progress } from '@/components/ui/progress';
import { TrendingUp, Clock, CheckCircle, CircleCheckBig, Upload, Mail, Download, Receipt, Activity, AlertTriangle, AlertOctagon, XCircle, History, ChevronDown, ChevronUp, RefreshCw, RotateCw, Eye, FileSpreadsheet, X, Loader2 } from 'lucide-react'; import { TrendingUp, Clock, CheckCircle, CheckCircle2, CircleCheckBig, Upload, Mail, Download, Receipt, Activity, AlertTriangle, AlertOctagon, XCircle, History, ChevronDown, ChevronUp, RefreshCw, RotateCw, Eye, FileSpreadsheet, X, Loader2 } from 'lucide-react';
import { formatDateTime, formatDateDDMMYYYY } from '@/utils/dateFormatter'; import { formatDateTime, formatDateDDMMYYYY } from '@/utils/dateFormatter';
import { formatHoursMinutes } from '@/utils/slaTracker'; import { formatHoursMinutes } from '@/utils/slaTracker';
import { import {
@ -26,7 +26,7 @@ import {
// InitiatorActionModal - Removed, using direct buttons instead // InitiatorActionModal - Removed, using direct buttons instead
} from './modals'; } from './modals';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { submitProposal, updateIODetails, submitCompletion, updateEInvoice, sendCreditNoteToDealer } from '@/services/dealerClaimApi'; import { submitProposal, updateIODetails, submitCompletion, updateEInvoice, sendCreditNoteToDealer, retriggerWFMPush } from '@/services/dealerClaimApi';
import { getWorkflowDetails, approveLevel, rejectLevel, handleInitiatorAction, getWorkflowHistory } from '@/services/workflowApi'; import { getWorkflowDetails, approveLevel, rejectLevel, handleInitiatorAction, getWorkflowHistory } from '@/services/workflowApi';
import { uploadDocument } from '@/services/documentApi'; import { uploadDocument } from '@/services/documentApi';
import { TokenManager } from '@/utils/tokenManager'; import { TokenManager } from '@/utils/tokenManager';
@ -1510,6 +1510,25 @@ export function DealerClaimWorkflowTab({
loadCompletionDocuments(); loadCompletionDocuments();
}, [request]); }, [request]);
const handleRetrigger = async () => {
try {
toast.loading('Retriggering WFM push...', { id: 'wfm-retrigger' });
await retriggerWFMPush(request.id);
toast.success('WFM push re-triggered successfully', { id: 'wfm-retrigger' });
// Refresh the request data if onRefresh is provided
if (onRefresh) {
onRefresh();
} else {
// Fallback or full page refresh
window.location.reload();
}
} catch (error: any) {
console.error('Error retriggering WFM push:', error);
toast.error(error.message || 'Failed to re-trigger WFM push', { id: 'wfm-retrigger' });
}
};
const handleDownloadCSV = async () => { const handleDownloadCSV = async () => {
try { try {
const requestId = request.id || request.requestId; const requestId = request.id || request.requestId;
@ -1764,23 +1783,63 @@ export function DealerClaimWorkflowTab({
</Button> </Button>
); );
})()} })()}
{/* CSV Export Button (Requestor Claim Approval) */} {/* CSV Export & WFM Push Status (Requestor Claim Approval) */}
{(() => { {(() => {
const isRequestorClaimStep = (step.levelName || step.title || '').toLowerCase().includes('requestor claim') || const isRequestorClaimStep = (step.levelName || step.title || '').toLowerCase().includes('requestor claim') ||
(step.levelName || step.title || '').toLowerCase().includes('requestor - claim'); (step.levelName || step.title || '').toLowerCase().includes('requestor - claim');
const hasInvoice = request?.invoice || (request?.irn && step.status === 'approved'); const hasInvoice = request?.invoice || (request?.irn && step.status === 'approved');
return isRequestorClaimStep && hasInvoice && ( const wfmStatus = request?.invoice?.wfmPushStatus || (request?.invoice as any)?.wfmPushStatus;
<Button const wfmError = request?.invoice?.wfmPushError || (request?.invoice as any)?.wfmPushError;
variant="ghost"
size="sm" return isRequestorClaimStep && hasInvoice && (
className="h-6 w-6 p-0 hover:bg-emerald-100 ml-1" <div className="flex items-center gap-1 ml-1">
title="Export CSV" <Button
onClick={handleDownloadCSV} variant="ghost"
> size="sm"
<FileSpreadsheet className="w-3.5 h-3.5 text-emerald-600" /> className="h-6 w-6 p-0 hover:bg-emerald-100"
</Button> title="Export CSV"
); onClick={handleDownloadCSV}
})()} >
<FileSpreadsheet className="w-3.5 h-3.5 text-emerald-600" />
</Button>
{/* WFM Push Status Indication */}
{wfmStatus === 'SUCCESS' ? (
<div title="Pushed to WFM successfully">
<CheckCircle2 className="w-3.5 h-3.5 text-green-500" />
</div>
) : wfmStatus === 'FAILED' ? (
<div className="flex items-center gap-1">
<div title={`WFM Push Failed: ${wfmError || 'Unknown error'}`}>
<XCircle className="w-3.5 h-3.5 text-red-500" />
</div>
<Button
variant="ghost"
size="sm"
className="h-5 px-1.5 text-[10px] text-red-600 hover:text-red-700 hover:bg-red-50 border border-red-200 h-auto py-0"
onClick={handleRetrigger}
>
Retry Push
</Button>
</div>
) : (
<div className="flex items-center gap-1">
<div title="WFM Push Pending">
<Clock className="w-3.5 h-3.5 text-amber-500" />
</div>
<Button
variant="ghost"
size="sm"
className="h-5 px-1.5 text-[10px] text-amber-600 hover:text-amber-700 hover:bg-amber-50 border border-amber-200 h-auto py-0"
onClick={handleRetrigger}
>
Push Now
</Button>
</div>
)}
</div>
);
})()}
</div> </div>
<p className="text-sm text-gray-600">{step.approver}</p> <p className="text-sm text-gray-600">{step.approver}</p>
<p className="text-sm text-gray-500 mt-2 italic">{step.description}</p> <p className="text-sm text-gray-500 mt-2 italic">{step.description}</p>

View File

@ -230,13 +230,6 @@ export function DealerDashboard({ onNavigate, onNewRequest: _onNewRequest }: Das
</div> </div>
</div> </div>
<div className="flex flex-wrap gap-4 mt-8"> <div className="flex flex-wrap gap-4 mt-8">
<Button
onClick={() => onNavigate?.('/new-request')}
className="bg-blue-600 hover:bg-blue-700 text-white border-0 shadow-lg hover:shadow-xl transition-all duration-200"
>
<FileText className="w-5 h-5 mr-2" />
Create New Claim
</Button>
<Button <Button
onClick={() => { onClick={() => {
setRefreshing(true); setRefreshing(true);
@ -266,13 +259,6 @@ export function DealerDashboard({ onNavigate, onNewRequest: _onNewRequest }: Das
You don't have any claims data yet. Once you create and submit claim requests, your analytics will appear here. You don't have any claims data yet. Once you create and submit claim requests, your analytics will appear here.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4"> <div className="flex flex-col sm:flex-row gap-4">
<Button
onClick={() => onNavigate?.('/new-request')}
className="bg-blue-600 hover:bg-blue-700 text-white"
>
<FileText className="w-5 h-5 mr-2" />
Create Your First Claim
</Button>
<Button <Button
onClick={() => { onClick={() => {
setRefreshing(true); setRefreshing(true);

View File

@ -690,6 +690,7 @@ function DealerClaimRequestDetailInner({ requestId: propRequestId, onBack, dynam
pausedByUserId={request?.pauseInfo?.pausedBy?.userId} pausedByUserId={request?.pauseInfo?.pausedBy?.userId}
currentUserId={currentUserId} currentUserId={currentUserId}
apiRequest={apiRequest} apiRequest={apiRequest}
hideApproveReject={isDealer}
/> />
)} )}
</div> </div>

View File

@ -331,7 +331,7 @@ export function useRequestDetails(
internalOrders: internalOrders || [], internalOrders: internalOrders || [],
// New normalized tables (also available via claimDetails for backward compatibility) // New normalized tables (also available via claimDetails for backward compatibility)
budgetTracking: (claimDetails as any)?.budgetTracking || null, budgetTracking: (claimDetails as any)?.budgetTracking || null,
invoice: (claimDetails as any)?.invoice || null, invoice: claimDetails?.invoice || (claimDetails as any)?.invoice || null,
creditNote: (claimDetails as any)?.creditNote || null, creditNote: (claimDetails as any)?.creditNote || null,
completionExpenses: (claimDetails as any)?.completionExpenses || null, completionExpenses: (claimDetails as any)?.completionExpenses || null,
templateType: wf.templateType || wf.template_type, templateType: wf.templateType || wf.template_type,

View File

@ -32,6 +32,7 @@ interface QuickActionsSidebarProps {
currentUserId?: string; // Current user's ID (kept for backwards compatibility) currentUserId?: string; // Current user's ID (kept for backwards compatibility)
apiRequest?: any; apiRequest?: any;
onEditClaimAmount?: () => void; onEditClaimAmount?: () => void;
hideApproveReject?: boolean;
} }
export function QuickActionsSidebar({ export function QuickActionsSidebar({
@ -52,6 +53,7 @@ export function QuickActionsSidebar({
currentUserId: currentUserIdProp, currentUserId: currentUserIdProp,
apiRequest, apiRequest,
onEditClaimAmount, onEditClaimAmount,
hideApproveReject = false,
}: QuickActionsSidebarProps) { }: QuickActionsSidebarProps) {
const { user } = useAuth(); const { user } = useAuth();
const [sharedRecipients, setSharedRecipients] = useState<SharedRecipient[]>([]); const [sharedRecipients, setSharedRecipients] = useState<SharedRecipient[]>([]);
@ -210,7 +212,7 @@ export function QuickActionsSidebar({
{/* Approve/Reject Buttons */} {/* Approve/Reject Buttons */}
<div className="pt-3 sm:pt-4 space-y-2"> <div className="pt-3 sm:pt-4 space-y-2">
{currentApprovalLevel && !isPaused && ( {currentApprovalLevel && !isPaused && !hideApproveReject && (
<> <>
<Button <Button
className="w-full bg-green-600 hover:bg-green-700 text-white h-9 sm:h-10 text-xs sm:text-sm" className="w-full bg-green-600 hover:bg-green-700 text-white h-9 sm:h-10 text-xs sm:text-sm"