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 dioxus_router::Link;
use oparl_types::OrganizationUrl;

use crate::{
    client::{get_body, get_meetings, get_organization},
    components::{MeetingList, OrganizationMembership},
    route::{Route, UrlEncoded},
};

#[derive(Debug, Clone, PartialEq, Props)]
pub struct OrganizationProps {
    organization_url: UrlEncoded<OrganizationUrl>,
}

struct OrganizationData {
    organization: oparl_types::Organization,
    meetings: Vec<oparl_types::Meeting>,
    body: oparl_types::Body,
}

impl OrganizationData {
    async fn get(organization_url: &OrganizationUrl) -> Result<Self, String> {
        let organization = get_organization(organization_url).await?;
        let meetings = if let Some(meeting_url) = organization.meeting.as_ref() {
            get_meetings(meeting_url).await?.data
        } else {
            Vec::new()
        };

        let body = get_body(organization.body.as_ref().unwrap()).await?;
        Ok(Self {
            organization,
            meetings,
            body,
        })
    }
}

#[component]
pub fn Organization(props: OrganizationProps) -> Element {
    let organization_url = use_signal(|| props.organization_url.get_inner().unwrap().clone());
    let data =
        { use_resource(move || async move { OrganizationData::get(&organization_url()).await }) };

    rsx! {
        match &*data.read_unchecked() {
            Some(Ok(data)) => {
                let organization_label = if let Some(name) = &data.organization.name {
                    t!("organization-label", name: name.as_str())
                } else {
                    t!("organization-unknown-label")
                };
                rsx! {
                    dioxus::document::Title { "{organization_label}" }
                    h1 {
                        "{organization_label}"
                    }

                    Link {
                        to: Route::Body{body_url: UrlEncoded::from(data.body.id.clone())},
                        { t!("body-label", name: data.body.name.as_str()) }
                    }

                    MeetingList {
                        meetings: data.meetings.clone()
                    }

                    div {
                        class: "card",

                        div {
                            class: "header",

                            h2 { { t!("members") } }
                        }

                        div {
                            class: "content",

                            ul {
                                class: "sectional",
                                style: "list-style-type: '🧑 '; padding-left: 1.5em;",

                                for membership_url in &data.organization.membership {
                                    li {
                                        key: "{membership_url}",
                                        OrganizationMembership {
                                            membership_url: membership_url.clone()
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            Some(Err(e)) => rsx! { p { { t!("loading-organization-failed", error: e.to_string()) } } },
            None => rsx! { p { { t!("loading") } } }
        }
    }
}