pib-viewer 0.8.0

A viewer for public governmental data served over OParl
// SPDX-FileCopyrightText: Politik im Blick developers
// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
//
// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2

use dioxus::{
    hooks::{use_resource, use_signal},
    prelude::{Props, component, dioxus_elements, rsx},
    signals::ReadableExt as _,
};
use dioxus_core::Element;
use dioxus_i18n::t;
use oparl_types::{BodyListUrl, SystemUrl};

use crate::{components::BodyList, route::UrlEncoded};

#[derive(Debug, Clone, PartialEq, Props)]
pub struct OParlSystemProps {
    system_url: UrlEncoded<SystemUrl>,
}

async fn get_system(system_url: &SystemUrl) -> Result<oparl_types::System, String> {
    let response = reqwest::get(format!("{system_url}"))
        .await
        .map_err(|e| format!("{e}"))?;
    response
        .json::<oparl_types::System>()
        .await
        .map_err(|e| format!("{e}"))
}

async fn get_bodies(
    body_list_url: &BodyListUrl,
) -> Result<oparl_types::DataListPage<oparl_types::Body>, String> {
    let response = reqwest::get(format!("{body_list_url}"))
        .await
        .map_err(|e| format!("{e}"))?;
    response
        .json::<oparl_types::DataListPage<oparl_types::Body>>()
        .await
        .map_err(|e| format!("{e}"))
}

#[derive(Debug, Clone, PartialEq)]
struct OParlSystemData {
    system: oparl_types::System,
    bodies: Vec<oparl_types::Body>,
}

impl OParlSystemData {
    async fn get(system_url: &SystemUrl) -> Result<Self, String> {
        let system = get_system(system_url).await?;
        let bodies = get_bodies(&system.body).await?;
        Ok(Self {
            system,
            bodies: bodies.data,
        })
    }
}

#[component]
pub fn OParlSystem(props: OParlSystemProps) -> Element {
    let system_url = use_signal(|| props.system_url.get_inner().unwrap().clone());
    let data = { use_resource(move || async move { OParlSystemData::get(&system_url()).await }) };

    rsx! {
        { t!("oparl-system-url", url: system_url.to_string()) }

        match &*data.read_unchecked() {
            Some(Ok(data)) => {
                let system_name = data.system.name.clone().unwrap_or(t!("unknown-system").into());
                rsx! {
                    dioxus::document::Title { "{system_name}" }
                    h1 {
                        "{system_name}"
                    }
                    BodyList {
                        bodies: data.bodies.clone(),
                    }
                }
            },
            Some(Err(e)) => rsx! {
                dioxus::document::Title { { t!("loading-failed") } },
                p { { t!("loading-system-failed", error: e.to_string()) } }
            },
            None =>  rsx! {
                dioxus::document::Title { { t!("loading") } },
                p { { t!("loading") } }
            }
        }
    }
}