Prepare for production build

- Downgrade react-native to 0.81.5 (matches Expo SDK 54)
- Downgrade react to 19.1.0 and related @react-native packages
- Disable New Architecture (react-native-nfc-manager untested)
- Add expo install/doctor exclusions for version-locked deps
- Configure babel to strip console.log/warn in production
- Add logger utility for development-only logging
- Add component and data module exports

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael
2026-01-23 10:10:30 -08:00
parent 63d815c1c2
commit bb6a9bbc22
9 changed files with 1428 additions and 2455 deletions

1
src/components/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './scan';

View File

@@ -0,0 +1,177 @@
/**
* Animated NFC Scan Indicator
*
* Shows pulsing concentric rings during NFC scanning
*/
import React, {useEffect, useRef} from 'react';
import {View, StyleSheet, Animated, Easing} from 'react-native';
import {DTColors} from '../../theme';
interface ScanAnimationProps {
/** Whether the animation is active */
isActive: boolean;
/** Color for the rings (defaults to modeNormal/cyan) */
color?: string;
/** Size of the component */
size?: number;
}
export function ScanAnimation({
isActive,
color = DTColors.modeNormal,
size = 200,
}: ScanAnimationProps) {
// Animation values for each ring
const ring1 = useRef(new Animated.Value(0)).current;
const ring2 = useRef(new Animated.Value(0)).current;
const ring3 = useRef(new Animated.Value(0)).current;
useEffect(() => {
if (!isActive) {
// Reset animations when not active
ring1.setValue(0);
ring2.setValue(0);
ring3.setValue(0);
return;
}
// Create staggered pulsing animations
const createPulse = (animatedValue: Animated.Value, delay: number) => {
return Animated.loop(
Animated.sequence([
Animated.delay(delay),
Animated.timing(animatedValue, {
toValue: 1,
duration: 2000,
easing: Easing.out(Easing.ease),
useNativeDriver: true,
}),
Animated.timing(animatedValue, {
toValue: 0,
duration: 0,
useNativeDriver: true,
}),
]),
);
};
const animation1 = createPulse(ring1, 0);
const animation2 = createPulse(ring2, 666);
const animation3 = createPulse(ring3, 1333);
animation1.start();
animation2.start();
animation3.start();
return () => {
animation1.stop();
animation2.stop();
animation3.stop();
};
}, [isActive, ring1, ring2, ring3]);
const createRingStyle = (animatedValue: Animated.Value) => {
const scale = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0.3, 1],
});
const opacity = animatedValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0.8, 0.4, 0],
});
return {
transform: [{scale}],
opacity,
borderColor: color,
};
};
return (
<View style={[styles.container, {width: size, height: size}]}>
{/* Pulsing rings */}
<Animated.View
style={[
styles.ring,
{width: size, height: size, borderRadius: size / 2},
createRingStyle(ring1),
]}
/>
<Animated.View
style={[
styles.ring,
{width: size, height: size, borderRadius: size / 2},
createRingStyle(ring2),
]}
/>
<Animated.View
style={[
styles.ring,
{width: size, height: size, borderRadius: size / 2},
createRingStyle(ring3),
]}
/>
{/* Center dot */}
<View style={[styles.centerDot, {backgroundColor: color}]} />
{/* NFC icon representation */}
<View style={styles.nfcIcon}>
<View style={[styles.nfcArc, styles.nfcArc1, {borderColor: color}]} />
<View style={[styles.nfcArc, styles.nfcArc2, {borderColor: color}]} />
<View style={[styles.nfcArc, styles.nfcArc3, {borderColor: color}]} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
},
ring: {
position: 'absolute',
borderWidth: 2,
},
centerDot: {
width: 12,
height: 12,
borderRadius: 6,
position: 'absolute',
},
nfcIcon: {
position: 'absolute',
width: 60,
height: 60,
justifyContent: 'center',
alignItems: 'flex-start',
paddingLeft: 10,
},
nfcArc: {
position: 'absolute',
borderWidth: 2,
borderLeftWidth: 0,
borderTopWidth: 0,
borderBottomWidth: 0,
borderTopRightRadius: 50,
borderBottomRightRadius: 50,
},
nfcArc1: {
width: 15,
height: 20,
left: 20,
},
nfcArc2: {
width: 25,
height: 34,
left: 20,
},
nfcArc3: {
width: 35,
height: 48,
left: 20,
},
});

