tinkr 0.0.43

Tinkr is a web framework for quickly building full-stack web applications with Leptos.
Documentation
use crate::RecordId;
use crate::components::{Alert, AlertSeverity};
use crate::order::list::OrderSideBarWrapper;
use leptos::prelude::*;
use leptos_router::hooks::use_params_map;

use super::order_details::OrderDetails;
use crate::order::order_model::OrderFull;

#[server]
pub async fn fetch_user_order(order_id: RecordId) -> Result<OrderFull, ServerFnError> {
    let user = crate::session::get_user().await?;

    // // Check if user is admin
    // if user.is_admin != Some(true) {
    //     return Err(ServerFnError::ServerError("Unauthorized".into()));
    // }

    let db = crate::db::db_init().await?;

    if order_id.table().to_string() != "order" {
        return Err(ServerFnError::ServerError("Invalid order ID".into()));
    }

    // Fetch the order (admin can see any order)
    let mut order_req = match user.is_admin {
        Some(true) => {
            db.query(
                r#"
            SELECT *, 
            user.* as user_full, 
            user.* as delivery_details, 
            (SELECT * from only payments WHERE order = $parent.id LIMIT 1) as payment 
            FROM ONLY $order_id
            LIMIT 1;
        "#,
            )
            .bind(("order_id", order_id))
            .await?
        }
        _ => {
            db.query(
                r#"
            SELECT *, 
            user.* as user_full, 
            user.* as delivery_details, 
            (SELECT * from only payments WHERE order = $parent.id LIMIT 1) as payment 
            FROM ONLY $order_id 
            WHERE user = $user_id
            LIMIT 1;
        "#,
            )
            .bind(("order_id", order_id))
            .bind(("user_id", user.id))
            .await?
        }
    };

    let order: Option<OrderFull> = order_req.take(0)?;

    let order: OrderFull = match order {
        Some(o) => o,
        None => return Err(ServerFnError::ServerError("Order not found".into())),
    };

    Ok(order)
}

#[server]
pub async fn fetch_admin_order(order_id: String) -> Result<OrderFull, ServerFnError> {
    let user = crate::session::get_user().await?;

    // Check if user is admin
    if user.is_admin != Some(true) {
        return Err(ServerFnError::ServerError("Unauthorized".into()));
    }

    let db = crate::db::db_init().await?;

    // Fetch the order (admin can see any order)
    let mut order_req = db
        .query("SELECT * FROM type::thing('order', $order_id) FETCH items, user;")
        .bind(("order_id", order_id))
        .await?;

    let orders = order_req.take::<Vec<OrderFull>>(0)?;

    if orders.is_empty() {
        return Err(ServerFnError::ServerError("Order not found".into()));
    }

    Ok(orders[0].clone())
}

#[server]
pub async fn update_order_admin(order: OrderFull) -> Result<(), ServerFnError> {
    let user = crate::session::get_user().await?;

    // Check if user is admin
    if user.is_admin != Some(true) {
        return Err(ServerFnError::ServerError("Unauthorized".into()));
    }

    let db = crate::db::db_init().await?;

    // Update the order
    let _: Option<OrderFull> = db
        .update(("order", order.id.key().to_string()))
        .content(serde_json::json!({
            "courier": order.courier,
            "tracking_number": order.tracking_number,
            "shipped": order.shipped,
            "client_received": order.client_received,
            "done": order.done,
        }))
        .await?;

    Ok(())
}

#[component]
pub fn UserOrderView() -> impl IntoView {
    let params = use_params_map();
    let order_id = move || params.read().get("order_id").unwrap_or_default();

    let order_resource = Resource::new(
        move || {
            let key = order_id();
            let out: RecordId = RecordId::from_table_key("order", &key);
            out
        },
        fetch_user_order,
    );

    view! {
        <Suspense fallback=move || {
            view! {
                <div class="">
                    <div class="text-center text-neutral-500 dark:text-neutral-400">
                        "Loading order..."
                    </div>
                </div>
            }
        }>

            {move || {
                order_resource
                    .get()
                    .map(|order_result| {
                        match order_result {
                            Ok(order) => {
                                view! { <OrderDetails order=order is_admin=false /> }.into_any()
                            }
                            Err(err) => {
                                view! {
                                    <Alert severity=AlertSeverity::Error>
                                        "Error loading order: " {err.to_string()}
                                    </Alert>
                                }
                                    .into_any()
                            }
                        }
                    })
            }}

        </Suspense>
    }
}

#[component]
pub fn OrderUserPage() -> impl IntoView {
    view! {
        <OrderSideBarWrapper>
            <UserOrderView />
        </OrderSideBarWrapper>
    }
}