Skip to content

Commit b77746e

Browse files
committed
simplify down to a local-only todo list
fix problems with js config
1 parent 809bb68 commit b77746e

14 files changed

Lines changed: 99 additions & 228 deletions

lib/mix/tasks/phx.sync.tanstack_db.ex renamed to lib/mix/tasks/phx.sync.tanstack_db.setup.ex

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
defmodule Mix.Tasks.Phx.Sync.TanstackDb.Docs do
1+
defmodule Mix.Tasks.Phx.Sync.TanstackDb.Setup.Docs do
22
@moduledoc false
33

44
@spec short_doc() :: String.t()
55
def short_doc do
6-
"Convert a Phoenix application to a Tanstack DB based frontend"
6+
"Convert a Phoenix application to use a Vite + Tanstack DB based frontend"
77
end
88

99
@spec example() :: String.t()
1010
def example do
11-
"mix phx.sync.tanstack_db"
11+
"mix phx.sync.tanstack_db.setup"
1212
end
1313

1414
@spec long_doc() :: String.t()
@@ -39,7 +39,7 @@ defmodule Mix.Tasks.Phx.Sync.TanstackDb.Docs do
3939
mix archive.install hex igniter_new
4040
4141
# create a new phoenix application and install phoenix_sync in `embedded` mode
42-
mix igniter.new my_app --install phoehix_sync --with phx.new --sync-mode embedded
42+
mix igniter.new my_app --install phoenix_sync --with phx.new --sync-mode embedded
4343
4444
# setup my_app to use tanstack db
4545
#{example()}
@@ -54,7 +54,7 @@ defmodule Mix.Tasks.Phx.Sync.TanstackDb.Docs do
5454
end
5555

5656
if Code.ensure_loaded?(Igniter) do
57-
defmodule Mix.Tasks.Phx.Sync.TanstackDb do
57+
defmodule Mix.Tasks.Phx.Sync.TanstackDb.Setup do
5858
import Igniter.Project.Application, only: [app_name: 1]
5959

6060
@shortdoc "#{__MODULE__.Docs.short_doc()}"
@@ -312,13 +312,12 @@ if Code.ensure_loaded?(Igniter) do
312312
|> create_new_file("assets/tsconfig.app.json")
313313
|> create_or_replace_file("assets/tsconfig.json")
314314
|> create_or_replace_file("assets/tailwind.config.js")
315-
|> create_new_file("assets/js/db/auth.ts")
316315
|> create_new_file("assets/js/db/collections.ts")
317-
|> create_new_file("assets/js/db/mutations.ts")
318316
|> create_new_file("assets/js/db/schema.ts")
319317
|> create_new_file("assets/js/routes/__root.tsx")
320318
|> create_new_file("assets/js/routes/index.tsx")
321319
|> create_new_file("assets/js/routes/about.tsx")
320+
|> create_new_file("assets/js/components/todos.tsx")
322321
|> create_new_file("assets/js/api.ts")
323322
|> create_new_file("assets/js/app.tsx")
324323
|> create_or_replace_file("assets/css/app.css")
@@ -375,7 +374,7 @@ if Code.ensure_loaded?(Igniter) do
375374
end
376375
end
377376
else
378-
defmodule Mix.Tasks.Phx.Sync.TanstackDb do
377+
defmodule Mix.Tasks.Phx.Sync.TanstackDb.Setup do
379378
@shortdoc "#{__MODULE__.Docs.short_doc()} | Install `igniter` to use"
380379

381380
@moduledoc __MODULE__.Docs.long_doc()

priv/igniter/phx.sync.tanstack_db/assets/css/app.css.eex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
@custom-variant phx-click-loading (&:where(.phx-click-loading, .phx-click-loading *));
1111
@custom-variant phx-submit-loading (&:where(.phx-submit-loading, .phx-submit-loading *));
1212
@custom-variant phx-change-loading (&:where(.phx-change-loading, .phx-change-loading *));
13+
@tailwind base;
14+
@tailwind components;
15+
@tailwind utilities;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { useLiveQuery, eq } from "@tanstack/react-db";
2+
import { todoCollection } from "../db/collections";
3+
4+
export function Todos() {
5+
const { data: todos } = useLiveQuery((query) =>
6+
query.from({ todo: todoCollection }),
7+
);
8+
9+
const toggleTodo = (todo) =>
10+
todoCollection.update(todo.id, (draft) => {
11+
draft.completed = !todo.completed;
12+
});
13+
14+
return (
15+
<ul className="flex flex-col list-none space-y-4">
16+
{todos.map((todo) => (
17+
<li
18+
key={todo.id}
19+
className="flex flex-row space-x-2 items-center leading-5"
20+
>
21+
<input
22+
className="block flex-initial rounded-2xl outline-none focus:outline-none"
23+
type="checkbox"
24+
checked={todo.completed}
25+
onChange={() => toggleTodo(todo)}
26+
id={`todo-${todo.id}`}
27+
/>
28+
<label
29+
className={`block flex-1 ${todo.completed ? "line-through" : ""}`}
30+
for={`todo-${todo.id}`}
31+
>
32+
{todo.title}
33+
</label>
34+
</li>
35+
))}
36+
</ul>
37+
);
38+
}
39+

priv/igniter/phx.sync.tanstack_db/assets/js/db/auth.ts.eex

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {createCollection, localStorageCollectionOptions,} from '@tanstack/react-db'
1+
import {createCollection, localOnlyCollectionOptions,} from '@tanstack/react-db'
22
import { ingestMutations } from './mutations'
33