View File

@@ -0,0 +1 @@
export {ScanAnimation} from './ScanAnimation';

209
src/data/chipInfo.ts Normal file
View File

@@ -0,0 +1,209 @@
/**
* Educational Chip Information
*
* Provides user-friendly explanations of NFC chip types
*/
import {ChipType, ChipFamily} from '../types/detection';
export interface ChipInfo {
/** Brief description of the chip */
description: string;
/** What this chip is commonly used for */
commonUses: string[];
/** Key capabilities */
capabilities: string[];
/** Security level indicator */
securityLevel: 'low' | 'medium' | 'high';
/** Memory capacity description */
memoryNote?: string;
}
export const CHIP_FAMILY_INFO: Record<ChipFamily, string> = {
[ChipFamily.NTAG]:
'NTAG chips are NXP-branded NFC Type 2 tags designed for consumer applications like sharing URLs, contact info, and app launches. This family includes MIFARE Ultralight variants.',
[ChipFamily.MIFARE_CLASSIC]:
'MIFARE Classic is a legacy contactless smart card technology commonly used in access control and transit systems.',
[ChipFamily.MIFARE_DESFIRE]:
'MIFARE DESFire is a high-security contactless smart card with advanced encryption, used in transit, access control, and payment applications.',
[ChipFamily.MIFARE_PLUS]:
'MIFARE Plus offers enhanced security over Classic, with optional AES encryption while maintaining backward compatibility.',
[ChipFamily.ISO15693]:
'ISO 15693 (NFC-V) tags operate at longer read distances than standard NFC, commonly used in library systems and industrial applications.',
[ChipFamily.JAVACARD]:
'JavaCard chips are programmable secure elements that can run multiple cryptographic applications, used in identity and payment systems.',
[ChipFamily.UNKNOWN]:
'This chip type could not be fully identified. It may be a less common or proprietary tag.',
};
export const CHIP_INFO: Partial<Record<ChipType, ChipInfo>> = {
// NTAG family
[ChipType.NTAG213]: {
description:
'Entry-level NTAG with 144 bytes of user memory, ideal for simple NFC applications.',
commonUses: ['URL sharing', 'Smart posters', 'Product authentication'],
capabilities: ['NFC Forum Type 2', 'Password protection', 'Counter function'],
securityLevel: 'low',
memoryNote: '144 bytes user memory',
},
[ChipType.NTAG215]: {
description:
'Mid-range NTAG commonly used for amiibo and similar applications.',
commonUses: ['Gaming (amiibo)', 'Access tokens', 'Loyalty cards'],
capabilities: ['NFC Forum Type 2', 'Password protection', 'Counter function'],
securityLevel: 'low',
memoryNote: '504 bytes user memory',
},
[ChipType.NTAG216]: {
description:
'Largest standard NTAG with 888 bytes, popular for implants and data storage.',
commonUses: ['NFC implants', 'vCards', 'Complex data storage'],
capabilities: ['NFC Forum Type 2', 'Password protection', 'Counter function'],
securityLevel: 'low',
memoryNote: '888 bytes user memory',
},
[ChipType.NTAG_I2C_1K]: {
description:
'NTAG with I2C interface allowing microcontroller communication alongside NFC.',
commonUses: ['IoT devices', 'Energy harvesting', 'Field detection'],
capabilities: ['NFC + I2C interface', 'Energy harvesting', 'Field detection'],
securityLevel: 'low',
memoryNote: '888 bytes user memory',
},
[ChipType.NTAG_I2C_2K]: {
description:
'Extended memory NTAG I2C with 1904 bytes and dual interface capability.',
commonUses: ['IoT devices', 'Data logging', 'Connected products'],
capabilities: ['NFC + I2C interface', 'Energy harvesting', 'SRAM buffer'],
securityLevel: 'low',
memoryNote: '1904 bytes user memory',
},
// MIFARE Classic
[ChipType.MIFARE_CLASSIC_1K]: {
description:
'Classic 1K is the most common access card, using Crypto-1 encryption (now considered weak).',
commonUses: ['Building access', 'Hotel keys', 'Transit cards'],
capabilities: ['16 sectors', 'Key-based authentication', 'Sector permissions'],
securityLevel: 'low',
memoryNote: '1KB (752 bytes usable)',
},
[ChipType.MIFARE_CLASSIC_4K]: {
description:
'Extended capacity Classic card with 4KB memory, same security as 1K.',
commonUses: ['Building access', 'Parking systems', 'Legacy transit'],
capabilities: ['40 sectors', 'Key-based authentication', 'Sector permissions'],
securityLevel: 'low',
memoryNote: '4KB (3440 bytes usable)',
},
// DESFire
[ChipType.DESFIRE_EV1]: {
description:
'First generation DESFire with AES-128 encryption for secure applications.',
commonUses: ['Secure access control', 'Transit systems', 'Campus cards'],
capabilities: ['AES-128/3DES', 'Multiple applications', 'Flexible file system'],
securityLevel: 'high',
memoryNote: '2KB, 4KB, or 8KB options',
},
[ChipType.DESFIRE_EV2]: {
description:
'Enhanced DESFire with improved security features and proximity check.',
commonUses: ['High-security access', 'Payment cards', 'Government ID'],
capabilities: [
'AES-128',
'Proximity check',
'Transaction MAC',
'Virtual Card Architecture',
],
securityLevel: 'high',
memoryNote: '2KB, 4KB, 8KB, 16KB, or 32KB options',
},
[ChipType.DESFIRE_EV3]: {
description:
'Latest DESFire generation with enhanced cryptography and secure messaging.',
commonUses: ['Transit', 'Access control', 'Micropayment', 'Loyalty'],
capabilities: [
'AES-128',
'Secure Dynamic Messaging',
'Transaction MAC',
'Sun authentication',
],
securityLevel: 'high',
memoryNote: '2KB, 4KB, 8KB, 16KB, or 32KB options',
},
// ISO 15693
[ChipType.SLIX]: {
description:
'Basic ISO 15693 (NFC-V) tag with longer read range than standard NFC.',
commonUses: ['Library systems', 'Inventory tracking', 'Industrial tags'],
capabilities: ['Long range', 'Anti-collision', 'AFI/DSFID support'],
securityLevel: 'low',
memoryNote: '128 bytes',
},
[ChipType.SLIX2]: {
description:
'Enhanced SLIX with more memory and improved security features.',
commonUses: ['Asset tracking', 'Brand protection', 'Library systems'],
capabilities: ['Long range', 'Password protection', 'Originality signature'],
securityLevel: 'medium',
memoryNote: '316 bytes',
},
[ChipType.ICODE_DNA]: {
description:
'Cryptographically secured NFC-V tag for brand protection and authentication.',
commonUses: ['Brand protection', 'Anti-counterfeiting', 'Secure supply chain'],
capabilities: [
'Cryptographic authentication',
'Rolling code',
'Originality check',
],
securityLevel: 'high',
memoryNote: '256 bytes',
},
// JavaCard
[ChipType.JCOP4]: {
description:
'Programmable secure element supporting Java Card applets for cryptographic applications.',
commonUses: ['Identity cards', 'Digital signatures', 'Secure authentication'],
capabilities: [
'Java Card OS',
'Multiple applets',
'FIDO2/WebAuthn',
'OpenPGP',
],
securityLevel: 'high',
},
};
/**
* Get educational info for a chip type
*/
export function getChipInfo(chipType: ChipType): ChipInfo | undefined {
return CHIP_INFO[chipType];
}
/**
* Get family description for a chip family
*/
export function getChipFamilyInfo(family: ChipFamily): string {
return CHIP_FAMILY_INFO[family];
}
/**
* Get security level description
*/
export function getSecurityLevelDescription(
level: 'low' | 'medium' | 'high',
): string {
switch (level) {
case 'low':
return 'Basic security - data can be read/written with standard tools';
case 'medium':
return 'Moderate security - some protection against casual attacks';
case 'high':
return 'Strong security - cryptographic protection against cloning';
}
}

2
src/data/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './products';
export * from './chipInfo';

View File

@@ -3,8 +3,6 @@
* All console.log statements in the app should use this logger
*/
/* eslint-disable no-console */
const isDev = __DEV__;
export const logger = {