@teardown/cli 1.2.38 → 2.0.41

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.
Files changed (182) hide show
  1. package/bin/teardown.js +11 -1
  2. package/package.json +77 -57
  3. package/src/cli/commands/init.ts +254 -0
  4. package/src/cli/commands/plugins.ts +93 -0
  5. package/src/cli/commands/prebuild.ts +168 -0
  6. package/src/cli/commands/run.ts +727 -0
  7. package/src/cli/commands/start.ts +87 -0
  8. package/src/cli/commands/validate.ts +62 -0
  9. package/src/cli/index.ts +59 -0
  10. package/src/config/index.ts +45 -0
  11. package/src/config/loader.ts +366 -0
  12. package/src/config/schema.ts +235 -0
  13. package/src/config/types.ts +322 -0
  14. package/src/index.ts +177 -0
  15. package/src/pipeline/cache.ts +179 -0
  16. package/src/pipeline/index.ts +10 -0
  17. package/src/pipeline/stages.ts +692 -0
  18. package/src/plugins/base.ts +370 -0
  19. package/src/plugins/capabilities/biometrics.ts +64 -0
  20. package/src/plugins/capabilities/bluetooth.ts +86 -0
  21. package/src/plugins/capabilities/calendar.ts +57 -0
  22. package/src/plugins/capabilities/camera.ts +77 -0
  23. package/src/plugins/capabilities/contacts.ts +57 -0
  24. package/src/plugins/capabilities/deep-linking.ts +124 -0
  25. package/src/plugins/capabilities/firebase.ts +138 -0
  26. package/src/plugins/capabilities/index.ts +96 -0
  27. package/src/plugins/capabilities/location.ts +87 -0
  28. package/src/plugins/capabilities/photo-library.ts +80 -0
  29. package/src/plugins/capabilities/push-notifications.ts +98 -0
  30. package/src/plugins/capabilities/sign-in-with-apple.ts +53 -0
  31. package/src/plugins/context.ts +220 -0
  32. package/src/plugins/index.ts +26 -0
  33. package/src/plugins/resolver.ts +321 -0
  34. package/src/templates/generator.ts +507 -0
  35. package/src/templates/index.ts +9 -0
  36. package/src/templates/paths.ts +25 -0
  37. package/src/transformers/android/gradle.ts +400 -0
  38. package/src/transformers/android/index.ts +19 -0
  39. package/src/transformers/android/manifest.ts +506 -0
  40. package/src/transformers/index.ts +39 -0
  41. package/src/transformers/ios/entitlements.ts +283 -0
  42. package/src/transformers/ios/index.ts +10 -0
  43. package/src/transformers/ios/pbxproj.ts +267 -0
  44. package/src/transformers/ios/plist.ts +198 -0
  45. package/src/utils/fs.ts +429 -0
  46. package/src/utils/index.ts +21 -0
  47. package/src/utils/logger.ts +203 -0
  48. package/templates/.gitignore +63 -0
  49. package/templates/Gemfile +3 -0
  50. package/templates/android/app/build.gradle.kts +97 -0
  51. package/templates/android/app/proguard-rules.pro +10 -0
  52. package/templates/android/app/src/main/AndroidManifest.xml +26 -0
  53. package/templates/android/app/src/main/java/com/appname/MainActivity.kt +22 -0
  54. package/templates/android/app/src/main/java/com/appname/MainApplication.kt +44 -0
  55. package/templates/android/app/src/main/res/values/strings.xml +3 -0
  56. package/templates/android/app/src/main/res/values/styles.xml +7 -0
  57. package/templates/android/build.gradle.kts +44 -0
  58. package/templates/android/gradle.properties +39 -0
  59. package/templates/android/settings.gradle.kts +12 -0
  60. package/templates/babel.config.js +15 -0
  61. package/templates/index.js +7 -0
  62. package/templates/ios/.xcode.env +11 -0
  63. package/templates/ios/AppName/AppDelegate.swift +25 -0
  64. package/templates/ios/AppName/AppName-Bridging-Header.h +4 -0
  65. package/templates/ios/AppName/AppName.entitlements +6 -0
  66. package/templates/ios/AppName/Images.xcassets/AppIcon.appiconset/Contents.json +35 -0
  67. package/templates/ios/AppName/Images.xcassets/Contents.json +6 -0
  68. package/templates/ios/AppName/Info.plist +49 -0
  69. package/templates/ios/AppName/LaunchScreen.storyboard +38 -0
  70. package/templates/ios/AppName.xcodeproj/project.pbxproj +402 -0
  71. package/templates/ios/AppName.xcodeproj/xcshareddata/xcschemes/AppName.xcscheme +78 -0
  72. package/templates/ios/Podfile +35 -0
  73. package/templates/metro.config.js +41 -0
  74. package/templates/package.json +57 -0
  75. package/templates/react-native.config.js +8 -0
  76. package/templates/src/app/index.tsx +34 -0
  77. package/templates/src/assets/fonts/.gitkeep +1 -0
  78. package/templates/src/assets/images/.gitkeep +1 -0
  79. package/templates/src/components/ui/accordion.tsx +114 -0
  80. package/templates/src/components/ui/avatar.tsx +75 -0
  81. package/templates/src/components/ui/button.tsx +93 -0
  82. package/templates/src/components/ui/card.tsx +120 -0
  83. package/templates/src/components/ui/checkbox.tsx +133 -0
  84. package/templates/src/components/ui/chip.tsx +95 -0
  85. package/templates/src/components/ui/dialog.tsx +134 -0
  86. package/templates/src/components/ui/divider.tsx +67 -0
  87. package/templates/src/components/ui/error-view.tsx +82 -0
  88. package/templates/src/components/ui/form-field.tsx +101 -0
  89. package/templates/src/components/ui/index.ts +100 -0
  90. package/templates/src/components/ui/popover.tsx +92 -0
  91. package/templates/src/components/ui/pressable-feedback.tsx +88 -0
  92. package/templates/src/components/ui/radio-group.tsx +153 -0
  93. package/templates/src/components/ui/scroll-shadow.tsx +108 -0
  94. package/templates/src/components/ui/select.tsx +165 -0
  95. package/templates/src/components/ui/skeleton-group.tsx +97 -0
  96. package/templates/src/components/ui/skeleton.tsx +87 -0
  97. package/templates/src/components/ui/spinner.tsx +87 -0
  98. package/templates/src/components/ui/surface.tsx +95 -0
  99. package/templates/src/components/ui/switch.tsx +124 -0
  100. package/templates/src/components/ui/tabs.tsx +154 -0
  101. package/templates/src/components/ui/text-field.tsx +106 -0
  102. package/templates/src/components/ui/toast.tsx +129 -0
  103. package/templates/src/contexts/.gitkeep +2 -0
  104. package/templates/src/core/clients/api/api.client.ts +113 -0
  105. package/templates/src/core/clients/api/index.ts +1 -0
  106. package/templates/src/core/clients/storage/index.ts +1 -0
  107. package/templates/src/core/clients/storage/storage.client.ts +121 -0
  108. package/templates/src/core/constants/index.ts +19 -0
  109. package/templates/src/core/core.ts +40 -0
  110. package/templates/src/core/index.ts +10 -0
  111. package/templates/src/global.css +87 -0
  112. package/templates/src/hooks/index.ts +6 -0
  113. package/templates/src/hooks/use-debounce.ts +23 -0
  114. package/templates/src/hooks/use-mounted.ts +21 -0
  115. package/templates/src/index.ts +28 -0
  116. package/templates/src/lib/index.ts +5 -0
  117. package/templates/src/lib/utils.ts +115 -0
  118. package/templates/src/modules/.gitkeep +6 -0
  119. package/templates/src/navigation/index.ts +8 -0
  120. package/templates/src/navigation/navigation-provider.tsx +36 -0
  121. package/templates/src/navigation/router.tsx +137 -0
  122. package/templates/src/providers/app.provider.tsx +29 -0
  123. package/templates/src/providers/index.ts +5 -0
  124. package/templates/src/routes/(tabs)/_layout.tsx +42 -0
  125. package/templates/src/routes/(tabs)/explore.tsx +161 -0
  126. package/templates/src/routes/(tabs)/home.tsx +138 -0
  127. package/templates/src/routes/(tabs)/profile.tsx +151 -0
  128. package/templates/src/routes/_layout.tsx +18 -0
  129. package/templates/src/routes/settings.tsx +194 -0
  130. package/templates/src/screens/auth/index.ts +6 -0
  131. package/templates/src/screens/auth/login.tsx +165 -0
  132. package/templates/src/screens/auth/register.tsx +203 -0
  133. package/templates/src/screens/home.tsx +204 -0
  134. package/templates/src/screens/index.ts +17 -0
  135. package/templates/src/screens/profile.tsx +210 -0
  136. package/templates/src/screens/settings.tsx +216 -0
  137. package/templates/src/screens/welcome.tsx +101 -0
  138. package/templates/src/styles/index.ts +103 -0
  139. package/templates/src/types/common.ts +71 -0
  140. package/templates/src/types/index.ts +5 -0
  141. package/templates/tsconfig.json +14 -0
  142. package/README.md +0 -15
  143. package/assets/favicon.ico +0 -0
  144. package/dist/commands/dev/dev.js +0 -55
  145. package/dist/commands/init/init-teardown.js +0 -26
  146. package/dist/index.js +0 -20
  147. package/dist/modules/dev/dev-menu/keyboard-handler.js +0 -138
  148. package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js +0 -105
  149. package/dist/modules/dev/dev-server/cdp/cdp.adapter.js +0 -12
  150. package/dist/modules/dev/dev-server/cdp/index.js +0 -18
  151. package/dist/modules/dev/dev-server/cdp/types.js +0 -2
  152. package/dist/modules/dev/dev-server/dev-server-checker.js +0 -72
  153. package/dist/modules/dev/dev-server/dev-server.js +0 -269
  154. package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +0 -165
  155. package/dist/modules/dev/dev-server/inspector/device.js +0 -577
  156. package/dist/modules/dev/dev-server/inspector/inspector.js +0 -204
  157. package/dist/modules/dev/dev-server/inspector/types.js +0 -2
  158. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +0 -61
  159. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +0 -64
  160. package/dist/modules/dev/dev-server/plugins/devtools.plugin.js +0 -50
  161. package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +0 -19
  162. package/dist/modules/dev/dev-server/plugins/multipart.plugin.js +0 -62
  163. package/dist/modules/dev/dev-server/plugins/systrace.plugin.js +0 -28
  164. package/dist/modules/dev/dev-server/plugins/types.js +0 -2
  165. package/dist/modules/dev/dev-server/plugins/wss/index.js +0 -19
  166. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js +0 -66
  167. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js +0 -128
  168. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js +0 -75
  169. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js +0 -198
  170. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js +0 -120
  171. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js +0 -357
  172. package/dist/modules/dev/dev-server/plugins/wss/types.js +0 -2
  173. package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js +0 -57
  174. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js +0 -26
  175. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js +0 -46
  176. package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js +0 -55
  177. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +0 -36
  178. package/dist/modules/dev/dev-server/sybmolicate/types.js +0 -2
  179. package/dist/modules/dev/terminal/base.terminal.reporter.js +0 -78
  180. package/dist/modules/dev/terminal/terminal.reporter.js +0 -76
  181. package/dist/modules/dev/types.js +0 -2
  182. package/dist/modules/dev/utils/log.js +0 -73
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Settings Screen
3
+ *
4
+ * App settings and preferences screen.
5
+ * This is a stack screen outside of the tab navigator.
6
+ */
7
+
8
+ import React from "react";
9
+ import { View, ScrollView, Switch, Pressable } from "react-native";
10
+ import { defineScreen } from "@teardown/navigation/primitives";
11
+ import { useTypedNavigation } from "@teardown/navigation/hooks";
12
+ import {
13
+ Text,
14
+ Button,
15
+ Card,
16
+ CardHeader,
17
+ CardTitle,
18
+ CardContent,
19
+ Separator,
20
+ } from "@/components/ui";
21
+
22
+ function SettingsScreen(): React.JSX.Element {
23
+ const navigation = useTypedNavigation();
24
+ const [notifications, setNotifications] = React.useState(true);
25
+ const [darkMode, setDarkMode] = React.useState(false);
26
+ const [analytics, setAnalytics] = React.useState(true);
27
+ const [biometrics, setBiometrics] = React.useState(false);
28
+
29
+ return (
30
+ <ScrollView className="flex-1 bg-background" contentContainerClassName="p-6 gap-6">
31
+ {/* Preferences Section */}
32
+ <View className="gap-2">
33
+ <Text variant="label" className="px-1">PREFERENCES</Text>
34
+ <Card>
35
+ <CardContent className="p-0">
36
+ <SettingRow
37
+ icon="🔔"
38
+ title="Push Notifications"
39
+ description="Receive push notifications"
40
+ value={notifications}
41
+ onValueChange={setNotifications}
42
+ />
43
+ <Separator />
44
+ <SettingRow
45
+ icon="🌙"
46
+ title="Dark Mode"
47
+ description="Use dark color theme"
48
+ value={darkMode}
49
+ onValueChange={setDarkMode}
50
+ />
51
+ <Separator />
52
+ <SettingRow
53
+ icon="📊"
54
+ title="Analytics"
55
+ description="Help improve the app"
56
+ value={analytics}
57
+ onValueChange={setAnalytics}
58
+ />
59
+ <Separator />
60
+ <SettingRow
61
+ icon="🔐"
62
+ title="Biometric Lock"
63
+ description="Require Face ID or Touch ID"
64
+ value={biometrics}
65
+ onValueChange={setBiometrics}
66
+ />
67
+ </CardContent>
68
+ </Card>
69
+ </View>
70
+
71
+ {/* Storage Section */}
72
+ <View className="gap-2">
73
+ <Text variant="label" className="px-1">STORAGE</Text>
74
+ <Card>
75
+ <CardContent className="gap-4 py-4">
76
+ <View className="flex-row justify-between">
77
+ <Text>Cache Size</Text>
78
+ <Text variant="muted">24.5 MB</Text>
79
+ </View>
80
+ <Button variant="outline" size="sm">
81
+ Clear Cache
82
+ </Button>
83
+ </CardContent>
84
+ </Card>
85
+ </View>
86
+
87
+ {/* About Section */}
88
+ <View className="gap-2">
89
+ <Text variant="label" className="px-1">ABOUT</Text>
90
+ <Card>
91
+ <CardContent className="p-0">
92
+ <InfoRow icon="📱" title="Version" value="1.0.0" />
93
+ <Separator />
94
+ <InfoRow icon="🔨" title="Build" value="1" />
95
+ <Separator />
96
+ <InfoRow icon="⚛️" title="React Native" value="0.76.9" />
97
+ </CardContent>
98
+ </Card>
99
+ </View>
100
+
101
+ {/* Legal Section */}
102
+ <View className="gap-2">
103
+ <Text variant="label" className="px-1">LEGAL</Text>
104
+ <Card>
105
+ <CardContent className="p-0">
106
+ <LinkRow icon="📄" title="Terms of Service" />
107
+ <Separator />
108
+ <LinkRow icon="🔒" title="Privacy Policy" />
109
+ <Separator />
110
+ <LinkRow icon="📜" title="Licenses" />
111
+ </CardContent>
112
+ </Card>
113
+ </View>
114
+
115
+ {/* Back Button */}
116
+ <Button variant="secondary" onPress={() => navigation.goBack()} fullWidth>
117
+ Go Back
118
+ </Button>
119
+ </ScrollView>
120
+ );
121
+ }
122
+
123
+ function SettingRow({
124
+ icon,
125
+ title,
126
+ description,
127
+ value,
128
+ onValueChange,
129
+ }: {
130
+ icon: string;
131
+ title: string;
132
+ description: string;
133
+ value: boolean;
134
+ onValueChange: (value: boolean) => void;
135
+ }): React.JSX.Element {
136
+ return (
137
+ <View className="flex-row items-center px-4 py-3">
138
+ <Text className="text-xl mr-3">{icon}</Text>
139
+ <View className="flex-1 mr-4">
140
+ <Text variant="large">{title}</Text>
141
+ <Text variant="muted">{description}</Text>
142
+ </View>
143
+ <Switch
144
+ value={value}
145
+ onValueChange={onValueChange}
146
+ trackColor={{ false: "#d1d5db", true: "#bfdbfe" }}
147
+ thumbColor={value ? "#3b82f6" : "#f3f4f6"}
148
+ />
149
+ </View>
150
+ );
151
+ }
152
+
153
+ function InfoRow({
154
+ icon,
155
+ title,
156
+ value,
157
+ }: {
158
+ icon: string;
159
+ title: string;
160
+ value: string;
161
+ }): React.JSX.Element {
162
+ return (
163
+ <View className="flex-row items-center px-4 py-3">
164
+ <Text className="text-xl mr-3">{icon}</Text>
165
+ <Text variant="large" className="flex-1">{title}</Text>
166
+ <Text variant="muted">{value}</Text>
167
+ </View>
168
+ );
169
+ }
170
+
171
+ function LinkRow({
172
+ icon,
173
+ title,
174
+ }: {
175
+ icon: string;
176
+ title: string;
177
+ }): React.JSX.Element {
178
+ return (
179
+ <Pressable className="flex-row items-center px-4 py-3 active:bg-muted/50">
180
+ <Text className="text-xl mr-3">{icon}</Text>
181
+ <Text variant="large" className="flex-1">{title}</Text>
182
+ <Text className="text-muted-foreground">›</Text>
183
+ </Pressable>
184
+ );
185
+ }
186
+
187
+ export default defineScreen({
188
+ component: SettingsScreen,
189
+ options: {
190
+ title: "Settings",
191
+ headerShown: true,
192
+ animation: "slide_from_right",
193
+ },
194
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Auth Screens Export
3
+ */
4
+
5
+ export { LoginScreen } from "./login";
6
+ export { RegisterScreen } from "./register";
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Login Screen
3
+ *
4
+ * Email/password login with social auth options.
5
+ */
6
+
7
+ import React, { useState } from "react";
8
+ import { View, ScrollView, Pressable, KeyboardAvoidingView, Platform } from "react-native";
9
+ import {
10
+ Text,
11
+ Button,
12
+ Input,
13
+ Card,
14
+ CardHeader,
15
+ CardTitle,
16
+ CardDescription,
17
+ CardContent,
18
+ CardFooter,
19
+ Separator,
20
+ } from "@/components/ui";
21
+
22
+ interface LoginScreenProps {
23
+ onLogin?: (email: string, password: string) => void;
24
+ onForgotPassword?: () => void;
25
+ onRegister?: () => void;
26
+ onSocialLogin?: (provider: "google" | "apple" | "github") => void;
27
+ loading?: boolean;
28
+ }
29
+
30
+ export function LoginScreen({
31
+ onLogin,
32
+ onForgotPassword,
33
+ onRegister,
34
+ onSocialLogin,
35
+ loading = false,
36
+ }: LoginScreenProps): React.JSX.Element {
37
+ const [email, setEmail] = useState("");
38
+ const [password, setPassword] = useState("");
39
+ const [errors, setErrors] = useState<{ email?: string; password?: string }>({});
40
+
41
+ const validate = (): boolean => {
42
+ const newErrors: { email?: string; password?: string } = {};
43
+
44
+ if (!email) {
45
+ newErrors.email = "Email is required";
46
+ } else if (!/\S+@\S+\.\S+/.test(email)) {
47
+ newErrors.email = "Please enter a valid email";
48
+ }
49
+
50
+ if (!password) {
51
+ newErrors.password = "Password is required";
52
+ } else if (password.length < 6) {
53
+ newErrors.password = "Password must be at least 6 characters";
54
+ }
55
+
56
+ setErrors(newErrors);
57
+ return Object.keys(newErrors).length === 0;
58
+ };
59
+
60
+ const handleLogin = () => {
61
+ if (validate()) {
62
+ onLogin?.(email, password);
63
+ }
64
+ };
65
+
66
+ return (
67
+ <KeyboardAvoidingView
68
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
69
+ className="flex-1 bg-background"
70
+ >
71
+ <ScrollView
72
+ contentContainerClassName="flex-grow justify-center p-6"
73
+ keyboardShouldPersistTaps="handled"
74
+ >
75
+ <Card className="w-full max-w-md self-center">
76
+ <CardHeader className="items-center">
77
+ <View className="mb-4 h-16 w-16 items-center justify-center rounded-2xl bg-primary">
78
+ <Text className="text-2xl font-bold text-primary-foreground">T</Text>
79
+ </View>
80
+ <CardTitle>Welcome back</CardTitle>
81
+ <CardDescription>Sign in to your account to continue</CardDescription>
82
+ </CardHeader>
83
+
84
+ <CardContent className="gap-4">
85
+ {/* Social Login Buttons */}
86
+ <View className="gap-3">
87
+ <Button
88
+ variant="outline"
89
+ fullWidth
90
+ onPress={() => onSocialLogin?.("google")}
91
+ >
92
+ <View className="flex-row items-center gap-2">
93
+ <Text>🔵</Text>
94
+ <Text className="font-semibold text-foreground">Continue with Google</Text>
95
+ </View>
96
+ </Button>
97
+
98
+ <Button
99
+ variant="outline"
100
+ fullWidth
101
+ onPress={() => onSocialLogin?.("apple")}
102
+ >
103
+ <View className="flex-row items-center gap-2">
104
+ <Text></Text>
105
+ <Text className="font-semibold text-foreground">Continue with Apple</Text>
106
+ </View>
107
+ </Button>
108
+ </View>
109
+
110
+ {/* Divider */}
111
+ <View className="flex-row items-center gap-4 my-2">
112
+ <Separator className="flex-1" />
113
+ <Text variant="muted">or</Text>
114
+ <Separator className="flex-1" />
115
+ </View>
116
+
117
+ {/* Email/Password Form */}
118
+ <View className="gap-4">
119
+ <Input
120
+ label="Email"
121
+ placeholder="you@example.com"
122
+ value={email}
123
+ onChangeText={setEmail}
124
+ error={errors.email}
125
+ keyboardType="email-address"
126
+ autoCapitalize="none"
127
+ autoComplete="email"
128
+ />
129
+
130
+ <View>
131
+ <Input
132
+ label="Password"
133
+ placeholder="Enter your password"
134
+ value={password}
135
+ onChangeText={setPassword}
136
+ error={errors.password}
137
+ secureTextEntry
138
+ autoComplete="password"
139
+ />
140
+ <Pressable onPress={onForgotPassword} className="mt-2 self-end">
141
+ <Text className="text-sm text-primary">Forgot password?</Text>
142
+ </Pressable>
143
+ </View>
144
+ </View>
145
+ </CardContent>
146
+
147
+ <CardFooter className="flex-col gap-4">
148
+ <Button fullWidth loading={loading} onPress={handleLogin}>
149
+ Sign In
150
+ </Button>
151
+
152
+ <View className="flex-row items-center justify-center gap-1">
153
+ <Text variant="muted">Don't have an account?</Text>
154
+ <Pressable onPress={onRegister}>
155
+ <Text className="font-semibold text-primary">Sign up</Text>
156
+ </Pressable>
157
+ </View>
158
+ </CardFooter>
159
+ </Card>
160
+ </ScrollView>
161
+ </KeyboardAvoidingView>
162
+ );
163
+ }
164
+
165
+ export default LoginScreen;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Register Screen
3
+ *
4
+ * Account registration with email/password.
5
+ */
6
+
7
+ import React, { useState } from "react";
8
+ import { View, ScrollView, Pressable, KeyboardAvoidingView, Platform } from "react-native";
9
+ import {
10
+ Text,
11
+ Button,
12
+ Input,
13
+ Card,
14
+ CardHeader,
15
+ CardTitle,
16
+ CardDescription,
17
+ CardContent,
18
+ CardFooter,
19
+ Separator,
20
+ } from "@/components/ui";
21
+
22
+ interface RegisterScreenProps {
23
+ onRegister?: (name: string, email: string, password: string) => void;
24
+ onLogin?: () => void;
25
+ onSocialLogin?: (provider: "google" | "apple" | "github") => void;
26
+ loading?: boolean;
27
+ }
28
+
29
+ export function RegisterScreen({
30
+ onRegister,
31
+ onLogin,
32
+ onSocialLogin,
33
+ loading = false,
34
+ }: RegisterScreenProps): React.JSX.Element {
35
+ const [name, setName] = useState("");
36
+ const [email, setEmail] = useState("");
37
+ const [password, setPassword] = useState("");
38
+ const [confirmPassword, setConfirmPassword] = useState("");
39
+ const [errors, setErrors] = useState<{
40
+ name?: string;
41
+ email?: string;
42
+ password?: string;
43
+ confirmPassword?: string;
44
+ }>({});
45
+
46
+ const validate = (): boolean => {
47
+ const newErrors: typeof errors = {};
48
+
49
+ if (!name.trim()) {
50
+ newErrors.name = "Name is required";
51
+ }
52
+
53
+ if (!email) {
54
+ newErrors.email = "Email is required";
55
+ } else if (!/\S+@\S+\.\S+/.test(email)) {
56
+ newErrors.email = "Please enter a valid email";
57
+ }
58
+
59
+ if (!password) {
60
+ newErrors.password = "Password is required";
61
+ } else if (password.length < 8) {
62
+ newErrors.password = "Password must be at least 8 characters";
63
+ }
64
+
65
+ if (!confirmPassword) {
66
+ newErrors.confirmPassword = "Please confirm your password";
67
+ } else if (password !== confirmPassword) {
68
+ newErrors.confirmPassword = "Passwords do not match";
69
+ }
70
+
71
+ setErrors(newErrors);
72
+ return Object.keys(newErrors).length === 0;
73
+ };
74
+
75
+ const handleRegister = () => {
76
+ if (validate()) {
77
+ onRegister?.(name, email, password);
78
+ }
79
+ };
80
+
81
+ return (
82
+ <KeyboardAvoidingView
83
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
84
+ className="flex-1 bg-background"
85
+ >
86
+ <ScrollView
87
+ contentContainerClassName="flex-grow justify-center p-6"
88
+ keyboardShouldPersistTaps="handled"
89
+ >
90
+ <Card className="w-full max-w-md self-center">
91
+ <CardHeader className="items-center">
92
+ <View className="mb-4 h-16 w-16 items-center justify-center rounded-2xl bg-primary">
93
+ <Text className="text-2xl font-bold text-primary-foreground">T</Text>
94
+ </View>
95
+ <CardTitle>Create an account</CardTitle>
96
+ <CardDescription>Enter your details to get started</CardDescription>
97
+ </CardHeader>
98
+
99
+ <CardContent className="gap-4">
100
+ {/* Social Login Buttons */}
101
+ <View className="gap-3">
102
+ <Button
103
+ variant="outline"
104
+ fullWidth
105
+ onPress={() => onSocialLogin?.("google")}
106
+ >
107
+ <View className="flex-row items-center gap-2">
108
+ <Text>🔵</Text>
109
+ <Text className="font-semibold text-foreground">Continue with Google</Text>
110
+ </View>
111
+ </Button>
112
+
113
+ <Button
114
+ variant="outline"
115
+ fullWidth
116
+ onPress={() => onSocialLogin?.("apple")}
117
+ >
118
+ <View className="flex-row items-center gap-2">
119
+ <Text></Text>
120
+ <Text className="font-semibold text-foreground">Continue with Apple</Text>
121
+ </View>
122
+ </Button>
123
+ </View>
124
+
125
+ {/* Divider */}
126
+ <View className="flex-row items-center gap-4 my-2">
127
+ <Separator className="flex-1" />
128
+ <Text variant="muted">or</Text>
129
+ <Separator className="flex-1" />
130
+ </View>
131
+
132
+ {/* Registration Form */}
133
+ <View className="gap-4">
134
+ <Input
135
+ label="Full Name"
136
+ placeholder="John Doe"
137
+ value={name}
138
+ onChangeText={setName}
139
+ error={errors.name}
140
+ autoCapitalize="words"
141
+ autoComplete="name"
142
+ />
143
+
144
+ <Input
145
+ label="Email"
146
+ placeholder="you@example.com"
147
+ value={email}
148
+ onChangeText={setEmail}
149
+ error={errors.email}
150
+ keyboardType="email-address"
151
+ autoCapitalize="none"
152
+ autoComplete="email"
153
+ />
154
+
155
+ <Input
156
+ label="Password"
157
+ placeholder="Create a password"
158
+ value={password}
159
+ onChangeText={setPassword}
160
+ error={errors.password}
161
+ hint="Must be at least 8 characters"
162
+ secureTextEntry
163
+ autoComplete="new-password"
164
+ />
165
+
166
+ <Input
167
+ label="Confirm Password"
168
+ placeholder="Confirm your password"
169
+ value={confirmPassword}
170
+ onChangeText={setConfirmPassword}
171
+ error={errors.confirmPassword}
172
+ secureTextEntry
173
+ autoComplete="new-password"
174
+ />
175
+ </View>
176
+
177
+ {/* Terms */}
178
+ <Text variant="muted" className="text-center">
179
+ By creating an account, you agree to our{" "}
180
+ <Text className="text-primary">Terms of Service</Text> and{" "}
181
+ <Text className="text-primary">Privacy Policy</Text>
182
+ </Text>
183
+ </CardContent>
184
+
185
+ <CardFooter className="flex-col gap-4">
186
+ <Button fullWidth loading={loading} onPress={handleRegister}>
187
+ Create Account
188
+ </Button>
189
+
190
+ <View className="flex-row items-center justify-center gap-1">
191
+ <Text variant="muted">Already have an account?</Text>
192
+ <Pressable onPress={onLogin}>
193
+ <Text className="font-semibold text-primary">Sign in</Text>
194
+ </Pressable>
195
+ </View>
196
+ </CardFooter>
197
+ </Card>
198
+ </ScrollView>
199
+ </KeyboardAvoidingView>
200
+ );
201
+ }
202
+
203
+ export default RegisterScreen;