)}
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.'}