use super::id::PageId;
use crate::context::{PageDataContextProvider, ServerContext, ServerContextProvider};
use crate::routing::{ErrorRouter, Params};
use crate::{
app::router::PageRouterWrapper,
components::error::{ErrorPage, NotFoundPage},
};
use http::{StatusCode, Uri};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use yew::Suspense;
use yew::{function_component, html::ChildrenProps, BaseComponent, Html, Properties};
#[derive(Clone, PartialEq, Properties)]
pub struct PageProps {
pub page_data: PageData,
pub router: PageRouterWrapper,
pub error_router: Arc<ErrorRouter>,
pub server_context: ServerContext,
}
#[function_component]
pub fn Page<ROOT>(props: &PageProps) -> Html
where
ROOT: BaseComponent<Properties = ChildrenProps>,
{
let props = props.clone();
yew::html! {
<PageDataContextProvider data={props.page_data.clone()}>
<ServerContextProvider server_context={props.server_context.clone()}>
<PageRouter<ROOT> ..props/>
</ServerContextProvider>
</PageDataContextProvider>
}
}
#[doc(hidden)]
#[function_component]
pub fn PageRouter<ROOT>(props: &PageProps) -> Html
where
ROOT: BaseComponent<Properties = ChildrenProps>,
{
let router = &props.router;
let error_router = &props.error_router;
let page_data = &props.page_data;
if let Some(error) = &page_data.error {
return match error_router.find(&error.status) {
Some(comp) => {
let props = page_data.props.clone();
yew::html! {
<Suspense>
{comp.render_with_props(props)}
</Suspense>
}
}
None => {
log::warn!("fallback error page was not registered");
yew::html! {
<ErrorPage status={error.status} message={error.message.clone()} />
}
}
};
}
match router.find_by_id(&page_data.id) {
Some(route) => {
let props = page_data.props.clone();
yew::html! {
<ROOT>
<Suspense>
{route.render(props)}
</Suspense>
</ROOT>
}
}
None => match error_router.find(&StatusCode::NOT_FOUND) {
Some(comp) => {
let props = page_data.props.clone();
yew::html! {
<Suspense>
{comp.render_with_props(props)}
</Suspense>
}
}
None => {
log::warn!("404 error page was not registered");
yew::html! {
<NotFoundPage />
}
}
},
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Properties)]
pub struct PageError {
#[serde(with = "crate::web::serde::status_code")]
pub status: StatusCode,
pub message: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PageData {
pub id: PageId,
#[serde(with = "crate::web::serde::uri")]
pub uri: Uri,
pub error: Option<PageError>,
pub props: serde_json::Value,
pub params: Params,
}