Skip to content

Commit

Permalink
Update demo
Browse files Browse the repository at this point in the history
  • Loading branch information
kirillku committed Jun 29, 2021
1 parent 63322bc commit ab997d9
Showing 1 changed file with 130 additions and 30 deletions.
160 changes: 130 additions & 30 deletions stories/Demo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { combine, createEffect, forward, restore } from "effector";
import {
combine,
createEffect,
createEvent,
createStore,
forward,
guard,
restore,
sample,
} from "effector";
import { useList, useStore } from "effector-react";
import * as React from "react";
import { createRoute, Link, Switch } from "../src";
import { $search, createRoute, CurrentRoute, Link, Switch } from "../src";

const HomeRoute = createRoute("/");
const AboutRoute = createRoute("/about");
Expand All @@ -11,17 +20,52 @@ const UserRoute = createRoute<"userSlug">(`${UsersRoute.path}/:userSlug`);
UsersRoute.match.watch((a) => console.log("Users", a));
UserRoute.match.watch((a) => console.log("User", a));

const USERS = [
{ id: "1", slug: "boris", name: "Boris" },
{ id: "2", slug: "john", name: "John" },
type User = {
id: string;
slug: string;
name: string;
age: number;
};

const USERS: User[] = [
{ id: "1", slug: "boris", name: "Boris", age: 5 },
{ id: "2", slug: "john", name: "John", age: 3 },
];

const wait = (ms = 1000) => new Promise((resolve) => setTimeout(resolve, ms));

const loadUsersFx = createEffect(() => wait().then(() => USERS));
const $users = restore(loadUsersFx.doneData, []);
const $status = createStore("idle")
.on(loadUsersFx, () => "loading")
.on(loadUsersFx.done, () => "success")
.on(loadUsersFx.fail, () => "error");

guard({
source: UsersRoute.open,
filter: $status.map((status) => status === "idle"),
target: loadUsersFx,
});

const getRandomUserSlug = (users: User[]): string =>
users[Math.floor(Math.random() * users.length)].slug;

forward({ from: UsersRoute.open, to: loadUsersFx });
const navigateToRandomUser = createEvent();

guard({
source: UserRoute.open,
filter: (match) => match.params.userSlug === "random",
target: navigateToRandomUser,
});

sample({
clock: navigateToRandomUser,
source: $users,
fn: (users) => ({
params: { userSlug: getRandomUserSlug(users) },
}),
target: UserRoute.navigate,
});

const $selectedUser = combine(
$users,
Expand All @@ -30,51 +74,107 @@ const $selectedUser = combine(
(match && users.find((user) => user.slug === match.params.userSlug)) || null
);

const styles = {
main: {
fontFamily: "Helvetica",
background: "wheat",
minHeight: "50vh",
},
nav: {
display: "flex",
gap: 10,
},
const UserNotFoundPage: React.FC = () => {
const userSlug = useStore(
UserRoute.match.map((match) => match && match.params.userSlug)
);

return (
<>
<h2>404</h2>
<p>
User <strong>{userSlug}</strong> not found
</p>
</>
);
};

const UserProfile: React.FC = () => {
const user = useStore($selectedUser);

if (!user) {
return <UserNotFoundPage />;
}

return (
user && (
<>
<h1>Info</h1>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<img
src={`https://loremflickr.com/320/240?lock=${user.id}`}
alt={user.name}
/>
)
</>
);
};

const UsersFilters: React.FC = () => {
const search = useStore($search);
const searchParams = new URLSearchParams(search);

const q = searchParams.get("q") || "";
const handleChange: React.InputHTMLAttributes<
HTMLInputElement
>["onChange"] = (event) => {
searchParams.set("q", event.target.value);
const search = searchParams.toString();
CurrentRoute.navigate({ search });
};

return <input placeholder="filter users" value={q} onChange={handleChange} />;
};

const $filteredUsers = combine(
$users,
$search.map((search) => new URLSearchParams(search).get("q") || null),
(users, q) =>
q
? users.filter((user) =>
user.name.toLowerCase().includes(q.toLowerCase())
)
: users
);

const Users: React.FC = () => {
const userList = useList($users, (user) => (
const userList = useList($filteredUsers, (user) => (
<li>
<Link to={UserRoute} params={{ userSlug: user.slug }}>
{user.name}
</Link>
</li>
));
const isLoading = useStore(loadUsersFx.pending);
const status = useStore($status);

if (isLoading) {
if (status === "loading") {
return <p>Loading...</p>;
}

if (status === "error") {
return <p>Error</p>;
}

return (
<>
<h2>List of users</h2>
<ul>{userList}</ul>
<UserRoute>
<UserProfile />
</UserRoute>
<Switch>
<UsersRoute exact>
<h2>List of users</h2>
<p>
<UsersFilters />
</p>
<ul>
{userList}
<li>
<Link to={UserRoute} params={{ userSlug: "random" }}>
Random
</Link>
</li>
</ul>
</UsersRoute>
<UserRoute>
<UserProfile />
</UserRoute>
</Switch>
</>
);
};
Expand All @@ -86,11 +186,11 @@ const NotFoundPage: React.FC = () => (
</>
);

const Demo: React.FC = () => {
const App: React.FC = () => {
return (
<main style={styles.main}>
<main className="App">
<h1>Effector Easy Router Demo</h1>
<nav style={styles.nav}>
<nav className="Nav">
<Link to={HomeRoute}>Home</Link>
<Link to={AboutRoute}>About</Link>
<Link to={UsersRoute}>Users</Link>
Expand All @@ -114,4 +214,4 @@ const Demo: React.FC = () => {
);
};

export default Demo;
export default App;

0 comments on commit ab997d9

Please sign in to comment.