From 8c2aa60195ed615a6d4fea3cd3abf9757b7ff462 Mon Sep 17 00:00:00 2001
From: laxmanhalaki
Date: Sat, 29 Nov 2025 16:17:14 +0530
Subject: [PATCH] resume pause and sla progress bar in detail screen modified
---
.../sla/SLAProgressBar/SLAProgressBar.tsx | 68 +++++++++---
.../CreateRequest/ApprovalWorkflowStep.tsx | 105 +++++++++++++++++-
src/pages/OpenRequests/OpenRequests.tsx | 92 +++++++++------
3 files changed, 214 insertions(+), 51 deletions(-)
diff --git a/src/components/sla/SLAProgressBar/SLAProgressBar.tsx b/src/components/sla/SLAProgressBar/SLAProgressBar.tsx
index 0af90a5..e4c2930 100644
--- a/src/components/sla/SLAProgressBar/SLAProgressBar.tsx
+++ b/src/components/sla/SLAProgressBar/SLAProgressBar.tsx
@@ -5,7 +5,7 @@ import { formatHoursMinutes } from '@/utils/slaTracker';
import { formatDateDDMMYYYY } from '@/utils/dateFormatter';
export interface SLAData {
- status: 'normal' | 'approaching' | 'critical' | 'breached';
+ status: 'on_track' | 'normal' | 'approaching' | 'critical' | 'breached';
percentageUsed: number;
elapsedText: string;
elapsedHours: number;
@@ -42,6 +42,47 @@ export function SLAProgressBar({
);
}
+ // Use percentage-based colors to match approver SLA tracker
+ // Green: 0-50%, Amber: 50-75%, Orange: 75-100%, Red: 100%+ (breached)
+ const percentageUsed = sla.percentageUsed || 0;
+ const rawStatus = sla.status || 'on_track';
+
+ // Determine colors based on percentage (matching ApprovalStepCard logic)
+ const getStatusColors = () => {
+ if (percentageUsed >= 100) {
+ return {
+ badge: 'bg-red-600 text-white animate-pulse',
+ progress: 'bg-red-600',
+ text: 'text-red-600'
+ };
+ } else if (percentageUsed >= 75) {
+ return {
+ badge: 'bg-orange-500 text-white',
+ progress: 'bg-orange-500',
+ text: 'text-orange-600'
+ };
+ } else if (percentageUsed >= 50) {
+ return {
+ badge: 'bg-amber-500 text-white',
+ progress: 'bg-amber-500',
+ text: 'text-amber-600'
+ };
+ } else {
+ return {
+ badge: 'bg-green-600 text-white',
+ progress: 'bg-green-600',
+ text: 'text-gray-700'
+ };
+ }
+ };
+
+ const colors = getStatusColors();
+
+ // Normalize status for warning messages (still use status for text warnings)
+ const normalizedStatus = (rawStatus === 'on_track' || rawStatus === 'normal')
+ ? 'normal'
+ : rawStatus;
+
return (
@@ -50,12 +91,7 @@ export function SLAProgressBar({
SLA Progress
{sla.percentageUsed || 0}% elapsed
@@ -64,12 +100,8 @@ export function SLAProgressBar({
@@ -95,13 +127,13 @@ export function SLAProgressBar({
)}
- {sla.status === 'critical' && (
+ {normalizedStatus === 'critical' && (
Approaching Deadline
)}
- {sla.status === 'breached' && (
+ {normalizedStatus === 'breached' && (
URGENT - Deadline Passed
diff --git a/src/components/workflow/CreateRequest/ApprovalWorkflowStep.tsx b/src/components/workflow/CreateRequest/ApprovalWorkflowStep.tsx
index 8247d32..172ed03 100644
--- a/src/components/workflow/CreateRequest/ApprovalWorkflowStep.tsx
+++ b/src/components/workflow/CreateRequest/ApprovalWorkflowStep.tsx
@@ -6,7 +6,7 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
-import { Users, Settings, Shield, User, CheckCircle, Minus, Plus } from 'lucide-react';
+import { Users, Settings, Shield, User, CheckCircle, Minus, Plus, Info, Clock } from 'lucide-react';
import { FormData } from '@/hooks/useCreateRequestForm';
import { useMultiUserSearch } from '@/hooks/useUserSearch';
import { ensureUserExists } from '@/services/userApi';
@@ -409,6 +409,109 @@ export function ApprovalWorkflowStep({
})}
+
+ {/* TAT Summary Section */}
+
+ {/* Approval Flow Summary */}
+
+
+
+
+
Approval Flow Summary
+
+ Your request will follow this sequence: You (Initiator) → {Array.from({ length: formData.approverCount || 1 }, (_, i) => `Level ${i + 1} Approver`).join(' → ')}. The final approver can close the request.
+
+
+
+
+
+ {/* TAT Summary */}
+
+
+
+
+
+
TAT Summary
+
+ {(() => {
+ // Calculate total calendar days (for display)
+ // Days: count as calendar days
+ // Hours: convert to calendar days (hours / 24)
+ const totalCalendarDays = formData.approvers?.reduce((sum: number, a: any) => {
+ const tat = Number(a.tat || 0);
+ const tatType = a.tatType || 'hours';
+ if (tatType === 'days') {
+ return sum + tat; // Calendar days
+ } else {
+ return sum + (tat / 24); // Convert hours to calendar days
+ }
+ }, 0) || 0;
+ const displayDays = Math.ceil(totalCalendarDays);
+ return (
+ <>
+
{displayDays} {displayDays === 1 ? 'Day' : 'Days'}
+
Total Duration
+ >
+ );
+ })()}
+
+
+
+
+ {formData.approvers?.map((approver: any, idx: number) => {
+ const tat = Number(approver.tat || 0);
+ const tatType = approver.tatType || 'hours';
+ // Convert days to hours: 1 day = 24 hours
+ const hours = tatType === 'days' ? tat * 24 : tat;
+ if (!tat) return null;
+ return (
+
+
+ Level {idx + 1}
+ {hours} {hours === 1 ? 'hour' : 'hours'}
+
+
+ );
+ })}
+
+ {(() => {
+ // Convert all TAT to hours first
+ // Days: 1 day = 24 hours
+ // Hours: already in hours
+ const totalHours = formData.approvers?.reduce((sum: number, a: any) => {
+ const tat = Number(a.tat || 0);
+ const tatType = a.tatType || 'hours';
+ if (tatType === 'days') {
+ // 1 day = 24 hours
+ return sum + (tat * 24);
+ } else {
+ return sum + tat;
+ }
+ }, 0) || 0;
+ // Convert total hours to working days (8 hours per working day)
+ const workingDays = Math.ceil(totalHours / 8);
+ if (totalHours === 0) return null;
+ return (
+
+
+
+
{totalHours}{totalHours === 1 ? 'h' : 'h'}
+
Total Hours
+
+
+
{workingDays}
+
Working Days*
+
+
+
*Based on 8-hour working days
+
+ );
+ })()}
+
+
+
+
+
);
diff --git a/src/pages/OpenRequests/OpenRequests.tsx b/src/pages/OpenRequests/OpenRequests.tsx
index ccdb86f..ce577ac 100644
--- a/src/pages/OpenRequests/OpenRequests.tsx
+++ b/src/pages/OpenRequests/OpenRequests.tsx
@@ -480,40 +480,68 @@ export function OpenRequests({ onViewRequest }: OpenRequestsProps) {
{/* SLA Display - Compact Version */}
- {request.currentLevelSLA && (
-
-
-
-
- TAT: {request.currentLevelSLA.percentageUsed}%
-
-
-
{request.currentLevelSLA.elapsedText}
-
- {request.currentLevelSLA.remainingText} left
-
+ {request.currentLevelSLA && (() => {
+ // Use percentage-based colors to match approver SLA tracker
+ // Green: 0-50%, Amber: 50-75%, Orange: 75-100%, Red: 100%+ (breached)
+ const percentUsed = request.currentLevelSLA.percentageUsed || 0;
+
+ const getSLAColors = () => {
+ if (percentUsed >= 100) {
+ return {
+ bg: 'bg-red-50 border border-red-200',
+ progress: 'bg-red-600',
+ text: 'text-red-600'
+ };
+ } else if (percentUsed >= 75) {
+ return {
+ bg: 'bg-orange-50 border border-orange-200',
+ progress: 'bg-orange-500',
+ text: 'text-orange-600'
+ };
+ } else if (percentUsed >= 50) {
+ return {
+ bg: 'bg-amber-50 border border-amber-200',
+ progress: 'bg-amber-500',
+ text: 'text-amber-600'
+ };
+ } else {
+ return {
+ bg: 'bg-green-50 border border-green-200',
+ progress: 'bg-green-600',
+ text: 'text-gray-700'
+ };
+ }
+ };
+
+ const colors = getSLAColors();
+
+ return (
+
+
+
+
+ TAT: {percentUsed}%
+
+
+ {request.currentLevelSLA.elapsedText}
+ = 100 ? 'text-red-600' :
+ percentUsed >= 75 ? 'text-orange-600' :
+ percentUsed >= 50 ? 'text-amber-600' :
+ 'text-gray-700'
+ }`}>
+ {request.currentLevelSLA.remainingText} left
+
+
+
-
- )}
+ );
+ })()}
{/* Metadata Row */}