Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions apps/mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="false" />
Comment on lines +1 to +4

<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2 changes: 2 additions & 0 deletions apps/mobile/ios/DevCard/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NFCReaderUsageDescription</key>
<string>DevCard needs NFC to write your profile link to your physical card.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"react-dom": "^19.1.0",
"react-native": "0.81.5",
"react-native-gesture-handler": "^2.28.0",
"react-native-nfc-manager": "^3.14.12",
"react-native-qrcode-svg": "^6.3.0",
"react-native-reanimated": "^4.1.7",
"react-native-safe-area-context": "^5.6.2",
Expand Down
65 changes: 63 additions & 2 deletions apps/mobile/src/screens/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import { useNavigation } from '@react-navigation/native';
import { COLORS, SPACING, FONT_SIZE, BORDER_RADIUS } from '../theme/tokens';
import { useAuth } from '../context/AuthContext';
import { API_BASE_URL } from '../config';

import { useNavigation } from '@react-navigation/native';
import NfcManager, { Ndef, NfcTech } from 'react-native-nfc-manager';

export default function SettingsScreen() {
const navigation = useNavigation<any>();
Expand All @@ -27,6 +26,51 @@ export default function SettingsScreen() {
const [role, setRole] = useState(user?.role || '');
const [company, setCompany] = useState(user?.company || '');
const [saving, setSaving] = useState(false);
const [writingNfc, setWritingNfc] = useState(false);

const writeNfcTag = async () => {
try {
const supported = await NfcManager.isSupported();
if (!supported) {
Alert.alert('Error', 'NFC is not supported on this device');
return;
}

setWritingNfc(true);
await NfcManager.start();

const res = await fetch(`${API_BASE_URL}/api/nfc/payload`, {
headers: { Authorization: `Bearer ${token}` },
});

if (!res.ok) {
throw new Error('Failed to fetch NFC payload');
}

const data = await res.json();
if (!data.payload) {
throw new Error('Invalid payload received');
}

Alert.alert('NFC', 'Hold your phone near an NFC tag');
await NfcManager.requestTechnology(NfcTech.Ndef);

const bytes = Ndef.encodeMessage([
Ndef.uriRecord(data.payload),
]);

if (bytes) {
await NfcManager.ndefHandler.writeNdefMessage(bytes);
Alert.alert('Success', 'Successfully wrote DevCard to NFC tag!');
}
Comment on lines +58 to +65
} catch (ex: any) {
console.warn(ex);
Alert.alert('Error', ex.message || 'Failed to write NFC tag. Please try again.');
} finally {
NfcManager.cancelTechnologyRequest();
setWritingNfc(false);
}
Comment on lines +70 to +72
};

const handleSave = async () => {
setSaving(true);
Expand Down Expand Up @@ -118,6 +162,23 @@ export default function SettingsScreen() {
</TouchableOpacity>
</View>

{/* Physical Cards */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionSubtitle}>Physical Cards</Text>
<TouchableOpacity
style={styles.settingRow}
onPress={writeNfcTag}
disabled={writingNfc}>
<View style={styles.settingRowLeft}>
<Text style={styles.settingRowIcon}>💳</Text>
<Text style={styles.settingRowText}>
{writingNfc ? 'Writing to NFC...' : 'Write to NFC Card'}
</Text>
</View>
<Text style={styles.settingRowArrow}>→</Text>
</TouchableOpacity>
Comment on lines +168 to +179
</View>

<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Text style={styles.logoutButtonText}>Log Out</Text>
</TouchableOpacity>
Expand Down