---
description:
globs:
alwaysApply: true
---
# SME Centralized Reporting System - Coding Standards & Development Patterns

## OVERVIEW
This document defines coding standards, development patterns, and implementation guidelines for the SME Centralized Reporting System React Native application.

---

## 1. CODING STANDARDS & CONVENTIONS

### File Naming Conventions
- **Components**: PascalCase (`ZohoProjectsDashboardScreen.tsx`)
- **Services**: camelCase (`zohoProjectsAPI.ts`)  
- **Store files**: camelCase (`zohoProjectsSlice.ts`)
- **Types**: PascalCase (`ProfileTypes.ts`)
- **Constants**: UPPER_SNAKE_CASE (`API_ENDPOINTS.ts`)
- **Utilities**: camelCase (`dateUtils.ts`)
- **Hooks**: camelCase with 'use' prefix (`useZohoProjectsData.ts`)

### Directory Naming Conventions
- **Modules**: camelCase (`auth`, `zohoProjects`, `hr`, `profile`)
- **Components**: camelCase (`widgets`, `forms`, `screens`)
- **Services**: camelCase (`integrations`, `analytics`)

### Module Directory Rules
- Place `screens`, `widgets`, and `forms` inside `components/` within each module.
- Keep `components/` for UI-only code. Do not add `utils` or `constants` under modules.
- Share cross-cutting helpers via `src/shared/utils` and global constants via `src/shared/constants`.

### Variable & Function Naming
```typescript
// Variables: camelCase
const projectList = [];
const isLoading = false;
const userPreferences = {};

// Functions: camelCase with descriptive verbs
const fetchZohoProjectsData = () => {};
const calculateOpenTasks = () => {};
const handleSubmitForm = () => {};

// Constants: UPPER_SNAKE_CASE
const API_BASE_URL = '';
const MAX_RETRY_ATTEMPTS = 3;
const DEFAULT_PAGE_SIZE = 20;

// Interfaces/Types: PascalCase
interface ZohoProject {
  id: string;
  name: string;
}

type LoadingState = 'idle' | 'loading' | 'succeeded' | 'failed';
```

---

### Inline Commenting Guidelines
- Always add clear, concise inline comments for non-obvious logic, complex conditions, side-effects, and business rules.
- Prefer sentence-case, developer-oriented comments that explain "why" not just "what".
- Document assumptions, edge cases, units, and non-trivial parameter/return semantics.
- Keep comments up-to-date when changing code; remove stale comments immediately.
- For components, briefly annotate major sections (effects, handlers, conditional rendering) and tricky UI logic.

Example:
```typescript
// Fetch projects on mount and when filters change to ensure fresh data
useEffect(() => {
  // Guard: avoid duplicate fetch while loading
  if (loading) return;
  dispatch(fetchZohoProjects());
}, [dispatch, loading, filters]);

// Compute SLA breach percentage (0-100). Includes only active tasks.
const breachRate = useMemo(() => {
  if (totalTasks === 0) return 0; // Avoid divide-by-zero
  return Math.round((breachedTasks / totalTasks) * 100);
}, [breachedTasks, totalTasks]);
```

---

## 2. COMPONENT STRUCTURE TEMPLATES

