summaryrefslogtreecommitdiff
path: root/apps/mobile/app/(tabs)/settings.tsx
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-18 17:44:50 +0000
committerGitHub <noreply@github.com>2026-01-18 17:44:50 +0000
commit869f21ee2efaefed6a5aa4fbd417c25df8dec02a (patch)
tree2a90820ac817173e5b7154e0ba5e4f5d095f9613 /apps/mobile/app/(tabs)/settings.tsx
parent219bca168508e1ea5e91e8a9ce98338afeddfbd2 (diff)
downloadsoryu-869f21ee2efaefed6a5aa4fbd417c25df8dec02a.tar.gz
soryu-869f21ee2efaefed6a5aa4fbd417c25df8dec02a.zip
Add React Native mobile app for Makima (#3)
* [WIP] Heartbeat checkpoint - 2026-01-18 02:58:27 UTC * feat(mobile): complete mobile app integration and verification - Add ThemeColors type export to Colors.ts for type safety - Export SUPABASE_URL from supabase.ts and use environment variables - Update .env.example with correct default URLs - Add comprehensive README.md with setup instructions Verified: - TypeScript compiles without errors - App exports successfully for iOS and Android - All screens accessible (login, dashboard, tasks, settings, task detail) - Auth flow working with Zustand store and Supabase Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'apps/mobile/app/(tabs)/settings.tsx')
-rw-r--r--apps/mobile/app/(tabs)/settings.tsx248
1 files changed, 248 insertions, 0 deletions
diff --git a/apps/mobile/app/(tabs)/settings.tsx b/apps/mobile/app/(tabs)/settings.tsx
new file mode 100644
index 0000000..f90e86c
--- /dev/null
+++ b/apps/mobile/app/(tabs)/settings.tsx
@@ -0,0 +1,248 @@
+import React, { useCallback } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ ScrollView,
+ TouchableOpacity,
+ useColorScheme,
+ Alert,
+ Linking,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { Colors } from '../../constants/Colors';
+import { getEnvironment } from '../../lib/api';
+import { useAuthStore } from '../../stores/authStore';
+import { config } from '../../lib/config';
+
+interface SettingsRowProps {
+ icon: keyof typeof Ionicons.glyphMap;
+ title: string;
+ value?: string;
+ onPress?: () => void;
+ showChevron?: boolean;
+}
+
+function SettingsRow({
+ icon,
+ title,
+ value,
+ onPress,
+ showChevron = true,
+}: SettingsRowProps) {
+ const colorScheme = useColorScheme() ?? 'light';
+ const colors = Colors[colorScheme];
+
+ const content = (
+ <View style={[styles.row, { borderBottomColor: colors.border }]}>
+ <View style={[styles.iconContainer, { backgroundColor: colors.tint + '20' }]}>
+ <Ionicons name={icon} size={20} color={colors.tint} />
+ </View>
+ <Text style={[styles.rowTitle, { color: colors.text }]}>{title}</Text>
+ {value && (
+ <Text style={[styles.rowValue, { color: colors.secondaryText }]}>
+ {value}
+ </Text>
+ )}
+ {showChevron && onPress && (
+ <Ionicons name="chevron-forward" size={20} color={colors.secondaryText} />
+ )}
+ </View>
+ );
+
+ if (onPress) {
+ return (
+ <TouchableOpacity onPress={onPress} activeOpacity={0.7}>
+ {content}
+ </TouchableOpacity>
+ );
+ }
+
+ return content;
+}
+
+export default function SettingsScreen() {
+ const colorScheme = useColorScheme() ?? 'light';
+ const colors = Colors[colorScheme];
+ const signOut = useAuthStore((state) => state.signOut);
+ const isLoading = useAuthStore((state) => state.isLoading);
+
+ const environment = getEnvironment();
+
+ const handleSignOut = useCallback(() => {
+ Alert.alert(
+ 'Sign Out',
+ 'Are you sure you want to sign out?',
+ [
+ { text: 'Cancel', style: 'cancel' },
+ {
+ text: 'Sign Out',
+ style: 'destructive',
+ onPress: () => signOut(),
+ },
+ ]
+ );
+ }, [signOut]);
+
+ const handleOpenUrl = useCallback((url: string) => {
+ Linking.openURL(url);
+ }, []);
+
+ return (
+ <ScrollView
+ style={[styles.container, { backgroundColor: colors.background }]}
+ contentContainerStyle={styles.content}
+ >
+ {/* Account Section */}
+ <View style={styles.section}>
+ <Text style={[styles.sectionTitle, { color: colors.secondaryText }]}>
+ Account
+ </Text>
+ <View style={[styles.card, { backgroundColor: colors.card }]}>
+ <SettingsRow
+ icon="person-outline"
+ title="Profile"
+ onPress={() => {}}
+ />
+ <SettingsRow
+ icon="notifications-outline"
+ title="Notifications"
+ onPress={() => {}}
+ />
+ <SettingsRow
+ icon="key-outline"
+ title="API Key"
+ onPress={() => {}}
+ />
+ </View>
+ </View>
+
+ {/* App Section */}
+ <View style={styles.section}>
+ <Text style={[styles.sectionTitle, { color: colors.secondaryText }]}>
+ App
+ </Text>
+ <View style={[styles.card, { backgroundColor: colors.card }]}>
+ <SettingsRow
+ icon="color-palette-outline"
+ title="Appearance"
+ value={colorScheme === 'dark' ? 'Dark' : 'Light'}
+ showChevron={false}
+ />
+ <SettingsRow
+ icon="server-outline"
+ title="Environment"
+ value={environment === 'local' ? 'Local' : 'Production'}
+ showChevron={false}
+ />
+ </View>
+ </View>
+
+ {/* Support Section */}
+ <View style={styles.section}>
+ <Text style={[styles.sectionTitle, { color: colors.secondaryText }]}>
+ Support
+ </Text>
+ <View style={[styles.card, { backgroundColor: colors.card }]}>
+ <SettingsRow
+ icon="help-circle-outline"
+ title="Help & Support"
+ onPress={() => handleOpenUrl(config.supportUrl)}
+ />
+ <SettingsRow
+ icon="document-text-outline"
+ title="Terms of Service"
+ onPress={() => handleOpenUrl(config.termsOfServiceUrl)}
+ />
+ <SettingsRow
+ icon="shield-checkmark-outline"
+ title="Privacy Policy"
+ onPress={() => handleOpenUrl(config.privacyPolicyUrl)}
+ />
+ </View>
+ </View>
+
+ {/* Sign Out */}
+ <View style={styles.section}>
+ <TouchableOpacity
+ style={[styles.signOutButton, { backgroundColor: colors.card }]}
+ onPress={handleSignOut}
+ activeOpacity={0.7}
+ disabled={isLoading}
+ >
+ <Ionicons name="log-out-outline" size={20} color="#ef4444" />
+ <Text style={styles.signOutText}>Sign Out</Text>
+ </TouchableOpacity>
+ </View>
+
+ {/* Version */}
+ <Text style={[styles.version, { color: colors.secondaryText }]}>
+ Makima Mobile v1.0.0
+ </Text>
+ </ScrollView>
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ content: {
+ padding: 16,
+ gap: 24,
+ },
+ section: {
+ gap: 8,
+ },
+ sectionTitle: {
+ fontSize: 13,
+ fontWeight: '600',
+ textTransform: 'uppercase',
+ letterSpacing: 0.5,
+ marginLeft: 16,
+ },
+ card: {
+ borderRadius: 12,
+ overflow: 'hidden',
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ padding: 12,
+ paddingHorizontal: 16,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ gap: 12,
+ },
+ iconContainer: {
+ width: 32,
+ height: 32,
+ borderRadius: 8,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ rowTitle: {
+ flex: 1,
+ fontSize: 16,
+ },
+ rowValue: {
+ fontSize: 14,
+ },
+ signOutButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 16,
+ borderRadius: 12,
+ gap: 8,
+ },
+ signOutText: {
+ fontSize: 16,
+ fontWeight: '600',
+ color: '#ef4444',
+ },
+ version: {
+ textAlign: 'center',
+ fontSize: 12,
+ marginTop: 8,
+ },
+});