this repo has no description
1import { createFileRoute } from "@tanstack/react-router";
2import { useSuspenseQuery } from "@tanstack/react-query";
3import { useLiveSuspenseQuery, eq, toArray } from "@tanstack/react-db";
4import * as v from "valibot";
5import { ChapterSplitColumn } from "~/chapters/chapter-split";
6import { DemoCard } from "~/demos/components/demo-card";
7import {
8 PokedexPagination,
9 PokedexTableResults,
10 PokedexTableSection,
11} from "~/demos/components/pokedex-table-section";
12import { getArticleQueryOptions } from "~/articles/querys";
13import {
14 pokemonCollection,
15 typesCollection,
16 pokemonTypesCollection,
17} from "~/demos/live-query/collections";
18import {
19 getPokemonListingQueryLimit,
20 toPokemonListing,
21} from "~/demos/pokemon-listing/pokemon-listing";
22
23const searchParamsSchema = v.object({
24 offset: v.optional(v.number(), 0),
25});
26
27export const Route = createFileRoute("/_chapters/live-query")({
28 staticData: {
29 routeTitle: "07_live-query",
30 routeSubtitle: "// Electric SQL synced collection",
31 },
32 ssr: false,
33 validateSearch: searchParamsSchema,
34 context: () => {
35 const liveQueryArticleQueryOptions = getArticleQueryOptions({
36 slug: "live-query",
37 });
38 return { liveQueryArticleQueryOptions };
39 },
40 loader: async ({ context: { queryClient, liveQueryArticleQueryOptions } }) => {
41 await queryClient.ensureQueryData(liveQueryArticleQueryOptions);
42 },
43 component: RouteComponent,
44});
45
46function RouteComponent() {
47 const { offset: currentOffset } = Route.useSearch();
48 const { liveQueryArticleQueryOptions } = Route.useRouteContext();
49
50 const {
51 data: { Article },
52 } = useSuspenseQuery(liveQueryArticleQueryOptions);
53
54 return (
55 <ChapterSplitColumn
56 blog={Article}
57 table={
58 <DemoCard className="mb-6">
59 <PokedexTableSection
60 currentOffset={currentOffset}
61 fallbackPagination={
62 <PokedexPagination prevOffset={null} nextOffset={null} to="/live-query" />
63 }
64 >
65 <PokemonTableContent currentOffset={currentOffset} />
66 </PokedexTableSection>
67 </DemoCard>
68 }
69 />
70 );
71}
72
73function PokemonTableContent({ currentOffset }: { currentOffset: number }) {
74 const { data } = useLiveSuspenseQuery(
75 (q) =>
76 q
77 .from({ pokemon: pokemonCollection })
78 .orderBy(({ pokemon }) => pokemon.dexId)
79 .offset(currentOffset)
80 .limit(getPokemonListingQueryLimit())
81 .select(({ pokemon }) => ({
82 id: pokemon.id,
83 name: pokemon.name,
84 dexId: pokemon.dexId,
85 types: toArray(
86 q
87 .from({ pokemonType: pokemonTypesCollection })
88 .join(
89 { type: typesCollection },
90 ({ pokemonType, type }) => eq(pokemonType.typeId, type.id),
91 "inner",
92 )
93 .where(({ pokemonType }) => eq(pokemonType.pokemonId, pokemon.id))
94 .orderBy(({ pokemonType }) => pokemonType.id)
95 .select(({ type }) => ({ name: type.name })),
96 ),
97 })),
98 [currentOffset],
99 );
100
101 const listing = toPokemonListing(data, { offset: currentOffset });
102
103 return (
104 <PokedexTableResults
105 pokemon={listing.pokemon}
106 pagination={
107 <PokedexPagination
108 prevOffset={listing.prevOffset}
109 nextOffset={listing.nextOffset}
110 to="/live-query"
111 />
112 }
113 />
114 );
115}