A versatile React Native PDF report generation library for any tracking app - pomodoro, expenses, skills, reading, habits, and more
npm install @rubixscript/react-native-pdf-report

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
``bash`
npm install @rubixscript/react-native-pdf-report
`bash`
npm install expo-linear-gradient @expo/vector-icons @react-native-community/datetimepicker
`tsx
import 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 (
onClose={() => setShowModal(false)}
darkMode={false}
data={data}
sessions={sessions}
onGenerateReport={handleGenerateReport}
labels={labels}
primaryColor="#007AFF"
/>
);
}
`
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!
`tsx
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',
},
];
data={tasks}
sessions={pomodoroSessions}
primaryColor="#E74C3C"
{...otherProps}
/>
`
`tsx
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',
},
];
data={categories}
sessions={expenses}
primaryColor="#2ECC71"
{...otherProps}
/>
`
`tsx
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,
},
},
];
data={skills}
sessions={practiceSessions}
primaryColor="#8B5CF6"
{...otherProps}
/>
`
`tsx
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
`
This PDF Report library is designed to work seamlessly with other RubixScript productivity libraries:
Combine PDF Report with the Flip Clock for a complete Pomodoro/productivity timer solution:
`tsx
import React, { useState } from 'react';
import { View, Button } from 'react-native';
import { FlipClockModal } from '@rubixscript/react-native-flip-clock';
import { PDFReportModal } from '@rubixscript/react-native-pdf-report';
const ProductivityApp = () => {
const [showFlipClock, setShowFlipClock] = useState(false);
const [showReport, setShowReport] = useState(false);
// Your Pomodoro tasks data
const tasks = [
{
id: '1',
title: 'Complete Project',
subtitle: 'Work',
progress: 60, // pomodoros completed
total: 10, // total estimated pomodoros
current: 6, // completed pomodoros
category: 'Work',
color: '#FF6347',
},
];
// Pomodoro sessions from Flip Clock
const pomodoroSessions = [
{
id: 's1',
itemId: '1',
date: new Date(),
duration: 25, // minutes from Flip Clock
value: 1, // 1 pomodoro completed
notes: 'Focused work session',
},
];
const pomodoroLabels: ReportLabels = {
itemLabel: 'Task',
itemLabelPlural: 'Tasks',
sessionLabel: 'Pomodoro Session',
sessionLabelPlural: 'Pomodoro Sessions',
reportTitle: 'Pomodoro Report',
progressLabel: 'Pomodoros Completed',
durationLabel: 'Focus Time',
};
return (
title="Start Pomodoro Timer"
onPress={() => setShowFlipClock(true)}
/>
title="Generate Report"
onPress={() => setShowReport(true)}
/>
{/ Flip Clock for timing /}
onClose={() => setShowFlipClock(false)}
phase="work"
theme="dark"
// ... timer props
/>
{/ PDF Report for analytics /}
onClose={() => setShowReport(false)}
darkMode={false}
data={tasks}
sessions={pomodoroSessions}
labels={pomodoroLabels}
primaryColor="#FF6347"
onGenerateReport={(options) => {
console.log('Generate Pomodoro PDF:', options);
}}
/>
);
};
`
Combine PDF Report with Productivity Charts for visual analytics before generating reports:
`tsx
import React, { useState } from 'react';
import { View, ScrollView, Button } from 'react-native';
import {
HeatmapChart,
ActivityBarChart,
ProgressCard,
generateHeatmapData,
useProductivityData,
} from '@rubixscript/react-native-productivity-charts';
import { PDFReportModal } from '@rubixscript/react-native-pdf-report';
const DashboardWithReport = () => {
const [showReport, setShowReport] = useState(false);
// Your tracking data
const sessions = [
{ date: new Date('2025-01-01'), value: 5 },
{ date: new Date('2025-01-02'), value: 8 },
// ... more sessions
];
// Generate data for Productivity Charts
const heatmapDays = generateHeatmapData(sessions, 150, 8);
const { stats, dailyData } = useProductivityData({ days: heatmapDays });
// Map sessions to PDF Report format
const reportSessions = sessions.map((session, index) => ({
id: s${index},
itemId: '1',
date: session.date,
value: session.value,
duration: session.value * 25, // Assuming 25 min per session
}));
const reportData = [
{
id: '1',
title: 'All Activities',
progress: stats.currentStreak * 10,
total: 100,
current: stats.totalSessions,
},
];
return (
{/ Visual Analytics with Productivity Charts /}
value={stats.currentStreak}
label="Day Streak"
/>
title="Generate PDF Report"
onPress={() => setShowReport(true)}
/>
{/ PDF Report Generation /}
onClose={() => setShowReport(false)}
darkMode={false}
data={reportData}
sessions={reportSessions}
onGenerateReport={(options) => {
console.log('Generate PDF with stats:', options);
}}
/>
);
};
`
A complete productivity app combining all three libraries:
`tsx
import React, { useState } from 'react';
import { View, ScrollView, Button } from 'react-native';
import { FlipClockModal } from '@rubixscript/react-native-flip-clock';
import {
HeatmapChart,
ProgressCard,
generateHeatmapData,
useProductivityData,
} from '@rubixscript/react-native-productivity-charts';
import { PDFReportModal } from '@rubixscript/react-native-pdf-report';
const CompleteProductivityApp = () => {
const [showTimer, setShowTimer] = useState(false);
const [showReport, setShowReport] = useState(false);
// Session data from your app
const sessions = [
{ date: new Date(), value: 4, duration: 100 },
// ... more sessions
];
const heatmapDays = generateHeatmapData(sessions, 90, 5);
const { stats } = useProductivityData({ days: heatmapDays });
return (
{/ Visual Stats /}
value={stats.totalTime}
label="Focus Minutes"
/>
{/ Timer Button /}
title="Start Focus Session"
onPress={() => setShowTimer(true)}
/>
{/ Report Button /}
title="Generate PDF Report"
onPress={() => setShowReport(true)}
/>
{/ Flip Clock Modal /}
onClose={() => setShowTimer(false)}
phase="work"
theme="dark"
time={1500}
isRunning={false}
onStart={() => console.log('Timer started')}
onPause={() => console.log('Timer paused')}
/>
{/ PDF Report Modal /}
onClose={() => setShowReport(false)}
darkMode={false}
data={[{
id: '1',
title: 'Focus Sessions',
progress: stats.totalSessions,
total: 100,
current: stats.totalSessions,
}]}
sessions={sessions.map((s, i) => ({
id: s${i},`
itemId: '1',
date: s.date,
value: s.value,
duration: s.duration,
}))}
labels={{
itemLabel: 'Goal',
itemLabelPlural: 'Goals',
sessionLabel: 'Focus Session',
sessionLabelPlural: 'Focus Sessions',
reportTitle: 'Productivity Report',
}}
primaryColor="#8B5CF6"
onGenerateReport={(options) => {
// Generate PDF with charts and statistics
console.log('Report options:', options);
}}
/>
);
};
| 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 |
`typescript`
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
isPinned?: boolean; // Pinned status
[key: string]: any; // Additional custom fields
}
`typescript`
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
[key: string]: any; // Additional custom fields
}
`typescript`
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"
}
`typescript`
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:
`tsx
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
];
{...otherProps}
/>
`
`tsx`
accentColor="#4ECDC4"
{...otherProps}
/>
The library uses a flexible data model that can store any custom fields:
`tsx`
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):
`tsx
// OLD (v1.x)
import { Book, ReadingSession } from '@rubixscript/react-native-pdf-report';
const books: Book[] = [...];
const sessions: ReadingSession[] = [...];
// NEW (v2.x) - Backward compatible
import { Book, ReadingSession } from '@rubixscript/react-native-pdf-report';
const books: Book[] = [...]; // Still works!
const sessions: ReadingSession[] = [...]; // Still works!
// OR use new generic types
import { DataItem, ActivitySession } from '@rubixscript/react-native-pdf-report';
const data: DataItem[] = [...];
const sessions: ActivitySession[] = [...];
`
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: useReportForm and useReportTypes
- 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:
`typescript`
import {
ReportTypeSelector,
DateRangeSelector,
ItemSelector,
CustomTitleInput,
ReportOptionsToggles,
ModalHeader,
ModalFooter,
} from '@rubixscript/react-native-pdf-report';
`typescript
import { useReportForm, useReportTypes } from '@rubixscript/react-native-pdf-report';
// In your component
const { selectedReportType, handleGenerateReport, ... } = useReportForm({
visible,
labels,
onGenerateReport,
onClose,
});
`
`typescript``
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
- GitHub Repository
- Report Issues
- RubixScript Website
If you find this library helpful, please give it a ā on GitHub!
For questions and support, please open an issue on GitHub.