Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions examples/react/todo/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"emulators": {
"firestore": {
"port": 8080
},
"ui": {
"enabled": true,
"port": 4002
},
"singleProjectMode": true
}
}
6 changes: 5 additions & 1 deletion examples/react/todo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"version": "0.0.38",
"dependencies": {
"@tanstack/electric-db-collection": "^0.0.14",
"@tanstack/firebase-db-collection": "file:../../../packages/firebase-db-collection",
"@tanstack/query-core": "^5.75.7",
"@tanstack/query-db-collection": "^0.0.14",
"@tanstack/react-db": "^0.0.32",
Expand All @@ -14,6 +15,7 @@
"drizzle-orm": "^0.40.1",
"drizzle-zod": "^0.7.0",
"express": "^4.19.2",
"firebase": "^11.2.0",
"postgres": "^3.4.7",
"react": "^19.1.0",
"react-dom": "^19.1.0",
Expand All @@ -39,6 +41,7 @@
"eslint": "^9.22.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.5",
"firebase-tools": "^13.31.0",
"pg": "^8.14.1",
"tsx": "^4.6.2",
"typescript": "^5.8.2",
Expand All @@ -50,7 +53,8 @@
"db:generate": "drizzle-kit generate",
"db:push": "tsx scripts/migrate.ts",
"db:studio": "drizzle-kit studio",
"dev": "docker compose up -d && vite dev",
"dev": "docker compose up -d && firebase emulators:start --only firestore & vite dev",
"dev:no-emulator": "docker compose up -d && vite dev",
"lint": "eslint . --fix",
"preview": "vite preview"
},
Expand Down
50 changes: 50 additions & 0 deletions examples/react/todo/src/lib/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { createCollection } from "@tanstack/react-db"
import { electricCollectionOptions } from "@tanstack/electric-db-collection"
import { queryCollectionOptions } from "@tanstack/query-db-collection"
import { trailBaseCollectionOptions } from "@tanstack/trailbase-db-collection"
import { firebaseCollectionOptions } from "@tanstack/firebase-db-collection"
import { QueryClient } from "@tanstack/query-core"
import { initClient } from "trailbase"
import { initializeApp } from "firebase/app"
import { connectFirestoreEmulator, getFirestore } from "firebase/firestore"
import { selectConfigSchema, selectTodoSchema } from "../db/validation"
import { api } from "./api"
import type { SelectConfig, SelectTodo } from "../db/validation"
Expand All @@ -14,6 +17,17 @@ const queryClient = new QueryClient()
// Create a TrailBase client.
const trailBaseClient = initClient(`http://localhost:4000`)

// Initialize Firebase
const firebaseApp = initializeApp({
projectId: `tanstack-db-demo`,
})
const firestore = getFirestore(firebaseApp)

// Connect to emulator in development
if (import.meta.env.DEV) {
connectFirestoreEmulator(firestore, `localhost`, 8080)
}

// Electric Todo Collection
export const electricTodoCollection = createCollection(
electricCollectionOptions({
Expand Down Expand Up @@ -228,3 +242,39 @@ export const trailBaseConfigCollection = createCollection(
},
})
)

// Firebase Todo Collection
export const firebaseTodoCollection = createCollection(
firebaseCollectionOptions({
id: `todos`,
firestore,
collectionName: `todos`,
getKey: (item) => item.id,
schema: selectTodoSchema,
rowUpdateMode: `partial`,
parse: {
created_at: (timestamp: any) =>
timestamp?.toDate?.() || new Date(timestamp),
updated_at: (timestamp: any) =>
timestamp?.toDate?.() || new Date(timestamp),
},
})
)

