create-better-t-stack 3.2.23 → 3.3.0

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 (86) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +1 -1
  5. package/dist/{src-Cx7HDf0b.js → src-82W1Q-C5.js} +82 -54
  6. package/package.json +1 -1
  7. package/templates/addons/biome/biome.json.hbs +5 -0
  8. package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +5 -5
  9. package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
  10. package/templates/auth/better-auth/convex/native/bare/components/sign-in.tsx.hbs +127 -0
  11. package/templates/auth/better-auth/convex/native/bare/components/sign-up.tsx.hbs +138 -0
  12. package/templates/auth/better-auth/convex/native/uniwind/components/sign-in.tsx.hbs +91 -0
  13. package/templates/auth/better-auth/convex/native/uniwind/components/sign-up.tsx.hbs +102 -0
  14. package/templates/auth/better-auth/native/bare/app/(drawer)/index.tsx.hbs +186 -0
  15. package/templates/auth/better-auth/native/bare/components/sign-in.tsx.hbs +131 -0
  16. package/templates/auth/better-auth/native/bare/components/sign-up.tsx.hbs +150 -0
  17. package/templates/auth/better-auth/native/unistyles/app/(drawer)/index.tsx.hbs +9 -1
  18. package/templates/auth/better-auth/native/unistyles/components/sign-in.tsx.hbs +5 -0
  19. package/templates/auth/better-auth/native/unistyles/components/sign-up.tsx.hbs +5 -0
  20. package/templates/auth/better-auth/native/uniwind/app/(drawer)/index.tsx.hbs +123 -0
  21. package/templates/auth/better-auth/native/uniwind/components/sign-in.tsx.hbs +90 -0
  22. package/templates/auth/better-auth/native/uniwind/components/sign-up.tsx.hbs +116 -0
  23. package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
  24. package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +287 -0
  25. package/templates/examples/ai/native/{nativewind → bare}/polyfills.js +1 -0
  26. package/templates/examples/ai/native/{nativewind → uniwind}/app/(drawer)/ai.tsx.hbs +52 -51
  27. package/templates/examples/ai/native/uniwind/polyfills.js +26 -0
  28. package/templates/examples/todo/native/bare/app/(drawer)/todos.tsx.hbs +521 -0
  29. package/templates/examples/todo/native/uniwind/app/(drawer)/todos.tsx.hbs +295 -0
  30. package/templates/extras/bunfig.toml.hbs +3 -3
  31. package/templates/frontend/native/bare/_gitignore +18 -0
  32. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/(tabs)/_layout.tsx.hbs +7 -12
  33. package/templates/frontend/native/bare/app/(drawer)/(tabs)/index.tsx.hbs +43 -0
  34. package/templates/frontend/native/bare/app/(drawer)/(tabs)/two.tsx.hbs +43 -0
  35. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/_layout.tsx.hbs +24 -1
  36. package/templates/frontend/native/bare/app/(drawer)/index.tsx.hbs +234 -0
  37. package/templates/frontend/native/bare/app/+not-found.tsx.hbs +65 -0
  38. package/templates/frontend/native/bare/app/_layout.tsx.hbs +163 -0
  39. package/templates/frontend/native/bare/app/modal.tsx.hbs +34 -0
  40. package/templates/frontend/native/{nativewind → bare}/app.json.hbs +1 -0
  41. package/templates/frontend/native/bare/components/container.tsx.hbs +25 -0
  42. package/templates/frontend/native/bare/components/header-button.tsx.hbs +47 -0
  43. package/templates/frontend/native/{nativewind → bare}/components/tabbar-icon.tsx.hbs +1 -0
  44. package/templates/frontend/native/{nativewind → bare}/lib/android-navigation-bar.tsx.hbs +1 -0
  45. package/templates/frontend/native/{nativewind → bare}/lib/constants.ts.hbs +1 -0
  46. package/templates/frontend/native/bare/lib/use-color-scheme.ts.hbs +20 -0
  47. package/templates/frontend/native/bare/metro.config.js.hbs +9 -0
  48. package/templates/frontend/native/{nativewind → bare}/package.json.hbs +1 -2
  49. package/templates/frontend/native/bare/tsconfig.json.hbs +11 -0
  50. package/templates/frontend/native/{nativewind → uniwind}/_gitignore +4 -8
  51. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/_layout.tsx.hbs +46 -0
  52. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/index.tsx.hbs +15 -0
  53. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/two.tsx.hbs +15 -0
  54. package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +83 -0
  55. package/templates/frontend/native/uniwind/app/(drawer)/index.tsx.hbs +151 -0
  56. package/templates/frontend/native/uniwind/app/+not-found.tsx.hbs +32 -0
  57. package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +131 -0
  58. package/templates/frontend/native/uniwind/app/modal.tsx.hbs +53 -0
  59. package/templates/frontend/native/uniwind/app.json.hbs +19 -0
  60. package/templates/frontend/native/uniwind/components/container.tsx.hbs +33 -0
  61. package/templates/frontend/native/uniwind/components/theme-toggle.tsx.hbs +35 -0
  62. package/templates/frontend/native/uniwind/contexts/app-theme-context.tsx.hbs +62 -0
  63. package/templates/frontend/native/uniwind/global.css +5 -0
  64. package/templates/frontend/native/uniwind/metro.config.js.hbs +13 -0
  65. package/templates/frontend/native/uniwind/package.json.hbs +54 -0
  66. package/templates/frontend/native/{nativewind → uniwind}/tsconfig.json.hbs +4 -8
  67. package/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs +0 -86
  68. package/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs +0 -97
  69. package/templates/auth/better-auth/native/nativewind/app/(drawer)/index.tsx.hbs +0 -95
  70. package/templates/auth/better-auth/native/nativewind/components/sign-in.tsx.hbs +0 -93
  71. package/templates/auth/better-auth/native/nativewind/components/sign-up.tsx.hbs +0 -104
  72. package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +0 -295
  73. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx.hbs +0 -19
  74. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx.hbs +0 -19
  75. package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +0 -178
  76. package/templates/frontend/native/nativewind/app/+not-found.tsx.hbs +0 -29
  77. package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +0 -175
  78. package/templates/frontend/native/nativewind/app/modal.tsx.hbs +0 -14
  79. package/templates/frontend/native/nativewind/babel.config.js.hbs +0 -14
  80. package/templates/frontend/native/nativewind/components/container.tsx.hbs +0 -8
  81. package/templates/frontend/native/nativewind/components/header-button.tsx.hbs +0 -26
  82. package/templates/frontend/native/nativewind/global.css +0 -50
  83. package/templates/frontend/native/nativewind/lib/use-color-scheme.ts.hbs +0 -12
  84. package/templates/frontend/native/nativewind/metro.config.js.hbs +0 -12
  85. package/templates/frontend/native/nativewind/tailwind.config.js.hbs +0 -59
  86. /package/templates/auth/clerk/convex/native/base/app/(auth)/{sign-out.tsx.hbs → sign-up.tsx.hbs} +0 -0
