history-init

This commit is contained in:
Lheorvine 2025-05-25 16:54:16 +02:00
parent b7f3a43495
commit 1f414d0a70
6 changed files with 125 additions and 36 deletions

View file

@ -13,6 +13,7 @@ use sqlx::FromRow;
use actix_web::http::header; use actix_web::http::header;
use sqlx::Row; use sqlx::Row;
use bigdecimal::FromPrimitive; use bigdecimal::FromPrimitive;
use std::convert::Infallible;
mod auth; mod auth;
@ -360,30 +361,25 @@ async fn checkout(
pool: web::Data<sqlx::PgPool>, pool: web::Data<sqlx::PgPool>,
data: web::Json<CheckoutRequest>, data: web::Json<CheckoutRequest>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
let token = req.headers().get("Authorization") let user_id = validate_token(get_token(&req)).await?;
.and_then(|h| h.to_str().ok());
let user_id = validate_token(token).await?; let mut transaction = pool.begin().await
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
let mut transaction = pool.begin().await.map_err(|e| {
actix_web::error::ErrorInternalServerError(e)
})?;
let total_bigdec = BigDecimal::from_f64(data.total)
.ok_or_else(|| actix_web::error::ErrorBadRequest("Invalid total value"))?;
// 1. Utwórz zamówienie
let order_id = sqlx::query!( let order_id = sqlx::query!(
"INSERT INTO zamowienia (user_id, suma_totalna) "INSERT INTO zamowienia (user_id, suma_totalna)
VALUES ($1, $2) RETURNING id", VALUES ($1, $2) RETURNING id",
user_id, user_id,
total_bigdec BigDecimal::from_f64(data.total).ok_or_else(||
actix_web::error::ErrorBadRequest("Invalid total value"))?
) )
.fetch_one(&mut *transaction) .fetch_one(&mut *transaction)
.await .await
.map_err(|e| actix_web::error::ErrorInternalServerError(e))? .map_err(|e| actix_web::error::ErrorInternalServerError(e))?
.id; .id;
// Dodaj pozycje zamówienia // 2. Dodaj pozycje zamówienia
for item in &data.items { for item in &data.items {
let book = sqlx::query!( let book = sqlx::query!(
"SELECT cena FROM ksiazki WHERE id = $1", "SELECT cena FROM ksiazki WHERE id = $1",
@ -406,11 +402,19 @@ async fn checkout(
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?; .map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
} }
transaction.commit().await.map_err(|e| { // 3. Wyczyść koszyk
actix_web::error::ErrorInternalServerError(e) sqlx::query!(
})?; "DELETE FROM koszyk WHERE user_id = $1",
user_id
)
.execute(&mut *transaction)
.await
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
Ok(HttpResponse::Ok().json(json!({"status": "success", "order_id": order_id}))) transaction.commit().await
.map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
Ok(HttpResponse::Ok().json(json!({"status": "success"})))
} }
#[actix_web::main] #[actix_web::main]

View file

@ -15,6 +15,11 @@
<main class="container py-5"> <main class="container py-5">
<h2 class="neon-title mb-4">Twój koszyk</h2> <h2 class="neon-title mb-4">Twój koszyk</h2>
<div id="cart-items" class="row g-4"></div> <div id="cart-items" class="row g-4"></div>
<div class="text-center mt-5">
<button id="checkoutBtn" class="btn btn-gothic btn-lg">
<i class="bi bi-wallet2"></i> Złóż zamówienie
</button>
</div>
</main> </main>
<script src="/js/cart.js"></script> <script src="/js/cart.js"></script>
</body> </body>

View file

@ -234,6 +234,18 @@ footer a {
} }
} }
.btn-outline-gothic {
border: 2px solid #0ff;
color: #0ff;
transition: all 0.3s ease;
}
.btn-outline-gothic:hover {
background-color: #0ff;
color: #000;
box-shadow: 0 0 15px #0ff;
}
.neon-title { .neon-title {
color: #0ff; color: #0ff;
text-shadow: 0 0 10px rgba(0, 255, 255, 0.5); text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);

View file

@ -89,3 +89,47 @@ document.addEventListener('DOMContentLoaded', async () => {
alert('Nie udało się załadować koszyka'); alert('Nie udało się załadować koszyka');
} }
}); });
document.getElementById('checkoutBtn').addEventListener('click', async () => {
try {
const token = localStorage.getItem('token');
if (!token) {
window.location.href = '/login.html';
return;
}
// Pobierz aktualną zawartość koszyka
const cartResponse = await fetch('/api/cart', {
headers: { 'Authorization': `Bearer ${token}` }
});
const cartItems = await cartResponse.json();
// Przygotuj dane do zamówienia
const checkoutData = {
items: cartItems.map(item => ({
book_id: item.book_id,
quantity: item.quantity
})),
total: cartItems.reduce((sum, item) =>
sum + (parseFloat(item.cena) * item.quantity), 0)
};
// Wyślij zamówienie
const response = await fetch('/api/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(checkoutData)
});
if (!response.ok) throw new Error('Błąd podczas składania zamówienia');
window.location.href = '/thankyou.html';
} catch (error) {
console.error('Error:', error);
alert('Nie udało się złożyć zamówienia: ' + error.message);
}
});

View file

@ -1,31 +1,38 @@
async function loadOrderHistory() { document.addEventListener('DOMContentLoaded', async () => {
try { try {
const response = await fetch('/api/order-history', { const token = localStorage.getItem('token');
headers: getAuthHeaders() if (!token) {
});
if (response.status === 401) {
window.location.href = '/login.html'; window.location.href = '/login.html';
return; return;
} }
const orders = await response.json(); const response = await fetch('/api/order-history', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) throw new Error('Błąd ładowania historii');
const orders = await response.json();
const container = document.getElementById('order-history'); const container = document.getElementById('order-history');
container.innerHTML = orders.map(order => ` container.innerHTML = '';
<div class="card dark-card mb-3">
<div class="card-body"> orders.forEach(order => {
<h5>Zamówienie #${order.id}</h5> const orderDate = new Date(order.data_zamowienia).toLocaleDateString();
<p>Data: ${new Date(order.data_zamowienia).toLocaleDateString()}</p> const orderHTML = `
<p>Status: ${order.status}</p> <div class="card dark-card mb-3">
<p>Suma: ${order.suma_totalna} PLN</p> <div class="card-body">
<h5 class="card-title">Zamówienie #${order.id}</h5>
<p class="card-text">Data: ${orderDate}</p>
<p class="card-text">Suma: ${order.suma_totalna} PLN</p>
<p class="card-text">Status: ${order.status || 'Przyjęto do realizacji'}</p>
</div>
</div> </div>
</div> `;
`).join(''); container.insertAdjacentHTML('beforeend', orderHTML);
});
} catch (error) { } catch (error) {
console.error('Error:', error); console.error('Error:', error);
alert('Nie udało się załadować historii zamówień');
} }
} });
document.addEventListener('DOMContentLoaded', loadOrderHistory);

17
static/thankyou.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Podziękowanie - Dark Athenaeum</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/styles.css" rel="stylesheet">
</head>
<body class="dark-theme">
<main class="container py-5 text-center">
<h1 class="neon-title mb-4">Dziękujemy za zakup!</h1>
<p class="inter-font fs-5">Twoje zamówienie zostało pomyślnie zrealizowane.</p>
<a href="/profile.html" class="btn btn-gothic">Zobacz historię zamówień</a>
<a href="/" class="btn btn-outline-gothic ms-2">Strona główna</a>
</main>
</body>
</html>