+ {/* Completed Approver - Show Completion Details */}
+ {isCompleted && actualHours !== undefined && (
+
+ )}
+
+ {/* Active Approver - Show Real-time Progress from Backend */}
+ {isActive && approval?.sla && (
+
+ )}
+
+ {/* Waiting Approver - Show Assignment Info */}
+ {isWaiting && (
+
+ )}
+
+ {/* Rejected Status */}
+ {isRejected && step.comment && (
+
)}
@@ -1601,14 +1711,6 @@ function RequestDetailInner({
{workNoteAttachments && workNoteAttachments.length > 0 ? (
{workNoteAttachments.map((file: any, index: number) => {
- const fileType = (file.type || '').toLowerCase();
- const displayType = fileType.includes('pdf') ? 'PDF' :
- fileType.includes('excel') || fileType.includes('spreadsheet') ? 'Excel' :
- fileType.includes('word') || fileType.includes('document') ? 'Word' :
- fileType.includes('powerpoint') || fileType.includes('presentation') ? 'PowerPoint' :
- fileType.includes('image') || fileType.includes('jpg') || fileType.includes('png') ? 'Image' :
- 'File';
-
return (
{
- const { getWorkNoteAttachmentPreviewUrl } = require('@/services/workflowApi');
setPreviewDocument({
fileName: file.name,
fileType: file.type,
diff --git a/src/services/userApi.ts b/src/services/userApi.ts
index c44fb71..7439e28 100644
--- a/src/services/userApi.ts
+++ b/src/services/userApi.ts
@@ -17,6 +17,23 @@ export async function searchUsers(query: string, limit: number = 10): Promise {
+ const res = await apiClient.post('/users/ensure', userData);
+ return (res.data?.data || res.data) as UserSummary;
+}
+
+export default { searchUsers, ensureUserExists };
diff --git a/src/utils/slaTracker.ts b/src/utils/slaTracker.ts
index c42cfcb..bfd665a 100644
--- a/src/utils/slaTracker.ts
+++ b/src/utils/slaTracker.ts
@@ -35,17 +35,22 @@ ensureConfigLoaded().catch(() => {});
/**
* Check if current time is within working hours
+ * @param date - Date to check
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function isWorkingTime(date: Date = new Date()): boolean {
+export function isWorkingTime(date: Date = new Date(), priority: string = 'standard'): boolean {
const day = date.getDay(); // 0 = Sunday, 6 = Saturday
const hour = date.getHours();
- // Weekend check
- if (day < WORK_START_DAY || day > WORK_END_DAY) {
- return false;
+ // For standard priority: exclude weekends
+ // For express priority: include weekends (calendar days)
+ if (priority === 'standard') {
+ if (day < WORK_START_DAY || day > WORK_END_DAY) {
+ return false;
+ }
}
- // Working hours check
+ // Working hours check (applies to both priorities)
if (hour < WORK_START_HOUR || hour >= WORK_END_HOUR) {
return false;
}
@@ -57,26 +62,30 @@ export function isWorkingTime(date: Date = new Date()): boolean {
/**
* Get next working time from a given date
+ * @param date - Current date
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function getNextWorkingTime(date: Date = new Date()): Date {
+export function getNextWorkingTime(date: Date = new Date(), priority: string = 'standard'): Date {
const result = new Date(date);
// If already in working time, return as is
- if (isWorkingTime(result)) {
+ if (isWorkingTime(result, priority)) {
return result;
}
- // If it's weekend, move to next Monday
- const day = result.getDay();
- if (day === 0) { // Sunday
- result.setDate(result.getDate() + 1);
- result.setHours(WORK_START_HOUR, 0, 0, 0);
- return result;
- }
- if (day === 6) { // Saturday
- result.setDate(result.getDate() + 2);
- result.setHours(WORK_START_HOUR, 0, 0, 0);
- return result;
+ // For standard priority: skip weekends
+ if (priority === 'standard') {
+ const day = result.getDay();
+ if (day === 0) { // Sunday
+ result.setDate(result.getDate() + 1);
+ result.setHours(WORK_START_HOUR, 0, 0, 0);
+ return result;
+ }
+ if (day === 6) { // Saturday
+ result.setDate(result.getDate() + 2);
+ result.setHours(WORK_START_HOUR, 0, 0, 0);
+ return result;
+ }
}
// If before work hours, move to work start
@@ -89,39 +98,47 @@ export function getNextWorkingTime(date: Date = new Date()): Date {
if (result.getHours() >= WORK_END_HOUR) {
result.setDate(result.getDate() + 1);
result.setHours(WORK_START_HOUR, 0, 0, 0);
- // Check if next day is weekend
- return getNextWorkingTime(result);
+ // Check if next day is weekend (only for standard priority)
+ return getNextWorkingTime(result, priority);
}
return result;
}
/**
- * Calculate elapsed working hours between two dates
+ * Calculate elapsed working hours between two dates with minute precision
+ * @param startDate - Start date
+ * @param endDate - End date (defaults to now)
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function calculateElapsedWorkingHours(startDate: Date, endDate: Date = new Date()): number {
+export function calculateElapsedWorkingHours(startDate: Date, endDate: Date = new Date(), priority: string = 'standard'): number {
let current = new Date(startDate);
const end = new Date(endDate);
- let elapsedHours = 0;
+ let elapsedMinutes = 0;
- // Move hour by hour and count only working hours
+ // Move minute by minute and count only working minutes
while (current < end) {
- if (isWorkingTime(current)) {
- elapsedHours++;
+ if (isWorkingTime(current, priority)) {
+ elapsedMinutes++;
}
- current.setHours(current.getHours() + 1);
+ current.setMinutes(current.getMinutes() + 1);
// Safety: stop if calculating more than 1 year
- if (elapsedHours > 8760) break;
+ const hoursSoFar = elapsedMinutes / 60;
+ if (hoursSoFar > 8760) break;
}
- return elapsedHours;
+ // Convert minutes to hours (with decimal precision)
+ return elapsedMinutes / 60;
}
/**
* Calculate remaining working hours to deadline
+ * @param deadline - Deadline date
+ * @param fromDate - Start date (defaults to now)
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function calculateRemainingWorkingHours(deadline: Date, fromDate: Date = new Date()): number {
+export function calculateRemainingWorkingHours(deadline: Date, fromDate: Date = new Date(), priority: string = 'standard'): number {
const deadlineTime = new Date(deadline).getTime();
const currentTime = new Date(fromDate).getTime();
@@ -131,15 +148,19 @@ export function calculateRemainingWorkingHours(deadline: Date, fromDate: Date =
}
// Calculate remaining working hours
- return calculateElapsedWorkingHours(fromDate, deadline);
+ return calculateElapsedWorkingHours(fromDate, deadline, priority);
}
/**
* Calculate SLA progress percentage
+ * @param startDate - Start date
+ * @param deadline - Deadline date
+ * @param currentDate - Current date (defaults to now)
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function calculateSLAProgress(startDate: Date, deadline: Date, currentDate: Date = new Date()): number {
- const totalHours = calculateElapsedWorkingHours(startDate, deadline);
- const elapsedHours = calculateElapsedWorkingHours(startDate, currentDate);
+export function calculateSLAProgress(startDate: Date, deadline: Date, currentDate: Date = new Date(), priority: string = 'standard'): number {
+ const totalHours = calculateElapsedWorkingHours(startDate, deadline, priority);
+ const elapsedHours = calculateElapsedWorkingHours(startDate, currentDate, priority);
if (totalHours === 0) return 0;
@@ -161,20 +182,22 @@ export interface SLAStatus {
statusText: string;
}
-export function getSLAStatus(startDate: string | Date, deadline: string | Date): SLAStatus {
+export function getSLAStatus(startDate: string | Date, deadline: string | Date, priority: string = 'standard'): SLAStatus {
const start = new Date(startDate);
const end = new Date(deadline);
const now = new Date();
- const isWorking = isWorkingTime(now);
- const elapsedHours = calculateElapsedWorkingHours(start, now);
- const totalHours = calculateElapsedWorkingHours(start, end);
+ const isWorking = isWorkingTime(now, priority);
+ const elapsedHours = calculateElapsedWorkingHours(start, now, priority);
+ const totalHours = calculateElapsedWorkingHours(start, end, priority);
const remainingHours = Math.max(0, totalHours - elapsedHours);
- const progress = calculateSLAProgress(start, end, now);
+ const progress = calculateSLAProgress(start, end, now, priority);
let statusText = '';
if (!isWorking) {
- statusText = 'SLA tracking paused (outside working hours)';
+ statusText = priority === 'express'
+ ? 'SLA tracking paused (outside working hours)'
+ : 'SLA tracking paused (outside working hours/days)';
} else if (remainingHours === 0) {
statusText = 'SLA deadline reached';
} else if (progress >= 100) {
@@ -194,7 +217,7 @@ export function getSLAStatus(startDate: string | Date, deadline: string | Date):
remainingHours,
totalHours,
isPaused: !isWorking,
- nextWorkingTime: !isWorking ? getNextWorkingTime(now) : undefined,
+ nextWorkingTime: !isWorking ? getNextWorkingTime(now, priority) : undefined,
statusText
};
}
@@ -204,29 +227,40 @@ export function getSLAStatus(startDate: string | Date, deadline: string | Date):
*/
export function formatWorkingHours(hours: number): string {
if (hours === 0) return '0h';
+ if (hours < 0) return '0h';
- const days = Math.floor(hours / 8); // 8 working hours per day
- const remainingHours = hours % 8;
+ const totalMinutes = Math.round(hours * 60);
+ const days = Math.floor(totalMinutes / (8 * 60)); // 8 working hours per day
+ const remainingMinutes = totalMinutes % (8 * 60);
+ const remainingHours = Math.floor(remainingMinutes / 60);
+ const minutes = remainingMinutes % 60;
- if (days > 0 && remainingHours > 0) {
+ if (days > 0 && remainingHours > 0 && minutes > 0) {
+ return `${days}d ${remainingHours}h ${minutes}m`;
+ } else if (days > 0 && remainingHours > 0) {
return `${days}d ${remainingHours}h`;
} else if (days > 0) {
return `${days}d`;
- } else {
+ } else if (remainingHours > 0 && minutes > 0) {
+ return `${remainingHours}h ${minutes}m`;
+ } else if (remainingHours > 0) {
return `${remainingHours}h`;
+ } else {
+ return `${minutes}m`;
}
}
/**
* Get time until next working period
+ * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
*/
-export function getTimeUntilNextWorking(): string {
- if (isWorkingTime()) {
+export function getTimeUntilNextWorking(priority: string = 'standard'): string {
+ if (isWorkingTime(new Date(), priority)) {
return 'In working hours';
}
const now = new Date();
- const next = getNextWorkingTime(now);
+ const next = getNextWorkingTime(now, priority);
const diff = next.getTime() - now.getTime();
const hours = Math.floor(diff / (1000 * 60 * 60));