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:
2
app.json
2
app.json
@@ -6,7 +6,7 @@
|
|||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"userInterfaceStyle": "dark",
|
"userInterfaceStyle": "dark",
|
||||||
"newArchEnabled": true,
|
"newArchEnabled": false,
|
||||||
"splash": {
|
"splash": {
|
||||||
"backgroundColor": "#000000"
|
"backgroundColor": "#000000"
|
||||||
},
|
},
|
||||||
|
|||||||
3451
package-lock.json
generated
3451
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@@ -17,12 +17,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/native": "^7.1.27",
|
"@react-navigation/native": "^7.1.27",
|
||||||
"@react-navigation/native-stack": "^7.9.1",
|
"@react-navigation/native-stack": "^7.9.1",
|
||||||
"babel-preset-expo": "^54.0.9",
|
"babel-preset-expo": "~54.0.10",
|
||||||
"expo": "^54.0.31",
|
"expo": "~54.0.32",
|
||||||
"expo-dev-client": "^6.0.20",
|
"expo-dev-client": "^6.0.20",
|
||||||
"expo-status-bar": "^3.0.9",
|
"expo-status-bar": "^3.0.9",
|
||||||
"react": "19.2.0",
|
"react": "19.1.0",
|
||||||
"react-native": "0.83.1",
|
"react-native": "0.81.5",
|
||||||
"react-native-nfc-manager": "^3.17.2",
|
"react-native-nfc-manager": "^3.17.2",
|
||||||
"react-native-paper": "^5.14.5",
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-safe-area-context": "~5.6.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
@@ -33,20 +33,40 @@
|
|||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.25.3",
|
"@babel/preset-env": "^7.25.3",
|
||||||
"@babel/runtime": "^7.25.0",
|
"@babel/runtime": "^7.25.0",
|
||||||
"@react-native/babel-preset": "0.83.1",
|
"@react-native/babel-preset": "0.81.1",
|
||||||
"@react-native/eslint-config": "0.83.1",
|
"@react-native/eslint-config": "0.81.1",
|
||||||
"@types/jest": "^29.5.13",
|
"@types/jest": "^29.5.13",
|
||||||
"@types/react": "^19.2.0",
|
"@types/react": "~19.1.0",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
"@types/react-test-renderer": "^19.1.0",
|
"@types/react-test-renderer": "~19.1.0",
|
||||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
"jest": "^29.6.3",
|
"jest": "^29.6.3",
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
"react-test-renderer": "19.2.0",
|
"react-test-renderer": "19.1.0",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"expo": {
|
||||||
|
"install": {
|
||||||
|
"exclude": [
|
||||||
|
"react",
|
||||||
|
"react-native",
|
||||||
|
"@types/react",
|
||||||
|
"@react-native/babel-preset",
|
||||||
|
"@react-native/eslint-config",
|
||||||
|
"react-test-renderer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"doctor": {
|
||||||
|
"reactNativeDirectoryCheck": {
|
||||||
|
"exclude": [
|
||||||
|
"react-native-nfc-manager",
|
||||||
|
"react-native-vector-icons"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/components/index.ts
Normal file
1
src/components/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './scan';
|
||||||
177
src/components/scan/ScanAnimation.tsx
Normal file
177
src/components/scan/ScanAnimation.tsx
Normal 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,
|
||||||
|
},
|
||||||
|
});
|
||||||
1
src/components/scan/index.ts
Normal file
1
src/components/scan/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {ScanAnimation} from './ScanAnimation';
|
||||||
209
src/data/chipInfo.ts
Normal file
209
src/data/chipInfo.ts
Normal 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
2
src/data/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './products';
|
||||||
|
export * from './chipInfo';
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
* All console.log statements in the app should use this logger
|
* All console.log statements in the app should use this logger
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-console */
|
|
||||||
|
|
||||||
const isDev = __DEV__;
|
const isDev = __DEV__;
|
||||||
|
|
||||||
export const logger = {
|
export const logger = {
|
||||||
|
|||||||
Reference in New Issue
Block a user