create-better-t-stack 2.2.4 → 2.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 (47) hide show
  1. package/dist/index.js +21 -29
  2. package/package.json +1 -1
  3. package/templates/addons/turborepo/{turbo.json → turbo.json.hbs} +7 -1
  4. package/templates/api/orpc/server/base/src/lib/context.ts.hbs +0 -2
  5. package/templates/auth/web/nuxt/app/components/SignInForm.vue +0 -1
  6. package/templates/auth/web/nuxt/app/components/SignUpForm.vue +0 -1
  7. package/templates/auth/web/nuxt/app/components/UserMenu.vue +0 -1
  8. package/templates/backend/convex/packages/backend/_gitignore +2 -0
  9. package/templates/backend/convex/packages/backend/convex/README.md +90 -0
  10. package/templates/backend/convex/packages/backend/convex/healthCheck.ts +7 -0
  11. package/templates/backend/convex/packages/backend/convex/schema.ts +9 -0
  12. package/templates/backend/convex/packages/backend/convex/todos.ts +42 -0
  13. package/templates/backend/convex/packages/backend/convex/tsconfig.json +25 -0
  14. package/templates/backend/convex/packages/backend/package.json.hbs +21 -0
  15. package/templates/base/package.json +2 -1
  16. package/templates/examples/todo/web/react/react-router/src/routes/todos.tsx.hbs +178 -93
  17. package/templates/examples/todo/web/react/tanstack-router/src/routes/todos.tsx.hbs +178 -92
  18. package/templates/examples/todo/web/react/tanstack-start/src/routes/todos.tsx.hbs +119 -18
  19. package/templates/extras/pnpm-workspace.yaml +1 -0
  20. package/templates/frontend/native/app/(drawer)/index.tsx.hbs +35 -7
  21. package/templates/frontend/native/app/_layout.tsx.hbs +27 -0
  22. package/templates/frontend/react/next/package.json +0 -2
  23. package/templates/frontend/react/next/src/app/page.tsx.hbs +26 -44
  24. package/templates/frontend/react/next/src/components/providers.tsx.hbs +15 -3
  25. package/templates/frontend/react/react-router/package.json +0 -2
  26. package/templates/frontend/react/react-router/src/root.tsx.hbs +31 -11
  27. package/templates/frontend/react/react-router/src/routes/_index.tsx.hbs +28 -47
  28. package/templates/frontend/react/tanstack-router/package.json +0 -2
  29. package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +18 -2
  30. package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +24 -1
  31. package/templates/frontend/react/tanstack-router/src/routes/index.tsx.hbs +24 -39
  32. package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +57 -13
  33. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +12 -10
  34. package/templates/frontend/react/tanstack-start/src/routes/index.tsx.hbs +31 -45
  35. /package/templates/backend/{elysia → server/elysia}/src/index.ts.hbs +0 -0
  36. /package/templates/backend/{express → server/express}/src/index.ts.hbs +0 -0
  37. /package/templates/backend/{hono → server/hono}/src/index.ts.hbs +0 -0
  38. /package/templates/backend/{next → server/next}/next-env.d.ts +0 -0
  39. /package/templates/backend/{next → server/next}/next.config.ts +0 -0
  40. /package/templates/backend/{next → server/next}/package.json +0 -0
  41. /package/templates/backend/{next → server/next}/src/app/route.ts +0 -0
  42. /package/templates/backend/{next → server/next}/src/middleware.ts +0 -0
  43. /package/templates/backend/{next → server/next}/tsconfig.json +0 -0
  44. /package/templates/backend/{server-base → server/server-base}/_gitignore +0 -0
  45. /package/templates/backend/{server-base → server/server-base}/package.json +0 -0
  46. /package/templates/backend/{server-base → server/server-base}/src/routers/index.ts.hbs +0 -0
  47. /package/templates/backend/{server-base → server/server-base}/tsconfig.json.hbs +0 -0
@@ -8,17 +8,24 @@ import {
8
8
  } from "@/components/ui/card";
9
9
  import { Checkbox } from "@/components/ui/checkbox";
10
10
  import { Input } from "@/components/ui/input";
