Overview Feature Documentation

Table of Contents

  1. Feature Overview
  2. Architecture
  3. Progress Calculation Methodology
  4. Component-Specific Calculations
  5. Data Flow
  6. API Integration
  7. UI Components
  8. State Management

Feature Overview

The Overview feature provides a comprehensive dashboard displaying organizational and individual performance metrics within the Nimbly audit application. It presents completion rates, progress trends, and comparative analytics to help users understand their audit performance over the last 30 days.

Key Metrics Displayed

  • Completion Rate: Overall task completion percentage for both individual users and company average
  • Completion by Type: Breakdown of completion rates across:
    • Schedules (Report-based tasks)
    • Issues (Issue resolution tasks)
    • LMS (Learning Management System tasks)
  • Completion Over Time: Weekly progress trends comparing individual and organizational performance

Default Filters Applied

All metrics in the Overview feature are automatically filtered by:

  • Time Period: Last 30 days (rolling window)
  • Organization: Current user’s organization
  • Active Status: Only active entities (sites, users, departments)
  • User Context: When viewing “My Tasks”, filtered by current user ID

Architecture

Frontend Structure

packages/app/features/overview/
├── screen.tsx                    # Main screen component
├── types.ts                      # TypeScript definitions
├── state.ts                      # Jotai atoms for state management
├── utils.ts                      # Utility functions
├── stylesheet.ts                 # Styled components
├── controllers/
│   ├── use-overview-controller.ts   # Main controller hook
│   └── overview-query.ts            # React Query hooks
└── components/
    ├── RefreshButton.tsx             # Manual refresh control
    ├── CompletionProgressChart.tsx   # Doughnut chart component
    ├── CompletionProgressBar.tsx     # Progress bar component
    └── CompletionProgressMultipleBarChart.tsx  # Weekly comparison chart

Backend Structure (api-statistics)

src/domains/dashboard/issue/
├── usecase/
│   └── dashboard.issue.usecase.ts   # Core business logic
└── models/
    └── dashboardIssuesResponse.ts   # Response types

Progress Calculation Methodology

The health score calculation is the core metric that combines multiple performance indicators. The system calculates scores at different levels with varying formulas based on the grouping context.

Core Metrics

1. RCR (Report Completion Rate)

  • Definition: Percentage of scheduled reports completed on time
  • Calculation: (Completed Reports / Total Scheduled Reports) × 100
  • Data Source: Schedule statistics from completed audits/inspections

2. IRR (Issue Resolution Rate)

  • Definition: Percentage of issues that have been resolved
  • Calculation: (Resolved Issues / Total Issues) × 100
  • Data Source: Issue tracking system

3. Issue Raised Percentage

  • Definition: Percentage of reports that resulted in issues being raised
  • Calculation: (Reports with Issues / Total Reports) × 100
  • Note: Lower percentages indicate better performance

4. LMS Score

  • Current Status: Always returns 0 (feature not yet implemented)
  • Future: Will track learning/training completion rates

Health Score Formulas

The health score calculation varies based on the grouping level:

Site/Department Level

healthScore = (0.5 × RCR) + (0.25 × (100 - issueRaisedPercentage)) + (0.25 × IRR)
 
Where:
- 50% weight: Report Completion Rate
- 25% weight: Low issue generation (inverse of issue raised percentage)
- 25% weight: Issue Resolution Rate
 
Breakdown:
- reportBasedScore = 0.5 × RCR
- issueBasedScore = 0.25 × (100 - issueRaisedPercentage) + 0.25 × IRR

Category Level

healthScore = (0.6 × IRR) + (0.4 × (100 - issueRaisedPercentage))
 
Where:
- 60% weight: Issue Resolution Rate
- 40% weight: Low issue generation
- Report completion is not considered at category level
 
Breakdown:
- reportBasedScore = 0
- issueBasedScore = 0.6 × IRR + 0.4 × (100 - issueRaisedPercentage)

User Level

healthScore = (0.6 × RCR) + (0.2 × issueAllocated) + (0.2 × resolvedOnTime)
 
Where:
- 60% weight: Report Completion Rate
- 20% weight: Issue allocation efficiency
- 20% weight: On-time resolution percentage
 
Additional Calculations:
- issueAllocated = Normalized value based on min/max issues assigned
- resolvedOnTime = Percentage of issues resolved within SLA
 
Breakdown:
- reportBasedScore = 0.6 × RCR
- issueBasedScore = 0.2 × issueAllocated + 0.2 × resolvedOnTime

Peer Comparison

