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>
}
}