tinkr 0.0.43

Tinkr is a web framework for quickly building full-stack web applications with Leptos.
Documentation
use crate::{AppError, Datetime, RecordId};
use leptos::prelude::*;

use partial_struct::Partial;
use serde::{Deserialize, Serialize};

#[cfg(feature = "ssr")]
use crate::db_init;

#[derive(Debug, Clone, Serialize, Deserialize, Partial)]
#[partial(
    "ProductDetail",
    derive(Debug, Serialize, Deserialize, Clone),
    omit(created_at, description, long_code, product_type, updated_at)
)]
pub struct ProductDetailFull {
    pub id: RecordId,
    pub code: String,
    pub brand_name: String,
    pub model_name: String,
    pub product_name: String,
    pub colour: String,

    pub created_at: Datetime,
    pub description: String,
    pub long_code: String,
    #[serde(rename = "type")]
    pub product_type: String,
    pub updated_at: Datetime,
}

#[server]
pub async fn get_product_from_id(
    product_id: Option<RecordId>,
) -> Result<ProductDetailFull, AppError> {
    let db = db_init().await?;

    let product_id = match product_id {
        Some(id) => id,
        None => return Err(AppError::new("Product ID not provided")),
    };

    let product: Option<ProductDetailFull> = db
        .query("SELECT * FROM product WHERE id = $product_id;")
        .bind(("product_id", product_id))
        .await?
        .take(0)?;

    match product {
        Some(p) => Ok(p),
        None => Err(AppError::new("Product not found")),
    }
}

#[component]
pub fn ProductDetailView(product: ProductDetailFull) -> impl IntoView {
    view! {
        <div class="p-4 border border-neutral-200 dark:border-neutral-700 rounded-lg">
            <h2 class="text-xl font-bold mb-2">{product.product_name.clone()}</h2>
            <p class="text-neutral-600 dark:text-neutral-400">
                {format!("Brand: {}", product.brand_name)}
            </p>
            <p class="text-neutral-600 dark:text-neutral-400">
                {format!("Model: {}", product.model_name)}
            </p>
            <p class="text-neutral-600 dark:text-neutral-400">
                {format!("Colour: {}", product.colour)}
            </p>
            <p class="text-neutral-600 dark:text-neutral-400">
                {format!("Code: {}", product.code)}
            </p>
            <p class="text-neutral-600 dark:text-neutral-400 mt-2">{product.description.clone()}</p>
        </div>
    }
}