This document outlines potential improvements for the Tip Calculator React Native app based on code analysis. Items are organized by priority and category.
Current State: No unit tests or integration tests exist. The test script exits with code 0 (no-op).
Issues:
package.json:11 - Test script: "test": "echo \"No tests specified\" && exit 0".test.ts, .spec.ts, etc.)TabOneScreen.tsx:40-49 is untestedRecommendations:
Example Test Cases:
// TabOneScreen.test.tsx
describe('Calculator Logic', () => {
test('calculates 15% tip correctly', () => { ... });
test('splits bill among multiple people', () => { ... });
test('handles empty bill amount', () => { ... });
test('handles zero people count', () => { ... });
});
Current State: Multiple empty files that serve no purpose.
Issues:
components/HermesDetector.tsx - 0 bytes, never importednavigation/LinkingConfiguration.ts - 0 bytes, not used in navigation setupmetro.config.js - 0 bytes, using default configurationmigrate.js - 0 bytes, appears to be leftoverRecommendations:
HermesDetector.tsx, LinkingConfiguration.ts, migrate.jsmetro.config.js (using defaults is fine, but empty file is confusing)Current State: No error boundaries or input validation.
Issues:
TabOneScreen.tsx:75-76parseFloat(billAmount) can produce NaN without user feedbackRecommendations:
App.tsx or navigation/index.tsxExample:
// Add validation
const validateBillAmount = (value: string) => {
const num = parseFloat(value);
if (isNaN(num)) return 'Please enter a valid number';
if (num < 0) return 'Amount cannot be negative';
if (num > 999999) return 'Amount too large';
return null;
};
Current State: Minimal accessibility implementation.
Issues:
accessibilityLabel props found in TabOneScreen.tsx:79,93,143,150accessibilityHint for complex interactionsaccessibilityRole attributesRecommendations:
accessibilityLabel to all interactive elementsaccessibilityHint for non-obvious actionsaccessibilityRole for semantic meaningExample:
<Button
accessibilityLabel="Select 15 percent tip"
accessibilityHint="Double tap to set tip percentage to 15"
accessibilityRole="button"
>
<ButtonText>15%</ButtonText>
</Button>
Current State: Good use of TypeScript but some areas lack proper typing.
Issues:
TabTwoScreen.tsx:12 - Component props use inline types instead of interfaceTabTwoScreen.tsx:42 - Using index as React key (anti-pattern)onChange uses inline type annotation (TabOneScreen.tsx:103)Recommendations:
RootStackParamList, TabParamList)id field to tippingData)tsconfig.jsonExample:
interface TippingInfo {
id: string;
title?: string;
text: string;
country?: string;
}
interface TippingInfoProps {
title?: string;
text: string;
}
Current State: Local state works but could be optimized.
Issues:
TippingInfo component (TabTwoScreen.tsx:12-17) recreated on every renderRecommendations:
TippingInfo component with React.memo()Example:
// Extract to separate file
const TippingInfo = React.memo(({ title, text }: TippingInfoProps) => (
<VStack space="sm">
{title && <Heading size="md">{title}</Heading>}
<Text>{text}</Text>
</VStack>
));
// Custom hook
const useCalculator = () => {
const [billAmount, setBillAmount] = useState('');
const [tipPct, setTipPct] = useState(15);
const [numberOfPeople, setNumberOfPeople] = useState(1);
const calculations = useMemo(() => {
// calculation logic
}, [billAmount, tipPct, numberOfPeople]);
return { billAmount, setBillAmount, tipPct, setTipPct, ... };
};
Current State: Simple structure but could scale better.
Issues:
TabOneScreen.tsxRecommendations:
constants/ directory for app-wide constantshooks/ directory for custom hookshooks/useCalculator.tsdata/tippingEtiquette.tsutils/ for helper functions (formatting, calculations)Suggested Structure:
src/
├── components/
│ └── calculator/
│ ├── BillInput.tsx
│ ├── TipSelector.tsx
│ └── SplitCalculator.tsx
├── hooks/
│ └── useCalculator.ts
├── data/
│ └── tippingEtiquette.ts
├── constants/
│ └── calculator.ts
├── utils/
│ ├── calculations.ts
│ └── formatting.ts
└── screens/
└── ...
Current State: All text hardcoded in English.
Issues:
$ (TabOneScreen.tsx:122,126,158)Recommendations:
react-i18next or expo-localizationCurrent State: Basic functionality works well but missing polish.
Improvements:
Current State: Good external docs but missing inline documentation.
Issues:
Recommendations:
Example:
/**
* Calculates tip amount and total with bill splitting
* @param billAmount - The pre-tip bill amount
* @param tipPercentage - Tip percentage (0-100)
* @param numberOfPeople - Number of people splitting the bill
* @returns Object containing tip, total, and per-person amounts
*/
export const calculateBill = (
billAmount: number,
tipPercentage: number,
numberOfPeople: number
): BillCalculation => {
// ...
};
Current State: Good build setup but some improvements possible.
Recommendations:
Current State: .env properly gitignored (as of recent commit).
Issues:
.env file contains absolute path to credentialsRecommendations:
docs/Current State: Some dependencies may not be actively used.
Potential Issues:
styled-components and styled-system installed but GluestackUI is primary UI library@react-native-community/masked-view may not be needed with current navigationreact-native-web included but web support unclearRecommendations:
npx depcheckCurrent State: Some configuration inconsistencies.
Issues:
.editorconfig.nvmrc for Node versionRecommendations:
.editorconfig for editor consistency.nvmrc with Node version requirementCurrent State: Good coverage but some issues.
Issues:
/android and /ios are gitignored but exist in git historyfastlane/metadata/ is gitignored but exists in repobuild-1757206257764.apk - 83MB)Recommendations:
git rm --cached build-*.apk.apk and .aab patterns to gitignore (already done)These can be implemented quickly for immediate impact:
Overall, this is a well-structured, functional app with good documentation and deployment processes. The main areas for improvement are:
The app demonstrates good practices in: