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.
- package/README.md +2 -2
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/{src-Cx7HDf0b.js → src-82W1Q-C5.js} +82 -54
- package/package.json +1 -1
- package/templates/addons/biome/biome.json.hbs +5 -0
- package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +5 -5
- package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
- package/templates/auth/better-auth/convex/native/bare/components/sign-in.tsx.hbs +127 -0
- package/templates/auth/better-auth/convex/native/bare/components/sign-up.tsx.hbs +138 -0
- package/templates/auth/better-auth/convex/native/uniwind/components/sign-in.tsx.hbs +91 -0
- package/templates/auth/better-auth/convex/native/uniwind/components/sign-up.tsx.hbs +102 -0
- package/templates/auth/better-auth/native/bare/app/(drawer)/index.tsx.hbs +186 -0
- package/templates/auth/better-auth/native/bare/components/sign-in.tsx.hbs +131 -0
- package/templates/auth/better-auth/native/bare/components/sign-up.tsx.hbs +150 -0
- package/templates/auth/better-auth/native/unistyles/app/(drawer)/index.tsx.hbs +9 -1
- package/templates/auth/better-auth/native/unistyles/components/sign-in.tsx.hbs +5 -0
- package/templates/auth/better-auth/native/unistyles/components/sign-up.tsx.hbs +5 -0
- package/templates/auth/better-auth/native/uniwind/app/(drawer)/index.tsx.hbs +123 -0
- package/templates/auth/better-auth/native/uniwind/components/sign-in.tsx.hbs +90 -0
- package/templates/auth/better-auth/native/uniwind/components/sign-up.tsx.hbs +116 -0
- package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
- package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +287 -0
- package/templates/examples/ai/native/{nativewind → bare}/polyfills.js +1 -0
- package/templates/examples/ai/native/{nativewind → uniwind}/app/(drawer)/ai.tsx.hbs +52 -51
- package/templates/examples/ai/native/uniwind/polyfills.js +26 -0
- package/templates/examples/todo/native/bare/app/(drawer)/todos.tsx.hbs +521 -0
- package/templates/examples/todo/native/uniwind/app/(drawer)/todos.tsx.hbs +295 -0
- package/templates/extras/bunfig.toml.hbs +3 -3
- package/templates/frontend/native/bare/_gitignore +18 -0
- package/templates/frontend/native/{nativewind → bare}/app/(drawer)/(tabs)/_layout.tsx.hbs +7 -12
- package/templates/frontend/native/bare/app/(drawer)/(tabs)/index.tsx.hbs +43 -0
- package/templates/frontend/native/bare/app/(drawer)/(tabs)/two.tsx.hbs +43 -0
- package/templates/frontend/native/{nativewind → bare}/app/(drawer)/_layout.tsx.hbs +24 -1
- package/templates/frontend/native/bare/app/(drawer)/index.tsx.hbs +234 -0
- package/templates/frontend/native/bare/app/+not-found.tsx.hbs +65 -0
- package/templates/frontend/native/bare/app/_layout.tsx.hbs +163 -0
- package/templates/frontend/native/bare/app/modal.tsx.hbs +34 -0
- package/templates/frontend/native/{nativewind → bare}/app.json.hbs +1 -0
- package/templates/frontend/native/bare/components/container.tsx.hbs +25 -0
- package/templates/frontend/native/bare/components/header-button.tsx.hbs +47 -0
- package/templates/frontend/native/{nativewind → bare}/components/tabbar-icon.tsx.hbs +1 -0
- package/templates/frontend/native/{nativewind → bare}/lib/android-navigation-bar.tsx.hbs +1 -0
- package/templates/frontend/native/{nativewind → bare}/lib/constants.ts.hbs +1 -0
- package/templates/frontend/native/bare/lib/use-color-scheme.ts.hbs +20 -0
- package/templates/frontend/native/bare/metro.config.js.hbs +9 -0
- package/templates/frontend/native/{nativewind → bare}/package.json.hbs +1 -2
- package/templates/frontend/native/bare/tsconfig.json.hbs +11 -0
- package/templates/frontend/native/{nativewind → uniwind}/_gitignore +4 -8
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/_layout.tsx.hbs +46 -0
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/index.tsx.hbs +15 -0
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/two.tsx.hbs +15 -0
- package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +83 -0
- package/templates/frontend/native/uniwind/app/(drawer)/index.tsx.hbs +151 -0
- package/templates/frontend/native/uniwind/app/+not-found.tsx.hbs +32 -0
- package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +131 -0
- package/templates/frontend/native/uniwind/app/modal.tsx.hbs +53 -0
- package/templates/frontend/native/uniwind/app.json.hbs +19 -0
- package/templates/frontend/native/uniwind/components/container.tsx.hbs +33 -0
- package/templates/frontend/native/uniwind/components/theme-toggle.tsx.hbs +35 -0
- package/templates/frontend/native/uniwind/contexts/app-theme-context.tsx.hbs +62 -0
- package/templates/frontend/native/uniwind/global.css +5 -0
- package/templates/frontend/native/uniwind/metro.config.js.hbs +13 -0
- package/templates/frontend/native/uniwind/package.json.hbs +54 -0
- package/templates/frontend/native/{nativewind → uniwind}/tsconfig.json.hbs +4 -8
- package/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs +0 -86
- package/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs +0 -97
- package/templates/auth/better-auth/native/nativewind/app/(drawer)/index.tsx.hbs +0 -95
- package/templates/auth/better-auth/native/nativewind/components/sign-in.tsx.hbs +0 -93
- package/templates/auth/better-auth/native/nativewind/components/sign-up.tsx.hbs +0 -104
- package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +0 -295
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx.hbs +0 -19
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx.hbs +0 -19
- package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +0 -178
- package/templates/frontend/native/nativewind/app/+not-found.tsx.hbs +0 -29
- package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +0 -175
- package/templates/frontend/native/nativewind/app/modal.tsx.hbs +0 -14
- package/templates/frontend/native/nativewind/babel.config.js.hbs +0 -14
- package/templates/frontend/native/nativewind/components/container.tsx.hbs +0 -8
- package/templates/frontend/native/nativewind/components/header-button.tsx.hbs +0 -26
- package/templates/frontend/native/nativewind/global.css +0 -50
- package/templates/frontend/native/nativewind/lib/use-color-scheme.ts.hbs +0 -12
- package/templates/frontend/native/nativewind/metro.config.js.hbs +0 -12
- package/templates/frontend/native/nativewind/tailwind.config.js.hbs +0 -59
- /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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
261
|
+
{{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
262
262
|
"mybettertapp://", "exp://"
|
|
263
263
|
{{/if}}
|
|
264
264
|
],
|