Skip to content

Commit

Permalink
More data in example
Browse files Browse the repository at this point in the history
  • Loading branch information
bloodyowl committed Apr 3, 2024
1 parent 31621fd commit 489da55
Show file tree
Hide file tree
Showing 8 changed files with 515 additions and 12 deletions.
51 changes: 44 additions & 7 deletions example/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Option } from "@swan-io/boxed";
import { useState } from "react";
import { useQuery } from "../../src";
import { graphql } from "../gql";
import { FilmDetails } from "./FilmDetails";
import { FilmList } from "./FilmList";

const allFilmsQuery = graphql(`
const AllFilmsQuery = graphql(`
query allFilmsWithVariablesQuery($first: Int!, $after: String) {
allFilms(first: $first, after: $after) {
...FilmsConnection
Expand All @@ -12,8 +14,15 @@ const allFilmsQuery = graphql(`
`);

export const App = () => {
const [optimize, setOptimize] = useState(false);
const [after, setAfter] = useState<string | null>(null);
const [data, { isLoading }] = useQuery(allFilmsQuery, { first: 3, after });
const [activeFilm, setActiveFilm] = useState<Option<string>>(Option.None());

const [data, { isLoading }] = useQuery(
AllFilmsQuery,
{ first: 3, after },
{ optimize },
);

return (
<div className="App">
Expand All @@ -28,11 +37,39 @@ export const App = () => {
return <div>No films</div>;
}
return (
<FilmList
films={allFilms}
onNextPage={setAfter}
isLoadingMore={isLoading}
/>
<div className="Main">
<div className="Sidebar">
<label>
<input
type="checkbox"
checked={optimize}
onChange={() => setOptimize((x) => !x)}
/>
Optimize
</label>
<FilmList
films={allFilms}
onNextPage={setAfter}
isLoadingMore={isLoading}
activeFilm={activeFilm}
onPressFilm={(filmId: string) =>
setActiveFilm(Option.Some(filmId))
}
/>
</div>
<div className="Contents">
{activeFilm.match({
None: () => <div>No film selected</div>,
Some: (filmId) => (
<FilmDetails
filmId={filmId}
key={filmId}
optimize={optimize}
/>
),
})}
</div>
</div>
);
},
}),
Expand Down
16 changes: 13 additions & 3 deletions example/components/Film.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@ export const FilmFragment = graphql(`
}
`);

export const Film = (props: { film: FragmentType<typeof FilmFragment> }) => {
const film = useFragment(FilmFragment, props.film);
type Props = {
film: FragmentType<typeof FilmFragment>;
isActive: boolean;
onPress: (filmId: string) => void;
};

export const Film = ({ film: data, isActive, onPress }: Props) => {
const film = useFragment(FilmFragment, data);
return (
<div>
<div
className="Film"
data-active={isActive}
onClick={() => onPress(film.id)}
>
<h3>{film.title}</h3>
<p>{film.releaseDate}</p>
</div>
Expand Down
65 changes: 65 additions & 0 deletions example/components/FilmCharacterList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useForwardPagination } from "../../src";
import { FragmentType, graphql, useFragment } from "../gql";

export const FilmCharactersConnectionFragment = graphql(`
fragment FilmCharactersConnection on FilmCharactersConnection {
edges {
node {
id
name
}
}
pageInfo {
hasNextPage
endCursor
}
}
`);

type Props = {
characters: FragmentType<typeof FilmCharactersConnectionFragment>;
onNextPage: (cursor: string | null) => void;
isLoadingMore: boolean;
};

export const FilmCharacterList = ({
characters,
onNextPage,
isLoadingMore,
}: Props) => {
const connection = useForwardPagination(
useFragment(FilmCharactersConnectionFragment, characters),
);

if (connection.edges == null) {
return null;
}

return (
<>
<ul>
{connection.edges.map((edge) => {
if (edge == null) {
return null;
}
const node = edge.node;
if (node == null) {
return null;
}
return <li key={node.id}>{node.name}</li>;
})}
</ul>

{isLoadingMore ? <div>Loading more</div> : null}

{connection.pageInfo.hasNextPage ? (
<button
onClick={() => onNextPage(connection.pageInfo.endCursor ?? null)}
disabled={isLoadingMore}
>
Load more
</button>
) : null}
</>
);
};
76 changes: 76 additions & 0 deletions example/components/FilmDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useState } from "react";
import { useQuery } from "../../src";
import { graphql } from "../gql";
import { FilmCharacterList } from "./FilmCharacterList";

export const FilmDetailsQuery = graphql(`
query FilmDetails($filmId: ID!, $first: Int!, $after: String) {
film(id: $filmId) {
id
title
director
openingCrawl
characterConnection(first: $first, after: $after) {
...FilmCharactersConnection
}
releaseDate
}
}
`);

type Props = {
filmId: string;
optimize: boolean;
};

export const FilmDetails = ({ filmId, optimize }: Props) => {
const [after, setAfter] = useState<string | null>(null);
const [data, { isLoading }] = useQuery(
FilmDetailsQuery,
{
filmId,
first: 5,
after,
},
{ optimize },
);

return (
<div className="FilmDetails" style={{ opacity: isLoading ? 0.5 : 1 }}>
{data.match({
NotAsked: () => null,
Loading: () => <div>Loading ...</div>,
Done: (result) =>
result.match({
Error: () => <div>An error occured</div>,
Ok: ({ film }) => {
if (film == null) {
return <div>No film</div>;
}
return (
<>
<h1>{film.title}</h1>
<div>Director: {film.director}</div>
<div>Release date: {film.releaseDate}</div>
<div>
Opening crawl:
<pre>{film.openingCrawl}</pre>
</div>
{film.characterConnection != null ? (
<>
<h2>Characters</h2>
<FilmCharacterList
characters={film.characterConnection}
onNextPage={setAfter}
isLoadingMore={isLoading}
/>
</>
) : null}
</>
);
},
}),
})}
</div>
);
};
22 changes: 20 additions & 2 deletions example/components/FilmList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Option } from "@swan-io/boxed";
import { useForwardPagination } from "../../src";
import { FragmentType, graphql, useFragment } from "../gql";
import { Film } from "./Film";
Expand All @@ -21,9 +22,17 @@ type Props = {
films: FragmentType<typeof FilmsConnectionFragment>;
onNextPage: (cursor: string | null) => void;
isLoadingMore: boolean;
activeFilm: Option<string>;
onPressFilm: (filmId: string) => void;
};

export const FilmList = ({ films, onNextPage, isLoadingMore }: Props) => {
export const FilmList = ({
films,
onNextPage,
activeFilm,
onPressFilm,
isLoadingMore,
}: Props) => {
const connection = useForwardPagination(
useFragment(FilmsConnectionFragment, films),
);
Expand All @@ -42,7 +51,16 @@ export const FilmList = ({ films, onNextPage, isLoadingMore }: Props) => {
if (node == null) {
return null;
}
return <Film film={node} key={node.id} />;
return (
<Film
film={node}
key={node.id}
isActive={activeFilm
.map((id) => node.id === id)
.getWithDefault(false)}
onPress={onPressFilm}
/>
);
})}

{isLoadingMore ? <div>Loading more</div> : null}
Expand Down
16 changes: 16 additions & 0 deletions example/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const documents = {
types.AllFilmsWithVariablesQueryDocument,
"\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n":
types.FilmItemFragmentDoc,
"\n fragment FilmCharactersConnection on FilmCharactersConnection {\n edges {\n node {\n id\n name\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n":
types.FilmCharactersConnectionFragmentDoc,
"\n query FilmDetails($filmId: ID!, $first: Int!, $after: String) {\n film(id: $filmId) {\n id\n title\n director\n openingCrawl\n characterConnection(first: $first, after: $after) {\n ...FilmCharactersConnection\n }\n releaseDate\n }\n }\n":
types.FilmDetailsDocument,
"\n fragment FilmsConnection on FilmsConnection {\n edges {\n node {\n id\n ...FilmItem\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n":
types.FilmsConnectionFragmentDoc,
};
Expand Down Expand Up @@ -47,6 +51,18 @@ export function graphql(
export function graphql(
source: "\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n",
): (typeof documents)["\n fragment FilmItem on Film {\n id\n title\n releaseDate\n producers\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment FilmCharactersConnection on FilmCharactersConnection {\n edges {\n node {\n id\n name\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n",
): (typeof documents)["\n fragment FilmCharactersConnection on FilmCharactersConnection {\n edges {\n node {\n id\n name\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query FilmDetails($filmId: ID!, $first: Int!, $after: String) {\n film(id: $filmId) {\n id\n title\n director\n openingCrawl\n characterConnection(first: $first, after: $after) {\n ...FilmCharactersConnection\n }\n releaseDate\n }\n }\n",
): (typeof documents)["\n query FilmDetails($filmId: ID!, $first: Int!, $after: String) {\n film(id: $filmId) {\n id\n title\n director\n openingCrawl\n characterConnection(first: $first, after: $after) {\n ...FilmCharactersConnection\n }\n releaseDate\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
Loading

0 comments on commit 489da55

Please sign in to comment.