#[cfg(feature = "ssr")]
use crate::AppError;
use leptos::prelude::*;
use partial_struct::Partial;
use serde::{Deserialize, Serialize};
use crate::{
Datetime, RecordId,
session::get_user,
user::{AdapterUser, DeliveryDetails},
};
#[cfg(feature = "ssr")]
use crate::db_init;
use crate::{
cart::cart::{CartItemWithProduct, ProductMini, SHIPPING_COST},
product::product::get_product_from_id,
};
use crate::payments::payment::Payment;
#[derive(Debug, Clone, Serialize, Deserialize, Partial, PartialEq)]
#[partial(
"OrderCreate",
derive(PartialEq, Clone, Debug, Serialize, Deserialize),
omit(id, user_full, payment)
)]
#[partial(
"OrderRow",
derive(PartialEq, Clone, Debug, Serialize, Deserialize),
omit(user_full, delivery_details)
)]
pub struct OrderFull {
pub id: RecordId,
pub client_received: bool,
pub courier: String,
pub created_at: Datetime,
pub done: bool,
pub items: Vec<OrderItem>,
pub paid: bool,
pub shipped: bool,
pub total: String,
pub tracking_number: String,
pub user: RecordId,
pub user_full: Option<AdapterUser>,
pub delivery_details: Option<DeliveryDetails>,
pub payment: Option<Payment>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OrderItem {
pub date_added: Datetime,
pub name: String,
pub price: f64,
pub product: Option<RecordId>,
pub variant: String,
}
#[component]
pub fn OrderItemView(item: OrderItem) -> impl IntoView {
let models_res = LocalResource::new(move || get_product_from_id(item.product.clone()));
move || {
let name = item.name.clone();
let product = models_res.get();
let product = match product {
Some(Ok(p)) => p,
_ => return view! { <div>"Loading..."</div> }.into_any(),
};
view! {
<div class="flex justify-between py-2 border-b border-neutral-200 dark:border-neutral-700">
<Transition>
<ProductMini
background=product.colour.clone()
brand_name=product.brand_name.clone()
model_name=product.model_name.clone()
product_name=product.product_name.clone()
product_code=product.code.clone()
product_variant=name.clone()
/>
</Transition>
</div>
}.into_any()
}
}
impl OrderFull {
pub fn order_ref(&self) -> String {
self.id.key().to_string()
}
pub fn format_created_at(&self) -> String {
"todo".to_string()
}
pub fn created_at_ago(&self) -> String {
"todo".to_string()
}
pub fn format_total(&self) -> String {
format!("R {}", self.total)
}
#[cfg(feature = "ssr")]
pub async fn create_from_cart() -> Result<RecordId, AppError> {
use crate::order::order_model::OrderItem;
let user = get_user().await?;
let db = db_init().await?;
println!("Creating order for user: {:?}", user);
let cart_items: Vec<OrderItem> = db
.query("SELECT * FROM cart_item WHERE user = $user;")
.bind(("user", user.id.clone()))
.await?
.take(0)?;
println!("Cart items: {:?}", cart_items);
if cart_items.is_empty() {
return Err(AppError::new("Cart is empty"));
}
let items_total: f64 = cart_items.iter().map(|i| i.price).sum();
let total_with_shipping = items_total + SHIPPING_COST;
let delivery_details: DeliveryDetails = user.clone().into();
let neworder: OrderCreate = OrderCreate {
client_received: false,
courier: "no courier".to_string(),
created_at: surrealdb::Datetime::from(chrono::Utc::now()),
done: false,
paid: false,
shipped: false,
items: cart_items,
total: total_with_shipping.to_string(),
tracking_number: "no Tracking Number".to_string(),
user: user.id.clone(),
delivery_details: Some(delivery_details),
};
let mut result = db
.query("CREATE order CONTENT $order;")
.bind(("order", neworder))
.await?;
let created_order: Option<OrderRow> = result.take(0)?;
let order_id = match created_order {
Some(order) => order.id,
None => return Err(AppError::new("Failed to create order")),
};
db.query("DELETE cart_item WHERE user = $user")
.bind(("user", user.id))
.await?;
Ok(order_id)
}
}
#[server]
pub async fn create_order_from_cart() -> Result<RecordId, ServerFnError> {
let output = OrderFull::create_from_cart().await?;
Ok(output)
}