The system calculates peer scores using the same formulas but with data from comparable organizations. This enables benchmarking:

value = |healthScore - healthScorePeers|
moreThanPeers = healthScore > healthScorePeers

Color Coding Logic

Progress indicators use color coding based on performance thresholds:

getColor(progress) {
    if (progress <= 20) return red;     // Critical
    if (progress <= 50) return yellow;  // Warning
    if (progress > 50) return green;    // Good
}

Data Flow

1. Initial Load

graph LR
    A[Screen Mount] --> B[Controller Hook]
    B --> C{Persisted Data?}
    C -->|No| D[Fetch All Metrics]
    C -->|Yes| E[Use Cached Data]
    D --> F[Update Atoms]
    F --> G[Render UI]
    E --> G

2. Data Fetching Process

  1. Payload Creation: Uses createPayload() to build request with:

    • Date range (last 30 days)
    • Metric type (‘health’)
    • Group by parameter (‘user’ or organization level)
    • User/Site/Department filters
  2. Parallel API Calls:

    • Organization level score
    • User level score
    • User weekly progress data
    • Organization weekly progress data
  3. Data Persistence: Results stored in Jotai atoms for state management

3. Manual Refresh

  • User clicks refresh button
  • All four API endpoints called simultaneously
  • Last updated timestamp recorded
  • UI updates with new data

API Integration

API Endpoints Overview

API NameEndpointMethodPurposeUsed ForResponse Data
Progress Scores/v1.0/statistics/dashboard/issue/detailPOSTFetch health scores and breakdown metricsBoth user-level and organization-level scoresProgressData object with health scores
Weekly Progress/v1.0/statistics/dashboard/issue/weekly-completion-scorePOSTFetch weekly progress data for trend analysisWeekly bar chart dataArray of ProgressDataByWeek objects

API Usage Breakdown

ComponentAPI CalledQuery ParametersData Usage
My Tasks (Doughnut)Progress ScoresuserIDs: [currentUser.userID]healthScore for percentage display
Company Average (Doughnut)Progress ScoresuserIDs: [] (all users)healthScore for organization average
Schedules Progress BarProgress ScoresuserIDs: [currentUser.userID]reportBasedScore for bar progress
Issues Progress BarProgress ScoresuserIDs: [currentUser.userID]issueBasedScore for bar progress
LMS Progress BarProgress ScoresuserIDs: [currentUser.userID]lmsBasedScore (currently always 0)
Weekly Bar ChartWeekly ProgressBoth user and org querieshealthScore from each week’s data

Detailed Endpoints

1. Progress Scores API

  • Endpoint: /v1.0/statistics/dashboard/issue/detail
  • Method: POST
  • Purpose: Fetch health scores and breakdown metrics
  • Called By:
    • useUserLevelScore() hook
    • useOrgLevelScore() hook

2. Weekly Progress API

  • Endpoint: /v1.0/statistics/dashboard/issue/weekly-completion-score
  • Method: POST
  • Purpose: Fetch weekly progress data for trend analysis
  • Called By:
    • useUserWeeklyProgressData() hook
    • useOrgWeeklyProgressData() hook

Request Payload Structure

interface OverviewPayload {
 metric: string; // 'health'
 groupBy: string; // 'user', 'site', 'department', 'category'
 startDate: string; // YYYY-MM-DD format
 endDate: string; // YYYY-MM-DD format
 siteIDs: string[]; // Filter by sites
 departmentIDs: string[]; // Filter by departments
 userIDs: string[]; // Filter by users (for user-level queries)
 questionnaireIDs: string[];
 categories: string[];
 roles: string[];
}

Response Structure

interface ProgressData {
 healthScore: number; // Overall health score (0-100)
 issueBasedScore: number; // Issue component score
 reportBasedScore: number; // Report component score
 lmsBasedScore: number; // LMS component (currently 0)
 healthScorePeers: number; // Peer average for comparison
 moreThanPeers: boolean; // Performance vs peers
 value: number; // Absolute difference from peers
}
 
interface ProgressDataByWeek {
 dateRange: {
  start: string;
  end: string;
 };
 week: string; // 'Week 1', 'Week 2', etc.
 score: ProgressData; // Same structure as above
}

UI Components

1. CompletionProgressChart

  • Type: Doughnut/Ring chart
  • Library: react-native-chart-kit
  • Props:
    • progress: Percentage value (0-100)
    • title: Chart label
  • Features:
    • Color-coded based on performance
    • Shows percentage in center
    • Loading state with spinner