// Firebase Config Collection
export const firebaseConfigCollection = createCollection(
firebaseCollectionOptions({
id: `config`,
firestore,
collectionName: `config`,
getKey: (item) => item.id,
schema: selectConfigSchema,
rowUpdateMode: `partial`,
parse: {
created_at: (timestamp: any) =>
timestamp?.toDate?.() || new Date(timestamp),
updated_at: (timestamp: any) =>
timestamp?.toDate?.() || new Date(timestamp),
},
})
)
24 changes: 21 additions & 3 deletions examples/react/todo/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { createServerRootRoute } from '@tanstack/react-start/server'
import { Route as rootRouteImport } from './routes/__root'
import { Route as TrailbaseRouteImport } from './routes/trailbase'
import { Route as QueryRouteImport } from './routes/query'
import { Route as FirebaseRouteImport } from './routes/firebase'
import { Route as ElectricRouteImport } from './routes/electric'
import { Route as IndexRouteImport } from './routes/index'
import { ServerRoute as ApiTodosServerRouteImport } from './routes/api/todos'
Expand All @@ -32,6 +33,11 @@ const QueryRoute = QueryRouteImport.update({
path: '/query',
getParentRoute: () => rootRouteImport,
} as any)
const FirebaseRoute = FirebaseRouteImport.update({
id: '/firebase',
path: '/firebase',
getParentRoute: () => rootRouteImport,
} as any)
const ElectricRoute = ElectricRouteImport.update({
id: '/electric',
path: '/electric',
Expand Down Expand Up @@ -66,33 +72,37 @@ const ApiConfigIdServerRoute = ApiConfigIdServerRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/electric': typeof ElectricRoute
'/firebase': typeof FirebaseRoute
'/query': typeof QueryRoute
'/trailbase': typeof TrailbaseRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/electric': typeof ElectricRoute
'/firebase': typeof FirebaseRoute
'/query': typeof QueryRoute
'/trailbase': typeof TrailbaseRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/electric': typeof ElectricRoute
'/firebase': typeof FirebaseRoute
'/query': typeof QueryRoute
'/trailbase': typeof TrailbaseRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/electric' | '/query' | '/trailbase'
fullPaths: '/' | '/electric' | '/firebase' | '/query' | '/trailbase'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/electric' | '/query' | '/trailbase'
id: '__root__' | '/' | '/electric' | '/query' | '/trailbase'
to: '/' | '/electric' | '/firebase' | '/query' | '/trailbase'
id: '__root__' | '/' | '/electric' | '/firebase' | '/query' | '/trailbase'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
ElectricRoute: typeof ElectricRoute
FirebaseRoute: typeof FirebaseRoute
QueryRoute: typeof QueryRoute
TrailbaseRoute: typeof TrailbaseRoute
}
Expand Down Expand Up @@ -149,6 +159,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof QueryRouteImport
parentRoute: typeof rootRouteImport
}
'/firebase': {
id: '/firebase'
path: '/firebase'
fullPath: '/firebase'
preLoaderRoute: typeof FirebaseRouteImport
parentRoute: typeof rootRouteImport
}
'/electric': {
id: '/electric'
path: '/electric'
Expand Down Expand Up @@ -225,6 +242,7 @@ const ApiTodosServerRouteWithChildren = ApiTodosServerRoute._addFileChildren(
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
ElectricRoute: ElectricRoute,
FirebaseRoute: FirebaseRoute,
QueryRoute: QueryRoute,
TrailbaseRoute: TrailbaseRoute,
}
Expand Down
20 changes: 20 additions & 0 deletions examples/react/todo/src/routes/firebase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createFileRoute } from "@tanstack/react-router"
import { TodoApp } from "../components/TodoApp"
import {
firebaseTodoCollection,
firebaseConfigCollection,
} from "../lib/collections"

export const Route = createFileRoute("/firebase")({
component: Firebase,
})

function Firebase() {
return (
<TodoApp
todoCollection={firebaseTodoCollection}
configCollection={firebaseConfigCollection}
type="Firebase"
/>
)
}
8 changes: 8 additions & 0 deletions examples/react/todo/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ function HomePage() {
</div>
</button>
</Link>
<Link to="/firebase" className="block w-full">
<button className="w-full px-6 py-4 bg-orange-500 text-white rounded-lg hover:bg-orange-600 transition-colors text-left">
<div className="font-semibold">Firebase Collections</div>
<div className="text-sm opacity-90 mt-1">
Real-time sync with Firestore
</div>
</button>
</Link>
</div>

<div className="mt-8 text-xs text-center text-gray-500">
Expand Down
Loading