···11-import { createServerFn } from "@tanstack/react-start";
22-import * as v from "valibot";
33-import { DB } from "~/data/db";
44-import { POKEMON_LIMIT } from "~/constants";
55-66-const PokemonListParamsSchema = v.object({
77- offset: v.optional(v.number()),
88-});
99-1010-const FilteredPokemonListParamsSchema = v.object({
1111- offset: v.optional(v.number()),
1212- nameFilter: v.optional(v.string()),
1313-});
1414-1515-const innerGetPokemonList = async (offset: number) => {
1616- // Fetch one extra item to check if there are more results
1717- const pokemon = await DB.queries.getPokemonAtOffset(offset, POKEMON_LIMIT + 1);
1818-1919- // Check if there are more results by looking at the extra item
2020- const hasMore = pokemon.length > POKEMON_LIMIT;
2121-2222- // Remove the extra item if it exists
2323- const results = hasMore ? pokemon.slice(0, -1) : pokemon;
2424-2525- return {
2626- pokemon: results,
2727- nextOffset: hasMore ? offset + POKEMON_LIMIT : null,
2828- prevOffset: offset > 0 ? Math.max(0, offset - POKEMON_LIMIT) : null,
2929- };
3030-};
3131-3232-const innerGetFilteredPokemonList = async (offset: number, nameFilter: string) => {
3333- // If no filter is provided, fall back to regular query
3434- if (!nameFilter.trim()) {
3535- return await innerGetPokemonList(offset);
3636- }
3737-3838- // Fetch one extra item to check if there are more results
3939- const pokemon = await DB.queries.getFilteredPokemonAtOffset(
4040- offset,
4141- POKEMON_LIMIT + 1,
4242- `%${nameFilter.trim()}%`,
4343- );
4444-4545- // Check if there are more results by looking at the extra item
4646- const hasMore = pokemon.length > POKEMON_LIMIT;
4747-4848- // Remove the extra item if it exists
4949- const results = hasMore ? pokemon.slice(0, -1) : pokemon;
5050-5151- return {
5252- pokemon: results,
5353- nextOffset: hasMore ? offset + POKEMON_LIMIT : null,
5454- prevOffset: offset > 0 ? Math.max(0, offset - POKEMON_LIMIT) : null,
5555- appliedFilter: nameFilter.trim(),
5656- };
5757-};
5858-5959-export const getServerPokemonList = createServerFn({ method: "GET" })
6060- .inputValidator((params) => {
6161- const validated = v.parse(PokemonListParamsSchema, params);
6262- const offset = validated.offset ?? 0;
6363-6464- if (offset < 0) throw new Error("Offset must be greater than or equal to 0");
6565-6666- return { offset };
6767- })
6868- .handler(async ({ data }) => {
6969- return await innerGetPokemonList(data.offset);
7070- });
7171-7272-export const getServerFilteredPokemonList = createServerFn({ method: "GET" })
7373- .inputValidator((params) => {
7474- const validated = v.parse(FilteredPokemonListParamsSchema, params);
7575- const offset = validated.offset ?? 0;
7676- const nameFilter = validated.nameFilter ?? "";
7777-7878- if (offset < 0) throw new Error("Offset must be greater than or equal to 0");
7979-8080- return { offset, nameFilter };
8181- })
8282- .handler(async ({ data }) => {
8383- return await innerGetFilteredPokemonList(data.offset, data.nameFilter);
8484- });
-40
src/util/lazily.ts
···11-/*
22- * src: github.com/JLarky/react-lazily/blob/main/src/core/lazily.ts
33- *
44- * MIT License
55- * Copyright (c) 2020 JLarky
66- *
77- * Permission is hereby granted, free of charge, to any person obtaining a copy
88- * of this software and associated documentation files (the "Software"), to deal
99- * in the Software without restriction, including without limitation the rights
1010- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1111- * copies of the Software, and to permit persons to whom the Software is
1212- * furnished to do so, subject to the following conditions:
1313- *
1414- * The above copyright notice and this permission notice shall be included in all
1515- * copies or substantial portions of the Software.
1616- *
1717- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1818- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1919- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2020- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2121- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2222- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2323- SOFTWARE.
2424- *
2525- */
2626-2727-import { lazy } from "react";
2828-2929-export const lazily = <T extends {}, U extends keyof T>(loader: (x?: string) => Promise<T>) =>
3030- new Proxy({} as unknown as T, {
3131- get: (_target, componentName: string | symbol) => {
3232- if (typeof componentName === "string") {
3333- return lazy(() =>
3434- loader(componentName).then((x) => ({
3535- default: x[componentName as U] as any as React.ComponentType<any>,
3636- })),
3737- );
3838- }
3939- },
4040- });