@nextsparkjs/mobile 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +339 -0
- package/dist/api/client.d.ts +102 -0
- package/dist/api/client.js +189 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/client.types.d.ts +39 -0
- package/dist/api/client.types.js +12 -0
- package/dist/api/client.types.js.map +1 -0
- package/dist/api/core/auth.d.ts +26 -0
- package/dist/api/core/auth.js +52 -0
- package/dist/api/core/auth.js.map +1 -0
- package/dist/api/core/index.d.ts +4 -0
- package/dist/api/core/index.js +5 -0
- package/dist/api/core/index.js.map +1 -0
- package/dist/api/core/teams.d.ts +20 -0
- package/dist/api/core/teams.js +19 -0
- package/dist/api/core/teams.js.map +1 -0
- package/dist/api/core/types.d.ts +58 -0
- package/dist/api/core/types.js +1 -0
- package/dist/api/core/types.js.map +1 -0
- package/dist/api/core/users.d.ts +43 -0
- package/dist/api/core/users.js +41 -0
- package/dist/api/core/users.js.map +1 -0
- package/dist/api/entities/factory.d.ts +43 -0
- package/dist/api/entities/factory.js +31 -0
- package/dist/api/entities/factory.js.map +1 -0
- package/dist/api/entities/index.d.ts +3 -0
- package/dist/api/entities/index.js +3 -0
- package/dist/api/entities/index.js.map +1 -0
- package/dist/api/entities/types.d.ts +32 -0
- package/dist/api/entities/types.js +1 -0
- package/dist/api/entities/types.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.js +15 -0
- package/dist/api/index.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/alert.d.ts +34 -0
- package/dist/lib/alert.js +73 -0
- package/dist/lib/alert.js.map +1 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +10 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/storage.d.ts +1 -0
- package/dist/lib/storage.js +29 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/providers/AuthProvider.d.ts +21 -0
- package/dist/providers/AuthProvider.js +113 -0
- package/dist/providers/AuthProvider.js.map +1 -0
- package/dist/providers/QueryProvider.d.ts +11 -0
- package/dist/providers/QueryProvider.js +23 -0
- package/dist/providers/QueryProvider.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/storage-BaRppHUz.d.ts +22 -0
- package/package.json +99 -0
- package/templates/app/(app)/_layout.tsx +216 -0
- package/templates/app/(app)/customer/[id].tsx +68 -0
- package/templates/app/(app)/customer/create.tsx +24 -0
- package/templates/app/(app)/customers.tsx +164 -0
- package/templates/app/(app)/index.tsx +310 -0
- package/templates/app/(app)/notifications.tsx +242 -0
- package/templates/app/(app)/profile.tsx +254 -0
- package/templates/app/(app)/settings.tsx +241 -0
- package/templates/app/(app)/task/[id].tsx +70 -0
- package/templates/app/(app)/task/create.tsx +24 -0
- package/templates/app/(app)/tasks.tsx +164 -0
- package/templates/app/_layout.tsx +54 -0
- package/templates/app/index.tsx +35 -0
- package/templates/app/login.tsx +179 -0
- package/templates/app.config.ts +39 -0
- package/templates/babel.config.js +9 -0
- package/templates/eas.json +18 -0
- package/templates/jest.config.js +12 -0
- package/templates/metro.config.js +23 -0
- package/templates/package.json.template +52 -0
- package/templates/src/components/entities/customers/CustomerCard.tsx +59 -0
- package/templates/src/components/entities/customers/CustomerForm.tsx +194 -0
- package/templates/src/components/entities/customers/index.ts +6 -0
- package/templates/src/components/entities/index.ts +9 -0
- package/templates/src/components/entities/tasks/TaskCard.tsx +89 -0
- package/templates/src/components/entities/tasks/TaskForm.tsx +231 -0
- package/templates/src/components/entities/tasks/index.ts +6 -0
- package/templates/src/components/features/index.ts +6 -0
- package/templates/src/components/navigation/BottomTabBar.tsx +80 -0
- package/templates/src/components/navigation/CreateSheet.tsx +108 -0
- package/templates/src/components/navigation/MoreSheet.tsx +403 -0
- package/templates/src/components/navigation/TopBar.tsx +74 -0
- package/templates/src/components/navigation/index.ts +8 -0
- package/templates/src/components/ui/index.ts +89 -0
- package/templates/src/components/ui/text.tsx +64 -0
- package/templates/src/config/api.config.ts +26 -0
- package/templates/src/config/app.config.ts +15 -0
- package/templates/src/config/hooks.ts +58 -0
- package/templates/src/config/permissions.config.ts +119 -0
- package/templates/src/constants/colors.ts +55 -0
- package/templates/src/data/notifications.mock.json +100 -0
- package/templates/src/entities/customers/api.ts +10 -0
- package/templates/src/entities/customers/constants.internal.ts +6 -0
- package/templates/src/entities/customers/constants.ts +14 -0
- package/templates/src/entities/customers/index.ts +9 -0
- package/templates/src/entities/customers/mutations.ts +58 -0
- package/templates/src/entities/customers/queries.ts +40 -0
- package/templates/src/entities/customers/types.ts +43 -0
- package/templates/src/entities/index.ts +8 -0
- package/templates/src/entities/tasks/api.ts +10 -0
- package/templates/src/entities/tasks/constants.internal.ts +6 -0
- package/templates/src/entities/tasks/constants.ts +39 -0
- package/templates/src/entities/tasks/index.ts +9 -0
- package/templates/src/entities/tasks/mutations.ts +108 -0
- package/templates/src/entities/tasks/queries.ts +42 -0
- package/templates/src/entities/tasks/types.ts +52 -0
- package/templates/src/hooks/useCustomers.ts +17 -0
- package/templates/src/hooks/useTasks.ts +18 -0
- package/templates/src/lib/utils.ts +10 -0
- package/templates/src/styles/globals.css +103 -0
- package/templates/src/types/index.ts +45 -0
- package/templates/tailwind.config.js +108 -0
- package/templates/tsconfig.json +15 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notifications Screen
|
|
3
|
+
* Displays mock notifications data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useMemo } from "react";
|
|
7
|
+
import { View, FlatList, Pressable, RefreshControl } from "react-native";
|
|
8
|
+
import { router } from "expo-router";
|
|
9
|
+
import { Text, Card, Badge, Separator, Button } from "@/src/components/ui";
|
|
10
|
+
import { cn } from "@/src/lib/utils";
|
|
11
|
+
import notificationsData from "@/src/data/notifications.mock.json";
|
|
12
|
+
|
|
13
|
+
interface Notification {
|
|
14
|
+
id: string;
|
|
15
|
+
type: string;
|
|
16
|
+
title: string;
|
|
17
|
+
message: string;
|
|
18
|
+
read: boolean;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
data: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const NOTIFICATION_ICONS: Record<string, string> = {
|
|
24
|
+
task_assigned: "📋",
|
|
25
|
+
task_completed: "✅",
|
|
26
|
+
task_due_soon: "⏰",
|
|
27
|
+
task_overdue: "🚨",
|
|
28
|
+
task_comment: "💬",
|
|
29
|
+
customer_added: "👤",
|
|
30
|
+
team_invite: "👥",
|
|
31
|
+
system: "⚙️",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const NOTIFICATION_COLORS: Record<string, string> = {
|
|
35
|
+
task_assigned: "bg-blue-100",
|
|
36
|
+
task_completed: "bg-green-100",
|
|
37
|
+
task_due_soon: "bg-amber-100",
|
|
38
|
+
task_overdue: "bg-red-100",
|
|
39
|
+
task_comment: "bg-purple-100",
|
|
40
|
+
customer_added: "bg-cyan-100",
|
|
41
|
+
team_invite: "bg-indigo-100",
|
|
42
|
+
system: "bg-gray-100",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function formatTimeAgo(dateString: string): string {
|
|
46
|
+
const date = new Date(dateString);
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const diffMs = now.getTime() - date.getTime();
|
|
49
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
50
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
51
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
52
|
+
|
|
53
|
+
if (diffMins < 60) {
|
|
54
|
+
return `hace ${diffMins} min`;
|
|
55
|
+
} else if (diffHours < 24) {
|
|
56
|
+
return `hace ${diffHours}h`;
|
|
57
|
+
} else if (diffDays === 1) {
|
|
58
|
+
return "ayer";
|
|
59
|
+
} else if (diffDays < 7) {
|
|
60
|
+
return `hace ${diffDays} días`;
|
|
61
|
+
} else {
|
|
62
|
+
return date.toLocaleDateString("es-ES", {
|
|
63
|
+
day: "numeric",
|
|
64
|
+
month: "short",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function NotificationItem({
|
|
70
|
+
notification,
|
|
71
|
+
onPress,
|
|
72
|
+
onMarkAsRead,
|
|
73
|
+
}: {
|
|
74
|
+
notification: Notification;
|
|
75
|
+
onPress: () => void;
|
|
76
|
+
onMarkAsRead: () => void;
|
|
77
|
+
}) {
|
|
78
|
+
const icon = NOTIFICATION_ICONS[notification.type] || "🔔";
|
|
79
|
+
const bgColor = NOTIFICATION_COLORS[notification.type] || "bg-gray-100";
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Pressable
|
|
83
|
+
onPress={onPress}
|
|
84
|
+
onLongPress={onMarkAsRead}
|
|
85
|
+
className={cn(
|
|
86
|
+
"mx-4 my-1 rounded-xl border bg-card p-4",
|
|
87
|
+
notification.read ? "border-border opacity-70" : "border-primary/20"
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
90
|
+
<View className="flex-row gap-3">
|
|
91
|
+
{/* Icon */}
|
|
92
|
+
<View
|
|
93
|
+
className={cn(
|
|
94
|
+
"h-10 w-10 items-center justify-center rounded-full",
|
|
95
|
+
bgColor
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
<Text className="text-lg">{icon}</Text>
|
|
99
|
+
</View>
|
|
100
|
+
|
|
101
|
+
{/* Content */}
|
|
102
|
+
<View className="flex-1">
|
|
103
|
+
<View className="flex-row items-start justify-between">
|
|
104
|
+
<Text
|
|
105
|
+
variant="subheading"
|
|
106
|
+
className={cn("flex-1", !notification.read && "font-bold")}
|
|
107
|
+
numberOfLines={1}
|
|
108
|
+
>
|
|
109
|
+
{notification.title}
|
|
110
|
+
</Text>
|
|
111
|
+
{!notification.read && (
|
|
112
|
+
<View className="ml-2 h-2 w-2 rounded-full bg-primary" />
|
|
113
|
+
)}
|
|
114
|
+
</View>
|
|
115
|
+
|
|
116
|
+
<Text variant="muted" className="mt-1" numberOfLines={2}>
|
|
117
|
+
{notification.message}
|
|
118
|
+
</Text>
|
|
119
|
+
|
|
120
|
+
<Text variant="muted" size="xs" className="mt-2">
|
|
121
|
+
{formatTimeAgo(notification.createdAt)}
|
|
122
|
+
</Text>
|
|
123
|
+
</View>
|
|
124
|
+
</View>
|
|
125
|
+
</Pressable>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default function NotificationsScreen() {
|
|
130
|
+
const [notifications, setNotifications] = useState<Notification[]>(
|
|
131
|
+
notificationsData.notifications as Notification[]
|
|
132
|
+
);
|
|
133
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
134
|
+
|
|
135
|
+
const unreadCount = useMemo(
|
|
136
|
+
() => notifications.filter((n) => !n.read).length,
|
|
137
|
+
[notifications]
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const handleRefresh = async () => {
|
|
141
|
+
setRefreshing(true);
|
|
142
|
+
// Simulate refresh delay
|
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
144
|
+
setRefreshing(false);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const handleNotificationPress = (notification: Notification) => {
|
|
148
|
+
// Mark as read
|
|
149
|
+
setNotifications((prev) =>
|
|
150
|
+
prev.map((n) => (n.id === notification.id ? { ...n, read: true } : n))
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Navigate based on type
|
|
154
|
+
if (notification.type.startsWith("task_") && notification.data.taskId) {
|
|
155
|
+
router.push(`/(app)/task/${notification.data.taskId}`);
|
|
156
|
+
} else if (notification.type === "customer_added" && notification.data.customerId) {
|
|
157
|
+
router.push(`/(app)/customer/${notification.data.customerId}`);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const handleMarkAsRead = (notificationId: string) => {
|
|
162
|
+
setNotifications((prev) =>
|
|
163
|
+
prev.map((n) => (n.id === notificationId ? { ...n, read: true } : n))
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const handleMarkAllAsRead = () => {
|
|
168
|
+
setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const handleClearAll = () => {
|
|
172
|
+
setNotifications([]);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<View className="flex-1 bg-secondary">
|
|
177
|
+
{/* Header */}
|
|
178
|
+
<View className="flex-row items-center justify-between bg-background px-4 py-3 border-b border-border">
|
|
179
|
+
<Pressable onPress={() => router.back()} className="p-2 -ml-2">
|
|
180
|
+
<Text size="xl">←</Text>
|
|
181
|
+
</Pressable>
|
|
182
|
+
<Text variant="heading" size="lg">
|
|
183
|
+
Notificaciones
|
|
184
|
+
</Text>
|
|
185
|
+
<View className="w-10" />
|
|
186
|
+
</View>
|
|
187
|
+
|
|
188
|
+
{/* Actions Bar */}
|
|
189
|
+
{notifications.length > 0 && (
|
|
190
|
+
<View className="flex-row items-center justify-between px-4 py-2 bg-background border-b border-border">
|
|
191
|
+
<View className="flex-row items-center gap-2">
|
|
192
|
+
{unreadCount > 0 && (
|
|
193
|
+
<Badge variant="default">
|
|
194
|
+
{unreadCount} sin leer
|
|
195
|
+
</Badge>
|
|
196
|
+
)}
|
|
197
|
+
</View>
|
|
198
|
+
<View className="flex-row gap-2">
|
|
199
|
+
{unreadCount > 0 && (
|
|
200
|
+
<Button variant="link" size="sm" onPress={handleMarkAllAsRead}>
|
|
201
|
+
Marcar todo leído
|
|
202
|
+
</Button>
|
|
203
|
+
)}
|
|
204
|
+
<Button variant="link" size="sm" onPress={handleClearAll} textStyle={{ color: '#ef4444' }}>
|
|
205
|
+
Limpiar
|
|
206
|
+
</Button>
|
|
207
|
+
</View>
|
|
208
|
+
</View>
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
{/* Notifications List */}
|
|
212
|
+
{notifications.length === 0 ? (
|
|
213
|
+
<View className="flex-1 items-center justify-center p-8">
|
|
214
|
+
<Text className="text-6xl mb-4">🔔</Text>
|
|
215
|
+
<Text variant="heading" size="lg" className="text-center">
|
|
216
|
+
Sin notificaciones
|
|
217
|
+
</Text>
|
|
218
|
+
<Text variant="muted" className="text-center mt-2">
|
|
219
|
+
Cuando recibas notificaciones, aparecerán aquí
|
|
220
|
+
</Text>
|
|
221
|
+
</View>
|
|
222
|
+
) : (
|
|
223
|
+
<FlatList
|
|
224
|
+
data={notifications}
|
|
225
|
+
keyExtractor={(item) => item.id}
|
|
226
|
+
renderItem={({ item }) => (
|
|
227
|
+
<NotificationItem
|
|
228
|
+
notification={item}
|
|
229
|
+
onPress={() => handleNotificationPress(item)}
|
|
230
|
+
onMarkAsRead={() => handleMarkAsRead(item.id)}
|
|
231
|
+
/>
|
|
232
|
+
)}
|
|
233
|
+
contentContainerStyle={{ paddingVertical: 8 }}
|
|
234
|
+
refreshControl={
|
|
235
|
+
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
|
|
236
|
+
}
|
|
237
|
+
ItemSeparatorComponent={() => <View className="h-1" />}
|
|
238
|
+
/>
|
|
239
|
+
)}
|
|
240
|
+
</View>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile Screen - User information and settings
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { View, Text, TextInput, ScrollView, StyleSheet } from 'react-native'
|
|
6
|
+
import { useAuth } from '@nextsparkjs/mobile'
|
|
7
|
+
import { Colors } from '@/src/constants/colors'
|
|
8
|
+
|
|
9
|
+
export default function ProfileScreen() {
|
|
10
|
+
const { user } = useAuth()
|
|
11
|
+
|
|
12
|
+
// Split name into first and last name
|
|
13
|
+
const nameParts = user?.name?.split(' ') || ['', '']
|
|
14
|
+
const firstName = nameParts[0] || ''
|
|
15
|
+
const lastName = nameParts.slice(1).join(' ') || ''
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<ScrollView style={styles.container}>
|
|
19
|
+
{/* Page Header */}
|
|
20
|
+
<View style={styles.header}>
|
|
21
|
+
<Text style={styles.pageTitle}>Información Personal</Text>
|
|
22
|
+
<Text style={styles.pageSubtitle}>
|
|
23
|
+
Gestiona tu información personal y preferencias básicas de tu cuenta.
|
|
24
|
+
</Text>
|
|
25
|
+
</View>
|
|
26
|
+
|
|
27
|
+
{/* Personal Data Card */}
|
|
28
|
+
<View style={styles.card}>
|
|
29
|
+
<View style={styles.cardHeader}>
|
|
30
|
+
<Text style={styles.cardIcon}>👤</Text>
|
|
31
|
+
<View>
|
|
32
|
+
<Text style={styles.cardTitle}>Datos Personales</Text>
|
|
33
|
+
<Text style={styles.cardSubtitle}>
|
|
34
|
+
Actualiza tu nombre, país, zona horaria e idioma preferido
|
|
35
|
+
</Text>
|
|
36
|
+
</View>
|
|
37
|
+
</View>
|
|
38
|
+
|
|
39
|
+
{/* Name Field */}
|
|
40
|
+
<View style={styles.field}>
|
|
41
|
+
<Text style={styles.label}>Nombre</Text>
|
|
42
|
+
<TextInput
|
|
43
|
+
style={styles.input}
|
|
44
|
+
value={firstName}
|
|
45
|
+
editable={false}
|
|
46
|
+
placeholder="Tu nombre"
|
|
47
|
+
placeholderTextColor={Colors.foregroundMuted}
|
|
48
|
+
/>
|
|
49
|
+
</View>
|
|
50
|
+
|
|
51
|
+
{/* Last Name Field */}
|
|
52
|
+
<View style={styles.field}>
|
|
53
|
+
<Text style={styles.label}>Apellido</Text>
|
|
54
|
+
<TextInput
|
|
55
|
+
style={styles.input}
|
|
56
|
+
value={lastName}
|
|
57
|
+
editable={false}
|
|
58
|
+
placeholder="Tu apellido"
|
|
59
|
+
placeholderTextColor={Colors.foregroundMuted}
|
|
60
|
+
/>
|
|
61
|
+
</View>
|
|
62
|
+
|
|
63
|
+
{/* Email Field */}
|
|
64
|
+
<View style={styles.field}>
|
|
65
|
+
<Text style={styles.label}>Email</Text>
|
|
66
|
+
<View style={styles.emailInputWrapper}>
|
|
67
|
+
<Text style={styles.emailIcon}>✉</Text>
|
|
68
|
+
<TextInput
|
|
69
|
+
style={[styles.input, styles.emailInput]}
|
|
70
|
+
value={user?.email || ''}
|
|
71
|
+
editable={false}
|
|
72
|
+
placeholder="Tu email"
|
|
73
|
+
placeholderTextColor={Colors.foregroundMuted}
|
|
74
|
+
/>
|
|
75
|
+
</View>
|
|
76
|
+
<Text style={styles.hint}>No se puede cambiar</Text>
|
|
77
|
+
</View>
|
|
78
|
+
|
|
79
|
+
{/* Auth Method */}
|
|
80
|
+
<View style={styles.field}>
|
|
81
|
+
<Text style={styles.label}>Método de Autenticación</Text>
|
|
82
|
+
<View style={styles.readOnlyRow}>
|
|
83
|
+
<Text style={styles.readOnlyIcon}>✉</Text>
|
|
84
|
+
<Text style={styles.readOnlyText}>Email</Text>
|
|
85
|
+
</View>
|
|
86
|
+
</View>
|
|
87
|
+
|
|
88
|
+
{/* Verification Status */}
|
|
89
|
+
<View style={styles.field}>
|
|
90
|
+
<Text style={styles.label}>Estado de Verificación</Text>
|
|
91
|
+
<View style={styles.readOnlyRow}>
|
|
92
|
+
<Text style={styles.verifiedIcon}>✓</Text>
|
|
93
|
+
<Text style={styles.verifiedText}>Verificado</Text>
|
|
94
|
+
</View>
|
|
95
|
+
</View>
|
|
96
|
+
|
|
97
|
+
{/* Language */}
|
|
98
|
+
<View style={styles.field}>
|
|
99
|
+
<Text style={styles.label}>Idioma</Text>
|
|
100
|
+
<View style={styles.selectWrapper}>
|
|
101
|
+
<Text style={styles.selectIcon}>文</Text>
|
|
102
|
+
<Text style={styles.selectText}>Español</Text>
|
|
103
|
+
<Text style={styles.selectChevron}>⌄</Text>
|
|
104
|
+
</View>
|
|
105
|
+
</View>
|
|
106
|
+
</View>
|
|
107
|
+
|
|
108
|
+
<View style={styles.spacer} />
|
|
109
|
+
</ScrollView>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const styles = StyleSheet.create({
|
|
114
|
+
container: {
|
|
115
|
+
flex: 1,
|
|
116
|
+
backgroundColor: Colors.backgroundSecondary,
|
|
117
|
+
},
|
|
118
|
+
header: {
|
|
119
|
+
padding: 20,
|
|
120
|
+
},
|
|
121
|
+
pageTitle: {
|
|
122
|
+
fontSize: 28,
|
|
123
|
+
fontWeight: '700',
|
|
124
|
+
color: Colors.foreground,
|
|
125
|
+
marginBottom: 8,
|
|
126
|
+
},
|
|
127
|
+
pageSubtitle: {
|
|
128
|
+
fontSize: 15,
|
|
129
|
+
color: Colors.foregroundSecondary,
|
|
130
|
+
lineHeight: 22,
|
|
131
|
+
},
|
|
132
|
+
card: {
|
|
133
|
+
backgroundColor: Colors.card,
|
|
134
|
+
marginHorizontal: 16,
|
|
135
|
+
borderRadius: 12,
|
|
136
|
+
padding: 20,
|
|
137
|
+
borderWidth: 1,
|
|
138
|
+
borderColor: Colors.border,
|
|
139
|
+
},
|
|
140
|
+
cardHeader: {
|
|
141
|
+
flexDirection: 'row',
|
|
142
|
+
alignItems: 'flex-start',
|
|
143
|
+
gap: 12,
|
|
144
|
+
marginBottom: 24,
|
|
145
|
+
},
|
|
146
|
+
cardIcon: {
|
|
147
|
+
fontSize: 20,
|
|
148
|
+
marginTop: 2,
|
|
149
|
+
},
|
|
150
|
+
cardTitle: {
|
|
151
|
+
fontSize: 18,
|
|
152
|
+
fontWeight: '600',
|
|
153
|
+
color: Colors.foreground,
|
|
154
|
+
},
|
|
155
|
+
cardSubtitle: {
|
|
156
|
+
fontSize: 14,
|
|
157
|
+
color: Colors.foregroundSecondary,
|
|
158
|
+
marginTop: 4,
|
|
159
|
+
lineHeight: 20,
|
|
160
|
+
},
|
|
161
|
+
field: {
|
|
162
|
+
marginBottom: 20,
|
|
163
|
+
},
|
|
164
|
+
label: {
|
|
165
|
+
fontSize: 14,
|
|
166
|
+
fontWeight: '500',
|
|
167
|
+
color: Colors.foreground,
|
|
168
|
+
marginBottom: 8,
|
|
169
|
+
},
|
|
170
|
+
input: {
|
|
171
|
+
backgroundColor: Colors.backgroundSecondary,
|
|
172
|
+
borderWidth: 1,
|
|
173
|
+
borderColor: Colors.border,
|
|
174
|
+
borderRadius: 8,
|
|
175
|
+
paddingHorizontal: 14,
|
|
176
|
+
paddingVertical: 12,
|
|
177
|
+
fontSize: 15,
|
|
178
|
+
color: Colors.foreground,
|
|
179
|
+
},
|
|
180
|
+
emailInputWrapper: {
|
|
181
|
+
flexDirection: 'row',
|
|
182
|
+
alignItems: 'center',
|
|
183
|
+
backgroundColor: Colors.backgroundSecondary,
|
|
184
|
+
borderWidth: 1,
|
|
185
|
+
borderColor: Colors.border,
|
|
186
|
+
borderRadius: 8,
|
|
187
|
+
paddingHorizontal: 14,
|
|
188
|
+
},
|
|
189
|
+
emailIcon: {
|
|
190
|
+
fontSize: 16,
|
|
191
|
+
color: Colors.foregroundMuted,
|
|
192
|
+
marginRight: 10,
|
|
193
|
+
},
|
|
194
|
+
emailInput: {
|
|
195
|
+
flex: 1,
|
|
196
|
+
borderWidth: 0,
|
|
197
|
+
paddingHorizontal: 0,
|
|
198
|
+
backgroundColor: 'transparent',
|
|
199
|
+
},
|
|
200
|
+
hint: {
|
|
201
|
+
fontSize: 12,
|
|
202
|
+
color: Colors.foregroundMuted,
|
|
203
|
+
marginTop: 6,
|
|
204
|
+
},
|
|
205
|
+
readOnlyRow: {
|
|
206
|
+
flexDirection: 'row',
|
|
207
|
+
alignItems: 'center',
|
|
208
|
+
gap: 8,
|
|
209
|
+
},
|
|
210
|
+
readOnlyIcon: {
|
|
211
|
+
fontSize: 16,
|
|
212
|
+
color: Colors.foregroundSecondary,
|
|
213
|
+
},
|
|
214
|
+
readOnlyText: {
|
|
215
|
+
fontSize: 15,
|
|
216
|
+
color: Colors.foreground,
|
|
217
|
+
},
|
|
218
|
+
verifiedIcon: {
|
|
219
|
+
fontSize: 16,
|
|
220
|
+
color: Colors.success,
|
|
221
|
+
},
|
|
222
|
+
verifiedText: {
|
|
223
|
+
fontSize: 15,
|
|
224
|
+
color: Colors.success,
|
|
225
|
+
fontWeight: '500',
|
|
226
|
+
},
|
|
227
|
+
selectWrapper: {
|
|
228
|
+
flexDirection: 'row',
|
|
229
|
+
alignItems: 'center',
|
|
230
|
+
backgroundColor: Colors.backgroundSecondary,
|
|
231
|
+
borderWidth: 1,
|
|
232
|
+
borderColor: Colors.border,
|
|
233
|
+
borderRadius: 8,
|
|
234
|
+
paddingHorizontal: 14,
|
|
235
|
+
paddingVertical: 12,
|
|
236
|
+
},
|
|
237
|
+
selectIcon: {
|
|
238
|
+
fontSize: 16,
|
|
239
|
+
color: Colors.foregroundSecondary,
|
|
240
|
+
marginRight: 10,
|
|
241
|
+
},
|
|
242
|
+
selectText: {
|
|
243
|
+
flex: 1,
|
|
244
|
+
fontSize: 15,
|
|
245
|
+
color: Colors.foreground,
|
|
246
|
+
},
|
|
247
|
+
selectChevron: {
|
|
248
|
+
fontSize: 16,
|
|
249
|
+
color: Colors.foregroundSecondary,
|
|
250
|
+
},
|
|
251
|
+
spacer: {
|
|
252
|
+
height: 40,
|
|
253
|
+
},
|
|
254
|
+
})
|