44
import type { Value } from '@electric-sql/client'
@@ -8,83 +8,23 @@ import type {
88
UpdateMutationFn,
99
DeleteMutationFn,
1010
} from '@tanstack/react-db'
11-
import {authSchema, userSchema,} from './schema'
1211

13-
import type { Auth, User } from './schema'
14-
15-
type CollectionKey = string | number
16-
17-
export const authCollection = createCollection<Auth>(
18-
localStorageCollectionOptions({
19-
storageKey: 'auth',
20-
getKey: (item: Auth) => item.key,
21-
onInsert: async () => true,
22-
onUpdate: async () => true,
23-
onDelete: async () => true,
24-
schema: authSchema,
12+
import { todoSchema } from './schema'
13+
import type { Todo } from './schema'
14+
15+
16+
export const todoCollection = createCollection<Todo>(
17+
localOnlyCollectionOptions({
18+
getKey: (todo: Todo) => todo.id,
19+
schema: todoSchema,
20+
initialData: [
21+
{ id: 1, title: 'Install Phoenix', completed: true },
22+
{ id: 2, title: 'Run mix phx.sync.tanstack_db.setup', completed: true },
23+
{ id: 3, title: 'Run the app', completed: true },
24+
{ id: 4, title: 'Build a to-do app', completed: true },
25+
{ id: 5, title: 'Convert to an Electric collection backed by Phoenix.Sync', completed: false },
26+
],
2527
})
2628
)
2729

28-
const headers = {
29-
Authorization: async () => {
30-
const auth = authCollection.get('current')
31-
32-
return auth ? `Bearer ${auth.user_id}` : 'Unauthenticated'
33-
},
34-
}
35-
36-
async function onError(error: Error) {
37-
const status =
38-
'status' in error && Number.isInteger(error.status)
39-
? error.status as number
40-
: undefined
41-
42-
if (status === 403 && authCollection.has('current')) {
43-
await authCollection.delete('current')
44-
45-
return { headers }
46-
}
47-
48-
if (status === 401) {
49-
await new Promise((resolve) => authCollection.subscribeChanges(resolve))
50-
51-
return { headers }
52-
}
53-
54-
throw error
55-
}
56-
57-
const parser = {
58-
timestamp: (dateStr: string) => {
59-
// Timestamps sync in as naive datetime strings with no
60-
// timezone info because they're all implicitly UTC.
61-
const utcDateStr = dateStr.endsWith('Z') ? dateStr : `${dateStr}Z`
62-
const date: Date = new Date(utcDateStr)
63-
64-
// Cast to `Value`` because we haven't fixed the typing yet
65-
// https://github.com/TanStack/db/pull/201
66-
return date as unknown as Value
67-
},
68-
}
69-
70-
const baseShapeOptions = {
71-
headers,
72-
onError,
73-
parser,
74-
}
75-
76-
function operationHandlers<Type extends object>() {
77-
return {
78-
onInsert: ingestMutations as InsertMutationFn<Type>,
79-
onUpdate: ingestMutations as UpdateMutationFn<Type>,
80-
onDelete: ingestMutations as DeleteMutationFn<Type>,
81-
}
82-
}
83-
84-
function relativeUrl(path: string) {
85-
return `${window.location.origin}${path}`
86-
}
87-
8830

89-
// @ts-ignore
90-
window.authCollection = authCollection

priv/igniter/phx.sync.tanstack_db/assets/js/db/mutations.ts.eex

Lines changed: 0 additions & 78 deletions
This file was deleted.
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
import * as z from 'zod/v4'
22

3-
4-
export const authSchema = z.object({
5-
key: z.literal('current'),
6-
user_id: z.uuid(),
7-
})
8-
9-
export const userSchema = z.object({
10-
id: z.uuid(),
11-
name: z.string()
3+
export const todoSchema = z.object({
4+
id: z.number(),
5+
title: z.string(),
6+
completed: z.boolean(),
127
})
138

14-
export type Auth = z.infer<typeof authSchema>
15-
export type User = z.infer<typeof userSchema>
16-
9+
export type Todo = z.infer<typeof todoSchema>

priv/igniter/phx.sync.tanstack_db/assets/js/routes/__root.tsx.eex

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { createRootRoute, Link, Outlet } from '@tanstack/react-router'
22
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
3-
import { useAuth } from '../db/auth'
4-
import { authCollection } from '../db/collections'
53

64
const RootLayout = () => (
75
<>
@@ -22,8 +20,5 @@ const RootLayout = () => (
2220

2321
export const Route = createRootRoute({
2422
component: RootLayout,
25-
loader: async () => {
26-
await authCollection.preload()
27-
},
2823
})
2924

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
import { createFileRoute } from '@tanstack/react-router'
1+
import { createFileRoute } from "@tanstack/react-router";
22

3-
export const Route = createFileRoute('/')({
3+
import { Todos } from "../components/todos";
4+
5+
export const Route = createFileRoute("/")({
46
component: Index,
5-
})
7+
});
68

79
function Index() {
810
return (
9-
<div className="p-2">
10-
<h3>Welcome Home!</h3>
11+
<div className="flex justify-center">
12+
<div className="w-1/2 space-y-4">
13+
<h3 className="m-4 text-3xl text-center text-gray-700">
14+
Welcome to the Sync Stack
15+
</h3>
16+
<div className="bg-white rounded-md p-4 border-2 border-gray-300">
17+
<Todos />
18+
</div>
19+
</div>
1120
</div>
12-
)
21+
);
1322
}
23+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module.exports = {
2-
content: ["./js/**/*.js", "../lib/**/*.*ex"],
2+
content: ["./js/**/*.{js,jsx,ts,tsx}", "../lib/**/*.*ex"],
33
};

0 commit comments

Comments
 (0)