Sangeetha-Grantha

Metadata Value
Status Active
Version 1.1.0
Last Updated 2026-09-10
Author Sangeetha Grantha Team
Document Type Evidence record

Comprehensive Code Quality Evaluation Report: KrithiEditor.tsx


[!NOTE] Historical evidence: results, counts, commands, and observations below belong to the original work described here. The editorial update date is not a new test or corpus verification. For present behavior, use current quality checks.

Review Date: 2026-01-27 Reviewer: Claude Code Analysis File: modules/frontend/sangita-admin-web/src/pages/KrithiEditor.tsx


Executive Summary

File Size: ~1,860 lines Component Type: Page-level editor component (complex form) Overall Assessment: The component is functional but has significant architectural issues that impact maintainability, testability, and scalability.


1. Component Architecture

Issues Identified

1.1 Monolithic Component (Critical)

The component is a single 1,860-line file handling multiple concerns:

Impact: Difficult to test, reason about, and modify without risk of regressions.

1.2 Inline Sub-components Without Memoization (Lines 50-120)

const SectionHeader: React.FC<...> = ({ title, action }) => (...)
const InputField = ({ label, value, onChange, ... }: any) => (...)
const SelectField = ({ label, value, onChange, ... }: any) => (...)
const TextareaField = ({ ... }: any) => (...)
const CheckboxField = ({ ... }: any) => (...)

Problems:

1.3 State Explosion

The component has 25+ useState calls:

const [activeTab, setActiveTab] = useState(...)
const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false)
const [sectionsLoading, setSectionsLoading] = useState(false)
const [lyricVariantsLoading, setLyricVariantsLoading] = useState(false)
const [tagsLoading, setTagsLoading] = useState(false)
// ... 20+ more

Impact: Complex state interdependencies, difficult to track state changes, prone to stale closure bugs.


2. Type Safety

Issues Identified

2.1 Pervasive Use of any (Critical)

const InputField = ({ label, value, onChange, ... }: any) => (...) // Line 57
const SelectField = ({ label, value, onChange, ... }: any) => (...) // Line 81
const TextareaField = ({ ... }: any) => (...) // Line 97
const CheckboxField = ({ ... }: any) => (...) // Line 110
const payload: any = {}; // Line 396
const mapKrithiDtoToDetail = (dto: any): Partial<KrithiDetail> => {...} // Line 199

Impact: Eliminates compile-time type checking, increases runtime errors.

2.2 Unsafe Type Assertions

workflowState as any // Line 235
e.target.value as any // Lines 1005, 1086)
tab as any // Line 746

Impact: Bypasses TypeScript safety, potential runtime errors.

2.3 Missing Interface Definitions

The inline components lack proper interfaces. For example:

interface InputFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  highlight?: boolean;
}

3. State Management

Issues Identified

3.1 Mixed State Update Patterns

The component mixes different patterns inconsistently:

// Pattern 1: Spread operator
setKrithi({ ...krithi, title: v })  // Line 822

// Pattern 2: Functional update
setKrithi(prev => ({ ...prev, composer: obj }))  // Line 326

Best practice: Always use functional updates when the new state depends on previous state.

3.2 Derived State Not Memoized

Values computed from state are recalculated on every render:

krithi.sections?.map(...)
krithi.lyricVariants?.map(...)

Should use useMemo for expensive computations.

3.3 Redundant State

const [rawKrithiDto, setRawKrithiDto] = useState<any>(null); // Line 245

This stores raw API response to remap later - indicates a design issue with the data loading strategy.


4. Side Effects & Data Fetching

Issues Identified

4.1 Complex useEffect Chains

Multiple interdependent effects create a waterfall of side effects:

// Effect 1: Load reference data (Lines 178-196)
useEffect(() => { loadRefs(); }, []);

// Effect 2: Load krithi (Lines 247-268)
useEffect(() => {...}, [krithiId, isNew]);

// Effect 3: Remap on reference data change (Lines 272-284)
useEffect(() => {...}, [rawKrithiDto, composers, ragas, ...]);

// Effect 4: Auto-load sections (Lines 287-316)
useEffect(() => {...}, [krithiId, isNew]);

// Effect 5: Reset sections flag (Lines 319-321)
useEffect(() => { sectionsLoadedRef.current = false; }, [krithiId]);

Impact: Hard to trace data flow, potential for race conditions, difficult to debug.

4.2 Missing Dependency Array Items

useEffect(() => {
    // Uses `composers`, `ragas`, `talas`, `deities`, `temples`
    // but they're not in deps (intentional but fragile)
}, [krithiId, isNew]);  // Line 268

4.3 No Request Cancellation

useEffect(() => {
    getKrithi(krithiId).then(...)  // No AbortController
}, [krithiId]);

Impact: Potential memory leaks, race conditions with rapid navigation.


5. Business Logic & Data Transformation

Issues Identified

5.1 Inline Business Logic (Lines 199-242)

The mapKrithiDtoToDetail function contains complex mapping logic that should be in a separate utility:

const mapKrithiDtoToDetail = (dto: any): Partial<KrithiDetail> => {
    // 40+ lines of transformation logic
    let workflowState = 'DRAFT';
    if (dto.workflowState) {
        workflowState = typeof dto.workflowState === 'string'
            ? dto.workflowState.toUpperCase().replace(/-/g, '_')
            : dto.workflowState;
    }
    // ... extensive mapping
}

Impact: Untestable, duplicated concepts, business logic mixed with UI.

5.2 Save Handler Complexity (Lines 392-674)

The handleSave function is ~280 lines containing:

This should be decomposed into smaller, testable functions.


6. UI/UX Patterns

Issues Identified

6.1 Tab Click Handler with Side Effects (Lines 745-795)

onClick={async () => {
    setActiveTab(tab as any);
    if (tab === 'Structure' && ...) {
        // 20+ lines of async data loading
    }
    if (tab === 'Lyrics' && ...) {
        // 20+ lines of async data loading
    }
}}

Impact: Tab clicks trigger side effects, making behavior unpredictable and hard to test.

6.2 Inconsistent Loading States

Different loading patterns for different data:

{loading ? <Spinner /> : <Content />}  // Main loading
{sectionsLoading && <Spinner />}       // Sections
{lyricVariantsLoading ? ... : ...}     // Variants (ternary)
{tagsLoading && <Spinner />}           // Tags

6.3 Magic Timeout

const timer = setTimeout(async () => {
    // Load sections after delay to ensure krithi state is set
}, 100);  // Line 313

Impact: Race condition workaround, fragile timing dependency.


7. Error Handling

Issues Identified

7.1 Inconsistent Error Handling

.catch(err => alert("Failed to load krithi: " + err.message))  // Line 260 - alert
.catch(err => console.error("Failed to load audit logs:", err))  // Line 266 - console
toast.error('Save failed: ' + (e.message || 'Unknown error'))  // Line 670 - toast

7.2 Silent Failures

} catch (err: any) {
    console.error('Failed to load sections:', err);
    // Don't show error toast on initial load - sections might not exist yet
}  // Lines 307-309

Impact: User doesn’t know when operations fail.


8. Performance Concerns

Issues Identified

8.1 No React.memo on Child Components

All inline components re-render on every state change.

8.2 No useCallback for Handlers

Handlers like handleSave, handleComposerChange, etc. are recreated every render:

const handleComposerChange = (id: string) => {...}  // Line 324

8.3 Large Render Tree

Rendering 6 tabs’ content conditionally but all tab content is evaluated:

{activeTab === 'Metadata' && (...)}  // ~200 lines
{activeTab === 'Structure' && (...)}  // ~130 lines
{activeTab === 'Lyrics' && (...)}     // ~220 lines
// etc.

9. Accessibility

Issues Identified

9.1 Missing ARIA Attributes

9.2 No Focus Management


10. Code Style & Consistency

Issues Identified

10.1 Inconsistent Naming

krithi  // State variable (Sanskrit spelling)
krithiId  // ID variable
KrithiEditor  // Component name
handleDeitySave  // Handler
handleTempleSave  // Handler
onBack  // Also a handler, different convention

10.2 Long Inline Styles

className={`w-full h-12 px-4 border rounded-lg text-ink-900 focus:ring-2 focus:ring-primary focus:border-transparent transition-all ${highlight ? 'border-purple-400 bg-purple-50' : 'border-border-light bg-slate-50'}`}

Should use CSS modules or component variants.


11. Recommendations Summary

Priority 1 (Critical)

  1. Extract into smaller components: MetadataTab, StructureTab, LyricsTab, etc.
  2. Add proper TypeScript interfaces for all props
  3. Use a state management solution (useReducer or external library) for complex form state
  4. Extract API/mapping logic into custom hooks or utilities

Priority 2 (High)

  1. Implement proper error boundaries
  2. Add loading/error states pattern (consider React Query or SWR)
  3. Memoize expensive computations with useMemo
  4. Wrap handlers with useCallback

Priority 3 (Medium)

  1. Add accessibility attributes (ARIA)
  2. Implement request cancellation with AbortController
  3. Create reusable form components with proper types
  4. Add unit tests for business logic functions

Priority 4 (Nice-to-have)

  1. Consider form library (react-hook-form) for validation
  2. Implement optimistic updates for better UX
  3. Add Storybook for component documentation

Metrics

Metric Current Target
Lines of code 1,860 <400 per file
useState calls 25+ <10 (use reducer)
any usages 15+ 0
useEffect hooks 5+ Consolidated or custom hooks
Cyclomatic complexity High Medium
Test coverage Unknown >80%

Conclusion

The component is functionally complete but suffers from classic React anti-patterns: monolithic design, type safety bypasses, complex state management, and mixed concerns. Refactoring into smaller, typed, testable components with proper state management would significantly improve maintainability and developer experience.


Resolution Summary & Checklist Alignment (2026-01-29)

This review captured the pre-refactor state of KrithiEditor.tsx. Since then, TRACK-023 (Krithi Editor Refactoring) has implemented most of the high-priority items from krithi-editor-refactor-checklist.md:

For a task-by-task implementation view, refer to krithi-editor-refactor-checklist.md, which tracks the detailed checklist items corresponding to the recommendations in this report.


Section index · Documentation home · Feature status