### Screen Component Template
```typescript
import React, { useEffect, useState } from 'react';
import {
  View,
  Text,
  ScrollView,
  RefreshControl,
  StyleSheet,
} from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import Icon from 'react-native-vector-icons/MaterialIcons';

// Shared imports
import { Container, LoadingSpinner, ErrorState } from '@/shared/components/ui';
import { COLORS, FONTS, SPACING } from '@/shared/styles/theme';

// Module imports
import { selectZohoProjects, selectZohoProjectsLoading } from '../store/selectors';
import { fetchZohoProjects } from '../store/zohoProjectsSlice';

// Types
import type { ZohoProjectsScreenProps } from '../types';

const ZohoProjectsDashboardScreen: React.FC<ZohoProjectsScreenProps> = ({
  navigation,
  route,
}) => {
  // State
  const [refreshing, setRefreshing] = useState(false);
  
  // Redux
  const dispatch = useDispatch();
  const data = useSelector(selectZohoProjects);
  const loading = useSelector(selectZohoProjectsLoading);

  // Effects
  useEffect(() => {
    dispatch(fetchZohoProjects());
  }, [dispatch]);

  // Handlers
  const handleRefresh = async () => {
    setRefreshing(true);
    await dispatch(fetchZohoProjects()).unwrap();
    setRefreshing(false);
  };

  const handleNavigateToDetails = (id: string) => {
    navigation.navigate('ProjectDetails', { id });
  };

  // Loading state
  if (loading && !data.length) {
    return <LoadingSpinner />;
  }

  // Error state
  if (error) {
    return <ErrorState onRetry={() => dispatch(fetchZohoProjects())} />;
  }

  return (
    <Container>
      <ScrollView
        style={styles.container}
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
        }
      >
        <View style={styles.header}>
          <Text style={styles.title}>Zoho Projects</Text>
          <Icon 
            name="insights" 
            size={24} 
            color={COLORS.primary}
          />
        </View>

        {/* Dashboard content */}
        <View style={styles.content}>
          {/* Widgets and components */}
        </View>
      </ScrollView>
    </Container>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: COLORS.background,
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: SPACING.md,
    backgroundColor: COLORS.surface,
  },
  title: {
    fontSize: 24,
    fontFamily: FONTS.bold,
    color: COLORS.text,
  },
  content: {
    padding: SPACING.md,
  },
});

export default ZohoProjectsDashboardScreen;
```

### Widget Component Template
```typescript
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { COLORS, FONTS, SPACING, SHADOWS } from '@/shared/styles/theme';

interface RevenueChartProps {
  data: RevenueData[];
  period: 'month' | 'quarter' | 'year';
  onPeriodChange: (period: 'month' | 'quarter' | 'year') => void;
  onPress?: () => void;
}

const RevenueChart: React.FC<RevenueChartProps> = ({
  data,
  period,
  onPeriodChange,
  onPress,
}) => {
  const totalRevenue = data.reduce((sum, item) => sum + item.amount, 0);
  
  return (
    <TouchableOpacity 
      style={styles.container} 
      onPress={onPress}
      activeOpacity={0.8}
    >
      <View style={styles.header}>
        <View style={styles.titleContainer}>
          <Icon name="trending-up" size={20} color={COLORS.primary} />
          <Text style={styles.title}>Revenue Analytics</Text>
        </View>
        
        <View style={styles.periodSelector}>
          {['month', 'quarter', 'year'].map((p) => (
            <TouchableOpacity
              key={p}
              style={[
                styles.periodButton,
                period === p && styles.periodButtonActive,
              ]}
              onPress={() => onPeriodChange(p as any)}
            >
              <Text
                style={[
                  styles.periodText,
                  period === p && styles.periodTextActive,
                ]}
              >
                {p.charAt(0).toUpperCase() + p.slice(1)}
              </Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>

      <View style={styles.content}>
        <Text style={styles.amount}>
          ${totalRevenue.toLocaleString()}
        </Text>
        <Text style={styles.subtitle}>Total Revenue</Text>
        
        {/* Chart component would go here */}
        <View style={styles.chartPlaceholder}>
          <Text style={styles.chartText}>Chart Component</Text>
        </View>
      </View>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: COLORS.surface,
    borderRadius: 12,
    padding: SPACING.md,
    ...SHADOWS.medium,
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: SPACING.md,
  },
  titleContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  title: {
    fontSize: 16,
    fontFamily: FONTS.medium,
    color: COLORS.text,
    marginLeft: SPACING.xs,
  },
  periodSelector: {
    flexDirection: 'row',
    backgroundColor: COLORS.background,
    borderRadius: 6,
    padding: 2,
  },
  periodButton: {
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 4,
  },
  periodButtonActive: {
    backgroundColor: COLORS.primary,
  },
  periodText: {
    fontSize: 12,
    fontFamily: FONTS.regular,
    color: COLORS.textLight,
  },
  periodTextActive: {
    color: COLORS.surface,
  },
  content: {
    alignItems: 'flex-start',
  },
  amount: {
    fontSize: 28,
    fontFamily: FONTS.bold,
    color: COLORS.text,
  },
  subtitle: {
    fontSize: 14,
    fontFamily: FONTS.regular,
    color: COLORS.textLight,
    marginBottom: SPACING.md,
  },
  chartPlaceholder: {
    width: '100%',
    height: 120,
    backgroundColor: COLORS.background,
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
  },
  chartText: {
    fontSize: 14,
    fontFamily: FONTS.regular,
    color: COLORS.textLight,
  },
});

export default RevenueChart;
```

