A versatile and customizable React Native PDF report generation library for any tracking app - pomodoro, expenses, skills, reading, habits, fitness, and more!
- π Universal Tracking: Works with any type of tracking app
- π¨ Fully Customizable: Custom labels, colors, and terminology
- π± Beautiful UI: Modern, responsive modal with smooth animations
- π Dark Mode: Full dark mode support
- π Multiple Report Types: Summary, monthly, yearly, custom range, and item-specific reports
- β‘ Type-Safe: Written in TypeScript with comprehensive type definitions
- π― Flexible Data Model: Generic data structures that adapt to your app's needs
- π§© Modular Architecture: Clean, maintainable code with reusable components
- π£ Custom Hooks: Powerful hooks for form management and logic
- π οΈ Utility Functions: Built-in formatters, validators, and helpers
- πͺ Production Ready: Battle-tested and optimized for performance
npm install @rubixscript/react-native-pdf-reportnpm install expo-linear-gradient @expo/vector-icons @react-native-community/datetimepickerimport React, { useState } from 'react';
import { View, Button } from 'react-native';
import { PDFReportModal, DataItem, ActivitySession, ReportLabels } from '@rubixscript/react-native-pdf-report';
export default function App() {
const [showModal, setShowModal] = useState(false);
// Your tracking data
const data: DataItem[] = [
{
id: '1',
title: 'My Item',
subtitle: 'Category or Author',
progress: 75,
total: 100,
current: 75,
startDate: new Date(),
},
];
const sessions: ActivitySession[] = [
{
id: 's1',
itemId: '1',
date: new Date(),
duration: 60,
value: 10,
},
];
// Customize labels for your app
const labels: ReportLabels = {
itemLabel: 'Task',
itemLabelPlural: 'Tasks',
sessionLabel: 'Session',
sessionLabelPlural: 'Sessions',
reportTitle: 'Activity Report',
};
const handleGenerateReport = (options) => {
console.log('Generate PDF with options:', options);
// Implement your PDF generation logic here
};
return (
<View>
<Button title="Generate Report" onPress={() => setShowModal(true)} />
<PDFReportModal
visible={showModal}
onClose={() => setShowModal(false)}
darkMode={false}
data={data}
sessions={sessions}
onGenerateReport={handleGenerateReport}
labels={labels}
primaryColor="#007AFF"
/>
</View>
);
}This library is perfect for:
- π Reading Trackers - Track books, pages read, reading sessions
- π Pomodoro Apps - Track work sessions, focus time, productivity
- π° Expense Trackers - Track spending, budgets, transactions
- π― Skill Trackers - Track learning progress, practice sessions
- π Fitness Apps - Track workouts, exercises, progress
- β Habit Trackers - Track daily habits, streaks, consistency
- β° Time Trackers - Track time spent on projects, tasks
- π Journal Apps - Track entries, moods, reflections
- And many more!
const pomodoroLabels: ReportLabels = {
itemLabel: 'Task',
itemLabelPlural: 'Tasks',
sessionLabel: 'Pomodoro Session',
sessionLabelPlural: 'Pomodoro Sessions',
reportTitle: 'Productivity Report',
summaryLabel: 'Productivity Summary',
progressLabel: 'Pomodoros Completed',
durationLabel: 'Focus Time',
totalLabel: 'Total Tasks',
};
const tasks: DataItem[] = [
{
id: '1',
title: 'Complete Project Proposal',
subtitle: 'Work Project',
progress: 60,
total: 10, // total pomodoros
current: 6, // completed pomodoros
category: 'Work',
color: '#E74C3C',
},
];
<PDFReportModal
labels={pomodoroLabels}
data={tasks}
sessions={pomodoroSessions}
primaryColor="#E74C3C"
{...otherProps}
/>const expenseLabels: ReportLabels = {
itemLabel: 'Category',
itemLabelPlural: 'Categories',
sessionLabel: 'Transaction',
sessionLabelPlural: 'Transactions',
reportTitle: 'Expense Report',
summaryLabel: 'Financial Summary',
progressLabel: 'Amount Spent',
};
const categories: DataItem[] = [
{
id: '1',
title: 'Groceries',
subtitle: 'Food & Beverages',
progress: 75, // % of budget used
total: 500, // budget
current: 375, // spent
category: 'Food',
color: '#2ECC71',
},
];
const expenses: ActivitySession[] = [
{
id: 'e1',
itemId: '1',
date: new Date(),
value: 85.50, // expense amount
notes: 'Weekly grocery shopping',
},
];
<PDFReportModal
labels={expenseLabels}
data={categories}
sessions={expenses}
primaryColor="#2ECC71"
{...otherProps}
/>const skillLabels: ReportLabels = {
itemLabel: 'Skill',
itemLabelPlural: 'Skills',
sessionLabel: 'Practice Session',
sessionLabelPlural: 'Practice Sessions',
reportTitle: 'Skill Development Report',
progressLabel: 'Skill Points Earned',
durationLabel: 'Practice Time',
};
const skills: DataItem[] = [
{
id: '1',
title: 'JavaScript',
subtitle: 'Programming Language',
progress: 75,
total: 100,
current: 75,
category: 'Programming',
metadata: {
level: 'Advanced',
hoursInvested: 250,
},
},
];
<PDFReportModal
labels={skillLabels}
data={skills}
sessions={practiceSessions}
primaryColor="#8B5CF6"
{...otherProps}
/>const readingLabels: ReportLabels = {
itemLabel: 'Book',
itemLabelPlural: 'Books',
sessionLabel: 'Reading Session',
sessionLabelPlural: 'Reading Sessions',
reportTitle: 'Reading Report',
progressLabel: 'Pages Read',
durationLabel: 'Reading Time',
};
// You can also use the legacy Book and ReadingSession types
// They are aliases for DataItem and ActivitySession| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
visible |
boolean |
Yes | - | Controls modal visibility |
onClose |
() => void |
Yes | - | Callback when modal is closed |
darkMode |
boolean |
Yes | - | Enable dark mode |
data |
DataItem[] |
Yes | - | Array of items to track |
sessions |
ActivitySession[] |
Yes | - | Array of activity sessions |
onGenerateReport |
(options: ReportOptions) => void |
Yes | - | Callback with report configuration |
labels |
ReportLabels |
No | Default labels | Custom text labels |
reportTypes |
ReportTypeConfig[] |
No | Default types | Custom report type configs |
userName |
string |
No | - | User name for personalization |
primaryColor |
string |
No | #007AFF |
Primary theme color |
accentColor |
string |
No | - | Accent theme color |
interface DataItem {
id: string; // Unique identifier
title: string; // Main title (book title, task name, etc.)
subtitle?: string; // Subtitle (author, category, etc.)
imageUri?: string; // Optional image URL
progress?: number; // Progress percentage (0-100)
total?: number; // Total units (pages, hours, etc.)
current?: number; // Current units completed
startDate?: Date | string; // Start date
completedDate?: Date | string; // Completion date
notes?: string[]; // Notes array
category?: string; // Category
color?: string; // Color for UI
metadata?: Record<string, any>; // Custom metadata
isPinned?: boolean; // Pinned status
[key: string]: any; // Additional custom fields
}interface ActivitySession {
id: string; // Unique identifier
itemId: string; // Reference to DataItem
date: Date | string; // Session date
startValue?: number; // Start value (page, time, etc.)
endValue?: number; // End value
duration?: number; // Duration in minutes
value?: number; // Numeric value (amount, points, etc.)
notes?: string; // Session notes
imageUrl?: string; // Optional image
metadata?: Record<string, any>; // Custom metadata
[key: string]: any; // Additional custom fields
}interface ReportLabels {
itemLabel?: string; // e.g., "Book", "Task", "Expense"
itemLabelPlural?: string; // e.g., "Books", "Tasks"
sessionLabel?: string; // e.g., "Session", "Transaction"
sessionLabelPlural?: string; // e.g., "Sessions", "Transactions"
reportTitle?: string; // e.g., "Reading Report"
summaryLabel?: string; // e.g., "Summary"
progressLabel?: string; // e.g., "Pages Read"
durationLabel?: string; // e.g., "Reading Time"
totalLabel?: string; // e.g., "Total Books"
}interface ReportOptions {
type: ReportType; // 'summary' | 'monthly' | 'yearly' | 'custom' | 'item-details'
startDate?: Date; // For custom reports
endDate?: Date; // For custom reports
includeCharts?: boolean; // Include charts in report
includeSessionDetails?: boolean; // Include session details
includeItemDetails?: boolean; // Include item details
includeAchievements?: boolean; // Include achievements
itemId?: string; // For item-specific reports
customTitle?: string; // Custom report title
labels?: ReportLabels; // Labels for the report
}You can define custom report types with your own icons and descriptions:
const customReportTypes: ReportTypeConfig[] = [
{
type: 'summary',
title: 'π― My Custom Summary',
description: 'All-time statistics',
icon: 'π―',
},
{
type: 'monthly',
title: 'π
Monthly Review',
description: 'This month\'s progress',
icon: 'π
',
},
// ... more custom types
];
<PDFReportModal
reportTypes={customReportTypes}
{...otherProps}
/><PDFReportModal
primaryColor="#FF6B6B"
accentColor="#4ECDC4"
{...otherProps}
/>The library uses a flexible data model that can store any custom fields:
const customData: DataItem[] = [
{
id: '1',
title: 'My Item',
subtitle: 'Subtitle',
// Add any custom fields
customField: 'custom value',
rating: 5,
tags: ['tag1', 'tag2'],
metadata: {
// Store complex custom data
anyData: 'you need',
},
},
];- β¨ Modern Design: Beautiful card-based UI with smooth animations
- π¨ Customizable Colors: Change primary and accent colors to match your brand
- π Dark Mode: Full dark mode support throughout
- π± Responsive: Works perfectly on all screen sizes
- β¨οΈ Accessibility: Touch-friendly with proper accessibility labels
- π Smooth Transitions: Animated modal with slide transitions
- π Date Pickers: Native date pickers for custom date ranges
- β Smart Validation: Form validation with helpful error messages
- β Modal Overlay Issue: Fixed modal not opening properly due to overlay blocking interaction
- β Generic Library: Transformed from reading-specific to universal tracking library
- β Improved Aesthetics: Enhanced UI with better spacing, colors, and typography
- β Better Accessibility: Improved touch targets and visual feedback
- β Type Safety: Comprehensive TypeScript types for better DX
If you're upgrading from v1.x (reading-specific version):
// OLD (v1.x)
import { Book, ReadingSession } from '@rubixscript/react-native-pdf-report';
const books: Book[] = [...];
const sessions: ReadingSession[] = [...];
<PDFReportModal books={books} readingSessions={sessions} />
// NEW (v2.x) - Backward compatible
import { Book, ReadingSession } from '@rubixscript/react-native-pdf-report';
const books: Book[] = [...]; // Still works!
const sessions: ReadingSession[] = [...]; // Still works!
<PDFReportModal data={books} sessions={sessions} />
// OR use new generic types
import { DataItem, ActivitySession } from '@rubixscript/react-native-pdf-report';
const data: DataItem[] = [...];
const sessions: ActivitySession[] = [...];
<PDFReportModal data={data} sessions={sessions} labels={customLabels} />The Book and ReadingSession types are still available as aliases for backward compatibility.
Check out the examples/ directory for complete working examples:
reading-tracker.tsx- Reading tracking apppomodoro-tracker.tsx- Productivity/pomodoro appexpense-tracker.tsx- Expense tracking appskill-tracker.tsx- Skill development app
This library follows a modular architecture for maintainability and extensibility:
- 8 Modular Components: Each with a single responsibility
- 2 Custom Hooks:
useReportFormanduseReportTypes - Utility Functions: Formatters, validators, and constants
- Type-Safe: Comprehensive TypeScript definitions
The main PDFReportModal component has been reduced from 795 lines to just 272 lines through modularization!
For detailed architecture documentation, see ARCHITECTURE.md.
PDFReportModal (Main Orchestrator)
βββ ModalHeader
βββ ScrollView
β βββ ReportTypeSelector
β βββ DateRangeSelector (conditional)
β βββ ItemSelector (conditional)
β βββ CustomTitleInput
β βββ ReportOptionsToggles
βββ ModalFooter
All components are exported and can be used independently:
import {
ReportTypeSelector,
DateRangeSelector,
ItemSelector,
CustomTitleInput,
ReportOptionsToggles,
ModalHeader,
ModalFooter,
} from '@rubixscript/react-native-pdf-report';import { useReportForm, useReportTypes } from '@rubixscript/react-native-pdf-report';
// In your component
const { selectedReportType, handleGenerateReport, ... } = useReportForm({
visible,
labels,
onGenerateReport,
onClose,
});import {
formatDate,
formatDuration,
formatCurrency,
validateDateRange,
DEFAULT_LABELS,
} from '@rubixscript/react-native-pdf-report';Contributions are welcome! Please feel free to submit a Pull Request.
When contributing, please:
- Follow the modular architecture patterns
- Keep components small and focused (< 150 lines)
- Add TypeScript types for all props
- Write tests for new functionality
- Update documentation
MIT Β© RubixScript Team
If you find this library helpful, please give it a β on GitHub!
For questions and support, please open an issue on GitHub.