2. CompletionProgressBar

  • Type: Horizontal progress bar
  • Props:
    • type: Schedule/Issues/LMS
    • progress: Percentage value
  • Features:
    • Icon representation for each type
    • Color-coded progress indicator
    • Percentage display

3. CompletionProgressMultipleBarChart

  • Type: Grouped bar chart
  • Purpose: Compare weekly trends
  • Features:
    • Dual bars (User vs Organization)
    • 4-week view
    • Legend support
    • Custom colors for differentiation

4. RefreshButton

  • Purpose: Manual data refresh
  • Features:
    • Shows last updated time
    • Loading state during refresh
    • Disabled in offline mode

State Management

Jotai Atoms

// Persisted score data
export const userLevelScoreAtom = atom<ProgressData>({});
export const orgLevelScoreAtom = atom<ProgressData>({});
 
// Weekly progress data
export const userWeeklyProgressDataAtom = atom<ProgressDataByWeek[]>([]);
export const orgWeeklyProgressDataAtom = atom<ProgressDataByWeek[]>([]);

Controller Hook Pattern

The useOverviewController hook manages:

  1. Data Fetching: Coordinates API calls
  2. State Persistence: Updates Jotai atoms
  3. Cache Management: Prevents unnecessary fetches
  4. Offline Support: Handles connectivity states
  5. Timestamp Management: Tracks last update time

Component-Specific Calculations

1. Completion Rate (Doughnut Charts)

My Tasks (User-Level Health Score)

// Query Filter
const userQuery = {
    metric: 'health',
    groupBy: 'user',
    userIDs: [currentUser.userID],
    startDate: '30 days ago',
    endDate: 'today',
    // Additional filters
    siteIDs: [],      // Empty = all sites
    departmentIDs: [], // Empty = all departments
    questionnaireIDs: [], // Empty = all questionnaires
    categories: [],   // Empty = all categories
    roles: []        // Empty = all roles
}
 
// Calculation Formula (User Level)
healthScore = (0.6 × RCR) + (0.2 × issueAllocationEfficiency) + (0.2 × onTimeResolution)
 
Where:
- RCR = Report Completion Rate for user's assigned tasks
- issueAllocationEfficiency = Normalized issue allocation score
- onTimeResolution = Percentage of issues resolved within SLA

Company Average (Organization-Level Health Score)

// Query Filter
const orgQuery = {
 metric: 'health',
 groupBy: 'user',
 userIDs: [], // Empty = all users in organization
 startDate: '30 days ago',
 endDate: 'today',
 // No user-specific filtering
 siteIDs: [],
 departmentIDs: [],
 questionnaireIDs: [],
 categories: [],
 roles: [],
};
 
// Calculation aggregates all users in the organization
// Uses same formula but with organization-wide data

2. Completion by Type (Progress Bars)

Schedules (Report-Based Score)

// Data Source: Schedule Statistics
const scheduleQuery = {
    // Filters completed vs scheduled reports
    doneBy: { $ne: [] },  // Reports marked as complete
    organizationID: currentUser.organizationID,
    userID: currentUser.userID, // For "My Tasks"
    dateRange: last30Days
}
 
// Calculation
reportBasedScore = {
    user: 0.6 × RCR,           // 60% weight for user level
    site: 0.5 × RCR,           // 50% weight for site level
    department: 0.5 × RCR,     // 50% weight for department level
    category: 0                // Not applicable for category level
}
 
// Display Value
scheduleProgress = reportBasedScore (directly from health score calculation)

Issues (Issue-Based Score)

// Data Source: Issue Statistics
const issueQuery = {
    organizationID: currentUser.organizationID,
    assignedTo: currentUser.userID, // For "My Tasks"
    dateRange: last30Days,
    status: ['open', 'in_progress', 'in_review', 'blocked', 'resolved']
}
 
// Calculation Components
const resolvedIssues = issues.filter(issue => issue.status === 'resolved')
const totalIssues = issues.length
const IRR = (resolvedIssues.length / totalIssues) × 100
 
const issueRaisedPercentage = (reportsWithIssues / totalReports) × 100
 
// Final Calculation
issueBasedScore = {
    user: 0.2 × issueAllocation + 0.2 × onTimeResolution,
    site: 0.25 × (100 - issueRaisedPercentage) + 0.25 × IRR,
    department: 0.25 × (100 - issueRaisedPercentage) + 0.25 × IRR,
    category: 0.6 × IRR + 0.4 × (100 - issueRaisedPercentage)
}
 
// Display Value
issueProgress = issueBasedScore (from health score breakdown)

LMS (Learning Management System)