11
- {{#if (eq api "orpc")}}
12
- import { orpc } from "@/utils/orpc";
13
- {{/if}}
14
- {{#if (eq api "trpc")}}
15
- import { trpc } from "@/utils/trpc";
16
- {{/if}}
17
- import { useMutation, useQuery } from "@tanstack/react-query";
18
11
  import { createFileRoute } from "@tanstack/react-router";
19
12
  import { Loader2, Trash2 } from "lucide-react";
20
13
  import { useState } from "react";
21
14
 
15
+ {{#if (eq backend "convex")}}
16
+ import { useMutation, useQuery } from "convex/react";
17
+ import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
18
+ import type { Id } from "@{{projectName}}/backend/convex/_generated/dataModel.d.ts";
19
+ {{else}}
20
+ {{#if (eq api "orpc")}}
21
+ import { orpc } from "@/utils/orpc";
22
+ {{/if}}
23
+ {{#if (eq api "trpc")}}
24
+ import { trpc } from "@/utils/trpc";
25
+ {{/if}}
26
+ import { useMutation, useQuery } from "@tanstack/react-query";
27
+ {{/if}}
28
+
22
29
  export const Route = createFileRoute("/todos")({
23
30
  component: TodosRoute,
24
31
  });
@@ -26,48 +33,70 @@ export const Route = createFileRoute("/todos")({
26
33
  function TodosRoute() {
27
34
  const [newTodoText, setNewTodoText] = useState("");
28
35
 
29
- {{#if (eq api "orpc")}}
30
- const todos = useQuery(orpc.todo.getAll.queryOptions());
31
- const createMutation = useMutation(
32
- orpc.todo.create.mutationOptions({
33
- onSuccess: () => {
34
- todos.refetch();
35
- setNewTodoText("");
36
- },
37
- }),
38
- );
39
- const toggleMutation = useMutation(
40
- orpc.todo.toggle.mutationOptions({
41
- onSuccess: () => todos.refetch(),
42
- }),
43
- );
44
- const deleteMutation = useMutation(
45
- orpc.todo.delete.mutationOptions({
46
- onSuccess: () => todos.refetch(),
47
- }),
48
- );
49
- {{/if}}
50
- {{#if (eq api "trpc")}}
51
- const todos = useQuery(trpc.todo.getAll.queryOptions());
52
- const createMutation = useMutation(
53
- trpc.todo.create.mutationOptions({
54
- onSuccess: () => {
55
- todos.refetch();
56
- setNewTodoText("");
57
- },
58
- }),
59
- );
60
- const toggleMutation = useMutation(
61
- trpc.todo.toggle.mutationOptions({
62
- onSuccess: () => todos.refetch(),
63
- }),
64
- );
65
- const deleteMutation = useMutation(
66
- trpc.todo.delete.mutationOptions({
67
- onSuccess: () => todos.refetch(),
68
- }),
69
- );
70
- {{/if}}
36
+ {{#if (eq backend "convex")}}
37
+ const todos = useQuery(api.todos.getAll);
38
+ const createTodo = useMutation(api.todos.create);
39
+ const toggleTodo = useMutation(api.todos.toggle);
40
+ const deleteTodo = useMutation(api.todos.deleteTodo);
41
+
42
+ const handleAddTodo = async (e: React.FormEvent) => {
43
+ e.preventDefault();
44
+ const text = newTodoText.trim();
45
+ if (!text) return;
46
+ await createTodo({ text });
47
+ setNewTodoText("");
48
+ };
49
+
50
+ const handleToggleTodo = (id: Id<"todos">, currentCompleted: boolean) => {
51
+ toggleTodo({ id, completed: !currentCompleted });
52
+ };
53
+
54
+ const handleDeleteTodo = (id: Id<"todos">) => {
55
+ deleteTodo({ id });
56
+ };
57
+ {{else}}
58
+ {{#if (eq api "orpc")}}
59
+ const todos = useQuery(orpc.todo.getAll.queryOptions());
60
+ const createMutation = useMutation(
61
+ orpc.todo.create.mutationOptions({
62
+ onSuccess: () => {
63
+ todos.refetch();
64
+ setNewTodoText("");
65
+ },
66
+ }),
67
+ );
68
+ const toggleMutation = useMutation(
69
+ orpc.todo.toggle.mutationOptions({
70
+ onSuccess: () => todos.refetch(),
71
+ }),
72
+ );
73
+ const deleteMutation = useMutation(
74
+ orpc.todo.delete.mutationOptions({
75
+ onSuccess: () => todos.refetch(),
76
+ }),
77
+ );
78
+ {{/if}}
79
+ {{#if (eq api "trpc")}}
80
+ const todos = useQuery(trpc.todo.getAll.queryOptions());
81
+ const createMutation = useMutation(
82
+ trpc.todo.create.mutationOptions({
83
+ onSuccess: () => {
84
+ todos.refetch();
85
+ setNewTodoText("");
86
+ },
87
+ }),
88
+ );
89
+ const toggleMutation = useMutation(
90
+ trpc.todo.toggle.mutationOptions({
91
+ onSuccess: () => todos.refetch(),
92
+ }),
93
+ );
94
+ const deleteMutation = useMutation(
95
+ trpc.todo.delete.mutationOptions({
96
+ onSuccess: () => todos.refetch(),
97
+ }),
98
+ );
99
+ {{/if}}
71
100
 
72
101
  const handleAddTodo = (e: React.FormEvent) => {
73
102
  e.preventDefault();
@@ -83,6 +112,7 @@ function TodosRoute() {
83
112
  const handleDeleteTodo = (id: number) => {
84
113
  deleteMutation.mutate({ id });
85
114
  };
115
+ {{/if}}
86
116
 
87
117
  return (
88
118
  <div className="mx-auto w-full max-w-md py-10">
@@ -100,60 +130,116 @@ function TodosRoute() {
100
130
  value={newTodoText}
101
131
  onChange={(e) => setNewTodoText(e.target.value)}
102
132
  placeholder="Add a new task..."
133
+ {{#if (eq backend "convex")}}
134
+ {{else}}
103
135
  disabled={createMutation.isPending}
136
+ {{/if}}
104
137
  />
105
138
  <Button
106
139
  type="submit"
140
+ {{#if (eq backend "convex")}}
141
+ disabled={!newTodoText.trim()}
142
+ {{else}}
107
143
  disabled={createMutation.isPending || !newTodoText.trim()}
144
+ {{/if}}
108
145
  >
109
- {createMutation.isPending ? (
110
- <Loader2 className="h-4 w-4 animate-spin" />
111
- ) : (
112
- "Add"
113
- )}
146
+ {{#if (eq backend "convex")}}
147
+ Add
148
+ {{else}}
149
+ {createMutation.isPending ? (
150
+ <Loader2 className="h-4 w-4 animate-spin" />
151
+ ) : (
152
+ "Add"
153
+ )}
154
+ {{/if}}
114
155
  </Button>
115
156
  </form>
116
157
 
117
- {todos.isLoading ? (
118
- <div className="flex justify-center py-4">
119
- <Loader2 className="h-6 w-6 animate-spin" />
120
- </div>
121
- ) : todos.data?.length === 0 ? (
122
- <p className="py-4 text-center">No todos yet. Add one above!</p>
123
- ) : (
124
- <ul className="space-y-2">
125
- {todos.data?.map((todo) => (
126
- <li
127
- key={todo.id}
128
- className="flex items-center justify-between rounded-md border p-2"
129
- >
130
- <div className="flex items-center space-x-2">
131
- <Checkbox
132
- checked={todo.completed}
133
- onCheckedChange={() =>
134
- handleToggleTodo(todo.id, todo.completed)
135
- }
136
- id={`todo-${todo.id}`}
137
- />
138
- <label
139
- htmlFor={`todo-${todo.id}`}
140
- className={`${todo.completed ? "line-through" : ""}`}
158
+ {{#if (eq backend "convex")}}
159
+ {todos === undefined ? (
160
+ <div className="flex justify-center py-4">
161
+ <Loader2 className="h-6 w-6 animate-spin" />
162
+ </div>
163
+ ) : todos.length === 0 ? (
164
+ <p className="py-4 text-center">No todos yet. Add one above!</p>
165
+ ) : (
166
+ <ul className="space-y-2">
167
+ {todos.map((todo) => (
168
+ <li
169
+ key={todo._id}
170
+ className="flex items-center justify-between rounded-md border p-2"
171
+ >
172
+ <div className="flex items-center space-x-2">
173
+ <Checkbox
174
+ checked={todo.completed}
175
+ onCheckedChange={() =>
176
+ handleToggleTodo(todo._id, todo.completed)
177
+ }
178
+ id={`todo-${todo._id}`}
179
+ />
180
+ <label
181
+ htmlFor={`todo-${todo._id}`}
182
+ className={`${todo.completed ? "line-through text-muted-foreground" : ""}`}
183
+ >
184
+ {todo.text}
185
+ </label>
186
+ </div>
187
+ <Button
188
+ variant="ghost"
189
+ size="icon"
190
+ onClick={() => handleDeleteTodo(todo._id)}
191
+ aria-label="Delete todo"
141
192
  >
142
- {todo.text}
143
- </label>
144
- </div>
145
- <Button
146
- variant="ghost"
147
- size="icon"
148
- onClick={() => handleDeleteTodo(todo.id)}
149
- aria-label="Delete todo"
193
+ <Trash2 className="h-4 w-4" />
194
+ </Button>
195
+ </li>
196
+ ))}
197
+ </ul>
198
+ )}
199
+ {{else}}
200
+ {todos.isLoading ? (
201
+ <div className="flex justify-center py-4">
202
+ <Loader2 className="h-6 w-6 animate-spin" />
203
+ </div>
204
+ ) : todos.data?.length === 0 ? (
205
+ <p className="py-4 text-center">
206
+ No todos yet. Add one above!
207
+ </p>
208
+ ) : (
209
+ <ul className="space-y-2">
210
+ {todos.data?.map((todo) => (
211
+ <li
212
+ key={todo.id}
213
+ className="flex items-center justify-between rounded-md border p-2"
150
214
  >
151
- <Trash2 className="h-4 w-4" />
152
- </Button>
153
- </li>
154
- ))}
155
- </ul>
156
- )}
215
+ <div className="flex items-center space-x-2">
216
+ <Checkbox
217
+ checked={todo.completed}
218
+ onCheckedChange={() =>
219
+ handleToggleTodo(todo.id, todo.completed)
220
+ }
221
+ id={`todo-${todo.id}`}
222
+ />
223
+ <label
224
+ htmlFor={`todo-${todo.id}`}
225
+ className={`${todo.completed ? "line-through" : ""}`}
226
+ >
227
+ {todo.text}
228
+ </label>
229
+ </div>
230
+ <Button
231
+ variant="ghost"
232
+ size="icon"
233
+ onClick={() => handleDeleteTodo(todo.id)}
234
+ aria-label="Delete todo"
235
+ >
236
+ <Trash2 className="h-4 w-4" />
237
+ </Button>
238
+ </li>
239
+ ))}
240
+ </ul>
241
+ )}
242
+ {{/if}}
157
243
  </CardContent>
158
244
  </Card>
159
245
  </div>
@@ -8,32 +8,79 @@ import {
8
8
  } from "@/components/ui/card";
9
9
  import { Checkbox } from "@/components/ui/checkbox";
10
10
  import { Input } from "@/components/ui/input";
11
- {{#if (eq api "trpc")}}
12
- import { useTRPC } from "@/utils/trpc";
13
- {{/if}}
14
- {{#if (eq api "orpc")}}
15
- import { useORPC } from "@/utils/orpc";
16
- {{/if}}
17
- import { useMutation, useQuery } from "@tanstack/react-query";
18
11
  import { createFileRoute } from "@tanstack/react-router";
19
12
  import { Loader2, Trash2 } from "lucide-react";
20
13
  import { useState } from "react";
21
14
 
15
+ {{#if (eq backend "convex")}}
16
+ import { useSuspenseQuery } from "@tanstack/react-query";
17
+ import { convexQuery } from "@convex-dev/react-query";
18
+ import { useMutation } from "convex/react";
19
+ import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
20
+ import type { Id } from "@{{projectName}}/backend/convex/_generated/dataModel.js";
21
+ {{else}}
22
+ {{#if (eq api "trpc")}}
23
+ import { useTRPC } from "@/utils/trpc";
24
+ {{/if}}
25
+ {{#if (eq api "orpc")}}
26
+ import { useORPC } from "@/utils/orpc";
27
+ {{/if}}
28
+ import { useMutation, useQuery } from "@tanstack/react-query";
29
+ {{/if}}
30
+
22
31
  export const Route = createFileRoute("/todos")({
23
32
  component: TodosRoute,
24
33
  });
25
34
 
26
35
  function TodosRoute() {
27
- {{#if (eq api "trpc")}}
36
+ const [newTodoText, setNewTodoText] = useState("");
37
+
38
+ {{#if (eq backend "convex")}}
39
+ const todosQuery = useSuspenseQuery(convexQuery(api.todos.getAll, {}));
40
+ const todos = todosQuery.data;
41
+
42
+ const createTodo = useMutation(api.todos.create);
43
+ const toggleTodo = useMutation(api.todos.toggle);
44
+ const removeTodo = useMutation(api.todos.deleteTodo);
45
+
46
+ const handleAddTodo = async (e: React.FormEvent) => {
47
+ e.preventDefault();
48
+ const text = newTodoText.trim();
49
+ if (text) {
50
+ setNewTodoText("");
51
+ try {
52
+ await createTodo({ text });
53
+ } catch (error) {
54
+ console.error("Failed to add todo:", error);
55
+ setNewTodoText(text);
56
+ }
57
+ }
58
+ };
59
+
60
+ const handleToggleTodo = async (id: Id<"todos">, completed: boolean) => {
61
+ try {
62
+ await toggleTodo({ id, completed: !completed });
63
+ } catch (error) {
64
+ console.error("Failed to toggle todo:", error);
65
+ }
66
+ };
67
+
68
+ const handleDeleteTodo = async (id: Id<"todos">) => {
69
+ try {
70
+ await removeTodo({ id });
71
+ } catch (error) {
72
+ console.error("Failed to delete todo:", error);
73
+ }
74
+ };
75
+ {{else}}
76
+ {{#if (eq api "trpc")}}
28
77
  const trpc = useTRPC();
29
- {{/if}}
30
- {{#if (eq api "orpc")}}
78
+ {{/if}}
79
+ {{#if (eq api "orpc")}}
31
80
  const orpc = useORPC();
32
- {{/if}}
33
-
34
- const [newTodoText, setNewTodoText] = useState("");
81
+ {{/if}}
35
82
 
36
- {{#if (eq api "trpc")}}
83
+ {{#if (eq api "trpc")}}
37
84
  const todos = useQuery(trpc.todo.getAll.queryOptions());
38
85
  const createMutation = useMutation(
39
86
  trpc.todo.create.mutationOptions({
@@ -53,8 +100,8 @@ function TodosRoute() {
53
100
  onSuccess: () => todos.refetch(),
54
101
  }),
55
102
  );
56
- {{/if}}
57
- {{#if (eq api "orpc")}}
103
+ {{/if}}
104
+ {{#if (eq api "orpc")}}
58
105
  const todos = useQuery(orpc.todo.getAll.queryOptions());
59
106
  const createMutation = useMutation(
60
107
  orpc.todo.create.mutationOptions({
@@ -74,7 +121,7 @@ function TodosRoute() {
74
121
  onSuccess: () => todos.refetch(),
75
122
  }),
76
123
  );
77
- {{/if}}
124
+ {{/if}}
78
125
 
79
126
  const handleAddTodo = (e: React.FormEvent) => {
80
127
  e.preventDefault();
@@ -90,12 +137,13 @@ function TodosRoute() {
90
137
  const handleDeleteTodo = (id: number) => {
91
138
  deleteMutation.mutate({ id });
92
139
  };
140
+ {{/if}}
93
141
 
94
142
  return (
95
143
  <div className="mx-auto w-full max-w-md py-10">
96
144
  <Card>
97
145
  <CardHeader>
98
- <CardTitle>Todo List</CardTitle>
146
+ <CardTitle>Todo List{{#if (eq backend "convex")}} (Convex){{/if}}</CardTitle>
99
147
  <CardDescription>Manage your tasks efficiently</CardDescription>
100
148
  </CardHeader>
101
149
  <CardContent>
@@ -107,20 +155,72 @@ function TodosRoute() {
107
155
  value={newTodoText}
108
156
  onChange={(e) => setNewTodoText(e.target.value)}
109
157
  placeholder="Add a new task..."
158
+ {{#unless (eq backend "convex")}}
110
159
  disabled={createMutation.isPending}
160
+ {{/unless}}
111
161
  />
112
162
  <Button
113
163
  type="submit"
164
+ {{#unless (eq backend "convex")}}
114
165
  disabled={createMutation.isPending || !newTodoText.trim()}
166
+ {{else}}
167
+ disabled={!newTodoText.trim()}
168
+ {{/unless}}
115
169
  >
170
+ {{#unless (eq backend "convex")}}
116
171
  {createMutation.isPending ? (
117
172
  <Loader2 className="h-4 w-4 animate-spin" />
118
173
  ) : (
119
174
  "Add"
120
175
  )}
176
+ {{else}}
177
+ Add
178
+ {{/unless}}
121
179
  </Button>
122
180
  </form>
123
181
 
182
+ {{#if (eq backend "convex")}}
183
+ {todos?.length === 0 ? (
184
+ <p className="py-4 text-center">No todos yet. Add one above!</p>
185
+ ) : (
186
+ <ul className="space-y-2">
187
+ {todos?.map((todo) => (
188
+ <li
189
+ key={todo._id}
190
+ className="flex items-center justify-between rounded-md border p-2"
191
+ >
192
+ <div className="flex items-center space-x-2">
193
+ <Checkbox
194
+ checked={todo.completed}
195
+ onCheckedChange={() =>
196
+ handleToggleTodo(todo._id, todo.completed)
197
+ }
198
+ id={`todo-${todo._id}`}
199
+ />
200
+ <label
201
+ htmlFor={`todo-${todo._id}`}
202
+ className={`${
203
+ todo.completed
204
+ ? "text-muted-foreground line-through"
205
+ : ""
206
+ }`}
207
+ >
208
+ {todo.text}
209
+ </label>
210
+ </div>
211
+ <Button
212
+ variant="ghost"
213
+ size="icon"
214
+ onClick={() => handleDeleteTodo(todo._id)}
215
+ aria-label="Delete todo"
216
+ >
217
+ <Trash2 className="h-4 w-4" />
218
+ </Button>
219
+ </li>
220
+ ))}
221
+ </ul>
222
+ )}
223
+ {{else}}
124
224
  {todos.isLoading ? (
125
225
  <div className="flex justify-center py-4">
126
226
  <Loader2 className="h-6 w-6 animate-spin" />
@@ -161,6 +261,7 @@ function TodosRoute() {
161
261
  ))}
162
262
  </ul>
163
263
  )}
264
+ {{/if}}
164
265
  </CardContent>
165
266
  </Card>
166
267
  </div>
@@ -1,2 +1,3 @@
1
1
  packages:
2
2
  - "apps/*"
3
+ - "packages/*"
@@ -1,12 +1,17 @@
1
- import { useQuery } from "@tanstack/react-query";
2
1
  import { View, Text, ScrollView } from "react-native";
3
2
  import { Container } from "@/components/container";
4
3
  {{#if (eq api "orpc")}}
4
+ import { useQuery } from "@tanstack/react-query";
5
5
  import { orpc } from "@/utils/orpc";
6
6
  {{/if}}
7
7
  {{#if (eq api "trpc")}}
8
+ import { useQuery } from "@tanstack/react-query";
8
9
  import { trpc } from "@/utils/trpc";
9
10
  {{/if}}
11
+ {{#if (eq backend "convex")}}
12
+ import { useQuery } from "convex/react";
13
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api.js";
14
+ {{/if}}
10
15
 
11
16
  export default function Home() {
12
17
  {{#if (eq api "orpc")}}
@@ -15,6 +20,9 @@ export default function Home() {
15
20
  {{#if (eq api "trpc")}}
16
21
  const healthCheck = useQuery(trpc.healthCheck.queryOptions());
17
22
  {{/if}}
23
+ {{#if (eq backend "convex")}}
24
+ const healthCheck = useQuery(api.healthCheck.get);
25
+ {{/if}}
18
26
 
19
27
  return (
20
28
  <Container>
@@ -28,15 +36,35 @@ export default function Home() {
28
36
  <View className="flex-row items-center gap-2">
29
37
  <View
30
38
  className={`h-2.5 w-2.5 rounded-full ${
31
- healthCheck.data ? "bg-green-500" : "bg-red-500"
39
+ {{#if (or (eq api "orpc") (eq api "trpc"))}}
40
+ healthCheck.data ? "bg-green-500" : "bg-red-500"
41
+ {{else}}
42
+ healthCheck ? "bg-green-500" : "bg-red-500"
43
+ {{/if}}
32
44
  }`}
33
45
  />
34
46
  <Text className="text-sm text-foreground">
35
- {healthCheck.isLoading
36
- ? "Checking..."
37
- : healthCheck.data
38
- ? "Connected"
39
- : "Disconnected"}
47
+ {{#if (eq api "orpc")}}
48
+ {healthCheck.isLoading
49
+ ? "Checking..."
50
+ : healthCheck.data
51
+ ? "Connected"
52
+ : "Disconnected"}
53
+ {{/if}}
54
+ {{#if (eq api "trpc")}}
55
+ {healthCheck.isLoading
56
+ ? "Checking..."
57
+ : healthCheck.data
58
+ ? "Connected"
59
+ : "Disconnected"}
60
+ {{/if}}
61
+ {{#if (eq backend "convex")}}
62
+ {healthCheck === undefined
63
+ ? "Checking..."
64
+ : healthCheck === "OK"
65
+ ? "Connected"
66
+ : "Error"}
67
+ {{/if}}
40
68
  </Text>
41
69
  </View>
42
70
  </View>
@@ -1,4 +1,8 @@
1
+ {{#if (eq backend "convex")}}
2
+ import { ConvexProvider, ConvexReactClient } from "convex/react";
3
+ {{else}}
1
4
  import { QueryClientProvider } from "@tanstack/react-query";
5
+ {{/if}}
2
6
  import { Stack } from "expo-router";
3
7
  import {
4
8
  DarkTheme,
@@ -35,6 +39,12 @@ export const unstable_settings = {
35
39
  initialRouteName: "(drawer)",
36
40
  };
37
41
 
42
+ {{#if (eq backend "convex")}}
43
+ const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, {
44
+ unsavedChangesWarning: false,
45
+ });
46
+ {{/if}}
47
+
38
48
  export default function RootLayout() {
39
49
  const hasMounted = useRef(false);
40
50
  const { colorScheme, isDarkColorScheme } = useColorScheme();
@@ -58,6 +68,22 @@ export default function RootLayout() {
58
68
  return null;
59
69
  }
60
70
  return (
71
+ {{#if (eq backend "convex")}}
72
+ <ConvexProvider client={convex}>
73
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
74
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
75
+ <GestureHandlerRootView style=\{{ flex: 1 }}>
76
+ <Stack>
77
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
78
+ <Stack.Screen
79
+ name="modal"
80
+ options=\{{ title: "Modal", presentation: "modal" }}
81
+ />
82
+ </Stack>
83
+ </GestureHandlerRootView>
84
+ </ThemeProvider>
85
+ </ConvexProvider>
86
+ {{else}}
61
87
  <QueryClientProvider client={queryClient}>
62
88
  <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
63
89
  <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
@@ -72,6 +98,7 @@ export default function RootLayout() {
72
98
  </GestureHandlerRootView>
73
99
  </ThemeProvider>
74
100
  </QueryClientProvider>
101
+ {{/if}}
75
102
  );
76
103
  }
77
104
 
@@ -14,7 +14,6 @@
14
14
  "@radix-ui/react-label": "^2.1.3",
15
15
  "@radix-ui/react-slot": "^1.2.0",
16
16
  "@tanstack/react-form": "^1.3.2",
17
- "@tanstack/react-query": "^5.72.2",
18
17
  "class-variance-authority": "^0.7.1",
19
18
  "clsx": "^2.1.1",
20
19
  "lucide-react": "^0.487.0",
@@ -29,7 +28,6 @@
29
28
  },
30
29
  "devDependencies": {
31
30
  "@tailwindcss/postcss": "^4",
32
- "@tanstack/react-query-devtools": "^5.72.2",
33
31
  "@types/node": "^20",
34
32
  "@types/react": "^19",
35
33
  "@types/react-dom": "^19",