@@ -0,0 +1,150 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ {{#if (eq api "trpc")}}
3
+ import { queryClient } from "@/utils/trpc";
4
+ {{/if}}
5
+ {{#if (eq api "orpc")}}
6
+ import { queryClient } from "@/utils/orpc";
7
+ {{/if}}
8
+ import { useState } from "react";
9
+ import {
10
+ ActivityIndicator,
11
+ Text,
12
+ TextInput,
13
+ TouchableOpacity,
14
+ View,
15
+ StyleSheet,
16
+ } from "react-native";
17
+ import { useColorScheme } from "@/lib/use-color-scheme";
18
+ import { NAV_THEME } from "@/lib/constants";
19
+
20
+ function SignUp() {
21
+ const { colorScheme } = useColorScheme();
22
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
23
+ const [name, setName] = useState("");
24
+ const [email, setEmail] = useState("");
25
+ const [password, setPassword] = useState("");
26
+ const [isLoading, setIsLoading] = useState(false);
27
+ const [error, setError] = useState<string | null>(null);
28
+
29
+ async function handleSignUp() {
30
+ setIsLoading(true);
31
+ setError(null);
32
+
33
+ await authClient.signUp.email(
34
+ {
35
+ name,
36
+ email,
37
+ password,
38
+ },
39
+ {
40
+ onError(error) {
41
+ setError(error.error?.message || "Failed to sign up");
42
+ setIsLoading(false);
43
+ },
44
+ onSuccess() {
45
+ setName("");
46
+ setEmail("");
47
+ setPassword("");
48
+ {{#if (eq api "orpc")}}
49
+ queryClient.refetchQueries();
50
+ {{/if}}
51
+ {{#if (eq api "trpc")}}
52
+ queryClient.refetchQueries();
53
+ {{/if}}
54
+ },
55
+ onFinished() {
56
+ setIsLoading(false);
57
+ },
58
+ }
59
+ );
60
+ }
61
+
62
+ return (
63
+ <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>
64
+ <Text style={[styles.title, { color: theme.text }]}>Create Account</Text>
65
+
66
+ {error ? (
67
+ <View style={[styles.errorContainer, { backgroundColor: theme.notification + "20" }]}>
68
+ <Text style={[styles.errorText, { color: theme.notification }]}>{error}</Text>
69
+ </View>
70
+ ) : null}
71
+
72
+ <TextInput
73
+ style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
74
+ placeholder="Name"
75
+ placeholderTextColor={theme.text}
76
+ value={name}
77
+ onChangeText={setName}
78
+ />
79
+
80
+ <TextInput
81
+ style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
82
+ placeholder="Email"
83
+ placeholderTextColor={theme.text}
84
+ value={email}
85
+ onChangeText={setEmail}
86
+ keyboardType="email-address"
87
+ autoCapitalize="none"
88
+ />
89
+
90
+ <TextInput
91
+ style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
92
+ placeholder="Password"
93
+ placeholderTextColor={theme.text}
94
+ value={password}
95
+ onChangeText={setPassword}
96
+ secureTextEntry
97
+ />
98
+
99
+ <TouchableOpacity
100
+ onPress={handleSignUp}
101
+ disabled={isLoading}
102
+ style={[styles.button, { backgroundColor: theme.primary, opacity: isLoading ? 0.5 : 1 }]}
103
+ >
104
+ {isLoading ? (
105
+ <ActivityIndicator size="small" color="#ffffff" />
106
+ ) : (
107
+ <Text style={styles.buttonText}>Sign Up</Text>
108
+ )}
109
+ </TouchableOpacity>
110
+ </View>
111
+ );
112
+ }
113
+
114
+ const styles = StyleSheet.create({
115
+ card: {
116
+ marginTop: 16,
117
+ padding: 16,
118
+ borderWidth: 1,
119
+ },
120
+ title: {
121
+ fontSize: 18,
122
+ fontWeight: "bold",
123
+ marginBottom: 12,
124
+ },
125
+ errorContainer: {
126
+ marginBottom: 12,
127
+ padding: 8,
128
+ },
129
+ errorText: {
130
+ fontSize: 14,
131
+ },
132
+ input: {
133
+ borderWidth: 1,
134
+ padding: 12,
135
+ fontSize: 16,
136
+ marginBottom: 12,
137
+ },
138
+ button: {
139
+ padding: 12,
140
+ alignItems: "center",
141
+ justifyContent: "center",
142
+ },
143
+ buttonText: {
144
+ color: "#ffffff",
145
+ fontSize: 16,
146
+ },
147
+ });
148
+
149
+ export { SignUp };
150
+
@@ -1,5 +1,4 @@
1
1
  import { authClient } from "@/lib/auth-client";
2
- import { useQuery } from "@tanstack/react-query";
3
2
  import { ScrollView, Text, TouchableOpacity, View } from "react-native";
4
3
  import { StyleSheet } from "react-native-unistyles";
5
4
 
@@ -7,9 +6,11 @@ import { Container } from "@/components/container";
7
6
  import { SignIn } from "@/components/sign-in";
8
7
  import { SignUp } from "@/components/sign-up";
9
8
  {{#if (eq api "orpc")}}
9
+ import { useQuery } from "@tanstack/react-query";
10
10
  import { queryClient, orpc } from "@/utils/orpc";
11
11
  {{/if}}
12
12
  {{#if (eq api "trpc")}}
13
+ import { useQuery } from "@tanstack/react-query";
13
14
  import { queryClient, trpc } from "@/utils/trpc";
14
15
  {{/if}}
15
16
 
@@ -43,13 +44,19 @@ export default function Home() {
43
44
  style={styles.signOutButton}
44
45
  onPress={() => {
45
46
  authClient.signOut();
47
+ {{#if (eq api "orpc")}}
48
+ queryClient.invalidateQueries();
49
+ {{/if}}
50
+ {{#if (eq api "trpc")}}
46
51
  queryClient.invalidateQueries();
52
+ {{/if}}
47
53
  }}
48
54
  >
49
55
  <Text style={styles.signOutButtonText}>Sign Out</Text>
50
56
  </TouchableOpacity>
51
57
  </View>
52
58
  ) : null}
59
+ {{#unless (eq api "none")}}
53
60
  <View style={styles.apiStatusCard}>
54
61
  <Text style={styles.cardTitle}>API Status</Text>
55
62
  <View style={styles.apiStatusRow}>
@@ -80,6 +87,7 @@ export default function Home() {
80
87
  </View>
81
88
  )}
82
89
  </View>
90
+ {{/unless}}
83
91
  {!session?.user && (
84
92
  <>
85
93
  <SignIn />
@@ -38,7 +38,12 @@ export function SignIn() {
38
38
  onSuccess: () => {
39
39
  setEmail("");
40
40
  setPassword("");
41
+ {{#if (eq api "orpc")}}
41
42
  queryClient.refetchQueries();
43
+ {{/if}}
44
+ {{#if (eq api "trpc")}}
45
+ queryClient.refetchQueries();
46
+ {{/if}}
42
47
  },
43
48
  onFinished: () => {
44
49
  setIsLoading(false);
@@ -41,7 +41,12 @@ export function SignUp() {
41
41
  setName("");
42
42
  setEmail("");
43
43
  setPassword("");
44
+ {{#if (eq api "orpc")}}
44
45
  queryClient.refetchQueries();
46
+ {{/if}}
47
+ {{#if (eq api "trpc")}}
48
+ queryClient.refetchQueries();
49
+ {{/if}}
45
50
  },
46
51
  onFinished: () => {
47
52
  setIsLoading(false);
@@ -0,0 +1,123 @@
1
+ import { Text, View, Pressable } from "react-native";
2
+ import { Container } from "@/components/container";
3
+ import { authClient } from "@/lib/auth-client";
4
+ import { Ionicons } from "@expo/vector-icons";
5
+ import { Card, Chip, useThemeColor } from "heroui-native";
6
+ import { SignIn } from "@/components/sign-in";
7
+ import { SignUp } from "@/components/sign-up";
8
+ {{#if (eq api "orpc")}}
9
+ import { useQuery } from "@tanstack/react-query";
10
+ import { queryClient, orpc } from "@/utils/orpc";
11
+ {{/if}}
12
+ {{#if (eq api "trpc")}}
13
+ import { useQuery } from "@tanstack/react-query";
14
+ import { queryClient, trpc } from "@/utils/trpc";
15
+ {{/if}}
16
+
17
+ export default function Home() {
18
+ {{#if (eq api "orpc")}}
19
+ const healthCheck = useQuery(orpc.healthCheck.queryOptions());
20
+ const privateData = useQuery(orpc.privateData.queryOptions());
21
+ const isConnected = healthCheck?.data === "OK";
22
+ const isLoading = healthCheck?.isLoading;
23
+ {{/if}}
24
+ {{#if (eq api "trpc")}}
25
+ const healthCheck = useQuery(trpc.healthCheck.queryOptions());
26
+ const privateData = useQuery(trpc.privateData.queryOptions());
27
+ const isConnected = healthCheck?.data === "OK";
28
+ const isLoading = healthCheck?.isLoading;
29
+ {{/if}}
30
+ const { data: session } = authClient.useSession();
31
+
32
+ const mutedColor = useThemeColor("muted");
33
+ const successColor = useThemeColor("success");
34
+ const dangerColor = useThemeColor("danger");
35
+ const foregroundColor = useThemeColor("foreground");
36
+
37
+ return (
38
+ <Container className="p-6">
39
+ <View className="py-4 mb-6">
40
+ <Text className="text-4xl font-bold text-foreground mb-2">
41
+ BETTER T STACK
42
+ </Text>
43
+ </View>
44
+
45
+ {session?.user ? (
46
+ <Card variant="secondary" className="mb-6 p-4">
47
+ <Text className="text-foreground text-base mb-2">
48
+ Welcome, <Text className="font-medium">{session.user.name}</Text>
49
+ </Text>
50
+ <Text className="text-muted text-sm mb-4">
51
+ {session.user.email}
52
+ </Text>
53
+ <Pressable className="bg-danger py-3 px-4 rounded-lg self-start active:opacity-70" onPress={()=> {
54
+ authClient.signOut();
55
+ {{#if (eq api "orpc")}}
56
+ queryClient.invalidateQueries();
57
+ {{/if}}
58
+ {{#if (eq api "trpc")}}
59
+ queryClient.invalidateQueries();
60
+ {{/if}}
61
+ }}
62
+ >
63
+ <Text className="text-foreground font-medium">Sign Out</Text>
64
+ </Pressable>
65
+ </Card>
66
+ ) : null}
67
+
68
+ {{#unless (eq api "none")}}
69
+ <Card variant="secondary" className="p-6">
70
+ <View className="flex-row items-center justify-between mb-4">
71
+ <Card.Title>System Status</Card.Title>
72
+ <Chip variant="secondary" color={isConnected ? "success" : "danger" } size="sm">
73
+ <Chip.Label>{isConnected ? "LIVE" : "OFFLINE"}</Chip.Label>
74
+ </Chip>
75
+ </View>
76
+
77
+ <Card className="p-4">
78
+ <View className="flex-row items-center">
79
+ <View className={`w-3 h-3 rounded-full mr-3 ${isConnected ? "bg-success" : "bg-muted" }`} />
80
+ <View className="flex-1">
81
+ <Text className="text-foreground font-medium mb-1">
82
+ {{#if (eq api "orpc")}}ORPC{{else}}TRPC{{/if}} Backend
83
+ </Text>
84
+ <Card.Description>
85
+ {isLoading
86
+ ? "Checking connection..."
87
+ : isConnected
88
+ ? "Connected to API"
89
+ : "API Disconnected"}
90
+ </Card.Description>
91
+ </View>
92
+ {isLoading && (
93
+ <Ionicons name="hourglass-outline" size={20} color={mutedColor} />
94
+ )}
95
+ {!isLoading && isConnected && (
96
+ <Ionicons name="checkmark-circle" size={20} color={successColor} />
97
+ )}
98
+ {!isLoading && !isConnected && (
99
+ <Ionicons name="close-circle" size={20} color={dangerColor} />
100
+ )}
101
+ </View>
102
+ </Card>
103
+ </Card>
104
+
105
+ <Card variant="secondary" className="mt-6 p-4">
106
+ <Card.Title className="mb-3">Private Data</Card.Title>
107
+ {privateData && (
108
+ <Card.Description>
109
+ {privateData.data?.message}
110
+ </Card.Description>
111
+ )}
112
+ </Card>
113
+ {{/unless}}
114
+
115
+ {!session?.user && (
116
+ <>
117
+ <SignIn />
118
+ <SignUp />
119
+ </>
120
+ )}
121
+ </Container>
122
+ );
123
+ }
@@ -0,0 +1,90 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ {{#if (eq api "trpc")}}
3
+ import { queryClient } from "@/utils/trpc";
4
+ {{/if}}
5
+ {{#if (eq api "orpc")}}
6
+ import { queryClient } from "@/utils/orpc";
7
+ {{/if}}
8
+ import { useState } from "react";
9
+ import {
10
+ ActivityIndicator,
11
+ Text,
12
+ TextInput,
13
+ Pressable,
14
+ View,
15
+ } from "react-native";
16
+ import { Card, useThemeColor } from "heroui-native";
17
+
18
+ function SignIn() {
19
+ const [email, setEmail] = useState("");
20
+ const [password, setPassword] = useState("");
21
+ const [isLoading, setIsLoading] = useState(false);
22
+ const [error, setError] = useState<string | null>(null);
23
+
24
+ const mutedColor = useThemeColor("muted");
25
+ const accentColor = useThemeColor("accent");
26
+ const foregroundColor = useThemeColor("foreground");
27
+ const dangerColor = useThemeColor("danger");
28
+
29
+ async function handleLogin() {
30
+ setIsLoading(true);
31
+ setError(null);
32
+
33
+ await authClient.signIn.email(
34
+ {
35
+ email,
36
+ password,
37
+ },
38
+ {
39
+ onError(error) {
40
+ setError(error.error?.message || "Failed to sign in");
41
+ setIsLoading(false);
42
+ },
43
+ onSuccess() {
44
+ setEmail("");
45
+ setPassword("");
46
+ {{#if (eq api "orpc")}}
47
+ queryClient.refetchQueries();
48
+ {{/if}}
49
+ {{#if (eq api "trpc")}}
50
+ queryClient.refetchQueries();
51
+ {{/if}}
52
+ },
53
+ onFinished() {
54
+ setIsLoading(false);
55
+ },
56
+ }
57
+ );
58
+ }
59
+
60
+ return (
61
+ <Card variant="secondary" className="mt-6 p-4">
62
+ <Card.Title className="mb-4">Sign In</Card.Title>
63
+
64
+ {error ? (
65
+ <View className="mb-4 p-3 bg-danger/10 rounded-lg">
66
+ <Text className="text-danger text-sm">{error}</Text>
67
+ </View>
68
+ ) : null}
69
+
70
+ <TextInput className="mb-3 py-3 px-4 rounded-lg bg-surface text-foreground border border-divider"
71
+ placeholder="Email" value={email} onChangeText={setEmail} placeholderTextColor={mutedColor}
72
+ keyboardType="email-address" autoCapitalize="none" />
73
+
74
+ <TextInput className="mb-4 py-3 px-4 rounded-lg bg-surface text-foreground border border-divider"
75
+ placeholder="Password" value={password} onChangeText={setPassword} placeholderTextColor={mutedColor}
76
+ secureTextEntry />
77
+
78
+ <Pressable onPress={handleLogin} disabled={isLoading}
79
+ className="bg-accent p-4 rounded-lg flex-row justify-center items-center active:opacity-70">
80
+ {isLoading ? (
81
+ <ActivityIndicator size="small" color={foregroundColor} />
82
+ ) : (
83
+ <Text className="text-foreground font-medium">Sign In</Text>
84
+ )}
85
+ </Pressable>
86
+ </Card>
87
+ );
88
+ }
89
+
90
+ export { SignIn };
@@ -0,0 +1,116 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ {{#if (eq api "trpc")}}
3
+ import { queryClient } from "@/utils/trpc";
4
+ {{/if}}
5
+ {{#if (eq api "orpc")}}
6
+ import { queryClient } from "@/utils/orpc";
7
+ {{/if}}
8
+ import { useState } from "react";
9
+ import {
10
+ ActivityIndicator,
11
+ Text,
12
+ TextInput,
13
+ Pressable,
14
+ View,
15
+ } from "react-native";
16
+ import { Card, useThemeColor } from "heroui-native";
17
+
18
+ function signUpHandler({
19
+ name,
20
+ email,
21
+ password,
22
+ setError,
23
+ setIsLoading,
24
+ setName,
25
+ setEmail,
26
+ setPassword,
27
+ }) {
28
+ setIsLoading(true);
29
+ setError(null);
30
+
31
+ authClient.signUp.email(
32
+ {
33
+ name,
34
+ email,
35
+ password,
36
+ },
37
+ {
38
+ onError(error) {
39
+ setError(error.error?.message || "Failed to sign up");
40
+ setIsLoading(false);
41
+ },
42
+ onSuccess() {
43
+ setName("");
44
+ setEmail("");
45
+ setPassword("");
46
+ {{#if (eq api "orpc")}}
47
+ queryClient.refetchQueries();
48
+ {{/if}}
49
+ {{#if (eq api "trpc")}}
50
+ queryClient.refetchQueries();
51
+ {{/if}}
52
+ },
53
+ onFinished() {
54
+ setIsLoading(false);
55
+ },
56
+ }
57
+ );
58
+ }
59
+
60
+ export function SignUp() {
61
+ const [name, setName] = useState("");
62
+ const [email, setEmail] = useState("");
63
+ const [password, setPassword] = useState("");
64
+ const [isLoading, setIsLoading] = useState(false);
65
+ const [error, setError] = useState<string | null>(null);
66
+
67
+ const mutedColor = useThemeColor("muted");
68
+ const accentColor = useThemeColor("accent");
69
+ const foregroundColor = useThemeColor("foreground");
70
+ const dangerColor = useThemeColor("danger");
71
+
72
+ function handlePress() {
73
+ signUpHandler({
74
+ name,
75
+ email,
76
+ password,
77
+ setError,
78
+ setIsLoading,
79
+ setName,
80
+ setEmail,
81
+ setPassword,
82
+ });
83
+ }
84
+
85
+ return (
86
+ <Card variant="secondary" className="mt-6 p-4">
87
+ <Card.Title className="mb-4">Create Account</Card.Title>
88
+
89
+ {error && (
90
+ <View className="mb-4 p-3 bg-danger/10 rounded-lg">
91
+ <Text className="text-danger text-sm">{error}</Text>
92
+ </View>
93
+ )}
94
+
95
+ <TextInput className="mb-3 py-3 px-4 rounded-lg bg-surface text-foreground border border-divider" placeholder="Name"
96
+ value={name} onChangeText={setName} placeholderTextColor={mutedColor} />
97
+
98
+ <TextInput className="mb-3 py-3 px-4 rounded-lg bg-surface text-foreground border border-divider"
99
+ placeholder="Email" value={email} onChangeText={setEmail} placeholderTextColor={mutedColor}
100
+ keyboardType="email-address" autoCapitalize="none" />
101
+
102
+ <TextInput className="mb-4 py-3 px-4 rounded-lg bg-surface text-foreground border border-divider"
103
+ placeholder="Password" value={password} onChangeText={setPassword} placeholderTextColor={mutedColor}
104
+ secureTextEntry />
105
+
106
+ <Pressable onPress={handlePress} disabled={isLoading}
107
+ className="bg-accent p-4 rounded-lg flex-row justify-center items-center active:opacity-70">
108
+ {isLoading ? (
109
+ <ActivityIndicator size="small" color={foregroundColor} />
110
+ ) : (
111
+ <Text className="text-foreground font-medium">Sign Up</Text>
112
+ )}
113
+ </Pressable>
114
+ </Card>
115
+ );
116
+ }
@@ -16,7 +16,7 @@ export const auth = betterAuth<BetterAuthOptions>({
16
16
  }),
17
17
  trustedOrigins: [
18
18
  process.env.CORS_ORIGIN || "",
19
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
19
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
20
20
  "mybettertapp://", "exp://"
21
21
  {{/if}}
22
22
  ],
@@ -77,7 +77,7 @@ export const auth = betterAuth<BetterAuthOptions>({
77
77
  }),
78
78
  trustedOrigins: [
79
79
  process.env.CORS_ORIGIN || "",
80
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
80
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
81
81
  "mybettertapp://", "exp://"
82
82
  {{/if}}
83
83
  ],
@@ -138,7 +138,7 @@ export const auth = betterAuth<BetterAuthOptions>({
138
138
  }),
139
139
  trustedOrigins: [
140
140
  env.CORS_ORIGIN,
141
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
141
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
142
142
  "mybettertapp://", "exp://"
143
143
  {{/if}}
144
144
  ],
@@ -206,7 +206,7 @@ export const auth = betterAuth<BetterAuthOptions>({
206
206
  database: mongodbAdapter(client),
207
207
  trustedOrigins: [
208
208
  process.env.CORS_ORIGIN || "",
209
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
209
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
210
210
  "mybettertapp://", "exp://"
211
211
  {{/if}}
212
212
  ],
@@ -258,7 +258,7 @@ export const auth = betterAuth<BetterAuthOptions>({
258
258
  database: "", // Invalid configuration
259
259
  trustedOrigins: [
260
260
  process.env.CORS_ORIGIN || "",
261
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
261
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
262
262
  "mybettertapp://", "exp://"
263
263
  {{/if}}
264
264
  ],