Router example

This commit is contained in:
Greg Johnston 2022-08-29 08:05:14 -04:00
parent d6c007dcc4
commit 89d30d017c
3 changed files with 140 additions and 50 deletions

View file

@ -2,6 +2,17 @@
<html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z"/>
<style>
a.active {
font-weight: bold;
}
.contact, .contact-list {
border: 1px solid #c0c0c0;
border-radius: 3px;
padding: 1rem;
}
</style>
</head>
<body></body>
</html>

View file

@ -29,17 +29,29 @@ pub struct Contact {
pub async fn get_contacts(search: String) -> Vec<ContactSummary> {
// fake an API call with an artificial delay
delay(Duration::from_millis(100)).await;
vec![ContactSummary {
id: 0,
first_name: "Bill".into(),
last_name: "Smith".into(),
}]
delay(Duration::from_millis(300)).await;
vec![
ContactSummary {
id: 0,
first_name: "Bill".into(),
last_name: "Smith".into(),
},
ContactSummary {
id: 1,
first_name: "Tim".into(),
last_name: "Jones".into(),
},
ContactSummary {
id: 2,
first_name: "Sally".into(),
last_name: "Stevens".into(),
},
]
}
pub async fn get_contact(id: Option<usize>) -> Option<Contact> {
// fake an API call with an artificial delay
delay(Duration::from_millis(350)).await;
delay(Duration::from_millis(500)).await;
match id {
Some(0) => Some(Contact {
id: 0,
@ -53,6 +65,30 @@ pub async fn get_contact(id: Option<usize>) -> Option<Contact> {
email: "bill@smith.com".into(),
phone: "617-121-1221".into(),
}),
Some(1) => Some(Contact {
id: 1,
first_name: "Tim".into(),
last_name: "Jones".into(),
address_1: "56 Main Street".into(),
address_2: "".into(),
city: "Chattanooga".into(),
state: "TN".into(),
zip: "13371".into(),
email: "timjones@lmail.com".into(),
phone: "232-123-1337".into(),
}),
Some(2) => Some(Contact {
id: 2,
first_name: "Sally".into(),
last_name: "Stevens".into(),
address_1: "404 E 123rd St".into(),
address_2: "Apt 7E".into(),
city: "New York".into(),
state: "NY".into(),
zip: "10082".into(),
email: "sally.stevens@wahoo.net".into(),
phone: "242-121-3789".into(),
}),
_ => None,
}
}

View file

@ -13,105 +13,148 @@ use crate::api::{get_contact, get_contacts};
fn contact_list(
cx: Scope,
params: ParamsMap,
params: Memo<ParamsMap>,
location: Location,
) -> Resource<String, Vec<ContactSummary>> {
log::debug!("(contact_list) reloading contact list");
create_resource(cx, location.search, move |s| get_contacts(s.to_string()))
create_resource(cx, location.search, get_contacts)
}
fn contact(
cx: Scope,
params: ParamsMap,
params: Memo<ParamsMap>,
location: Location,
) -> Resource<Option<usize>, Option<Contact>> {
log::debug!("(contact) reloading contact");
create_resource(
cx,
move || {
params
params()
.get("id")
.cloned()
.unwrap_or_default()
.parse::<usize>()
.ok()
},
move |id| get_contact(id),
get_contact,
)
}
pub fn router_example(cx: Scope) -> Element {
view! {
<div>
<nav>
<a href="/">"Contacts"</a>
<a href="/about">"About"</a>
<a href="/settings">"Settings"</a>
</nav>
<main>
<Router
mode=BrowserIntegration {}
base="/"
>
<Routes>
<Router
mode=BrowserIntegration {}
>
<Routes>
<Route path=""
element=move |cx| view! { <Index/> }
>
<Route
path=""
element=move || view! { <ContactList/> }
path="contacts"
element=move |cx| view! { <ContactList/> }
loader=contact_list.into()
>
<Route
path=":id"
loader=contact.into()
element=move || view! { <Contact/> }
element=move |cx| view! { <Contact/> }
/>
<Route
path="about"
loader=contact.into()
element=move |cx| view! { <p class="contact">"Here is your list of contacts"</p> }
/>
<Route
path=""
loader=contact.into()
element=move |cx| view! { <p class="contact">"Select a contact."</p> }
/>
</Route>
<Route
path="about"
element=move || view! { <About/> }
element=move |cx| view! { <About/> }
/>
<Route
path="settings"
element=move || view! { <Settings/> }
element=move |cx| view! { <Settings/> }
/>
</Routes>
</Router>
</main>
</Route>
</Routes>
</Router>
</div>
}
}
#[component]
pub fn ContactList(cx: Scope) -> Vec<Element> {
let contacts = use_loader::<Resource<String, Vec<ContactSummary>>>(cx);
pub fn Index(cx: Scope) -> Vec<Element> {
view! {
<>
<h1>"Contacts"</h1>
<ul>
<For each={move || contacts.read().unwrap_or_default()} key=|contact| contact.id>
{|cx, contact: &ContactSummary| {
view! {
<li><a href=format!("/contacts/{}", contact.id)> {&contact.first_name} " " {&contact.last_name}</a></li>
}
}}
</For>
</ul>
<div><Outlet/></div>
<nav>
<NavLink to="contacts".into()>"Contacts"</NavLink>
<NavLink to="about".into()>"About"</NavLink>
<NavLink to="settings".into()>"Settings"</NavLink>
</nav>
<main><Outlet/></main>
</>
}
}
#[component]
pub fn Contact(cx: Scope) -> Element {
//let contact = use_loader::<Resource<Option<usize>, Option<Contact>>>(cx);
pub fn ContactList(cx: Scope) -> Element {
let contacts = use_loader::<Resource<String, Vec<ContactSummary>>>(cx);
log::debug!(
"[ContactList] before <Suspense/>, use_route(cx).path() is {:?}",
use_route(cx).path()
);
view! {
<pre>"Contact info here"</pre>
<div class="contact-list">
<h1>"Contacts"</h1>
<Link to="about".into()>"About"</Link>
<NavLink to={0.to_string()}>"Link to first contact"</NavLink>
<ul>
<Suspense fallback=move || view! { <p>"Loading contacts..."</p> }>{
move || {
log::debug!("[ContactList] inside <Suspense/>, use_route(cx) is now {:?}", use_route(cx).path());
view! {
<For each={move || contacts.read().unwrap_or_default()} key=|contact| contact.id>
{move |cx, contact: &ContactSummary| {
view! {
<li><NavLink to={contact.id.to_string()}><span>{&contact.first_name} " " {&contact.last_name}</span></NavLink></li>
}
}}
</For>
}
}
}</Suspense>
</ul>
<Outlet/>
</div>
}
}
#[component]
pub fn About(cx: Scope) -> Vec<Element> {
pub fn Contact(cx: Scope) -> Element {
let contact = use_loader::<Resource<Option<usize>, Option<Contact>>>(cx);
view! {
<div class="contact">
<Suspense fallback=move || view! { <p>"Loading..."</p> }>{
move || contact.read().flatten().map(|contact| view! {
<section class="card">
<h1>{contact.first_name} " " {contact.last_name}</h1>
<p>{contact.address_1}<br/>{contact.address_2}</p>
</section>
})
}</Suspense>
</div>
}
}
#[component]
pub fn About(_cx: Scope) -> Vec<Element> {
view! {
<>
<h1>"About"</h1>
@ -121,7 +164,7 @@ pub fn About(cx: Scope) -> Vec<Element> {
}
#[component]
pub fn Settings(cx: Scope) -> Vec<Element> {
pub fn Settings(_cx: Scope) -> Vec<Element> {
view! {
<>
<h1>"Settings"</h1>