---

## 3. REDUX STATE MANAGEMENT PATTERNS

### Store Configuration
```typescript
// src/store/store.ts
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { combineReducers } from '@reduxjs/toolkit';

// Import slices
import authSlice from '@/modules/auth/store/authSlice';
import hrSlice from '@/modules/hr/store/hrSlice';
import zohoProjectsSlice from '@/modules/zohoProjects/store/zohoProjectsSlice';
import profileSlice from '@/modules/profile/store/profileSlice';
import uiSlice from '@/shared/store/uiSlice';

const rootReducer = combineReducers({
  auth: authSlice.reducer,
  hr: hrSlice.reducer,
  zohoProjects: zohoProjectsSlice.reducer,
  profile: profileSlice.reducer,
  ui: uiSlice.reducer,
});

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  whitelist: ['auth', 'hr', 'zohoProjects', 'profile'],
  blacklist: ['ui'], // Don't persist UI state
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['persist/FLUSH', 'persist/REHYDRATE', 'persist/PAUSE', 'persist/PERSIST', 'persist/PURGE', 'persist/REGISTER'],
      },
    }),
});

export const persistor = persistStore(store);

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
```

### Redux Slice Template (Zoho Projects example)
```typescript
// src/modules/zohoProjects/store/zohoProjectsSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { zohoProjectsAPI } from '../services/zohoProjectsAPI';
import type { ZohoProjectsState, ZohoProject, ZohoProjectsFilters } from './types';

// Initial state
const initialState: ZohoProjectsState = {
  projects: [],
  loading: false,
  error: null,
  filters: { owner: 'all', status: 'all' },
  lastUpdated: null,
};

// Async thunks
export const fetchZohoProjects = createAsyncThunk(
  'zohoProjects/fetch',
  async () => {
    const response = await zohoProjectsAPI.getProjects();
    return response.data;
  }
);

export const updateZohoProject = createAsyncThunk(
  'zohoProjects/update',
  async (project: Partial<ZohoProject>) => {
    const response = await zohoProjectsAPI.updateProject(project);
    return response.data;
  }
);

// Slice
const zohoProjectsSlice = createSlice({
  name: 'zohoProjects',
  initialState,
  reducers: {
    setFilters: (state, action: PayloadAction<Partial<ZohoProjectsFilters>>) => {
      state.filters = { ...state.filters, ...action.payload };
    },
    clearError: (state) => {
      state.error = null;
    },
    resetState: () => initialState,
  },
  extraReducers: (builder) => {
    // add async case reducers here
  },
});

export default zohoProjectsSlice;
```

### Redux Slice Template
```typescript
// src/modules/finance/store/financeSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { financeAPI } from '../services/financeAPI';
import type { FinanceState, FinanceData, FinanceFilters } from './types';

// Initial state
const initialState: FinanceState = {
  data: [],
  loading: false,
  error: null,
  filters: {
    period: 'month',
    category: 'all',
    dateRange: null,
  },
  lastUpdated: null,
};

// Async thunks
export const fetchFinanceData = createAsyncThunk(
  'finance/fetchData',
  async (params?: { refresh?: boolean }) => {
    const response = await financeAPI.getData(params);
    return response.data;
  }
);

export const updateFinanceData = createAsyncThunk(
  'finance/updateData',
  async (data: Partial<FinanceData>) => {
    const response = await financeAPI.updateData(data);
    return response.data;
  }
);

// Slice
const financeSlice = createSlice({
  name: 'finance',
  initialState,
  reducers: {
    setFilters: (state, action: PayloadAction<Partial<FinanceFilters>>) => {
      state.filters = { ...state.filters, ...action.payload };
    },
    clearError: (state) => {
      state.error = null;
    },
    resetState: () => initialState,
  },
  extraReducers: (builder) => {
    builder
      // Fetch data cases
      .addCase(fetchFinanceData