feat: Integrate Expo mobile application into monorepo (#16)

- Add mobile/ directory with Expo React Native project
- Create API client with JWT auth and token refresh using AsyncStorage
- Implement AuthContext for login/register/logout flow
- Add screens: Login, Register, Library, Search, Settings
- Set up React Navigation with AuthStack and MainTabs
- Create packages/shared/ with shared types and utilities
- Add shared validation utilities (email, password strength)
- Update root package.json workspaces to include mobile + shared
- Add spec document docs/backend/009-expo-integration.md
This commit is contained in:
Marko (Hermes Implementer)
2026-05-29 02:50:09 +00:00
parent 332b539880
commit fa82fab44a
36 changed files with 2051 additions and 4 deletions
+91
View File
@@ -0,0 +1,91 @@
import { type ReactNode } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Alert,
} from "react-native";
import { useAuth } from "../context/AuthContext";
export default function SettingsScreen(): ReactNode {
const { state, logout } = useAuth();
const handleLogout = () => {
Alert.alert("Logout", "Are you sure you want to sign out?", [
{ text: "Cancel", style: "cancel" },
{ text: "Sign Out", style: "destructive", onPress: logout },
]);
};
return (
<View style={styles.container}>
<View style={styles.section}>
<Text style={styles.sectionTitle}>Account</Text>
<View style={styles.infoRow}>
<Text style={styles.label}>Username</Text>
<Text style={styles.value}>{state.user?.username ?? "—"}</Text>
</View>
<View style={styles.infoRow}>
<Text style={styles.label}>Email</Text>
<Text style={styles.value}>{state.user?.email ?? "—"}</Text>
</View>
</View>
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Text style={styles.logoutText}>Sign Out</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#0f0f23",
padding: 16,
},
section: {
backgroundColor: "#1a1a2e",
borderRadius: 12,
padding: 16,
marginBottom: 24,
borderWidth: 1,
borderColor: "#333",
},
sectionTitle: {
fontSize: 18,
fontWeight: "600",
color: "#fff",
marginBottom: 16,
},
infoRow: {
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: "#333",
},
label: {
fontSize: 14,
color: "#888",
},
value: {
fontSize: 14,
color: "#fff",
fontWeight: "500",
},
logoutButton: {
backgroundColor: "rgba(255, 69, 58, 0.15)",
borderRadius: 8,
padding: 16,
alignItems: "center",
borderWidth: 1,
borderColor: "rgba(255, 69, 58, 0.3)",
},
logoutText: {
color: "#ff453a",
fontSize: 16,
fontWeight: "600",
},
});