From fc46f322820314f4a81d891fdb1296ff624009d3 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Mon, 12 Jan 2026 15:05:49 +0530 Subject: [PATCH] oonclusin remark fallback added --- src/custom/pages/RequestDetail.tsx | 6 ++ .../components/request-detail/OverviewTab.tsx | 35 +++++--- src/dealer-claim/pages/RequestDetail.tsx | 6 ++ src/hooks/useConclusionRemark.ts | 85 ++++++++++++++++++- .../components/tabs/OverviewTab.tsx | 36 +++++--- 5 files changed, 143 insertions(+), 25 deletions(-) diff --git a/src/custom/pages/RequestDetail.tsx b/src/custom/pages/RequestDetail.tsx index 3a04eab..04b6284 100644 --- a/src/custom/pages/RequestDetail.tsx +++ b/src/custom/pages/RequestDetail.tsx @@ -197,6 +197,9 @@ function CustomRequestDetailInner({ requestId: propRequestId, onBack, dynamicReq aiGenerated, handleGenerateConclusion, handleFinalizeConclusion, + generationAttempts, + generationFailed, + maxAttemptsReached, } = useConclusionRemark(request, requestIdentifier, isInitiator, refreshDetails, onBack, setActionStatus, setShowActionStatusModal); // Load system policy on mount @@ -510,6 +513,9 @@ function CustomRequestDetailInner({ requestId: propRequestId, onBack, dynamicReq currentUserIsApprover={!!currentApprovalLevel} pausedByUserId={request?.pauseInfo?.pausedBy?.userId} currentUserId={(user as any)?.userId} + generationAttempts={generationAttempts} + generationFailed={generationFailed} + maxAttemptsReached={maxAttemptsReached} /> diff --git a/src/dealer-claim/components/request-detail/OverviewTab.tsx b/src/dealer-claim/components/request-detail/OverviewTab.tsx index 956d1b2..b3f3412 100644 --- a/src/dealer-claim/components/request-detail/OverviewTab.tsx +++ b/src/dealer-claim/components/request-detail/OverviewTab.tsx @@ -41,6 +41,9 @@ interface ClaimManagementOverviewTabProps { aiGenerated?: boolean; handleGenerateConclusion?: () => void; handleFinalizeConclusion?: () => void; + generationAttempts?: number; + generationFailed?: boolean; + maxAttemptsReached?: boolean; } export function ClaimManagementOverviewTab({ @@ -58,6 +61,9 @@ export function ClaimManagementOverviewTab({ aiGenerated = false, handleGenerateConclusion, handleFinalizeConclusion, + generationAttempts = 0, + generationFailed = false, + maxAttemptsReached = false, }: ClaimManagementOverviewTabProps) { // Check if this is a claim management request if (!isClaimManagementRequest(apiRequest)) { @@ -182,17 +188,24 @@ export function ClaimManagementOverviewTab({ {handleGenerateConclusion && ( - +
+ + {aiGenerated && !maxAttemptsReached && !generationFailed && ( + + {2 - generationAttempts} attempts remaining + + )} +
)} diff --git a/src/dealer-claim/pages/RequestDetail.tsx b/src/dealer-claim/pages/RequestDetail.tsx index f5917f4..57f38e0 100644 --- a/src/dealer-claim/pages/RequestDetail.tsx +++ b/src/dealer-claim/pages/RequestDetail.tsx @@ -230,6 +230,9 @@ function DealerClaimRequestDetailInner({ requestId: propRequestId, onBack, dynam aiGenerated, handleGenerateConclusion, handleFinalizeConclusion, + generationAttempts, + generationFailed, + maxAttemptsReached, } = useConclusionRemark( request, requestIdentifier, @@ -587,6 +590,9 @@ function DealerClaimRequestDetailInner({ requestId: propRequestId, onBack, dynam aiGenerated={aiGenerated} handleGenerateConclusion={handleGenerateConclusion} handleFinalizeConclusion={handleFinalizeConclusion} + generationAttempts={generationAttempts} + generationFailed={generationFailed} + maxAttemptsReached={maxAttemptsReached} /> diff --git a/src/hooks/useConclusionRemark.ts b/src/hooks/useConclusionRemark.ts index 0489ff3..a58bcc2 100644 --- a/src/hooks/useConclusionRemark.ts +++ b/src/hooks/useConclusionRemark.ts @@ -42,6 +42,18 @@ export function useConclusionRemark( // State: Tracks if current conclusion was AI-generated (shows badge in UI) const [aiGenerated, setAiGenerated] = useState(false); + // State: Tracks number of AI generation attempts + const [generationAttempts, setGenerationAttempts] = useState(0); + + // State: Tracks if AI generation failed (unable to generate) + const [generationFailed, setGenerationFailed] = useState(false); + + // State: Tracks if max attempts (3 for success, 1 for fail) reached + const [maxAttemptsReached, setMaxAttemptsReached] = useState(false); + + // State: Tracks number of AI generation failures + const [failureAttempts, setFailureAttempts] = useState(0); + /** * Function: fetchExistingConclusion * @@ -113,8 +125,12 @@ export function useConclusionRemark( * 5. Handle errors silently (user can type manually) */ const handleGenerateConclusion = async () => { + // Safety check: Prevent generation if max attempts already reached + if (maxAttemptsReached) return; + try { setConclusionLoading(true); + setGenerationFailed(false); // Lazy load: Import conclusion API const { generateConclusion } = await import('@/services/conclusionApi'); @@ -122,14 +138,74 @@ export function useConclusionRemark( // API Call: Generate AI conclusion based on request data const result = await generateConclusion(request.requestId || requestIdentifier); + const newAttempts = generationAttempts + 1; + setGenerationAttempts(newAttempts); + + // Check for "unable to generate" or similar keywords in proper response + const isUnableToGenerate = !result?.aiGeneratedRemark || + result.aiGeneratedRemark.toLowerCase().includes('unable to generate') || + result.aiGeneratedRemark.toLowerCase().includes('sorry'); + + if (isUnableToGenerate) { + const newFailures = failureAttempts + 1; + setFailureAttempts(newFailures); + + if (newFailures >= 2) { + setMaxAttemptsReached(true); + setActionStatus?.({ + success: false, + title: 'AI Generation Limit Reached', + message: "We're unable to process a conclusion remark at this time after 2 attempts. Please proceed with a manual approach using the editor below." + }); + } else { + setActionStatus?.({ + success: false, + title: 'System Note', + message: "We're unable to process a conclusion remark at the moment. You have one more attempt remaining, or you can proceed manually." + }); + } + setShowActionStatusModal?.(true); + setConclusionRemark(result?.aiGeneratedRemark || ''); + setAiGenerated(false); + return; + } + // Success: Load AI-generated remark setConclusionRemark(result.aiGeneratedRemark); setAiGenerated(true); + setFailureAttempts(0); // Reset failures on success + + // Limit to 2 successful attempts + if (newAttempts >= 2) { + setMaxAttemptsReached(true); + setActionStatus?.({ + success: true, + title: 'Maximum Attempts Reached', + message: "You've reached the maximum of 2 regeneration attempts. Feel free to manually edit the current suggestion to fit your specific needs." + }); + setShowActionStatusModal?.(true); + } } catch (err) { - // Fail silently: User can write conclusion manually console.error('[useConclusionRemark] AI generation failed:', err); - setConclusionRemark(''); + const newFailures = failureAttempts + 1; + setFailureAttempts(newFailures); setAiGenerated(false); + + if (newFailures >= 2) { + setMaxAttemptsReached(true); + setActionStatus?.({ + success: false, + title: 'System Note', + message: "We're unable to process your request at the moment. Since the maximum of 2 attempts is reached, please proceed with a manual approach." + }); + } else { + setActionStatus?.({ + success: false, + title: 'System Note', + message: "We're unable to process your request at the moment. You have one more attempt remaining, or you can proceed manually." + }); + } + setShowActionStatusModal?.(true); } finally { setConclusionLoading(false); } @@ -276,7 +352,10 @@ export function useConclusionRemark( conclusionSubmitting, aiGenerated, handleGenerateConclusion, - handleFinalizeConclusion + handleFinalizeConclusion, + generationAttempts, + generationFailed, + maxAttemptsReached }; } diff --git a/src/pages/RequestDetail/components/tabs/OverviewTab.tsx b/src/pages/RequestDetail/components/tabs/OverviewTab.tsx index aa94b26..a1b95b7 100644 --- a/src/pages/RequestDetail/components/tabs/OverviewTab.tsx +++ b/src/pages/RequestDetail/components/tabs/OverviewTab.tsx @@ -32,6 +32,9 @@ interface OverviewTabProps { currentUserIsApprover?: boolean; pausedByUserId?: string; currentUserId?: string; + generationAttempts?: number; + generationFailed?: boolean; + maxAttemptsReached?: boolean; } export function OverviewTab({ @@ -51,6 +54,9 @@ export function OverviewTab({ currentUserIsApprover = false, pausedByUserId: _pausedByUserId, currentUserId: _currentUserId, + generationAttempts = 0, + generationFailed = false, + maxAttemptsReached = false, }: OverviewTabProps) { void _onPause; // Marked as intentionally unused - available for future use const { user } = useAuth(); @@ -64,6 +70,7 @@ export function OverviewTab({ // Retrigger: Only for initiator when approver paused (initiator asks approver to resume) const canRetrigger = isPaused && isInitiator && pausedByUserId && pausedByUserId !== currentUserId && onRetrigger; + return (
{/* Request Initiator Card */} @@ -345,17 +352,24 @@ export function OverviewTab({ : 'All approvals are complete. Please review and finalize the conclusion to close this request.'}
- +
+ + {aiGenerated && !maxAttemptsReached && !generationFailed && ( + + {2 - generationAttempts} attempts remaining + + )} +