//! Admin Leptos application root and router. use leptos::prelude::*; use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context}; use leptos_router::components::Router; use crate::routes::AdminRoutes; /// Application state for the admin app. /// /// Note: We intentionally don't derive `FromRef` because both pools are /// the same type (`PgPool`), which would cause a conflicting implementation. /// Instead, handlers should use Extension extractors for the pools. #[cfg(feature = "ssr")] #[derive(Clone)] pub struct AdminAppState { /// The primary database pool for this admin instance. /// For Owner App: chattyness_owner pool (no RLS) /// For Admin App: chattyness_app pool (RLS enforced) pub pool: sqlx::PgPool, pub leptos_options: LeptosOptions, } #[cfg(feature = "ssr")] impl axum::extract::FromRef for LeptosOptions { fn from_ref(state: &AdminAppState) -> Self { state.leptos_options.clone() } } #[cfg(feature = "ssr")] impl axum::extract::FromRef for sqlx::PgPool { fn from_ref(state: &AdminAppState) -> Self { state.pool.clone() } } /// Shell component for SSR. /// /// The `data-app="admin"` attribute tells the WASM hydration script to mount /// AdminApp. pub fn admin_shell(options: LeptosOptions) -> impl IntoView { view! { } } /// Main admin application component. /// /// This wraps `AdminRoutes` with a `Router` for standalone use (e.g., chattyness-owner). /// Routes are nested under `/admin` to match the link paths used in page components. /// For embedding in a combined app (e.g., chattyness-app), use `AdminRoutes` directly. #[component] pub fn AdminApp() -> impl IntoView { // Provide meta context for title and meta tags provide_meta_context(); view! { <Router base="/admin"> <AdminRoutes /> </Router> } }