// Current Implementation
lmsBasedScore = 0; // Feature not yet implemented
 
// Future Implementation (Planned)
const lmsQuery = {
 organizationID: currentUser.organizationID,
 userID: currentUser.userID,
 dateRange: last30Days,
 completionStatus: ['completed', 'in_progress', 'not_started'],
};
 
// Planned Calculation
// lmsProgress = (completedCourses / assignedCourses) × 100

3. Completion Over Time (Weekly Bar Chart)

My Tasks vs Overall Comparison

// Data Processing
const weeklyRanges = getWeeklyRanges(startDate, endDate); // 4 weeks
const userWeeklyData = [];
const orgWeeklyData = [];
 
// For each week
weeklyRanges.forEach((week, index) => {
 // User Data Query
 const userWeekQuery = {
  ...baseQuery,
  userIDs: [currentUser.userID],
  startDate: week.start,
  endDate: week.end,
 };
 
 // Organization Data Query
 const orgWeekQuery = {
  ...baseQuery,
  userIDs: [], // All users
  startDate: week.start,
  endDate: week.end,
 };
 
 // Store weekly health scores
 userWeeklyData[index] = getUserHealthScore(userWeekQuery);
 orgWeeklyData[index] = getOrgHealthScore(orgWeekQuery);
});
 
// Chart Data Mapping
const chartData = userWeeklyData.map((userWeek, index) => [
 {
  value: userWeek.healthScore,
  frontColor: '#63cfca', // Teal for user
  gradientColor: '#009FFF',
  spacing: 6,
  label: `Week ${index + 1}`,
 },
 {
  value: orgWeeklyData[index].healthScore,
  frontColor: '#FFB74D', // Orange for organization
  gradientColor: '#fff64d',
 },
]);

4. Peer Comparison Logic

Peer Selection Filters

const peerQuery = {
 // Same industry/sector
 industry: currentOrg.industry,
 sector: currentOrg.sector,
 
 // Similar organization size (±20% employee count)
 employeeCount: {
  $gte: currentOrg.employeeCount * 0.8,
  $lte: currentOrg.employeeCount * 1.2,
 },
 
 // Active organizations only
 status: 'active',
 
 // Exclude current organization
 organizationID: { $ne: currentUser.organizationID },
};
 
// Peer Score Calculation
const peerHealthScore = calculateAverageHealthScore(peerOrganizations);
const comparison = {
 value: Math.abs(currentHealthScore - peerHealthScore),
 moreThanPeers: currentHealthScore > peerHealthScore,
};

5. Color Coding and Thresholds

// Performance Thresholds
const getProgressColor = (score) => {
 if (score <= 20) return '#DC3545'; // Red - Critical
 if (score <= 50) return '#FFC107'; // Yellow - Warning
 if (score > 50) return '#28A745'; // Green - Good
};
 
// Applied to all progress indicators:
// - Doughnut chart colors
// - Progress bar colors
// - Weekly trend indicators

6. Data Refresh and Caching

Automatic Filters Applied on Refresh

const refreshFilters = {
 // Time window always updates to current rolling 30 days
 startDate: dayjs().subtract(30, 'days').format('YYYY-MM-DD'),
 endDate: dayjs().format('YYYY-MM-DD'),
 
 // User context maintained
 organizationID: currentUser.organizationID,
 userIDs: [currentUser.userID], // For user-specific queries
 
 // No manual filters - Overview uses default organizational scope
 siteIDs: [], // All sites in organization
 departmentIDs: [], // All departments in organization
 questionnaireIDs: [], // All questionnaires
 categories: [], // All categories
 roles: [], // All roles
};

Optimization Strategies

  1. Conditional Fetching: Only fetches when on overview screen
  2. Data Persistence: Caches results to prevent redundant API calls
  3. Parallel Requests: All metrics fetched simultaneously
  4. Offline Mode: Uses cached data when offline

Performance Considerations

Data Caching

  • Results persisted in Jotai atoms
  • Survives navigation between tabs
  • Manual refresh available for updates

Network Optimization

  • Batch API calls in parallel
  • Network mode set to ‘online’ only
  • Error handling with user feedback

UI Responsiveness

  • Loading states for each component
  • Progressive data display
  • Smooth animations in charts

Usage Example

// In a React Native screen
import OverviewScreen from 'app/features/overview/screen';
 
// The screen automatically:
// 1. Fetches data on mount (if needed)
// 2. Displays cached data immediately
// 3. Updates UI when new data arrives
// 4. Handles refresh requests
// 5. Manages offline states
 
<OverviewScreen />